From 34e491640531bd81a0e2238fd599e1aafe53613e Mon Sep 17 00:00:00 2001 From: Coccinelle Date: Sun, 3 Oct 2010 13:46:58 +0200 Subject: [PATCH] Release coccinelle-0.1 * First public release of the source code: * Features - embeded python scripting - position --- .depend | 44 + Makefile | 399 + Makefile.config | 16 + authors.txt | 39 + bugs.txt | 2 + changes.txt | 18 + cocci.ml | 1413 + cocci.mli | 32 + commitmsg | 6 + commons/.depend | 96 + commons/Makefile | 279 + commons/authors.txt | 5 + commons/backtrace.ml | 40 + commons/backtrace_c.c | 9 + commons/common.ml | 5300 +++ commons/common.mli | 1792 + commons/common_extra.ml | 31 + commons/copyright.txt | 17 + commons/credits.txt | 8 + commons/glimpse.ml | 110 + commons/interfaces.ml | 194 + commons/license.txt | 520 + commons/oarray.ml | 45 + commons/oarray.mli | 28 + commons/oassoc.ml | 40 + commons/oassoc.mli | 17 + commons/oassoc_buffer.ml | 124 + commons/oassoc_buffer.mli | 28 + commons/oassocb.ml | 24 + commons/oassocbdb.ml | 119 + commons/oassocbdb.mli | 25 + commons/oassocdbm.ml | 72 + commons/oassocdbm.mli | 28 + commons/oassoch.ml | 34 + commons/oassocid.ml | 20 + commons/objet.ml | 29 + commons/objet.mli | 18 + commons/ocamlextra/ANSITerminal.ml | 219 + commons/ocamlextra/ANSITerminal.mli | 107 + commons/ocamlextra/dumper.ml | 85 + commons/ocamlextra/dumper.mli | 6 + commons/ocamlextra/dynArray.ml | 448 + commons/ocamlextra/dynArray.mli | 281 + commons/ocamlextra/enum.ml | 376 + commons/ocamlextra/enum.mli | 201 + commons/ocamlextra/mapb.ml | 144 + commons/ocamlextra/parser_combinators.ml | 370 + commons/ocamlextra/parser_combinators.mli | 154 + commons/ocamlextra/setPt.ml | 346 + commons/ocamlextra/setb.ml | 302 + commons/ocamlextra/setb.mli | 159 + commons/ocamlextra/suffix_tree.ml | 318 + commons/ocamlextra/suffix_tree.mli | 90 + commons/ocamlextra/suffix_tree_ext.ml | 335 + commons/ocamlextra/suffix_tree_ext.mli | 98 + commons/ocollection.ml | 107 + commons/ocollection.mli | 34 + commons/ofullcommon.ml | 23 + commons/ograph.ml | 30 + commons/ograph.mli | 21 + commons/ograph2way.ml | 86 + commons/ograph2way.mli | 33 + commons/ograph_extended.ml | 268 + commons/ograph_extended.mli | 73 + commons/osequence.ml | 13 + commons/osequence.mli | 8 + commons/oset.ml | 50 + commons/oset.mli | 28 + commons/osetb.ml | 36 + commons/oseth.ml | 62 + commons/oseti.ml | 35 + commons/osetpt.ml | 33 + commons/seti.ml | 350 + configure | 227 + copyright.txt | 21 + credits.txt | 11 + ctl/.depend | 19 + ctl/Makefile | 95 + ctl/ast_ctl.ml | 98 + ctl/ctl_engine.ml | 2418 ++ ctl/ctl_engine.mli | 64 + ctl/double_negate_ml | 75 + ctl/flag_ctl.ml | 38 + ctl/pretty_print_ctl.ml | 183 + ctl/pretty_print_ctl.mli | 4 + ctl/test_ctl.ml | 302 + ctl/wrapper_ctl.ml | 258 + ctl/wrapper_ctl.mli | 65 + demos/check_region.c | 21 + demos/check_region.cocci | 14 + demos/ctr_unit_test.c | 28 + demos/ctr_unit_test.cocci | 79 + demos/demo_rule9/README | 73 + demos/demo_rule9/g_NCR5380.c | 942 + demos/demo_rule9/g_NCR5380.res | 938 + demos/demo_rule9/nsp_cs.c | 1958 ++ demos/demo_rule9/nsp_cs.res | 1942 ++ demos/demo_rule9/rule9.cocci | 59 + demos/demo_rule9/rule9_1.cocci | 21 + demos/demo_rule9/rule9_2.cocci | 21 + demos/demo_rule9/rule9_3.cocci | 28 + demos/demo_rule9/rule9_4.cocci | 40 + demos/demo_rule9/rule9_5.cocci | 57 + demos/demo_rule9/scsiglue.c | 916 + demos/demo_rule9/scsiglue.res | 901 + demos/demo_rule9/sym53c8xx.c | 14738 ++++++++ demos/demo_rule9/sym53c8xx.res | 14732 ++++++++ demos/foo.c | 8 + demos/foo.cocci | 4 + demos/foobar.c | 13 + demos/foobar.cocci | 14 + demos/headers.cocci | 54 + demos/headers.iso | 6 + demos/headers2.iso | 13 + demos/interprocedural_adhoc.c | 30 + demos/interprocedural_adhoc.cocci | 28 + demos/ioctl_multiple_rules.c | 23 + demos/ioctl_multiple_rules.cocci | 21 + demos/iso-kzalloc.c | 7 + demos/iso-kzalloc.cocci | 10 + demos/itimer.c | 30 + demos/itimer.cocci | 8 + demos/itimer.patch | 36 + demos/itimer.res | 32 + demos/itimerfullfunc.sgrep | 37 + demos/janitorings/ARRAY_SIZE.cocci | 106 + demos/janitorings/BUG_ON.cocci | 18 + demos/janitorings/BUG_ON.sgrep | 3 + demos/janitorings/alloc_page.cocci | 35 + demos/janitorings/bad_zero-orig.cocci | 33 + demos/janitorings/bad_zero.c | 10 + demos/janitorings/bad_zero.cocci | 51 + demos/janitorings/bad_zero_affect.cocci | 9 + demos/janitorings/clear_page.cocci | 32 + demos/janitorings/is_power_of_2.cocci | 93 + demos/janitorings/kcalloc_un.cocci | 9 + demos/janitorings/kzalloc-fix.cocci | 10 + demos/janitorings/kzalloc-orig.cocci | 239 + demos/janitorings/kzalloc.cocci | 273 + demos/janitorings/list_for_each.c | 9 + demos/janitorings/list_for_each.cocci | 43 + demos/janitorings/list_for_each_safe.c | 10 + demos/janitorings/list_for_each_safe.sgrep | 7 + demos/janitorings/netdev_find_allocfunc.c | 4 + demos/janitorings/netdev_find_allocfunc.sgrep | 15 + demos/janitorings/netdev_priv.c | 14 + demos/janitorings/netdev_priv.cocci | 106 + demos/janitorings/netdev_priv2.cocci | 7 + demos/janitorings/netdev_priv_dangerous.sgrep | 55 + demos/janitorings/remove_cast_kmalloc.cocci | 26 + demos/janitorings/set_current_state.cocci | 6 + demos/janitorings/static_initfunc.c | 21 + demos/janitorings/static_initfunc.cocci | 83 + demos/janitorings/string-array-decl-opti.c | 17 + .../janitorings/string-array-decl-opti.cocci | 20 + demos/janitorings/useless_cast.c | 26 + demos/janitorings/useless_cast.cocci | 36 + demos/launch.sh | 8 + demos/manual/already_tagged.c | 12 + demos/manual/already_tagged.cocci | 10 + demos/manual/get_put.c | 9 + demos/manual/get_put.cocci | 8 + demos/manual/get_put_full.c | 9 + demos/manual/get_put_full.cocci | 13 + demos/manual/get_put_ver1.c | 10 + demos/not.c | 9 + demos/not.cocci | 8 + demos/not.res | 9 + demos/posmult.c | 8 + demos/posmult.cocci | 20 + demos/printloc.c | 4 + demos/printloc.cocci | 26 + demos/proc_info.c | 139 + demos/proc_info.cocci | 57 + demos/pycocci.c | 22 + demos/pycocci.cocci | 15 + demos/sgrep/README | 3 + demos/sgrep/a_and_b.c | 26 + demos/sgrep/a_and_b.sgrep | 19 + demos/sgrep/dangerous_GFP_KERNEL.sgrep | 44 + demos/sgrep/dangerous_GFP_KERNEL2.sgrep | 12 + .../sgrep/dangerous_arith_pointer_cast.sgrep | 9 + demos/sgrep/device_id.sgrep | 37 + demos/sgrep/double_cast.sgrep | 9 + demos/sgrep/free.sgrep | 196 + demos/sgrep/intr4.sgrep | 21 + demos/sgrep/null.sgrep | 101 + demos/sgrep/run.sh | 7 + demos/sgrep/simple.c | 18 + demos/sgrep/simple.sgrep | 20 + demos/simple.c | 4 + demos/simple.cocci | 5 + demos/type_fields.c | 17 + demos/type_fields.cocci | 8 + demos/unsigned.cocci | 9 + demos/unsigned.txt | 129 + demos/usb_submit_urb.c | 194 + demos/usb_submit_urb.cocci | 18 + demos/video_usercopy.c | 30 + demos/video_usercopy.cocci | 30 + demos/xxx_info.c | 14 + demos/xxx_info.cocci | 18 + docs/SmPL-ver2-tutorial-ols07.pdf | Bin 0 -> 147073 bytes docs/SmPL-with-grammar-ercim-evos06.pdf | Bin 0 -> 256889 bytes docs/cocci-python.txt | 50 + docs/developer.txt | 134 + docs/graph-module-dependencies.ps | 6475 ++++ docs/manual.tex | 257 + ...ntic-patches-for-collateral-evolutions.ppt | Bin 0 -> 664576 bytes docs/semantic-patches-talk-ols07.odp | Bin 0 -> 52523 bytes docs/semantic-patches-talk-ols07.ppt | Bin 0 -> 659456 bytes emacs/cocci-ediff.el | 878 + emacs/cocci.el | 363 + empty.h | 0 empty.iso | 0 engine/.depend | 141 + engine/Makefile | 123 + engine/asttoctl.ml | 1462 + engine/asttoctl.mli | 9 + engine/asttoctl2.ml | 2222 ++ engine/asttoctl2.mli | 12 + engine/asttomember.ml | 327 + engine/asttomember.mli | 2 + engine/c_vs_c.ml | 291 + engine/c_vs_c.mli | 3 + engine/check_exhaustive_pattern.ml | 183 + engine/check_reachability.ml | 208 + engine/check_reachability.mli | 13 + engine/cocci_vs_c_3.ml | 3419 ++ engine/cocci_vs_c_3.mli | 181 + engine/ctlcocci_integration.ml | 422 + engine/ctlcocci_integration.mli | 25 + engine/ctltotex.ml | 308 + engine/ctltotex.mli | 7 + engine/flag_engine.ml | 34 + engine/isomorphisms_c_c.ml | 72 + engine/lib_engine.ml | 84 + engine/main.ml | 45 + engine/pattern3.ml | 467 + engine/pattern3.mli | 6 + engine/postprocess_transinfo.ml | 105 + engine/postprocess_transinfo.mli | 11 + engine/pretty_print_engine.ml | 161 + engine/pretty_print_engine.mli | 20 + engine/sgrep.ml | 148 + engine/tests/Makefile | 10 + engine/tests/test1 | 278 + engine/tests/test1.tex | 667 + engine/transformation3.ml | 526 + engine/transformation3.mli | 5 + env.csh | 8 + env.sh | 34 + extra/.depend | 17 + extra/Makefile | 72 + extra/c_info.ml | 525 + extra/c_info.mli | 53 + extra/classic_patch.ml | 30 + extra/classic_patch.mli | 9 + extra/kbuild.ml | 229 + extra/kbuild.mli | 28 + extra/maintainers.ml | 106 + extra/maintainers.mli | 25 + flag_cocci.ml | 60 + globals/.depend | 0 globals/Makefile | 70 + globals/config.ml | 8 + globals/flag.ml | 16 + install.txt | 17 + license.txt | 339 + main.ml | 785 + menhirlib/.depend | 10 + menhirlib/Makefile | 85 + menhirlib/convert.ml | 122 + menhirlib/engine.ml | 367 + menhirlib/engineTypes.ml | 331 + menhirlib/infiniteArray.ml | 64 + menhirlib/license.txt | 629 + menhirlib/packedIntArray.ml | 199 + menhirlib/readme.txt | 7 + menhirlib/rowDisplacement.ml | 272 + menhirlib/tableFormat.ml | 134 + menhirlib/tableInterpreter.ml | 186 + parsing_c/.depend | 98 + parsing_c/Makefile | 109 + parsing_c/ast_c.ml | 790 + parsing_c/ast_to_flow.ml | 1320 + parsing_c/ast_to_flow.mli | 22 + parsing_c/authors.txt | 1 + parsing_c/compare_c.ml | 361 + parsing_c/compare_c.mli | 21 + parsing_c/control_flow_c.ml | 362 + parsing_c/control_flow_c.mli | 104 + parsing_c/copyright.txt | 18 + parsing_c/credits.txt | 10 + parsing_c/flag_parsing_c.ml | 116 + parsing_c/lexer_c.mll | 719 + parsing_c/lexer_parser.ml | 111 + parsing_c/lexer_parser.mli | 39 + parsing_c/lib_parsing_c.ml | 143 + parsing_c/license.txt | 341 + parsing_c/parse_c.ml | 1060 + parsing_c/parse_c.mli | 70 + parsing_c/parser_c.mly | 1475 + parsing_c/parsing_hacks.ml | 2149 ++ parsing_c/parsing_hacks.mli | 49 + parsing_c/pretty_print_c.ml | 937 + parsing_c/pretty_print_c.mli | 23 + parsing_c/semantic_c.ml | 1 + parsing_c/test_parsing_c.ml | 277 + parsing_c/test_parsing_c.mli | 21 + parsing_c/token_helpers.ml | 411 + parsing_c/token_helpers.mli | 37 + parsing_c/type_annoter_c.ml | 652 + parsing_c/type_annoter_c.mli | 17 + parsing_c/unparse_c2.ml | 760 + parsing_c/unparse_c2.mli | 7 + parsing_c/unparse_cocci2.ml | 757 + parsing_c/unparse_cocci2.mli | 11 + parsing_c/unparse_hrule.ml | 156 + parsing_c/unparse_hrule.mli | 7 + parsing_c/visitor_c.ml | 1196 + parsing_c/visitor_c.mli | 104 + parsing_cocci/.depend | 180 + parsing_cocci/Makefile | 137 + parsing_cocci/README | 32 + parsing_cocci/arity.ml | 1054 + parsing_cocci/arity.mli | 1 + parsing_cocci/ast0_cocci.ml | 641 + parsing_cocci/ast0_cocci.mli | 449 + parsing_cocci/ast0toast.ml | 916 + parsing_cocci/ast0toast.mli | 26 + parsing_cocci/ast_cocci.ml | 668 + parsing_cocci/ast_cocci.mli | 579 + parsing_cocci/check_meta.ml | 528 + parsing_cocci/check_meta.mli | 6 + parsing_cocci/comm_assoc.ml | 86 + parsing_cocci/comm_assoc.mli | 3 + parsing_cocci/compute_lines.ml | 760 + parsing_cocci/compute_lines.mli | 23 + parsing_cocci/context_neg.ml | 992 + parsing_cocci/context_neg.mli | 8 + parsing_cocci/data.ml | 147 + parsing_cocci/data.mli | 93 + parsing_cocci/disjdistr.ml | 393 + parsing_cocci/disjdistr.mli | 2 + parsing_cocci/flag_parsing_cocci.ml | 29 + parsing_cocci/free_vars.ml | 789 + parsing_cocci/free_vars.mli | 10 + parsing_cocci/function_prototypes.ml | 426 + parsing_cocci/function_prototypes.mli | 5 + parsing_cocci/get_constants.ml | 322 + parsing_cocci/get_constants.mli | 1 + parsing_cocci/get_constants2.ml | 494 + parsing_cocci/get_constants2.mli | 4 + parsing_cocci/index.ml | 220 + parsing_cocci/index.mli | 15 + parsing_cocci/insert_plus.ml | 941 + parsing_cocci/insert_plus.mli | 1 + parsing_cocci/iso_compile.ml | 105 + parsing_cocci/iso_compile.mli | 2 + parsing_cocci/iso_pattern.ml | 2306 ++ parsing_cocci/iso_pattern.mli | 8 + parsing_cocci/lexer_cocci.mll | 700 + parsing_cocci/lexer_script.mll | 42 + parsing_cocci/main.ml | 46 + parsing_cocci/merge.ml | 212 + parsing_cocci/merge.mli | 4 + parsing_cocci/parse_aux.ml | 467 + parsing_cocci/parse_cocci.ml | 1512 + parsing_cocci/parse_cocci.mli | 10 + parsing_cocci/parser_cocci.mly | 1361 + parsing_cocci/parser_cocci_menhir.ml | 28763 ++++++++++++++++ parsing_cocci/parser_cocci_menhir.mli | 180 + parsing_cocci/parser_cocci_menhir.mly | 1765 + parsing_cocci/plus.ml | 227 + parsing_cocci/plus.mli | 3 + parsing_cocci/pretty_print_cocci.ml | 855 + parsing_cocci/pretty_print_cocci.mli | 35 + parsing_cocci/semantic_cocci.ml | 23 + parsing_cocci/simple_assignments.ml | 119 + parsing_cocci/simple_assignments.mli | 1 + parsing_cocci/single_statement.ml | 596 + parsing_cocci/single_statement.mli | 1 + parsing_cocci/test.cocci | 54 + parsing_cocci/test2.cocci | 39 + parsing_cocci/test_exps.ml | 89 + parsing_cocci/test_exps.mli | 3 + parsing_cocci/tests/1.cocci | 20 + parsing_cocci/tests/10.cocci | 11 + parsing_cocci/tests/11.cocci | 102 + parsing_cocci/tests/12.cocci | 41 + parsing_cocci/tests/13.cocci | 10 + parsing_cocci/tests/14.cocci | 36 + parsing_cocci/tests/15.cocci | 17 + parsing_cocci/tests/16.cocci | 8 + parsing_cocci/tests/17.cocci | 17 + parsing_cocci/tests/18.cocci | 25 + parsing_cocci/tests/19.cocci | 39 + parsing_cocci/tests/2.cocci | 29 + parsing_cocci/tests/20.cocci | 20 + parsing_cocci/tests/21.cocci | 41 + parsing_cocci/tests/22.cocci | 42 + parsing_cocci/tests/23.cocci | 31 + parsing_cocci/tests/24.cocci | 0 parsing_cocci/tests/25.cocci | 24 + parsing_cocci/tests/26.cocci | 8 + parsing_cocci/tests/27.cocci | 16 + parsing_cocci/tests/28.cocci | 14 + parsing_cocci/tests/29.cocci | 28 + parsing_cocci/tests/3.cocci | 44 + parsing_cocci/tests/30.cocci | 20 + parsing_cocci/tests/4.cocci | 33 + parsing_cocci/tests/5.cocci | 35 + parsing_cocci/tests/6.cocci | 362 + parsing_cocci/tests/7.cocci | 7 + parsing_cocci/tests/8.cocci | 62 + parsing_cocci/tests/9.cocci | 45 + parsing_cocci/tests/Makefile | 69 + parsing_cocci/tests/problems | 61 + parsing_cocci/top_level.ml | 98 + parsing_cocci/top_level.mli | 1 + parsing_cocci/type_cocci.ml | 117 + parsing_cocci/type_cocci.mli | 29 + parsing_cocci/type_infer.ml | 356 + parsing_cocci/type_infer.mli | 1 + parsing_cocci/unify_ast.ml | 565 + parsing_cocci/unify_ast.mli | 5 + parsing_cocci/unitary_ast0.ml | 284 + parsing_cocci/unitary_ast0.mli | 12 + parsing_cocci/unparse_ast0.ml | 651 + parsing_cocci/unparse_ast0.mli | 13 + parsing_cocci/visitor_ast.ml | 1048 + parsing_cocci/visitor_ast.mli | 114 + parsing_cocci/visitor_ast0.ml | 1028 + parsing_cocci/visitor_ast0.mli | 121 + popl/Makefile | 102 + popl/ast_popl.ml | 38 + popl/asttopopl.ml | 74 + popl/asttopopl.mli | 1 + popl/insert_befaft.ml | 113 + popl/insert_befaft.mli | 1 + popl/insert_quantifiers.ml | 95 + popl/insert_quantifiers.mli | 1 + popl/popl.ml | 39 + popl/popl.mli | 5 + popl/popltoctl.ml | 202 + popl/popltoctl.mli | 5 + popl/pretty_print_popl.ml | 76 + popl/pretty_print_popl.mli | 2 + popl09/.depend | 33 + popl09/Makefile | 101 + popl09/ast_popl.ml | 48 + popl09/asttopopl.ml | 98 + popl09/asttopopl.mli | 1 + popl09/flag_popl.ml | 24 + popl09/insert_quantifiers.ml | 113 + popl09/insert_quantifiers.mli | 1 + popl09/popl.ml | 38 + popl09/popl.mli | 5 + popl09/popltoctl.ml | 238 + popl09/popltoctl.mli | 5 + popl09/pretty_print_popl.ml | 97 + popl09/pretty_print_popl.mli | 2 + prim.c | 7 + pycaml/Makefile | 32 + pycaml/Makefile.in | 40 + pycaml/OCamlMakefile | 1231 + pycaml/acinclude.m4 | 3724 ++ pycaml/aclocal.m4 | 3655 ++ pycaml/configure | 4142 +++ pycaml/configure.in | 121 + pycaml/getprefix.py | 3 + pycaml/getversion.py | 3 + pycaml/license.txt | 504 + pycaml/modif-orig.txt | 107 + pycaml/ocamlobj.ml | 12 + pycaml/pycaml.html | 321 + pycaml/pycaml.ml | 541 + pycaml/pycaml_ml.c | 1467 + pycaml/pycamltest.ml | 31 + pycaml/tupletest.ml | 17 + python/.depend | 22 + python/Makefile | 146 + python/coccilib/Makefile | 10 + python/coccilib/__init__.py | 1 + python/coccilib/coccigui/Makefile | 6 + python/coccilib/coccigui/__init__.py | 1 + python/coccilib/coccigui/coccigui.py | 129 + python/coccilib/coccigui/pycoccimodel.py | 22 + python/coccilib/coccigui/pygui.glade | 108 + python/coccilib/coccigui/pygui.gladep | 8 + python/coccilib/coccigui/vim.py | 282 + python/coccilib/coccigui/vimcom.py | 728 + python/coccilib/coccigui/vimeditor.py | 269 + python/coccilib/coccigui/vimembed.py | 142 + python/coccilib/elems.py | 28 + python/coccilib/output.py | 115 + python/no_pycocci.ml | 93 + python/no_pycocci_aux.ml | 76 + python/pycocci.ml | 1 + python/pycocci_aux.ml | 1 + python/yes_pycocci.ml | 241 + python/yes_pycocci_aux.ml | 79 + readme.txt | 31 + runspatch.opt | 18 + scripts/extract_c_and_res.pl | 231 + scripts/extract_examples.pl | 22 + scripts/extractor.awk | 94 + scripts/extractor_README.pl | 62 + scripts/gather_failed.pl | 12 + scripts/glimpseindex_cocci.sh | 3 + scripts/readme.pl | 79 + scripts/stat_directories.pl | 40 + scripts/stat_directories_complete.pl | 30 + scripts/stat_directory_complete.pl | 367 + standard.h | 787 + standard.iso | 656 + test.ml | 1 + testing.ml | 430 + testing.mli | 65 + tests/A_and_E.c | 10 + tests/A_and_E.cocci | 8 + tests/A_and_E.res | 10 + tests/A_and_E_ver1.c | 10 + tests/A_and_E_ver1.res | 11 + tests/a3d.c | 18 + tests/a3d.cocci | 14 + tests/a3d.res | 18 + tests/addelse.c | 3 + tests/addelse.cocci | 14 + tests/addelse.res | 2 + tests/after_if.c | 4 + tests/after_if.cocci | 4 + tests/after_if.res | 4 + tests/ali.c | 18 + tests/ali.cocci | 32 + tests/allbound.c | 4 + tests/allbound.cocci | 15 + tests/andparen.c | 3 + tests/andparen.cocci | 16 + tests/anon.c | 16 + tests/anon.cocci | 18 + tests/anon.res | 16 + tests/ar.c | 12 + tests/ar.cocci | 11 + tests/ar.res | 7 + tests/arg.c | 6 + tests/arg.cocci | 14 + tests/arg.res | 6 + tests/argument.c | 8 + tests/argument.cocci | 11 + tests/argument.res | 6 + tests/array.c | 11 + tests/array.cocci | 7 + tests/array_init.c | 3 + tests/array_init.cocci | 16 + tests/array_init.res | 2 + tests/array_size.c | 2 + tests/array_size.cocci | 7 + tests/array_size.res | 2 + tests/arraysz.c | 10 + tests/arraysz.cocci | 7 + tests/arraysz.res | 10 + tests/assign.c | 4 + tests/assign.cocci | 7 + tests/axnet.c | 15 + tests/axnet.cocci | 28 + tests/b1.c | 7 + tests/b1.cocci | 10 + tests/b1.res | 7 + tests/b2.c | 9 + tests/b2.cocci | 10 + tests/b2.res | 9 + tests/bad_assign.cocci | 148 + tests/bad_define.c | 1 + tests/bad_define.cocci | 25 + tests/bad_define.res | 0 tests/bad_iso_example.c | 4 + tests/bad_iso_example.cocci | 23 + tests/bad_iso_example.res | 4 + tests/bad_noputm1 | 168 + tests/bad_subsumption.c | 40 + tests/bad_subsumption.cocci | 73 + tests/bad_typedef.c | 17 + tests/bad_typedef.cocci | 17 + tests/bad_typedef.res | 17 + tests/bad_zero.cocci | 71 + tests/badaw.c | 36 + tests/badaw.cocci | 30 + tests/badcomma.c | 4 + tests/badcomma.cocci | 3 + tests/badexp.c | 4 + tests/badexp.cocci | 9 + tests/badexp.res | 4 + tests/badexp1.c | 4 + tests/badexp1.cocci | 9 + tests/badfree.c | 6 + tests/badfree.cocci | 10 + tests/badpos.c | 6 + tests/badpos.cocci | 8 + tests/badpos.res | 6 + tests/badpost.cocci | 17 + tests/badprint.c | 7 + tests/badtypedef.c | 11 + tests/badtypedef.cocci | 12 + tests/badtypedef.res | 11 + tests/bitfield.c | 15 + tests/bitfield.cocci | 9 + tests/bitfield.res | 15 + tests/braces.c | 9 + tests/braces.cocci | 6 + tests/braces.res | 9 + tests/break.c | 23 + tests/break.cocci | 21 + tests/break.res | 23 + tests/bug1.c | 5 + tests/bug1.cocci | 11 + tests/bug1.res | 6 + tests/bug_expopt.c | 63 + tests/bug_expopt.cocci | 16 + tests/bugloop.c | 17 + tests/bugloop.cocci | 9 + tests/bugloop.res | 13 + tests/bugon.c | 5 + tests/bugon.cocci | 4 + tests/bugon.res | 4 + tests/cards.c | 3 + tests/cards.cocci | 6 + tests/cards.res | 1 + tests/cast.c | 3 + tests/cast.cocci | 6 + tests/cast.res | 2 + tests/cast_iso.c | 6 + tests/cast_iso.cocci | 15 + tests/cast_iso.res | 5 + tests/comment.c | 6 + tests/comment.cocci | 5 + tests/compare.c | 14 + tests/compare.cocci | 4 + tests/compare.res | 14 + tests/const.c | 3 + tests/const.cocci | 5 + tests/const.res | 3 + tests/const1.c | 5 + tests/const1.cocci | 6 + tests/const1bis.c | 5 + tests/const1bis.cocci | 6 + tests/const1bis.res | 5 + tests/const_adding.c | 7 + tests/const_adding.cocci | 13 + tests/const_adding.res | 7 + tests/const_array.c | 32 + tests/const_array.cocci | 15 + tests/const_array.res | 21 + tests/const_implicit_iso.c | 4 + tests/const_implicit_iso.cocci | 6 + tests/const_implicit_iso.res | 4 + tests/constty.c | 7 + tests/constty.cocci | 6 + tests/constty.res | 6 + tests/constx.c | 8 + tests/constx.cocci | 7 + tests/constx.res | 8 + tests/cr.c | 12 + tests/cr.cocci | 13 + tests/cr1.c | 20 + tests/cr1.cocci | 20 + tests/cs_check.c | 10 + tests/cs_check.cocci | 6 + tests/cs_check.res | 10 + tests/cst.c | 5 + tests/cst.cocci | 8 + tests/cst.res | 5 + tests/csw.c | 14 + tests/csw.cocci | 7 + tests/csw.res | 6 + tests/ctr_unit_test.c | 28 + tests/ctr_unit_test.cocci | 79 + tests/dbg.c | 8 + tests/dbg.cocci | 7 + tests/dbg.res | 9 + tests/dc_close.c | 11 + tests/dc_close.cocci | 15 + tests/dc_close.res | 12 + tests/debug.c | 5 + tests/debug.cocci | 7 + tests/debug.res | 4 + tests/dec.c | 4 + tests/dec.cocci | 8 + tests/dec.res | 5 + tests/decl.c | 5 + tests/decl.cocci | 10 + tests/decl.res | 6 + tests/decl1.c | 7 + tests/decl1.cocci | 12 + tests/decl2.c | 10 + tests/decl2.cocci | 11 + tests/decl2.res | 10 + tests/decl_space.c | 4 + tests/decl_space.cocci | 13 + tests/decl_space.res | 4 + tests/decl_split.c | 3 + tests/decl_split.cocci | 7 + tests/decl_split.res | 2 + tests/decl_ver1.c | 20 + tests/define_chip_t.c | 22 + tests/define_chip_t.cocci | 14 + tests/define_exp.c | 7 + tests/define_exp.cocci | 9 + tests/define_exp.res | 6 + tests/define_param.c | 14 + tests/define_param.cocci | 21 + tests/define_param.res | 12 + tests/dep.c | 3 + tests/dep.cocci | 14 + tests/deref.c | 6 + tests/deref.cocci | 6 + tests/deref.res | 6 + tests/desc.c | 2 + tests/detect_alloc.cocci | 13 + tests/devlink.c | 12 + tests/devlink.cocci | 4 + tests/devlink.res | 12 + tests/disjexpr.c | 3 + tests/disjexpr.cocci | 9 + tests/disjexpr.res | 3 + tests/disjexpr_ver1.c | 3 + tests/disjexpr_ver1.res | 3 + tests/disjexpr_ver2.c | 3 + tests/disjexpr_ver2.res | 3 + tests/distribute.c | 4 + tests/distribute.cocci | 11 + tests/distribute.res | 4 + tests/double.c | 5 + tests/double.cocci | 9 + tests/double.res | 5 + tests/double_assign.c | 9 + tests/double_assign.cocci | 25 + tests/double_assign.res | 8 + tests/doublepos.c | 6 + tests/doublepos.cocci | 19 + tests/doublepos.res | 5 + tests/dowhile.c | 7 + tests/dowhile.cocci | 6 + tests/dowhile.res | 5 + tests/dropf.c | 3 + tests/dropf.cocci | 6 + tests/dropf.res | 3 + tests/dropparam.c | 13 + tests/dropparam.cocci | 25 + tests/dropparam.res | 12 + tests/edots.c | 7 + tests/edots.cocci | 6 + tests/edots.res | 7 + tests/edots_ver1.c | 7 + tests/edots_ver1.res | 7 + tests/empty.c | 9 + tests/empty.cocci | 20 + tests/empty.res | 9 + tests/end_commas.c | 4 + tests/end_commas.cocci | 10 + tests/end_commas.res | 4 + tests/endif.c | 23 + tests/endif.cocci | 7 + tests/endif.res | 28 + tests/exp.c | 14 + tests/exp.cocci | 5 + tests/exp.res | 14 + tests/expnest.c | 6 + tests/expnest.cocci | 7 + tests/expnest.res | 6 + tests/expopt.c | 5 + tests/expopt.cocci | 13 + tests/expopt.res | 5 + tests/expopt2.c | 5 + tests/expopt2.cocci | 13 + tests/expopt2.res | 5 + tests/expopt3.c | 5 + tests/expopt3.cocci | 15 + tests/expopt3.res | 5 + tests/expopt3_ver1.c | 6 + tests/expopt3_ver1.res | 6 + tests/expopt3_ver2.c | 5 + tests/expopt3_ver2.res | 5 + tests/expopt4.c | 12 + tests/expopt4.cocci | 20 + tests/fields.c | 5 + tests/fields.cocci | 9 + tests/fields.res | 8 + tests/fieldsmin.c | 5 + tests/fieldsmin.cocci | 9 + tests/fieldsmin.res | 3 + tests/fix_flow_need.c | 11 + tests/fix_flow_need.cocci | 7 + tests/fix_flow_need.res | 10 + tests/fn_todo.c | 10 + tests/fn_todo.cocci | 12 + tests/fn_todo.res | 10 + tests/fnptr.c | 12 + tests/fnptr.cocci | 5 + tests/fnptr.res | 12 + tests/fnret.c | 1 + tests/fnret.cocci | 6 + tests/fnret.res | 1 + tests/fns.c | 12 + tests/fns.cocci | 42 + tests/four.c | 5 + tests/four.cocci | 26 + tests/four.res | 3 + tests/foura.c | 5 + tests/foura.cocci | 11 + tests/foura.res | 4 + tests/fp.c | 3 + tests/fp.cocci | 9 + tests/fp.res | 2 + tests/free.c | 75 + tests/free.cocci | 68 + tests/free_ver5.c | 7 + tests/fun.c | 1 + tests/fun.cocci | 5 + tests/fun.res | 2 + tests/gilles-question.c | 9 + tests/gilles-question.cocci | 6 + tests/gilles-question.res | 9 + tests/gotobreak.c | 15 + tests/gotobreak.cocci | 10 + tests/gotobreak.res | 15 + tests/hd.c | 3 + tests/hd.cocci | 7 + tests/hd.h | 1 + tests/hd.res | 3 + tests/header_modif.c | 6 + tests/header_modif.cocci | 9 + tests/header_modif.h | 3 + tests/headers.c | 22 + tests/headers.cocci | 15 + tests/headers.res | 22 + tests/hex.c | 3 + tests/hex.cocci | 3 + tests/hex.res | 2 + tests/hex2.c | 3 + tests/hex2.cocci | 3 + tests/hex2.res | 2 + tests/if2.c | 6 + tests/if2.cocci | 10 + tests/ifbr.c | 4 + tests/ifbr.cocci | 15 + tests/ifbr.res | 4 + tests/ifdef1.c | 13 + tests/ifdef1.cocci | 7 + tests/ifdef1.res | 16 + tests/ifdef2.c | 13 + tests/ifdef2.cocci | 8 + tests/ifdef2.res | 18 + tests/ifdef3.c | 13 + tests/ifdef3.cocci | 11 + tests/ifdef3.res | 20 + tests/ifdef4.c | 13 + tests/ifdef4.cocci | 11 + tests/ifdef4.res | 16 + tests/ifdef5.c | 13 + tests/ifdef5.cocci | 13 + tests/ifdef5.res | 23 + tests/ifdef6.c | 13 + tests/ifdef6.cocci | 7 + tests/ifdef6.res | 16 + tests/ifend.c | 7 + tests/ifend.cocci | 4 + tests/ifend.res | 5 + tests/ifzer.c | 8 + tests/ifzer.cocci | 4 + tests/ifzer.res | 7 + tests/inc.c | 2 + tests/inc.cocci | 11 + tests/inc.res | 1 + tests/incdir.c | 5 + tests/incdir.cocci | 6 + tests/incdir.res | 5 + tests/incdir2.c | 1 + tests/incl.c | 6 + tests/incl.cocci | 11 + tests/incl.res | 8 + tests/inclifdef.c | 4 + tests/inclifdef.cocci | 5 + tests/inclifdef.res | 5 + tests/include.c | 10 + tests/include.cocci | 6 + tests/include.res | 8 + tests/include/linux/serio.h | 4 + tests/include/linux/serio.h.res | 4 + tests/incompatible_value.c | 12 + tests/incompatible_value.cocci | 20 + tests/incompatible_value.res | 12 + tests/inherited.c | 10 + tests/inherited.cocci | 31 + tests/inherited.res | 10 + tests/inherited_ver1.c | 10 + tests/inherited_ver1.res | 10 + tests/inhpos.c | 3 + tests/inhpos.cocci | 14 + tests/inhpos.res | 2 + tests/initializer.c | 5 + tests/initializer.cocci | 11 + tests/initializer.res | 6 + tests/initializer_iso.c | 26 + tests/initializer_iso.cocci | 28 + tests/initializer_many_fields.c | 2 + tests/initializer_many_fields.cocci | 5 + tests/initializer_many_fields.res | 2 + tests/inline.c | 1 + tests/inline.cocci | 4 + tests/inline.res | 2 + tests/ioctl.cocci | 81 + tests/isococci.c | 6 + tests/isococci.cocci | 5 + tests/isococci.res | 5 + tests/isotest.c | 8 + tests/isotest.cocci | 5 + tests/isotest.res | 8 + tests/isotest2.c | 8 + tests/isotest2.cocci | 7 + tests/isotest2.res | 7 + tests/iterator.c | 10 + tests/iterator.cocci | 10 + tests/iterator.res | 6 + tests/jloop1.c | 18 + tests/jloop1.cocci | 11 + tests/jloop1.res | 17 + tests/join.c | 11 + tests/join.cocci | 12 + tests/julia10.c | 7 + tests/julia10.cocci | 8 + tests/julia10.res | 5 + tests/julia7.c | 7 + tests/julia7.cocci | 10 + tests/julia7.res | 6 + tests/keep_comma.c | 4 + tests/keep_comma.cocci | 5 + tests/keep_comma.res | 4 + tests/km.c | 5 + tests/km.cocci | 14 + tests/km.res | 5 + tests/kmalloc.c | 9 + tests/kmalloc.cocci | 11 + tests/kmalloc.res | 7 + tests/kmc.c | 14 + tests/kmc.cocci | 11 + tests/kmc.res | 13 + tests/ktype.c | 10 + tests/ktype.cocci | 12 + tests/ktype.res | 8 + tests/labels_metastatement.c | 9 + tests/labels_metastatement.cocci | 6 + tests/labels_metastatement.res | 10 + tests/labels_metastatement2.cocci | 5 + tests/labels_metastatement3.cocci | 6 + tests/labels_metastatement_ver1.c | 5 + tests/labels_metastatement_ver1.res | 9 + tests/local.c | 1 + tests/local.cocci | 10 + tests/local.res | 1 + tests/localid.c | 9 + tests/localid.cocci | 19 + tests/localid.res | 8 + tests/longint.c | 9 + tests/longint.cocci | 12 + tests/loop.c | 5 + tests/loop.cocci | 6 + tests/loop.res | 3 + tests/lvalue.c | 4 + tests/lvalue.cocci | 5 + tests/lvalue.res | 4 + tests/macro.c | 5 + tests/macro.cocci | 6 + tests/macro.res | 1 + tests/match_const.c | 1 + tests/match_const.cocci | 6 + tests/match_const.res | 0 tests/match_no_meta.c | 7 + tests/match_no_meta.cocci | 11 + tests/match_no_meta.res | 7 + tests/max.c | 3 + tests/max.cocci | 15 + tests/max.res | 3 + tests/mem.cocci | 19 + tests/memset.cocci | 69 + tests/metahex.c | 4 + tests/metahex.cocci | 6 + tests/metahex.res | 2 + tests/metaruleelem.c | 7 + tests/metaruleelem.cocci | 7 + tests/metaruleelem.res | 8 + tests/metastatement.c | 5 + tests/metastatement.cocci | 9 + tests/metastatement2.c | 6 + tests/metastatement2.cocci | 6 + tests/metastatement2.res | 5 + tests/metastatement_for.c | 12 + tests/metastatement_for.cocci | 8 + tests/metastatement_for.res | 9 + tests/metastatement_if.c | 12 + tests/metastatement_if.cocci | 8 + tests/metastatement_if.res | 9 + tests/mf.c | 12 + tests/mf.cocci | 21 + tests/minstruct.c | 5 + tests/minstruct.cocci | 9 + tests/minstruct.res | 5 + tests/minusall.c | 1 + tests/minusall.cocci | 4 + tests/minusall.res | 0 tests/minusdots.c | 9 + tests/minusdots.cocci | 9 + tests/minusdots.res | 4 + tests/minusdots_ver1.c | 6 + tests/minusdots_ver1.res | 3 + tests/mult.c | 6 + tests/mult.cocci | 13 + tests/multi_func.c | 15 + tests/multi_func.cocci | 11 + tests/multi_func1.c | 26 + tests/multi_func1.cocci | 81 + tests/multi_func1.res | 24 + tests/multi_func1_ver2.c | 4 + tests/multi_inc.c | 5 + tests/multi_inc.cocci | 5 + tests/multi_inc1.h | 1 + tests/multi_inc2.h | 1 + tests/multidecl.c | 13 + tests/multidecl.cocci | 24 + tests/multiplus.c | 19 + tests/multiplus.cocci | 17 + tests/multiplus.res | 19 + tests/multitype.c | 7 + tests/multitype.cocci | 14 + tests/multitype.res | 7 + tests/multitypedef.c | 9 + tests/multitypedef.cocci | 8 + tests/multitypedef.res | 9 + tests/multivars.c | 5 + tests/multivars.cocci | 6 + tests/multivars.res | 5 + tests/multr.c | 7 + tests/multr.cocci | 12 + tests/nest.c | 7 + tests/nest.cocci | 21 + tests/nest.res | 7 + tests/nest2.c | 5 + tests/nest2.cocci | 10 + tests/nest3.c | 9 + tests/nest3.cocci | 10 + tests/nestone.c | 4 + tests/nestone.cocci | 15 + tests/nestone.res | 3 + tests/nestplus.c | 5 + tests/nestplus.cocci | 18 + tests/nestseq.c | 5 + tests/nestseq.cocci | 10 + tests/nestseq.res | 6 + tests/neststruct.c | 13 + tests/neststruct.cocci | 8 + tests/neststruct.res | 13 + tests/nl.c | 4 + tests/nl.cocci | 5 + tests/nl.res | 4 + tests/nocast.c | 4 + tests/nocast.cocci | 13 + tests/nocast.res | 3 + tests/not.c | 9 + tests/not.cocci | 8 + tests/not.res | 9 + tests/noty.c | 3 + tests/noty.cocci | 7 + tests/noty.res | 4 + tests/nstruct.c | 4 + tests/nstruct.cocci | 9 + tests/null.c | 9 + tests/null.cocci | 79 + tests/null_type.c | 8 + tests/null_type.cocci | 6 + tests/null_type.res | 8 + tests/null_ver11.c | 112 + tests/of.c | 16 + tests/of.cocci | 21 + tests/of.res | 20 + tests/oneline.c | 4 + tests/oneline.cocci | 5 + tests/oneline.res | 4 + tests/opt.c | 3 + tests/opt.cocci | 14 + tests/opt.res | 3 + tests/optional_qualifier.c | 2 + tests/optional_qualifier.cocci | 9 + tests/optional_qualifier.res | 2 + tests/optional_storage.c | 12 + tests/optional_storage.cocci | 9 + tests/optional_storage.res | 12 + tests/orexp.c | 3 + tests/orexp.cocci | 9 + tests/orexp.res | 3 + tests/param.c | 1 + tests/param.cocci | 4 + tests/param.res | 2 + tests/param1.c | 1 + tests/param1.cocci | 4 + tests/param1_ver1.c | 1 + tests/param_end.c | 15 + tests/param_end.cocci | 15 + tests/param_end.res | 15 + tests/param_ver1.c | 1 + tests/param_ver1.res | 2 + tests/parameters_dots.c | 7 + tests/parameters_dots.cocci | 3 + tests/parameters_dots.res | 4 + tests/paren1.c | 3 + tests/paren1.cocci | 3 + tests/partial.c | 3 + tests/partial.cocci | 6 + tests/partial.res | 3 + tests/pb_cfg.c | 10 + tests/pb_cfg.cocci | 4 + tests/pb_distribute_type.c | 15 + tests/pb_distribute_type.cocci | 10 + tests/pb_distribute_type.res | 15 + tests/pb_distribute_type2.c | 15 + tests/pb_distribute_type2.cocci | 11 + tests/pb_distribute_type2.res | 15 + tests/pb_distribute_type3.c | 15 + tests/pb_distribute_type3.cocci | 12 + tests/pb_distribute_type3.res | 15 + tests/pb_distribute_type4.c | 15 + tests/pb_distribute_type4.cocci | 11 + tests/pb_distribute_type4.res | 15 + tests/pb_params_iso.c | 18 + tests/pb_params_iso.cocci | 31 + tests/pb_params_iso.res | 17 + tests/pb_tag_symbols.c | 5 + tests/pb_tag_symbols.cocci | 7 + tests/pb_tag_symbols.res | 3 + tests/pci_noputm.cocci | 111 + tests/pmac.c | 11 + tests/pmac.cocci | 4 + tests/pmac.res | 8 + tests/posiso.c | 11 + tests/posiso.cocci | 14 + tests/posiso.res | 9 + tests/positionc.c | 9 + tests/positionc.cocci | 37 + tests/positionc.res | 7 + tests/positions3.c | 12 + tests/positions3.cocci | 26 + tests/posmult.c | 8 + tests/posmult.cocci | 25 + tests/posnpb.c | 7 + tests/posnpb.cocci | 41 + tests/post.c | 8 + tests/post.cocci | 15 + tests/post.res | 6 + tests/ppos.c | 16 + tests/ppos.cocci | 36 + tests/print_return.c | 4 + tests/print_return.cocci | 11 + tests/print_return.res | 3 + tests/proto.c | 10 + tests/proto.cocci | 10 + tests/proto.res | 3 + tests/proto2.c | 10 + tests/proto2.cocci | 11 + tests/proto2.res | 10 + tests/proto_ver1.c | 10 + tests/proto_ver1.res | 3 + tests/proto_ver2.c | 997 + tests/proto_ver2.res | 987 + tests/protoassert.c | 6 + tests/protoassert.cocci | 10 + tests/protoassert.res | 9 + tests/protox.c | 3 + tests/protox.cocci | 17 + tests/protox.res | 3 + tests/pt_regs_summary | 89 + tests/rcu2.cocci | 287 + tests/rcu3.c | 8 + tests/rcu3.cocci | 8 + tests/rcu3.res | 8 + tests/rcu3_ver1.c | 15 + tests/remstruct.c | 16 + tests/remstruct.cocci | 11 + tests/remstruct.res | 5 + tests/replace_typedef.c | 10 + tests/replace_typedef.cocci | 25 + tests/replace_typedef.res | 10 + tests/request_irq.cocci | 77 + tests/request_irq_sgrep.cocci | 80 + tests/reserved.c | 8 + tests/reserved.cocci | 9 + tests/reserved.res | 5 + tests/ret.c | 7 + tests/ret.cocci | 10 + tests/ret2.c | 6 + tests/ret2.cocci | 10 + tests/retmacro.c | 17 + tests/retmacro.cocci | 6 + tests/retmacro.res | 17 + tests/rets.c | 4 + tests/rets.cocci | 7 + tests/rets.res | 4 + tests/return.c | 6 + tests/return.cocci | 26 + tests/return.res | 7 + tests/return_implicit.c | 4 + tests/return_implicit.cocci | 11 + tests/return_implicit.res | 5 + tests/rule19a.c | 23 + tests/rule19a.cocci | 15 + tests/rule3.cocci | 13 + tests/same_expr.c | 6 + tests/same_expr.cocci | 5 + tests/same_expr.res | 5 + tests/scope_problem.c | 15 + tests/scope_problem.cocci | 11 + tests/scope_problem.res | 12 + tests/scripting/array/script4.c | 22 + tests/scripting/array/script4.cocci | 15 + tests/scripting/script1.c | 9 + tests/scripting/script1.cocci | 7 + tests/scripting/script2.c | 12 + tests/scripting/script2.cocci | 8 + tests/scripting/script3.c | 18 + tests/scripting/script3.cocci | 10 + tests/scripting/script4.c | 18 + tests/scripting/script4.cocci | 14 + tests/scripting/script5.c | 18 + tests/scripting/script5.cocci | 11 + tests/scripting/script6.c | 18 + tests/scripting/script6.cocci | 7 + tests/scripting/script7.c | 14 + tests/scripting/script7.cocci | 9 + tests/scripting/script8.c | 18 + tests/scripting/script8.cocci | 10 + tests/send_pci1 | 49 + tests/send_pci2 | 49 + tests/serio.c | 8 + tests/serio.cocci | 33 + tests/serio.res | 8 + tests/sgrep.c | 7 + tests/sgrep.cocci | 13 + tests/shadow.c | 4 + tests/shared_brace.c | 9 + tests/shared_brace.cocci | 9 + tests/shared_brace.res | 7 + tests/signed.c | 5 + tests/signed.cocci | 12 + tests/signed.res | 5 + tests/sis.c | 6 + tests/sis.cocci | 9 + tests/sis.res | 3 + tests/size_t.cocci | 46 + tests/sizeof.c | 7 + tests/sizeof.cocci | 9 + tests/sizeof.res | 7 + tests/sizeof_julia.c | 5 + tests/sizeof_julia.cocci | 6 + tests/sizeof_julia.res | 5 + tests/skip.c | 5 + tests/skip.cocci | 17 + tests/skip.res | 3 + tests/soc.c | 7 + tests/sp.c | 4 + tests/sp.cocci | 10 + tests/sp.res | 4 + tests/spaces.c | 3 + tests/spaces.cocci | 6 + tests/spaces.res | 3 + tests/spl.c | 12 + tests/spl.cocci | 16 + tests/spl.res | 14 + tests/stat.c | 1 + tests/stat.cocci | 6 + tests/stat.res | 0 tests/static.c | 4 + tests/static.cocci | 8 + tests/static.res | 4 + tests/stm1.c | 5 + tests/stm1.cocci | 7 + tests/stm1.res | 5 + tests/stm10.c | 6 + tests/stm10.cocci | 7 + tests/stm10.res | 7 + tests/stm10_ver1.c | 5 + tests/stm10_ver1.res | 6 + tests/stm2.c | 5 + tests/stm2.cocci | 7 + tests/stm2.res | 4 + tests/stm3.c | 5 + tests/stm3.cocci | 7 + tests/stm3.res | 5 + tests/stm4.c | 5 + tests/stm4.cocci | 7 + tests/stm4.res | 6 + tests/stm5.c | 5 + tests/stm5.cocci | 8 + tests/stm5.res | 7 + tests/stm6.c | 5 + tests/stm6.cocci | 7 + tests/stm6.res | 6 + tests/stm7.c | 5 + tests/stm7.cocci | 8 + tests/stm7.res | 5 + tests/stm8.c | 5 + tests/stm8.cocci | 7 + tests/stm8.res | 6 + tests/stmt.c | 4 + tests/stmt.cocci | 11 + tests/stmt.res | 5 + tests/strangeorder.c | 15 + tests/strangeorder.cocci | 11 + tests/strangeorder.res | 17 + tests/string.c | 1 + tests/string.cocci | 6 + tests/string.res | 1 + tests/struct.c | 14 + tests/struct.cocci | 25 + tests/struct.res | 12 + tests/struct_metavar.c | 18 + tests/struct_metavar.cocci | 26 + tests/struct_metavar.res | 17 + tests/struct_typedef.c | 15 + tests/struct_typedef.cocci | 10 + tests/struct_typedef.res | 15 + tests/sw.c | 1 + tests/sw.cocci | 4 + tests/sw.res | 1 + tests/switch.c | 8 + tests/switch.cocci | 4 + tests/switch.res | 7 + tests/switch_case.c | 8 + tests/switch_case.cocci | 13 + tests/switch_label.c | 9 + tests/tadb.c | 12 + tests/td.c | 5 + tests/td.cocci | 8 + tests/td.res | 5 + tests/test0.c | 5 + tests/test0.cocci | 4 + tests/test0.res | 5 + tests/test1.c | 16 + tests/test1.cocci | 9 + tests/test1.res | 15 + tests/test10.c | 9 + tests/test10.cocci | 11 + tests/test10.res | 9 + tests/test10_ver1.c | 9 + tests/test10_ver1.res | 9 + tests/test11.c | 7 + tests/test11.cocci | 11 + tests/test11.res | 7 + tests/test11_ver1.c | 7 + tests/test11_ver1.res | 7 + tests/test12.c | 8 + tests/test12.cocci | 8 + tests/test12.res | 8 + tests/test1_ver1.c | 15 + tests/test1_ver2.c | 15 + tests/test2.c | 8 + tests/test2.cocci | 7 + tests/test2.res | 8 + tests/test3.c | 10 + tests/test3.cocci | 9 + tests/test3.res | 10 + tests/test4.c | 9 + tests/test4.cocci | 9 + tests/test4.res | 8 + tests/test5.c | 22 + tests/test5.cocci | 8 + tests/test5.res | 22 + tests/test5_ver1.c | 22 + tests/test5_ver1.res | 23 + tests/test6.c | 26 + tests/test6.cocci | 8 + tests/test6.res | 26 + tests/test6_ver1.c | 26 + tests/test7.c | 11 + tests/test7.cocci | 7 + tests/test7.res | 13 + tests/test8.c | 12 + tests/test8.cocci | 13 + tests/test8.res | 11 + tests/test9.c | 18 + tests/test9.cocci | 13 + tests/test9.res | 18 + tests/test9_ver1.c | 18 + tests/three.c | 20 + tests/three.cocci | 31 + tests/three_types.c | 11 + tests/three_types.cocci | 25 + tests/three_types.res | 11 + tests/threea.c | 4 + tests/threea.cocci | 15 + tests/threea.res | 3 + tests/top.c | 2 + tests/top.cocci | 5 + tests/top.res | 1 + tests/topdec.c | 8 + tests/topdec.cocci | 6 + tests/topdec.res | 8 + tests/topdec_ver1.c | 7 + tests/topdec_ver1.res | 7 + tests/topdec_ver2.c | 8 + tests/topdec_ver2.res | 8 + tests/toplevel_macrostmt.c | 10 + tests/toplevel_macrostmt.cocci | 11 + tests/toplevel_macrostmt.res | 9 + tests/toplevel_struct.c | 85 + tests/toplevel_struct.cocci | 44 + tests/toplevel_struct.res | 86 + tests/toplevel_struct_modif.c | 70 + tests/toplevel_struct_modif.cocci | 10 + tests/tup.c | 10 + tests/tup.cocci | 22 + tests/tup.res | 10 + tests/twoproto.c | 11 + tests/twoproto.cocci | 12 + tests/twoproto.res | 9 + tests/ty.c | 4 + tests/ty.cocci | 5 + tests/ty.res | 6 + tests/ty1.c | 4 + tests/ty1.cocci | 9 + tests/ty1.res | 3 + tests/ty_tyexp.c | 12 + tests/ty_tyexp.cocci | 5 + tests/ty_tyexp.res | 11 + tests/type.c | 5 + tests/type.cocci | 11 + tests/type.res | 5 + tests/type1.c | 5 + tests/type1.cocci | 11 + tests/type1.res | 5 + tests/type_annotated.c | 20 + tests/type_annotated.cocci | 8 + tests/type_annotated.res | 20 + tests/type_annotated_fields.c | 42 + tests/type_annotated_fields.cocci | 17 + tests/type_infer.c | 6 + tests/type_infer.cocci | 16 + tests/type_iso.c | 24 + tests/type_iso.cocci | 5 + tests/type_ver1.c | 5 + tests/type_ver1.res | 5 + tests/type_ver2.c | 5 + tests/type_ver2.res | 5 + tests/typedef.c | 15 + tests/typedef.cocci | 19 + tests/typedef.res | 15 + tests/typedef3.c | 13 + tests/typedef3.cocci | 25 + tests/typedef3.res | 13 + tests/typedef_double.c | 7 + tests/typedef_double.cocci | 19 + tests/typedef_double.res | 7 + tests/typeof.c | 6 + tests/typeof.cocci | 8 + tests/typeof.res | 4 + tests/typeur.c | 6 + tests/typeur.h | 2 + tests/used_after.c | 10 + tests/used_after.cocci | 20 + tests/used_after_ver1.c | 19 + tests/useless_cast.c | 21 + tests/useless_cast.cocci | 9 + tests/useless_cast.res | 20 + tests/varargs.c | 4 + tests/varargs.cocci | 6 + tests/varargs.res | 4 + tests/video.c | 36 + tests/video.cocci | 27 + tests/video1.c | 35 + tests/video1.cocci | 30 + tests/video1_ver1.c | 398 + tests/video1bis.c | 9 + tests/video1bis.cocci | 10 + tests/video1bis.res | 7 + tests/video2.c | 29 + tests/video2.cocci | 20 + tests/video3.c | 35 + tests/video3.cocci | 29 + tests/video4.c | 15 + tests/video4.cocci | 16 + tests/video_ver1.c | 36 + tests/video_ver2.c | 41 + tests/video_ver3.c | 25 + tests/void.c | 5 + tests/void.cocci | 6 + tests/void.res | 9 + tests/voyager.c | 8 + tests/voyager.cocci | 22 + tests/vpos.c | 9 + tests/vpos.cocci | 17 + tests/vpos.res | 9 + tests/whitespace.c | 3 + tests/whitespace.cocci | 6 + tests/whitespace.res | 3 + tests/wierd_argument.c | 7 + tests/wierd_argument.cocci | 7 + tests/wierd_argument.res | 7 + tests/wierdinit.c | 9 + tests/wierdinit.cocci | 6 + tests/wierdinit.res | 9 + tests/ws2.c | 6 + tests/ws2.cocci | 7 + tests/ws2.res | 5 + tests/x.c | 6 + tests/x.cocci | 9 + tests/xloop.c | 5 + tests/xloop.cocci | 5 + tests/y.c | 4 + tests/y.cocci | 19 + tests/y2.c | 14 + tests/y2.cocci | 10 + tests/y2.res | 11 + tests/yellow.c | 89 + tests/yloop.c | 12 + tests/yloop.cocci | 11 + tests/zero.c | 6 + tests/zero.cocci | 5 + tests/zero.res | 2 + tools/Makefile | 78 + tools/alloc_free.ml | 176 + tools/bridge.ml | 245 + tools/dir_stats.ml | 163 + tools/distributed/Makefile | 8 + tools/distributed/README | 11 + tools/distributed/cleanup.ml | 71 + tools/distributed/cleanup_script | 7 + tools/distributed/spatch_linux.c | 128 + tools/distributed/spatch_linux_script | 11 + tools/extract_c_and_res.ml | 49 + tools/generate_dependencies.ml | 100 + tools/gitgrep.ml | 187 + tools/gitsort.ml | 126 + tools/licensify.ml | 84 + tools/process_isoprofile.ml | 147 + tools/split_patch.ml | 264 + 1543 files changed, 195964 insertions(+) create mode 100644 .depend create mode 100644 Makefile create mode 100644 Makefile.config create mode 100644 authors.txt create mode 100644 bugs.txt create mode 100644 changes.txt create mode 100644 cocci.ml create mode 100644 cocci.mli create mode 100644 commitmsg create mode 100644 commons/.depend create mode 100644 commons/Makefile create mode 100644 commons/authors.txt create mode 100644 commons/backtrace.ml create mode 100644 commons/backtrace_c.c create mode 100644 commons/common.ml create mode 100644 commons/common.mli create mode 100644 commons/common_extra.ml create mode 100644 commons/copyright.txt create mode 100644 commons/credits.txt create mode 100644 commons/glimpse.ml create mode 100644 commons/interfaces.ml create mode 100644 commons/license.txt create mode 100644 commons/oarray.ml create mode 100644 commons/oarray.mli create mode 100644 commons/oassoc.ml create mode 100644 commons/oassoc.mli create mode 100644 commons/oassoc_buffer.ml create mode 100644 commons/oassoc_buffer.mli create mode 100644 commons/oassocb.ml create mode 100644 commons/oassocbdb.ml create mode 100644 commons/oassocbdb.mli create mode 100644 commons/oassocdbm.ml create mode 100644 commons/oassocdbm.mli create mode 100644 commons/oassoch.ml create mode 100644 commons/oassocid.ml create mode 100644 commons/objet.ml create mode 100644 commons/objet.mli create mode 100644 commons/ocamlextra/ANSITerminal.ml create mode 100644 commons/ocamlextra/ANSITerminal.mli create mode 100644 commons/ocamlextra/dumper.ml create mode 100644 commons/ocamlextra/dumper.mli create mode 100644 commons/ocamlextra/dynArray.ml create mode 100644 commons/ocamlextra/dynArray.mli create mode 100644 commons/ocamlextra/enum.ml create mode 100644 commons/ocamlextra/enum.mli create mode 100644 commons/ocamlextra/mapb.ml create mode 100644 commons/ocamlextra/parser_combinators.ml create mode 100644 commons/ocamlextra/parser_combinators.mli create mode 100644 commons/ocamlextra/setPt.ml create mode 100644 commons/ocamlextra/setb.ml create mode 100644 commons/ocamlextra/setb.mli create mode 100644 commons/ocamlextra/suffix_tree.ml create mode 100644 commons/ocamlextra/suffix_tree.mli create mode 100644 commons/ocamlextra/suffix_tree_ext.ml create mode 100644 commons/ocamlextra/suffix_tree_ext.mli create mode 100644 commons/ocollection.ml create mode 100644 commons/ocollection.mli create mode 100644 commons/ofullcommon.ml create mode 100644 commons/ograph.ml create mode 100644 commons/ograph.mli create mode 100644 commons/ograph2way.ml create mode 100644 commons/ograph2way.mli create mode 100644 commons/ograph_extended.ml create mode 100644 commons/ograph_extended.mli create mode 100644 commons/osequence.ml create mode 100644 commons/osequence.mli create mode 100644 commons/oset.ml create mode 100644 commons/oset.mli create mode 100644 commons/osetb.ml create mode 100644 commons/oseth.ml create mode 100644 commons/oseti.ml create mode 100644 commons/osetpt.ml create mode 100644 commons/seti.ml create mode 100755 configure create mode 100644 copyright.txt create mode 100644 credits.txt create mode 100644 ctl/.depend create mode 100644 ctl/Makefile create mode 100644 ctl/ast_ctl.ml create mode 100644 ctl/ctl_engine.ml create mode 100644 ctl/ctl_engine.mli create mode 100644 ctl/double_negate_ml create mode 100644 ctl/flag_ctl.ml create mode 100644 ctl/pretty_print_ctl.ml create mode 100644 ctl/pretty_print_ctl.mli create mode 100644 ctl/test_ctl.ml create mode 100644 ctl/wrapper_ctl.ml create mode 100644 ctl/wrapper_ctl.mli create mode 100644 demos/check_region.c create mode 100644 demos/check_region.cocci create mode 100644 demos/ctr_unit_test.c create mode 100644 demos/ctr_unit_test.cocci create mode 100644 demos/demo_rule9/README create mode 100644 demos/demo_rule9/g_NCR5380.c create mode 100644 demos/demo_rule9/g_NCR5380.res create mode 100644 demos/demo_rule9/nsp_cs.c create mode 100644 demos/demo_rule9/nsp_cs.res create mode 100644 demos/demo_rule9/rule9.cocci create mode 100644 demos/demo_rule9/rule9_1.cocci create mode 100644 demos/demo_rule9/rule9_2.cocci create mode 100644 demos/demo_rule9/rule9_3.cocci create mode 100644 demos/demo_rule9/rule9_4.cocci create mode 100644 demos/demo_rule9/rule9_5.cocci create mode 100644 demos/demo_rule9/scsiglue.c create mode 100644 demos/demo_rule9/scsiglue.res create mode 100644 demos/demo_rule9/sym53c8xx.c create mode 100644 demos/demo_rule9/sym53c8xx.res create mode 100644 demos/foo.c create mode 100644 demos/foo.cocci create mode 100644 demos/foobar.c create mode 100644 demos/foobar.cocci create mode 100644 demos/headers.cocci create mode 100644 demos/headers.iso create mode 100644 demos/headers2.iso create mode 100644 demos/interprocedural_adhoc.c create mode 100644 demos/interprocedural_adhoc.cocci create mode 100644 demos/ioctl_multiple_rules.c create mode 100644 demos/ioctl_multiple_rules.cocci create mode 100644 demos/iso-kzalloc.c create mode 100644 demos/iso-kzalloc.cocci create mode 100644 demos/itimer.c create mode 100644 demos/itimer.cocci create mode 100644 demos/itimer.patch create mode 100644 demos/itimer.res create mode 100644 demos/itimerfullfunc.sgrep create mode 100644 demos/janitorings/ARRAY_SIZE.cocci create mode 100644 demos/janitorings/BUG_ON.cocci create mode 100644 demos/janitorings/BUG_ON.sgrep create mode 100644 demos/janitorings/alloc_page.cocci create mode 100644 demos/janitorings/bad_zero-orig.cocci create mode 100644 demos/janitorings/bad_zero.c create mode 100644 demos/janitorings/bad_zero.cocci create mode 100644 demos/janitorings/bad_zero_affect.cocci create mode 100644 demos/janitorings/clear_page.cocci create mode 100644 demos/janitorings/is_power_of_2.cocci create mode 100644 demos/janitorings/kcalloc_un.cocci create mode 100644 demos/janitorings/kzalloc-fix.cocci create mode 100644 demos/janitorings/kzalloc-orig.cocci create mode 100644 demos/janitorings/kzalloc.cocci create mode 100644 demos/janitorings/list_for_each.c create mode 100644 demos/janitorings/list_for_each.cocci create mode 100644 demos/janitorings/list_for_each_safe.c create mode 100644 demos/janitorings/list_for_each_safe.sgrep create mode 100644 demos/janitorings/netdev_find_allocfunc.c create mode 100644 demos/janitorings/netdev_find_allocfunc.sgrep create mode 100644 demos/janitorings/netdev_priv.c create mode 100644 demos/janitorings/netdev_priv.cocci create mode 100644 demos/janitorings/netdev_priv2.cocci create mode 100644 demos/janitorings/netdev_priv_dangerous.sgrep create mode 100644 demos/janitorings/remove_cast_kmalloc.cocci create mode 100644 demos/janitorings/set_current_state.cocci create mode 100644 demos/janitorings/static_initfunc.c create mode 100644 demos/janitorings/static_initfunc.cocci create mode 100644 demos/janitorings/string-array-decl-opti.c create mode 100644 demos/janitorings/string-array-decl-opti.cocci create mode 100644 demos/janitorings/useless_cast.c create mode 100644 demos/janitorings/useless_cast.cocci create mode 100755 demos/launch.sh create mode 100644 demos/manual/already_tagged.c create mode 100644 demos/manual/already_tagged.cocci create mode 100644 demos/manual/get_put.c create mode 100644 demos/manual/get_put.cocci create mode 100644 demos/manual/get_put_full.c create mode 100644 demos/manual/get_put_full.cocci create mode 100644 demos/manual/get_put_ver1.c create mode 100644 demos/not.c create mode 100644 demos/not.cocci create mode 100644 demos/not.res create mode 100644 demos/posmult.c create mode 100644 demos/posmult.cocci create mode 100644 demos/printloc.c create mode 100644 demos/printloc.cocci create mode 100644 demos/proc_info.c create mode 100644 demos/proc_info.cocci create mode 100644 demos/pycocci.c create mode 100644 demos/pycocci.cocci create mode 100644 demos/sgrep/README create mode 100644 demos/sgrep/a_and_b.c create mode 100644 demos/sgrep/a_and_b.sgrep create mode 100644 demos/sgrep/dangerous_GFP_KERNEL.sgrep create mode 100644 demos/sgrep/dangerous_GFP_KERNEL2.sgrep create mode 100644 demos/sgrep/dangerous_arith_pointer_cast.sgrep create mode 100644 demos/sgrep/device_id.sgrep create mode 100644 demos/sgrep/double_cast.sgrep create mode 100644 demos/sgrep/free.sgrep create mode 100644 demos/sgrep/intr4.sgrep create mode 100644 demos/sgrep/null.sgrep create mode 100644 demos/sgrep/run.sh create mode 100644 demos/sgrep/simple.c create mode 100644 demos/sgrep/simple.sgrep create mode 100644 demos/simple.c create mode 100644 demos/simple.cocci create mode 100644 demos/type_fields.c create mode 100644 demos/type_fields.cocci create mode 100644 demos/unsigned.cocci create mode 100644 demos/unsigned.txt create mode 100644 demos/usb_submit_urb.c create mode 100644 demos/usb_submit_urb.cocci create mode 100644 demos/video_usercopy.c create mode 100644 demos/video_usercopy.cocci create mode 100644 demos/xxx_info.c create mode 100644 demos/xxx_info.cocci create mode 100644 docs/SmPL-ver2-tutorial-ols07.pdf create mode 100644 docs/SmPL-with-grammar-ercim-evos06.pdf create mode 100644 docs/cocci-python.txt create mode 100644 docs/developer.txt create mode 100644 docs/graph-module-dependencies.ps create mode 100644 docs/manual.tex create mode 100644 docs/semantic-patches-for-collateral-evolutions.ppt create mode 100644 docs/semantic-patches-talk-ols07.odp create mode 100644 docs/semantic-patches-talk-ols07.ppt create mode 100644 emacs/cocci-ediff.el create mode 100644 emacs/cocci.el create mode 100644 empty.h create mode 100644 empty.iso create mode 100644 engine/.depend create mode 100644 engine/Makefile create mode 100644 engine/asttoctl.ml create mode 100644 engine/asttoctl.mli create mode 100644 engine/asttoctl2.ml create mode 100644 engine/asttoctl2.mli create mode 100644 engine/asttomember.ml create mode 100644 engine/asttomember.mli create mode 100644 engine/c_vs_c.ml create mode 100644 engine/c_vs_c.mli create mode 100644 engine/check_exhaustive_pattern.ml create mode 100644 engine/check_reachability.ml create mode 100644 engine/check_reachability.mli create mode 100644 engine/cocci_vs_c_3.ml create mode 100644 engine/cocci_vs_c_3.mli create mode 100644 engine/ctlcocci_integration.ml create mode 100644 engine/ctlcocci_integration.mli create mode 100644 engine/ctltotex.ml create mode 100644 engine/ctltotex.mli create mode 100644 engine/flag_engine.ml create mode 100644 engine/isomorphisms_c_c.ml create mode 100644 engine/lib_engine.ml create mode 100644 engine/main.ml create mode 100644 engine/pattern3.ml create mode 100644 engine/pattern3.mli create mode 100644 engine/postprocess_transinfo.ml create mode 100644 engine/postprocess_transinfo.mli create mode 100644 engine/pretty_print_engine.ml create mode 100644 engine/pretty_print_engine.mli create mode 100644 engine/sgrep.ml create mode 100644 engine/tests/Makefile create mode 100644 engine/tests/test1 create mode 100644 engine/tests/test1.tex create mode 100644 engine/transformation3.ml create mode 100644 engine/transformation3.mli create mode 100644 env.csh create mode 100644 env.sh create mode 100644 extra/.depend create mode 100644 extra/Makefile create mode 100644 extra/c_info.ml create mode 100644 extra/c_info.mli create mode 100644 extra/classic_patch.ml create mode 100644 extra/classic_patch.mli create mode 100644 extra/kbuild.ml create mode 100644 extra/kbuild.mli create mode 100644 extra/maintainers.ml create mode 100644 extra/maintainers.mli create mode 100644 flag_cocci.ml create mode 100644 globals/.depend create mode 100644 globals/Makefile create mode 100644 globals/config.ml create mode 100644 globals/flag.ml create mode 100644 install.txt create mode 100644 license.txt create mode 100644 main.ml create mode 100644 menhirlib/.depend create mode 100644 menhirlib/Makefile create mode 100644 menhirlib/convert.ml create mode 100644 menhirlib/engine.ml create mode 100644 menhirlib/engineTypes.ml create mode 100644 menhirlib/infiniteArray.ml create mode 100644 menhirlib/license.txt create mode 100644 menhirlib/packedIntArray.ml create mode 100644 menhirlib/readme.txt create mode 100644 menhirlib/rowDisplacement.ml create mode 100644 menhirlib/tableFormat.ml create mode 100644 menhirlib/tableInterpreter.ml create mode 100644 parsing_c/.depend create mode 100644 parsing_c/Makefile create mode 100644 parsing_c/ast_c.ml create mode 100644 parsing_c/ast_to_flow.ml create mode 100644 parsing_c/ast_to_flow.mli create mode 100644 parsing_c/authors.txt create mode 100644 parsing_c/compare_c.ml create mode 100644 parsing_c/compare_c.mli create mode 100644 parsing_c/control_flow_c.ml create mode 100644 parsing_c/control_flow_c.mli create mode 100644 parsing_c/copyright.txt create mode 100644 parsing_c/credits.txt create mode 100644 parsing_c/flag_parsing_c.ml create mode 100644 parsing_c/lexer_c.mll create mode 100644 parsing_c/lexer_parser.ml create mode 100644 parsing_c/lexer_parser.mli create mode 100644 parsing_c/lib_parsing_c.ml create mode 100644 parsing_c/license.txt create mode 100644 parsing_c/parse_c.ml create mode 100644 parsing_c/parse_c.mli create mode 100644 parsing_c/parser_c.mly create mode 100644 parsing_c/parsing_hacks.ml create mode 100644 parsing_c/parsing_hacks.mli create mode 100644 parsing_c/pretty_print_c.ml create mode 100644 parsing_c/pretty_print_c.mli create mode 100644 parsing_c/semantic_c.ml create mode 100644 parsing_c/test_parsing_c.ml create mode 100644 parsing_c/test_parsing_c.mli create mode 100644 parsing_c/token_helpers.ml create mode 100644 parsing_c/token_helpers.mli create mode 100644 parsing_c/type_annoter_c.ml create mode 100644 parsing_c/type_annoter_c.mli create mode 100644 parsing_c/unparse_c2.ml create mode 100644 parsing_c/unparse_c2.mli create mode 100644 parsing_c/unparse_cocci2.ml create mode 100644 parsing_c/unparse_cocci2.mli create mode 100644 parsing_c/unparse_hrule.ml create mode 100644 parsing_c/unparse_hrule.mli create mode 100644 parsing_c/visitor_c.ml create mode 100644 parsing_c/visitor_c.mli create mode 100644 parsing_cocci/.depend create mode 100644 parsing_cocci/Makefile create mode 100644 parsing_cocci/README create mode 100644 parsing_cocci/arity.ml create mode 100644 parsing_cocci/arity.mli create mode 100644 parsing_cocci/ast0_cocci.ml create mode 100644 parsing_cocci/ast0_cocci.mli create mode 100644 parsing_cocci/ast0toast.ml create mode 100644 parsing_cocci/ast0toast.mli create mode 100644 parsing_cocci/ast_cocci.ml create mode 100644 parsing_cocci/ast_cocci.mli create mode 100644 parsing_cocci/check_meta.ml create mode 100644 parsing_cocci/check_meta.mli create mode 100644 parsing_cocci/comm_assoc.ml create mode 100644 parsing_cocci/comm_assoc.mli create mode 100644 parsing_cocci/compute_lines.ml create mode 100644 parsing_cocci/compute_lines.mli create mode 100644 parsing_cocci/context_neg.ml create mode 100644 parsing_cocci/context_neg.mli create mode 100644 parsing_cocci/data.ml create mode 100644 parsing_cocci/data.mli create mode 100644 parsing_cocci/disjdistr.ml create mode 100644 parsing_cocci/disjdistr.mli create mode 100644 parsing_cocci/flag_parsing_cocci.ml create mode 100644 parsing_cocci/free_vars.ml create mode 100644 parsing_cocci/free_vars.mli create mode 100644 parsing_cocci/function_prototypes.ml create mode 100644 parsing_cocci/function_prototypes.mli create mode 100644 parsing_cocci/get_constants.ml create mode 100644 parsing_cocci/get_constants.mli create mode 100644 parsing_cocci/get_constants2.ml create mode 100644 parsing_cocci/get_constants2.mli create mode 100644 parsing_cocci/index.ml create mode 100644 parsing_cocci/index.mli create mode 100644 parsing_cocci/insert_plus.ml create mode 100644 parsing_cocci/insert_plus.mli create mode 100644 parsing_cocci/iso_compile.ml create mode 100644 parsing_cocci/iso_compile.mli create mode 100644 parsing_cocci/iso_pattern.ml create mode 100644 parsing_cocci/iso_pattern.mli create mode 100644 parsing_cocci/lexer_cocci.mll create mode 100644 parsing_cocci/lexer_script.mll create mode 100644 parsing_cocci/main.ml create mode 100644 parsing_cocci/merge.ml create mode 100644 parsing_cocci/merge.mli create mode 100644 parsing_cocci/parse_aux.ml create mode 100644 parsing_cocci/parse_cocci.ml create mode 100644 parsing_cocci/parse_cocci.mli create mode 100644 parsing_cocci/parser_cocci.mly create mode 100644 parsing_cocci/parser_cocci_menhir.ml create mode 100644 parsing_cocci/parser_cocci_menhir.mli create mode 100644 parsing_cocci/parser_cocci_menhir.mly create mode 100644 parsing_cocci/plus.ml create mode 100644 parsing_cocci/plus.mli create mode 100644 parsing_cocci/pretty_print_cocci.ml create mode 100644 parsing_cocci/pretty_print_cocci.mli create mode 100644 parsing_cocci/semantic_cocci.ml create mode 100644 parsing_cocci/simple_assignments.ml create mode 100644 parsing_cocci/simple_assignments.mli create mode 100644 parsing_cocci/single_statement.ml create mode 100644 parsing_cocci/single_statement.mli create mode 100644 parsing_cocci/test.cocci create mode 100644 parsing_cocci/test2.cocci create mode 100644 parsing_cocci/test_exps.ml create mode 100644 parsing_cocci/test_exps.mli create mode 100644 parsing_cocci/tests/1.cocci create mode 100644 parsing_cocci/tests/10.cocci create mode 100644 parsing_cocci/tests/11.cocci create mode 100644 parsing_cocci/tests/12.cocci create mode 100644 parsing_cocci/tests/13.cocci create mode 100644 parsing_cocci/tests/14.cocci create mode 100644 parsing_cocci/tests/15.cocci create mode 100644 parsing_cocci/tests/16.cocci create mode 100644 parsing_cocci/tests/17.cocci create mode 100644 parsing_cocci/tests/18.cocci create mode 100644 parsing_cocci/tests/19.cocci create mode 100644 parsing_cocci/tests/2.cocci create mode 100644 parsing_cocci/tests/20.cocci create mode 100644 parsing_cocci/tests/21.cocci create mode 100644 parsing_cocci/tests/22.cocci create mode 100644 parsing_cocci/tests/23.cocci create mode 100644 parsing_cocci/tests/24.cocci create mode 100644 parsing_cocci/tests/25.cocci create mode 100644 parsing_cocci/tests/26.cocci create mode 100644 parsing_cocci/tests/27.cocci create mode 100644 parsing_cocci/tests/28.cocci create mode 100644 parsing_cocci/tests/29.cocci create mode 100644 parsing_cocci/tests/3.cocci create mode 100644 parsing_cocci/tests/30.cocci create mode 100644 parsing_cocci/tests/4.cocci create mode 100644 parsing_cocci/tests/5.cocci create mode 100644 parsing_cocci/tests/6.cocci create mode 100644 parsing_cocci/tests/7.cocci create mode 100644 parsing_cocci/tests/8.cocci create mode 100644 parsing_cocci/tests/9.cocci create mode 100644 parsing_cocci/tests/Makefile create mode 100644 parsing_cocci/tests/problems create mode 100644 parsing_cocci/top_level.ml create mode 100644 parsing_cocci/top_level.mli create mode 100644 parsing_cocci/type_cocci.ml create mode 100644 parsing_cocci/type_cocci.mli create mode 100644 parsing_cocci/type_infer.ml create mode 100644 parsing_cocci/type_infer.mli create mode 100644 parsing_cocci/unify_ast.ml create mode 100644 parsing_cocci/unify_ast.mli create mode 100644 parsing_cocci/unitary_ast0.ml create mode 100644 parsing_cocci/unitary_ast0.mli create mode 100644 parsing_cocci/unparse_ast0.ml create mode 100644 parsing_cocci/unparse_ast0.mli create mode 100644 parsing_cocci/visitor_ast.ml create mode 100644 parsing_cocci/visitor_ast.mli create mode 100644 parsing_cocci/visitor_ast0.ml create mode 100644 parsing_cocci/visitor_ast0.mli create mode 100644 popl/Makefile create mode 100644 popl/ast_popl.ml create mode 100644 popl/asttopopl.ml create mode 100644 popl/asttopopl.mli create mode 100644 popl/insert_befaft.ml create mode 100644 popl/insert_befaft.mli create mode 100644 popl/insert_quantifiers.ml create mode 100644 popl/insert_quantifiers.mli create mode 100644 popl/popl.ml create mode 100644 popl/popl.mli create mode 100644 popl/popltoctl.ml create mode 100644 popl/popltoctl.mli create mode 100644 popl/pretty_print_popl.ml create mode 100644 popl/pretty_print_popl.mli create mode 100644 popl09/.depend create mode 100644 popl09/Makefile create mode 100644 popl09/ast_popl.ml create mode 100644 popl09/asttopopl.ml create mode 100644 popl09/asttopopl.mli create mode 100644 popl09/flag_popl.ml create mode 100644 popl09/insert_quantifiers.ml create mode 100644 popl09/insert_quantifiers.mli create mode 100644 popl09/popl.ml create mode 100644 popl09/popl.mli create mode 100644 popl09/popltoctl.ml create mode 100644 popl09/popltoctl.mli create mode 100644 popl09/pretty_print_popl.ml create mode 100644 popl09/pretty_print_popl.mli create mode 100644 prim.c create mode 100644 pycaml/Makefile create mode 100644 pycaml/Makefile.in create mode 100644 pycaml/OCamlMakefile create mode 100644 pycaml/acinclude.m4 create mode 100644 pycaml/aclocal.m4 create mode 100644 pycaml/configure create mode 100644 pycaml/configure.in create mode 100644 pycaml/getprefix.py create mode 100644 pycaml/getversion.py create mode 100644 pycaml/license.txt create mode 100644 pycaml/modif-orig.txt create mode 100644 pycaml/ocamlobj.ml create mode 100644 pycaml/pycaml.html create mode 100644 pycaml/pycaml.ml create mode 100644 pycaml/pycaml_ml.c create mode 100644 pycaml/pycamltest.ml create mode 100644 pycaml/tupletest.ml create mode 100644 python/.depend create mode 100644 python/Makefile create mode 100644 python/coccilib/Makefile create mode 100644 python/coccilib/__init__.py create mode 100644 python/coccilib/coccigui/Makefile create mode 100644 python/coccilib/coccigui/__init__.py create mode 100644 python/coccilib/coccigui/coccigui.py create mode 100644 python/coccilib/coccigui/pycoccimodel.py create mode 100644 python/coccilib/coccigui/pygui.glade create mode 100644 python/coccilib/coccigui/pygui.gladep create mode 100644 python/coccilib/coccigui/vim.py create mode 100644 python/coccilib/coccigui/vimcom.py create mode 100644 python/coccilib/coccigui/vimeditor.py create mode 100644 python/coccilib/coccigui/vimembed.py create mode 100644 python/coccilib/elems.py create mode 100644 python/coccilib/output.py create mode 100644 python/no_pycocci.ml create mode 100644 python/no_pycocci_aux.ml create mode 120000 python/pycocci.ml create mode 120000 python/pycocci_aux.ml create mode 100644 python/yes_pycocci.ml create mode 100644 python/yes_pycocci_aux.ml create mode 100644 readme.txt create mode 100755 runspatch.opt create mode 100755 scripts/extract_c_and_res.pl create mode 100755 scripts/extract_examples.pl create mode 100755 scripts/extractor.awk create mode 100755 scripts/extractor_README.pl create mode 100755 scripts/gather_failed.pl create mode 100755 scripts/glimpseindex_cocci.sh create mode 100755 scripts/readme.pl create mode 100755 scripts/stat_directories.pl create mode 100755 scripts/stat_directories_complete.pl create mode 100755 scripts/stat_directory_complete.pl create mode 100644 standard.h create mode 100644 standard.iso create mode 100644 test.ml create mode 100644 testing.ml create mode 100644 testing.mli create mode 100644 tests/A_and_E.c create mode 100644 tests/A_and_E.cocci create mode 100644 tests/A_and_E.res create mode 100644 tests/A_and_E_ver1.c create mode 100644 tests/A_and_E_ver1.res create mode 100644 tests/a3d.c create mode 100644 tests/a3d.cocci create mode 100644 tests/a3d.res create mode 100644 tests/addelse.c create mode 100644 tests/addelse.cocci create mode 100644 tests/addelse.res create mode 100644 tests/after_if.c create mode 100644 tests/after_if.cocci create mode 100644 tests/after_if.res create mode 100644 tests/ali.c create mode 100644 tests/ali.cocci create mode 100644 tests/allbound.c create mode 100644 tests/allbound.cocci create mode 100644 tests/andparen.c create mode 100644 tests/andparen.cocci create mode 100644 tests/anon.c create mode 100644 tests/anon.cocci create mode 100644 tests/anon.res create mode 100644 tests/ar.c create mode 100644 tests/ar.cocci create mode 100644 tests/ar.res create mode 100644 tests/arg.c create mode 100644 tests/arg.cocci create mode 100644 tests/arg.res create mode 100644 tests/argument.c create mode 100644 tests/argument.cocci create mode 100644 tests/argument.res create mode 100644 tests/array.c create mode 100644 tests/array.cocci create mode 100644 tests/array_init.c create mode 100644 tests/array_init.cocci create mode 100644 tests/array_init.res create mode 100644 tests/array_size.c create mode 100644 tests/array_size.cocci create mode 100644 tests/array_size.res create mode 100644 tests/arraysz.c create mode 100644 tests/arraysz.cocci create mode 100644 tests/arraysz.res create mode 100644 tests/assign.c create mode 100644 tests/assign.cocci create mode 100644 tests/axnet.c create mode 100644 tests/axnet.cocci create mode 100644 tests/b1.c create mode 100644 tests/b1.cocci create mode 100644 tests/b1.res create mode 100644 tests/b2.c create mode 100644 tests/b2.cocci create mode 100644 tests/b2.res create mode 100644 tests/bad_assign.cocci create mode 100644 tests/bad_define.c create mode 100644 tests/bad_define.cocci create mode 100644 tests/bad_define.res create mode 100644 tests/bad_iso_example.c create mode 100644 tests/bad_iso_example.cocci create mode 100644 tests/bad_iso_example.res create mode 100644 tests/bad_noputm1 create mode 100644 tests/bad_subsumption.c create mode 100644 tests/bad_subsumption.cocci create mode 100644 tests/bad_typedef.c create mode 100644 tests/bad_typedef.cocci create mode 100644 tests/bad_typedef.res create mode 100644 tests/bad_zero.cocci create mode 100644 tests/badaw.c create mode 100644 tests/badaw.cocci create mode 100644 tests/badcomma.c create mode 100644 tests/badcomma.cocci create mode 100644 tests/badexp.c create mode 100644 tests/badexp.cocci create mode 100644 tests/badexp.res create mode 100644 tests/badexp1.c create mode 100644 tests/badexp1.cocci create mode 100644 tests/badfree.c create mode 100644 tests/badfree.cocci create mode 100644 tests/badpos.c create mode 100644 tests/badpos.cocci create mode 100644 tests/badpos.res create mode 100644 tests/badpost.cocci create mode 100644 tests/badprint.c create mode 100644 tests/badtypedef.c create mode 100644 tests/badtypedef.cocci create mode 100644 tests/badtypedef.res create mode 100644 tests/bitfield.c create mode 100644 tests/bitfield.cocci create mode 100644 tests/bitfield.res create mode 100644 tests/braces.c create mode 100644 tests/braces.cocci create mode 100644 tests/braces.res create mode 100644 tests/break.c create mode 100644 tests/break.cocci create mode 100644 tests/break.res create mode 100644 tests/bug1.c create mode 100644 tests/bug1.cocci create mode 100644 tests/bug1.res create mode 100644 tests/bug_expopt.c create mode 100644 tests/bug_expopt.cocci create mode 100644 tests/bugloop.c create mode 100644 tests/bugloop.cocci create mode 100644 tests/bugloop.res create mode 100644 tests/bugon.c create mode 100644 tests/bugon.cocci create mode 100644 tests/bugon.res create mode 100644 tests/cards.c create mode 100644 tests/cards.cocci create mode 100644 tests/cards.res create mode 100644 tests/cast.c create mode 100644 tests/cast.cocci create mode 100644 tests/cast.res create mode 100644 tests/cast_iso.c create mode 100644 tests/cast_iso.cocci create mode 100644 tests/cast_iso.res create mode 100644 tests/comment.c create mode 100644 tests/comment.cocci create mode 100644 tests/compare.c create mode 100644 tests/compare.cocci create mode 100644 tests/compare.res create mode 100644 tests/const.c create mode 100644 tests/const.cocci create mode 100644 tests/const.res create mode 100644 tests/const1.c create mode 100644 tests/const1.cocci create mode 100644 tests/const1bis.c create mode 100644 tests/const1bis.cocci create mode 100644 tests/const1bis.res create mode 100644 tests/const_adding.c create mode 100644 tests/const_adding.cocci create mode 100644 tests/const_adding.res create mode 100644 tests/const_array.c create mode 100644 tests/const_array.cocci create mode 100644 tests/const_array.res create mode 100644 tests/const_implicit_iso.c create mode 100644 tests/const_implicit_iso.cocci create mode 100644 tests/const_implicit_iso.res create mode 100644 tests/constty.c create mode 100644 tests/constty.cocci create mode 100644 tests/constty.res create mode 100644 tests/constx.c create mode 100644 tests/constx.cocci create mode 100644 tests/constx.res create mode 100644 tests/cr.c create mode 100644 tests/cr.cocci create mode 100644 tests/cr1.c create mode 100644 tests/cr1.cocci create mode 100644 tests/cs_check.c create mode 100644 tests/cs_check.cocci create mode 100644 tests/cs_check.res create mode 100644 tests/cst.c create mode 100644 tests/cst.cocci create mode 100644 tests/cst.res create mode 100644 tests/csw.c create mode 100644 tests/csw.cocci create mode 100644 tests/csw.res create mode 100644 tests/ctr_unit_test.c create mode 100644 tests/ctr_unit_test.cocci create mode 100644 tests/dbg.c create mode 100644 tests/dbg.cocci create mode 100644 tests/dbg.res create mode 100644 tests/dc_close.c create mode 100644 tests/dc_close.cocci create mode 100644 tests/dc_close.res create mode 100644 tests/debug.c create mode 100644 tests/debug.cocci create mode 100644 tests/debug.res create mode 100644 tests/dec.c create mode 100644 tests/dec.cocci create mode 100644 tests/dec.res create mode 100644 tests/decl.c create mode 100644 tests/decl.cocci create mode 100644 tests/decl.res create mode 100644 tests/decl1.c create mode 100644 tests/decl1.cocci create mode 100644 tests/decl2.c create mode 100644 tests/decl2.cocci create mode 100644 tests/decl2.res create mode 100644 tests/decl_space.c create mode 100644 tests/decl_space.cocci create mode 100644 tests/decl_space.res create mode 100644 tests/decl_split.c create mode 100644 tests/decl_split.cocci create mode 100644 tests/decl_split.res create mode 100644 tests/decl_ver1.c create mode 100644 tests/define_chip_t.c create mode 100644 tests/define_chip_t.cocci create mode 100644 tests/define_exp.c create mode 100644 tests/define_exp.cocci create mode 100644 tests/define_exp.res create mode 100644 tests/define_param.c create mode 100644 tests/define_param.cocci create mode 100644 tests/define_param.res create mode 100644 tests/dep.c create mode 100644 tests/dep.cocci create mode 100644 tests/deref.c create mode 100644 tests/deref.cocci create mode 100644 tests/deref.res create mode 100644 tests/desc.c create mode 100644 tests/detect_alloc.cocci create mode 100644 tests/devlink.c create mode 100644 tests/devlink.cocci create mode 100644 tests/devlink.res create mode 100644 tests/disjexpr.c create mode 100644 tests/disjexpr.cocci create mode 100644 tests/disjexpr.res create mode 100644 tests/disjexpr_ver1.c create mode 100644 tests/disjexpr_ver1.res create mode 100644 tests/disjexpr_ver2.c create mode 100644 tests/disjexpr_ver2.res create mode 100644 tests/distribute.c create mode 100644 tests/distribute.cocci create mode 100644 tests/distribute.res create mode 100644 tests/double.c create mode 100644 tests/double.cocci create mode 100644 tests/double.res create mode 100644 tests/double_assign.c create mode 100644 tests/double_assign.cocci create mode 100644 tests/double_assign.res create mode 100644 tests/doublepos.c create mode 100644 tests/doublepos.cocci create mode 100644 tests/doublepos.res create mode 100644 tests/dowhile.c create mode 100644 tests/dowhile.cocci create mode 100644 tests/dowhile.res create mode 100644 tests/dropf.c create mode 100644 tests/dropf.cocci create mode 100644 tests/dropf.res create mode 100644 tests/dropparam.c create mode 100644 tests/dropparam.cocci create mode 100644 tests/dropparam.res create mode 100644 tests/edots.c create mode 100644 tests/edots.cocci create mode 100644 tests/edots.res create mode 100644 tests/edots_ver1.c create mode 100644 tests/edots_ver1.res create mode 100644 tests/empty.c create mode 100644 tests/empty.cocci create mode 100644 tests/empty.res create mode 100644 tests/end_commas.c create mode 100644 tests/end_commas.cocci create mode 100644 tests/end_commas.res create mode 100644 tests/endif.c create mode 100644 tests/endif.cocci create mode 100644 tests/endif.res create mode 100644 tests/exp.c create mode 100644 tests/exp.cocci create mode 100644 tests/exp.res create mode 100644 tests/expnest.c create mode 100644 tests/expnest.cocci create mode 100644 tests/expnest.res create mode 100644 tests/expopt.c create mode 100644 tests/expopt.cocci create mode 100644 tests/expopt.res create mode 100644 tests/expopt2.c create mode 100644 tests/expopt2.cocci create mode 100644 tests/expopt2.res create mode 100644 tests/expopt3.c create mode 100644 tests/expopt3.cocci create mode 100644 tests/expopt3.res create mode 100644 tests/expopt3_ver1.c create mode 100644 tests/expopt3_ver1.res create mode 100644 tests/expopt3_ver2.c create mode 100644 tests/expopt3_ver2.res create mode 100644 tests/expopt4.c create mode 100644 tests/expopt4.cocci create mode 100644 tests/fields.c create mode 100644 tests/fields.cocci create mode 100644 tests/fields.res create mode 100644 tests/fieldsmin.c create mode 100644 tests/fieldsmin.cocci create mode 100644 tests/fieldsmin.res create mode 100644 tests/fix_flow_need.c create mode 100644 tests/fix_flow_need.cocci create mode 100644 tests/fix_flow_need.res create mode 100644 tests/fn_todo.c create mode 100644 tests/fn_todo.cocci create mode 100644 tests/fn_todo.res create mode 100644 tests/fnptr.c create mode 100644 tests/fnptr.cocci create mode 100644 tests/fnptr.res create mode 100644 tests/fnret.c create mode 100644 tests/fnret.cocci create mode 100644 tests/fnret.res create mode 100644 tests/fns.c create mode 100644 tests/fns.cocci create mode 100644 tests/four.c create mode 100644 tests/four.cocci create mode 100644 tests/four.res create mode 100644 tests/foura.c create mode 100644 tests/foura.cocci create mode 100644 tests/foura.res create mode 100644 tests/fp.c create mode 100644 tests/fp.cocci create mode 100644 tests/fp.res create mode 100644 tests/free.c create mode 100644 tests/free.cocci create mode 100644 tests/free_ver5.c create mode 100644 tests/fun.c create mode 100644 tests/fun.cocci create mode 100644 tests/fun.res create mode 100644 tests/gilles-question.c create mode 100644 tests/gilles-question.cocci create mode 100644 tests/gilles-question.res create mode 100644 tests/gotobreak.c create mode 100644 tests/gotobreak.cocci create mode 100644 tests/gotobreak.res create mode 100644 tests/hd.c create mode 100644 tests/hd.cocci create mode 100644 tests/hd.h create mode 100644 tests/hd.res create mode 100644 tests/header_modif.c create mode 100644 tests/header_modif.cocci create mode 100644 tests/header_modif.h create mode 100644 tests/headers.c create mode 100644 tests/headers.cocci create mode 100644 tests/headers.res create mode 100644 tests/hex.c create mode 100644 tests/hex.cocci create mode 100644 tests/hex.res create mode 100644 tests/hex2.c create mode 100644 tests/hex2.cocci create mode 100644 tests/hex2.res create mode 100644 tests/if2.c create mode 100644 tests/if2.cocci create mode 100644 tests/ifbr.c create mode 100644 tests/ifbr.cocci create mode 100644 tests/ifbr.res create mode 100644 tests/ifdef1.c create mode 100644 tests/ifdef1.cocci create mode 100644 tests/ifdef1.res create mode 100644 tests/ifdef2.c create mode 100644 tests/ifdef2.cocci create mode 100644 tests/ifdef2.res create mode 100644 tests/ifdef3.c create mode 100644 tests/ifdef3.cocci create mode 100644 tests/ifdef3.res create mode 100644 tests/ifdef4.c create mode 100644 tests/ifdef4.cocci create mode 100644 tests/ifdef4.res create mode 100644 tests/ifdef5.c create mode 100644 tests/ifdef5.cocci create mode 100644 tests/ifdef5.res create mode 100644 tests/ifdef6.c create mode 100644 tests/ifdef6.cocci create mode 100644 tests/ifdef6.res create mode 100644 tests/ifend.c create mode 100644 tests/ifend.cocci create mode 100644 tests/ifend.res create mode 100644 tests/ifzer.c create mode 100644 tests/ifzer.cocci create mode 100644 tests/ifzer.res create mode 100644 tests/inc.c create mode 100644 tests/inc.cocci create mode 100644 tests/inc.res create mode 100644 tests/incdir.c create mode 100644 tests/incdir.cocci create mode 100644 tests/incdir.res create mode 100644 tests/incdir2.c create mode 100644 tests/incl.c create mode 100644 tests/incl.cocci create mode 100644 tests/incl.res create mode 100644 tests/inclifdef.c create mode 100644 tests/inclifdef.cocci create mode 100644 tests/inclifdef.res create mode 100644 tests/include.c create mode 100644 tests/include.cocci create mode 100644 tests/include.res create mode 100644 tests/include/linux/serio.h create mode 100644 tests/include/linux/serio.h.res create mode 100644 tests/incompatible_value.c create mode 100644 tests/incompatible_value.cocci create mode 100644 tests/incompatible_value.res create mode 100644 tests/inherited.c create mode 100644 tests/inherited.cocci create mode 100644 tests/inherited.res create mode 100644 tests/inherited_ver1.c create mode 100644 tests/inherited_ver1.res create mode 100644 tests/inhpos.c create mode 100644 tests/inhpos.cocci create mode 100644 tests/inhpos.res create mode 100644 tests/initializer.c create mode 100644 tests/initializer.cocci create mode 100644 tests/initializer.res create mode 100644 tests/initializer_iso.c create mode 100644 tests/initializer_iso.cocci create mode 100644 tests/initializer_many_fields.c create mode 100644 tests/initializer_many_fields.cocci create mode 100644 tests/initializer_many_fields.res create mode 100644 tests/inline.c create mode 100644 tests/inline.cocci create mode 100644 tests/inline.res create mode 100644 tests/ioctl.cocci create mode 100644 tests/isococci.c create mode 100644 tests/isococci.cocci create mode 100644 tests/isococci.res create mode 100644 tests/isotest.c create mode 100644 tests/isotest.cocci create mode 100644 tests/isotest.res create mode 100644 tests/isotest2.c create mode 100644 tests/isotest2.cocci create mode 100644 tests/isotest2.res create mode 100644 tests/iterator.c create mode 100644 tests/iterator.cocci create mode 100644 tests/iterator.res create mode 100644 tests/jloop1.c create mode 100644 tests/jloop1.cocci create mode 100644 tests/jloop1.res create mode 100644 tests/join.c create mode 100644 tests/join.cocci create mode 100644 tests/julia10.c create mode 100644 tests/julia10.cocci create mode 100644 tests/julia10.res create mode 100644 tests/julia7.c create mode 100644 tests/julia7.cocci create mode 100644 tests/julia7.res create mode 100644 tests/keep_comma.c create mode 100644 tests/keep_comma.cocci create mode 100644 tests/keep_comma.res create mode 100644 tests/km.c create mode 100644 tests/km.cocci create mode 100644 tests/km.res create mode 100644 tests/kmalloc.c create mode 100644 tests/kmalloc.cocci create mode 100644 tests/kmalloc.res create mode 100644 tests/kmc.c create mode 100644 tests/kmc.cocci create mode 100644 tests/kmc.res create mode 100644 tests/ktype.c create mode 100644 tests/ktype.cocci create mode 100644 tests/ktype.res create mode 100644 tests/labels_metastatement.c create mode 100644 tests/labels_metastatement.cocci create mode 100644 tests/labels_metastatement.res create mode 100644 tests/labels_metastatement2.cocci create mode 100644 tests/labels_metastatement3.cocci create mode 100644 tests/labels_metastatement_ver1.c create mode 100644 tests/labels_metastatement_ver1.res create mode 100644 tests/local.c create mode 100644 tests/local.cocci create mode 100644 tests/local.res create mode 100644 tests/localid.c create mode 100644 tests/localid.cocci create mode 100644 tests/localid.res create mode 100644 tests/longint.c create mode 100644 tests/longint.cocci create mode 100644 tests/loop.c create mode 100644 tests/loop.cocci create mode 100644 tests/loop.res create mode 100644 tests/lvalue.c create mode 100644 tests/lvalue.cocci create mode 100644 tests/lvalue.res create mode 100644 tests/macro.c create mode 100644 tests/macro.cocci create mode 100644 tests/macro.res create mode 100644 tests/match_const.c create mode 100644 tests/match_const.cocci create mode 100644 tests/match_const.res create mode 100644 tests/match_no_meta.c create mode 100644 tests/match_no_meta.cocci create mode 100644 tests/match_no_meta.res create mode 100644 tests/max.c create mode 100644 tests/max.cocci create mode 100644 tests/max.res create mode 100644 tests/mem.cocci create mode 100644 tests/memset.cocci create mode 100644 tests/metahex.c create mode 100644 tests/metahex.cocci create mode 100644 tests/metahex.res create mode 100644 tests/metaruleelem.c create mode 100644 tests/metaruleelem.cocci create mode 100644 tests/metaruleelem.res create mode 100644 tests/metastatement.c create mode 100644 tests/metastatement.cocci create mode 100644 tests/metastatement2.c create mode 100644 tests/metastatement2.cocci create mode 100644 tests/metastatement2.res create mode 100644 tests/metastatement_for.c create mode 100644 tests/metastatement_for.cocci create mode 100644 tests/metastatement_for.res create mode 100644 tests/metastatement_if.c create mode 100644 tests/metastatement_if.cocci create mode 100644 tests/metastatement_if.res create mode 100644 tests/mf.c create mode 100644 tests/mf.cocci create mode 100644 tests/minstruct.c create mode 100644 tests/minstruct.cocci create mode 100644 tests/minstruct.res create mode 100644 tests/minusall.c create mode 100644 tests/minusall.cocci create mode 100644 tests/minusall.res create mode 100644 tests/minusdots.c create mode 100644 tests/minusdots.cocci create mode 100644 tests/minusdots.res create mode 100644 tests/minusdots_ver1.c create mode 100644 tests/minusdots_ver1.res create mode 100644 tests/mult.c create mode 100644 tests/mult.cocci create mode 100644 tests/multi_func.c create mode 100644 tests/multi_func.cocci create mode 100644 tests/multi_func1.c create mode 100644 tests/multi_func1.cocci create mode 100644 tests/multi_func1.res create mode 100644 tests/multi_func1_ver2.c create mode 100644 tests/multi_inc.c create mode 100644 tests/multi_inc.cocci create mode 100644 tests/multi_inc1.h create mode 100644 tests/multi_inc2.h create mode 100644 tests/multidecl.c create mode 100644 tests/multidecl.cocci create mode 100644 tests/multiplus.c create mode 100644 tests/multiplus.cocci create mode 100644 tests/multiplus.res create mode 100644 tests/multitype.c create mode 100644 tests/multitype.cocci create mode 100644 tests/multitype.res create mode 100644 tests/multitypedef.c create mode 100644 tests/multitypedef.cocci create mode 100644 tests/multitypedef.res create mode 100644 tests/multivars.c create mode 100644 tests/multivars.cocci create mode 100644 tests/multivars.res create mode 100644 tests/multr.c create mode 100644 tests/multr.cocci create mode 100644 tests/nest.c create mode 100644 tests/nest.cocci create mode 100644 tests/nest.res create mode 100644 tests/nest2.c create mode 100644 tests/nest2.cocci create mode 100644 tests/nest3.c create mode 100644 tests/nest3.cocci create mode 100644 tests/nestone.c create mode 100644 tests/nestone.cocci create mode 100644 tests/nestone.res create mode 100644 tests/nestplus.c create mode 100644 tests/nestplus.cocci create mode 100644 tests/nestseq.c create mode 100644 tests/nestseq.cocci create mode 100644 tests/nestseq.res create mode 100644 tests/neststruct.c create mode 100644 tests/neststruct.cocci create mode 100644 tests/neststruct.res create mode 100644 tests/nl.c create mode 100644 tests/nl.cocci create mode 100644 tests/nl.res create mode 100644 tests/nocast.c create mode 100644 tests/nocast.cocci create mode 100644 tests/nocast.res create mode 100644 tests/not.c create mode 100644 tests/not.cocci create mode 100644 tests/not.res create mode 100644 tests/noty.c create mode 100644 tests/noty.cocci create mode 100644 tests/noty.res create mode 100644 tests/nstruct.c create mode 100644 tests/nstruct.cocci create mode 100644 tests/null.c create mode 100644 tests/null.cocci create mode 100644 tests/null_type.c create mode 100644 tests/null_type.cocci create mode 100644 tests/null_type.res create mode 100644 tests/null_ver11.c create mode 100644 tests/of.c create mode 100644 tests/of.cocci create mode 100644 tests/of.res create mode 100644 tests/oneline.c create mode 100644 tests/oneline.cocci create mode 100644 tests/oneline.res create mode 100644 tests/opt.c create mode 100644 tests/opt.cocci create mode 100644 tests/opt.res create mode 100644 tests/optional_qualifier.c create mode 100644 tests/optional_qualifier.cocci create mode 100644 tests/optional_qualifier.res create mode 100644 tests/optional_storage.c create mode 100644 tests/optional_storage.cocci create mode 100644 tests/optional_storage.res create mode 100644 tests/orexp.c create mode 100644 tests/orexp.cocci create mode 100644 tests/orexp.res create mode 100644 tests/param.c create mode 100644 tests/param.cocci create mode 100644 tests/param.res create mode 100644 tests/param1.c create mode 100644 tests/param1.cocci create mode 100644 tests/param1_ver1.c create mode 100644 tests/param_end.c create mode 100644 tests/param_end.cocci create mode 100644 tests/param_end.res create mode 100644 tests/param_ver1.c create mode 100644 tests/param_ver1.res create mode 100644 tests/parameters_dots.c create mode 100644 tests/parameters_dots.cocci create mode 100644 tests/parameters_dots.res create mode 100644 tests/paren1.c create mode 100644 tests/paren1.cocci create mode 100644 tests/partial.c create mode 100644 tests/partial.cocci create mode 100644 tests/partial.res create mode 100644 tests/pb_cfg.c create mode 100644 tests/pb_cfg.cocci create mode 100644 tests/pb_distribute_type.c create mode 100644 tests/pb_distribute_type.cocci create mode 100644 tests/pb_distribute_type.res create mode 100644 tests/pb_distribute_type2.c create mode 100644 tests/pb_distribute_type2.cocci create mode 100644 tests/pb_distribute_type2.res create mode 100644 tests/pb_distribute_type3.c create mode 100644 tests/pb_distribute_type3.cocci create mode 100644 tests/pb_distribute_type3.res create mode 100644 tests/pb_distribute_type4.c create mode 100644 tests/pb_distribute_type4.cocci create mode 100644 tests/pb_distribute_type4.res create mode 100644 tests/pb_params_iso.c create mode 100644 tests/pb_params_iso.cocci create mode 100644 tests/pb_params_iso.res create mode 100644 tests/pb_tag_symbols.c create mode 100644 tests/pb_tag_symbols.cocci create mode 100644 tests/pb_tag_symbols.res create mode 100644 tests/pci_noputm.cocci create mode 100644 tests/pmac.c create mode 100644 tests/pmac.cocci create mode 100644 tests/pmac.res create mode 100644 tests/posiso.c create mode 100644 tests/posiso.cocci create mode 100644 tests/posiso.res create mode 100644 tests/positionc.c create mode 100644 tests/positionc.cocci create mode 100644 tests/positionc.res create mode 100644 tests/positions3.c create mode 100644 tests/positions3.cocci create mode 100644 tests/posmult.c create mode 100644 tests/posmult.cocci create mode 100644 tests/posnpb.c create mode 100644 tests/posnpb.cocci create mode 100644 tests/post.c create mode 100644 tests/post.cocci create mode 100644 tests/post.res create mode 100644 tests/ppos.c create mode 100644 tests/ppos.cocci create mode 100644 tests/print_return.c create mode 100644 tests/print_return.cocci create mode 100644 tests/print_return.res create mode 100644 tests/proto.c create mode 100644 tests/proto.cocci create mode 100644 tests/proto.res create mode 100644 tests/proto2.c create mode 100644 tests/proto2.cocci create mode 100644 tests/proto2.res create mode 100644 tests/proto_ver1.c create mode 100644 tests/proto_ver1.res create mode 100644 tests/proto_ver2.c create mode 100644 tests/proto_ver2.res create mode 100644 tests/protoassert.c create mode 100644 tests/protoassert.cocci create mode 100644 tests/protoassert.res create mode 100644 tests/protox.c create mode 100644 tests/protox.cocci create mode 100644 tests/protox.res create mode 100644 tests/pt_regs_summary create mode 100644 tests/rcu2.cocci create mode 100644 tests/rcu3.c create mode 100644 tests/rcu3.cocci create mode 100644 tests/rcu3.res create mode 100644 tests/rcu3_ver1.c create mode 100644 tests/remstruct.c create mode 100644 tests/remstruct.cocci create mode 100644 tests/remstruct.res create mode 100644 tests/replace_typedef.c create mode 100644 tests/replace_typedef.cocci create mode 100644 tests/replace_typedef.res create mode 100644 tests/request_irq.cocci create mode 100644 tests/request_irq_sgrep.cocci create mode 100644 tests/reserved.c create mode 100644 tests/reserved.cocci create mode 100644 tests/reserved.res create mode 100644 tests/ret.c create mode 100644 tests/ret.cocci create mode 100644 tests/ret2.c create mode 100644 tests/ret2.cocci create mode 100644 tests/retmacro.c create mode 100644 tests/retmacro.cocci create mode 100644 tests/retmacro.res create mode 100644 tests/rets.c create mode 100644 tests/rets.cocci create mode 100644 tests/rets.res create mode 100644 tests/return.c create mode 100644 tests/return.cocci create mode 100644 tests/return.res create mode 100644 tests/return_implicit.c create mode 100644 tests/return_implicit.cocci create mode 100644 tests/return_implicit.res create mode 100644 tests/rule19a.c create mode 100644 tests/rule19a.cocci create mode 100644 tests/rule3.cocci create mode 100644 tests/same_expr.c create mode 100644 tests/same_expr.cocci create mode 100644 tests/same_expr.res create mode 100644 tests/scope_problem.c create mode 100644 tests/scope_problem.cocci create mode 100644 tests/scope_problem.res create mode 100644 tests/scripting/array/script4.c create mode 100644 tests/scripting/array/script4.cocci create mode 100644 tests/scripting/script1.c create mode 100644 tests/scripting/script1.cocci create mode 100644 tests/scripting/script2.c create mode 100644 tests/scripting/script2.cocci create mode 100644 tests/scripting/script3.c create mode 100644 tests/scripting/script3.cocci create mode 100644 tests/scripting/script4.c create mode 100644 tests/scripting/script4.cocci create mode 100644 tests/scripting/script5.c create mode 100644 tests/scripting/script5.cocci create mode 100644 tests/scripting/script6.c create mode 100644 tests/scripting/script6.cocci create mode 100644 tests/scripting/script7.c create mode 100644 tests/scripting/script7.cocci create mode 100644 tests/scripting/script8.c create mode 100644 tests/scripting/script8.cocci create mode 100644 tests/send_pci1 create mode 100644 tests/send_pci2 create mode 100644 tests/serio.c create mode 100644 tests/serio.cocci create mode 100644 tests/serio.res create mode 100644 tests/sgrep.c create mode 100644 tests/sgrep.cocci create mode 100644 tests/shadow.c create mode 100644 tests/shared_brace.c create mode 100644 tests/shared_brace.cocci create mode 100644 tests/shared_brace.res create mode 100644 tests/signed.c create mode 100644 tests/signed.cocci create mode 100644 tests/signed.res create mode 100644 tests/sis.c create mode 100644 tests/sis.cocci create mode 100644 tests/sis.res create mode 100644 tests/size_t.cocci create mode 100644 tests/sizeof.c create mode 100644 tests/sizeof.cocci create mode 100644 tests/sizeof.res create mode 100644 tests/sizeof_julia.c create mode 100644 tests/sizeof_julia.cocci create mode 100644 tests/sizeof_julia.res create mode 100644 tests/skip.c create mode 100644 tests/skip.cocci create mode 100644 tests/skip.res create mode 100644 tests/soc.c create mode 100644 tests/sp.c create mode 100644 tests/sp.cocci create mode 100644 tests/sp.res create mode 100644 tests/spaces.c create mode 100644 tests/spaces.cocci create mode 100644 tests/spaces.res create mode 100644 tests/spl.c create mode 100644 tests/spl.cocci create mode 100644 tests/spl.res create mode 100644 tests/stat.c create mode 100644 tests/stat.cocci create mode 100644 tests/stat.res create mode 100644 tests/static.c create mode 100644 tests/static.cocci create mode 100644 tests/static.res create mode 100644 tests/stm1.c create mode 100644 tests/stm1.cocci create mode 100644 tests/stm1.res create mode 100644 tests/stm10.c create mode 100644 tests/stm10.cocci create mode 100644 tests/stm10.res create mode 100644 tests/stm10_ver1.c create mode 100644 tests/stm10_ver1.res create mode 100644 tests/stm2.c create mode 100644 tests/stm2.cocci create mode 100644 tests/stm2.res create mode 100644 tests/stm3.c create mode 100644 tests/stm3.cocci create mode 100644 tests/stm3.res create mode 100644 tests/stm4.c create mode 100644 tests/stm4.cocci create mode 100644 tests/stm4.res create mode 100644 tests/stm5.c create mode 100644 tests/stm5.cocci create mode 100644 tests/stm5.res create mode 100644 tests/stm6.c create mode 100644 tests/stm6.cocci create mode 100644 tests/stm6.res create mode 100644 tests/stm7.c create mode 100644 tests/stm7.cocci create mode 100644 tests/stm7.res create mode 100644 tests/stm8.c create mode 100644 tests/stm8.cocci create mode 100644 tests/stm8.res create mode 100644 tests/stmt.c create mode 100644 tests/stmt.cocci create mode 100644 tests/stmt.res create mode 100644 tests/strangeorder.c create mode 100644 tests/strangeorder.cocci create mode 100644 tests/strangeorder.res create mode 100644 tests/string.c create mode 100644 tests/string.cocci create mode 100644 tests/string.res create mode 100644 tests/struct.c create mode 100644 tests/struct.cocci create mode 100644 tests/struct.res create mode 100644 tests/struct_metavar.c create mode 100644 tests/struct_metavar.cocci create mode 100644 tests/struct_metavar.res create mode 100644 tests/struct_typedef.c create mode 100644 tests/struct_typedef.cocci create mode 100644 tests/struct_typedef.res create mode 100644 tests/sw.c create mode 100644 tests/sw.cocci create mode 100644 tests/sw.res create mode 100644 tests/switch.c create mode 100644 tests/switch.cocci create mode 100644 tests/switch.res create mode 100644 tests/switch_case.c create mode 100644 tests/switch_case.cocci create mode 100644 tests/switch_label.c create mode 100644 tests/tadb.c create mode 100644 tests/td.c create mode 100644 tests/td.cocci create mode 100644 tests/td.res create mode 100644 tests/test0.c create mode 100644 tests/test0.cocci create mode 100644 tests/test0.res create mode 100644 tests/test1.c create mode 100644 tests/test1.cocci create mode 100644 tests/test1.res create mode 100644 tests/test10.c create mode 100644 tests/test10.cocci create mode 100644 tests/test10.res create mode 100644 tests/test10_ver1.c create mode 100644 tests/test10_ver1.res create mode 100644 tests/test11.c create mode 100644 tests/test11.cocci create mode 100644 tests/test11.res create mode 100644 tests/test11_ver1.c create mode 100644 tests/test11_ver1.res create mode 100644 tests/test12.c create mode 100644 tests/test12.cocci create mode 100644 tests/test12.res create mode 100644 tests/test1_ver1.c create mode 100644 tests/test1_ver2.c create mode 100644 tests/test2.c create mode 100644 tests/test2.cocci create mode 100644 tests/test2.res create mode 100644 tests/test3.c create mode 100644 tests/test3.cocci create mode 100644 tests/test3.res create mode 100644 tests/test4.c create mode 100644 tests/test4.cocci create mode 100644 tests/test4.res create mode 100644 tests/test5.c create mode 100644 tests/test5.cocci create mode 100644 tests/test5.res create mode 100644 tests/test5_ver1.c create mode 100644 tests/test5_ver1.res create mode 100644 tests/test6.c create mode 100644 tests/test6.cocci create mode 100644 tests/test6.res create mode 100644 tests/test6_ver1.c create mode 100644 tests/test7.c create mode 100644 tests/test7.cocci create mode 100644 tests/test7.res create mode 100644 tests/test8.c create mode 100644 tests/test8.cocci create mode 100644 tests/test8.res create mode 100644 tests/test9.c create mode 100644 tests/test9.cocci create mode 100644 tests/test9.res create mode 100644 tests/test9_ver1.c create mode 100644 tests/three.c create mode 100644 tests/three.cocci create mode 100644 tests/three_types.c create mode 100644 tests/three_types.cocci create mode 100644 tests/three_types.res create mode 100644 tests/threea.c create mode 100644 tests/threea.cocci create mode 100644 tests/threea.res create mode 100644 tests/top.c create mode 100644 tests/top.cocci create mode 100644 tests/top.res create mode 100644 tests/topdec.c create mode 100644 tests/topdec.cocci create mode 100644 tests/topdec.res create mode 100644 tests/topdec_ver1.c create mode 100644 tests/topdec_ver1.res create mode 100644 tests/topdec_ver2.c create mode 100644 tests/topdec_ver2.res create mode 100644 tests/toplevel_macrostmt.c create mode 100644 tests/toplevel_macrostmt.cocci create mode 100644 tests/toplevel_macrostmt.res create mode 100644 tests/toplevel_struct.c create mode 100644 tests/toplevel_struct.cocci create mode 100644 tests/toplevel_struct.res create mode 100644 tests/toplevel_struct_modif.c create mode 100644 tests/toplevel_struct_modif.cocci create mode 100644 tests/tup.c create mode 100644 tests/tup.cocci create mode 100644 tests/tup.res create mode 100644 tests/twoproto.c create mode 100644 tests/twoproto.cocci create mode 100644 tests/twoproto.res create mode 100644 tests/ty.c create mode 100644 tests/ty.cocci create mode 100644 tests/ty.res create mode 100644 tests/ty1.c create mode 100644 tests/ty1.cocci create mode 100644 tests/ty1.res create mode 100644 tests/ty_tyexp.c create mode 100644 tests/ty_tyexp.cocci create mode 100644 tests/ty_tyexp.res create mode 100644 tests/type.c create mode 100644 tests/type.cocci create mode 100644 tests/type.res create mode 100644 tests/type1.c create mode 100644 tests/type1.cocci create mode 100644 tests/type1.res create mode 100644 tests/type_annotated.c create mode 100644 tests/type_annotated.cocci create mode 100644 tests/type_annotated.res create mode 100644 tests/type_annotated_fields.c create mode 100644 tests/type_annotated_fields.cocci create mode 100644 tests/type_infer.c create mode 100644 tests/type_infer.cocci create mode 100644 tests/type_iso.c create mode 100644 tests/type_iso.cocci create mode 100644 tests/type_ver1.c create mode 100644 tests/type_ver1.res create mode 100644 tests/type_ver2.c create mode 100644 tests/type_ver2.res create mode 100644 tests/typedef.c create mode 100644 tests/typedef.cocci create mode 100644 tests/typedef.res create mode 100644 tests/typedef3.c create mode 100644 tests/typedef3.cocci create mode 100644 tests/typedef3.res create mode 100644 tests/typedef_double.c create mode 100644 tests/typedef_double.cocci create mode 100644 tests/typedef_double.res create mode 100644 tests/typeof.c create mode 100644 tests/typeof.cocci create mode 100644 tests/typeof.res create mode 100644 tests/typeur.c create mode 100644 tests/typeur.h create mode 100644 tests/used_after.c create mode 100644 tests/used_after.cocci create mode 100644 tests/used_after_ver1.c create mode 100644 tests/useless_cast.c create mode 100644 tests/useless_cast.cocci create mode 100644 tests/useless_cast.res create mode 100644 tests/varargs.c create mode 100644 tests/varargs.cocci create mode 100644 tests/varargs.res create mode 100644 tests/video.c create mode 100644 tests/video.cocci create mode 100644 tests/video1.c create mode 100644 tests/video1.cocci create mode 100644 tests/video1_ver1.c create mode 100644 tests/video1bis.c create mode 100644 tests/video1bis.cocci create mode 100644 tests/video1bis.res create mode 100644 tests/video2.c create mode 100644 tests/video2.cocci create mode 100644 tests/video3.c create mode 100644 tests/video3.cocci create mode 100644 tests/video4.c create mode 100644 tests/video4.cocci create mode 100644 tests/video_ver1.c create mode 100644 tests/video_ver2.c create mode 100644 tests/video_ver3.c create mode 100644 tests/void.c create mode 100644 tests/void.cocci create mode 100644 tests/void.res create mode 100644 tests/voyager.c create mode 100644 tests/voyager.cocci create mode 100644 tests/vpos.c create mode 100644 tests/vpos.cocci create mode 100644 tests/vpos.res create mode 100644 tests/whitespace.c create mode 100644 tests/whitespace.cocci create mode 100644 tests/whitespace.res create mode 100644 tests/wierd_argument.c create mode 100644 tests/wierd_argument.cocci create mode 100644 tests/wierd_argument.res create mode 100644 tests/wierdinit.c create mode 100644 tests/wierdinit.cocci create mode 100644 tests/wierdinit.res create mode 100644 tests/ws2.c create mode 100644 tests/ws2.cocci create mode 100644 tests/ws2.res create mode 100644 tests/x.c create mode 100644 tests/x.cocci create mode 100644 tests/xloop.c create mode 100644 tests/xloop.cocci create mode 100644 tests/y.c create mode 100644 tests/y.cocci create mode 100644 tests/y2.c create mode 100644 tests/y2.cocci create mode 100644 tests/y2.res create mode 100644 tests/yellow.c create mode 100644 tests/yloop.c create mode 100644 tests/yloop.cocci create mode 100644 tests/zero.c create mode 100644 tests/zero.cocci create mode 100644 tests/zero.res create mode 100644 tools/Makefile create mode 100644 tools/alloc_free.ml create mode 100644 tools/bridge.ml create mode 100644 tools/dir_stats.ml create mode 100644 tools/distributed/Makefile create mode 100644 tools/distributed/README create mode 100644 tools/distributed/cleanup.ml create mode 100644 tools/distributed/cleanup_script create mode 100644 tools/distributed/spatch_linux.c create mode 100755 tools/distributed/spatch_linux_script create mode 100644 tools/extract_c_and_res.ml create mode 100644 tools/generate_dependencies.ml create mode 100644 tools/gitgrep.ml create mode 100644 tools/gitsort.ml create mode 100644 tools/licensify.ml create mode 100644 tools/process_isoprofile.ml create mode 100644 tools/split_patch.ml diff --git a/.depend b/.depend new file mode 100644 index 0000000..0df0e6f --- /dev/null +++ b/.depend @@ -0,0 +1,44 @@ +cocci.cmi: commons/common.cmi parsing_cocci/ast_cocci.cmi +testing.cmi: commons/common.cmi parsing_cocci/ast_cocci.cmi +cocci.cmo: parsing_cocci/visitor_ast.cmi parsing_c/unparse_hrule.cmi \ + parsing_c/unparse_c2.cmi parsing_c/type_annoter_c.cmi \ + engine/transformation3.cmi python/pycocci.cmo \ + engine/pretty_print_engine.cmi parsing_cocci/pretty_print_cocci.cmi \ + popl09/popl.cmi parsing_c/parsing_hacks.cmi parsing_cocci/parse_cocci.cmi \ + parsing_c/parse_c.cmi commons/ograph_extended.cmi engine/lib_engine.cmo \ + parsing_c/flag_parsing_c.cmo ctl/flag_ctl.cmo flag_cocci.cmo \ + globals/flag.cmo engine/ctltotex.cmi engine/ctlcocci_integration.cmi \ + parsing_c/control_flow_c.cmi parsing_c/compare_c.cmi commons/common.cmi \ + engine/asttomember.cmi engine/asttoctl2.cmi parsing_c/ast_to_flow.cmi \ + parsing_cocci/ast_cocci.cmi parsing_c/ast_c.cmo cocci.cmi +cocci.cmx: parsing_cocci/visitor_ast.cmx parsing_c/unparse_hrule.cmx \ + parsing_c/unparse_c2.cmx parsing_c/type_annoter_c.cmx \ + engine/transformation3.cmx python/pycocci.cmx \ + engine/pretty_print_engine.cmx parsing_cocci/pretty_print_cocci.cmx \ + popl09/popl.cmx parsing_c/parsing_hacks.cmx parsing_cocci/parse_cocci.cmx \ + parsing_c/parse_c.cmx commons/ograph_extended.cmx engine/lib_engine.cmx \ + parsing_c/flag_parsing_c.cmx ctl/flag_ctl.cmx flag_cocci.cmx \ + globals/flag.cmx engine/ctltotex.cmx engine/ctlcocci_integration.cmx \ + parsing_c/control_flow_c.cmx parsing_c/compare_c.cmx commons/common.cmx \ + engine/asttomember.cmx engine/asttoctl2.cmx parsing_c/ast_to_flow.cmx \ + parsing_cocci/ast_cocci.cmx parsing_c/ast_c.cmx cocci.cmi +main.cmo: testing.cmi parsing_c/test_parsing_c.cmi python/pycocci.cmo \ + parsing_c/parse_c.cmi extra/kbuild.cmi popl09/flag_popl.cmo \ + parsing_cocci/flag_parsing_cocci.cmo parsing_c/flag_parsing_c.cmo \ + engine/flag_engine.cmo ctl/flag_ctl.cmo flag_cocci.cmo globals/flag.cmo \ + engine/ctlcocci_integration.cmi globals/config.cmo commons/common.cmi \ + cocci.cmi +main.cmx: testing.cmx parsing_c/test_parsing_c.cmx python/pycocci.cmx \ + parsing_c/parse_c.cmx extra/kbuild.cmx popl09/flag_popl.cmx \ + parsing_cocci/flag_parsing_cocci.cmx parsing_c/flag_parsing_c.cmx \ + engine/flag_engine.cmx ctl/flag_ctl.cmx flag_cocci.cmx globals/flag.cmx \ + engine/ctlcocci_integration.cmx globals/config.cmx commons/common.cmx \ + cocci.cmx +testing.cmo: parsing_cocci/pretty_print_cocci.cmi \ + parsing_cocci/parse_cocci.cmi flag_cocci.cmo globals/flag.cmo \ + globals/config.cmo parsing_c/compare_c.cmi commons/common.cmi cocci.cmi \ + testing.cmi +testing.cmx: parsing_cocci/pretty_print_cocci.cmx \ + parsing_cocci/parse_cocci.cmx flag_cocci.cmx globals/flag.cmx \ + globals/config.cmx parsing_c/compare_c.cmx commons/common.cmx cocci.cmx \ + testing.cmi diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a6c7122 --- /dev/null +++ b/Makefile @@ -0,0 +1,399 @@ +# Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +# Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +# This file is part of Coccinelle. +# +# Coccinelle is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, according to version 2 of the License. +# +# Coccinelle is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Coccinelle. If not, see . +# +# The authors reserve the right to distribute this or future versions of +# Coccinelle under other licenses. + + +############################################################################# +# Configuration section +############################################################################# + +-include Makefile.config + +VERSION=$(shell cat globals/config.ml |grep version |perl -p -e 's/.*"(.*)".*/$$1/;') + +############################################################################## +# Variables +############################################################################## +TARGET=spatch + +SRC=flag_cocci.ml cocci.ml testing.ml test.ml main.ml + + +ifeq ($(FEATURE_PYTHON),1) +PYCMA=pycaml/pycaml.cma +PYDIR=pycaml +PYLIB=dllpycaml_stubs.so +# the following is essential for Coccinelle to compile under gentoo (wierd) +OPTLIBFLAGS=-cclib dllpycaml_stubs.so +else +PYCMA= +PYDIR= +PYLIB= +OPTLIBFLAGS= +endif + + +SYSLIBS=str.cma unix.cma +LIBS=commons/commons.cma globals/globals.cma\ + ctl/ctl.cma \ + parsing_cocci/cocci_parser.cma parsing_c/parsing_c.cma \ + engine/cocciengine.cma popl09/popl.cma \ + extra/extra.cma $(PYCMA) python/coccipython.cma + +MAKESUBDIRS=commons globals menhirlib $(PYDIR) ctl parsing_cocci parsing_c \ + engine popl09 extra python +INCLUDEDIRS=commons globals menhirlib $(PYDIR) ctl parsing_cocci parsing_c \ + engine popl09 extra python + +############################################################################## +# Generic variables +############################################################################## + +INCLUDES=$(INCLUDEDIRS:%=-I %) + +OBJS= $(SRC:.ml=.cmo) +OPTOBJS= $(SRC:.ml=.cmx) + +EXEC=$(TARGET) + +############################################################################## +# Generic ocaml variables +############################################################################## + +OCAMLCFLAGS= #-g -dtypes # -w A + +# for profiling add -p -inline 0 +# but 'make forprofiling' below does that for you. +# This flag is also used in subdirectories so don't change its name here. +OPTFLAGS= +# the following is essential for Coccinelle to compile under gentoo +# but is now defined above in this file +#OPTLIBFLAGS=-cclib dllpycaml_stubs.so + +# the OPTBIN variable is here to allow to use ocamlc.opt instead of +# ocaml, when it is available, which speeds up compilation. So +# if you want the fast version of the ocaml chain tools, set this var +# or setenv it to ".opt" in your startup script. +OPTBIN= #.opt + +OCAMLC=ocamlc$(OPTBIN) $(OCAMLCFLAGS) $(INCLUDES) +OCAMLOPT=ocamlopt$(OPTBIN) $(OPTFLAGS) $(INCLUDES) +OCAMLLEX=ocamllex #-ml # -ml for debugging lexer, but slightly slower +OCAMLYACC=ocamlyacc -v +OCAMLDEP=ocamldep $(INCLUDES) +OCAMLMKTOP=ocamlmktop -g -custom $(INCLUDES) + +# can also be set via 'make static' +STATIC= #-ccopt -static + +# can also be unset via 'make purebytecode' +BYTECODE_STATIC=-custom + +############################################################################## +# Top rules +############################################################################## + +all: rec $(EXEC) +opt: rec.opt $(EXEC).opt +all.opt: opt + +rec: + set -e; for i in $(MAKESUBDIRS); \ + do $(MAKE) -C $$i OCAMLCFLAGS="$(OCAMLCFLAGS)" all; done +rec.opt: + set -e; for i in $(MAKESUBDIRS); do $(MAKE) -C $$i all.opt; done +clean:: + set -e; for i in $(MAKESUBDIRS); do $(MAKE) -C $$i clean; done + + +$(EXEC): $(LIBS) $(OBJS) + $(OCAMLC) $(BYTECODE_STATIC) -o $@ $(SYSLIBS) $^ + +$(EXEC).opt: $(LIBS:.cma=.cmxa) $(OPTOBJS) + $(OCAMLOPT) $(STATIC) -o $@ $(SYSLIBS:.cma=.cmxa) $(OPTLIBFLAGS) $^ + +$(EXEC).top: $(LIBS) $(OBJS) + $(OCAMLMKTOP) -custom -o $@ $(SYSLIBS) $^ + +clean:: + rm -f $(TARGET) $(TARGET).opt $(TARGET).top + + +clean:: + rm -f dllpycaml_stubs.so + + +.PHONY: tools + +tools: + $(MAKE) -C tools +clean:: + $(MAKE) -C tools clean + + +static: + rm -f spatch.opt spatch + $(MAKE) STATIC="-ccopt -static" spatch.opt + cp spatch.opt spatch + +purebytecode: + rm -f spatch.opt spatch + $(MAKE) BYTECODE_STATIC="" spatch + + +############################################################################## +# Install +############################################################################## + +# don't remove DESTDIR, it can be set by package build system like ebuild +install: all + mkdir -p $(DESTDIR)$(BINDIR) + mkdir -p $(DESTDIR)$(LIBDIR) + mkdir -p $(DESTDIR)$(SHAREDIR) + cp spatch $(DESTDIR)$(BINDIR) + cp -f dllpycaml_stubs.so $(DESTDIR)$(LIBDIR) + cp standard.h $(DESTDIR)$(SHAREDIR) + cp standard.iso $(DESTDIR)$(SHAREDIR) + mkdir -p $(DESTDIR)$(SHAREDIR)/python + cp -a python/coccilib $(DESTDIR)$(SHAREDIR)/python + @echo "" + @echo "You can also install spatch by copying the program spatch" + @echo "(available in this directory) anywhere you want and" + @echo "give it the right options to find its configuration files." + +uninstall: + rm -f $(DESTDIR)$(BINDIR)/spatch + rm -f $(DESTDIR)$(LIBDIR)/dllpycaml_stubs.so + rm -f $(DESTDIR)$(SHAREDIR)/standard.h + rm -f $(DESTDIR)$(SHAREDIR)/standard.iso + rm -rf $(DESTDIR)$(SHAREDIR)/python/coccilib + + + +version: + @echo $(VERSION) + + +############################################################################## +# Package rules +############################################################################## + +PACKAGE=coccinelle-$(VERSION) + +BINSRC=spatch env.sh env.csh standard.h standard.iso \ + *.txt docs/* \ + demos/foo.* demos/simple.* +# $(PYLIB) python/coccilib/ demos/printloc.* +BINSRC2=$(BINSRC:%=$(PACKAGE)/%) + +TMP=/tmp +OCAMLVERSION=$(shell ocaml -version |perl -p -e 's/.*version (.*)/$$1/;') + +# Procedure to do first time: +# cd ~/release +# cvs checkout coccinelle +# cd coccinelle +# cvs update -d -P +# touch **/* +# make licensify + +# Procedure to do each time: +# cvs update +# ./configure --without-python +# make package +# make website +# Check also that run an ocaml in /usr/bin + +# To test you can try compile and run spatch from different instances +# like my ~/coccinelle, ~/release/coccinelle, and the /tmp/coccinelle-0.X +# downloaded from the website. + +# For 'make srctar' it must done from a clean +# repo such as ~/release/coccinelle. It must also be a repo where +# the scripts/licensify has been run at least once. +# For the 'make bintar' I can do it from my original repo. + + +package: + make srctar + make bintar + make staticbintar + make bytecodetar + +# I currently pre-generate the parser so the user does not have to +# install menhir on his machine. I also do a few cleanups like 'rm todo_pos'. +# You may have first to do a 'make licensify'. +srctar: + make clean + cp -a . $(TMP)/$(PACKAGE) + cd $(TMP)/$(PACKAGE); cd parsing_cocci/; make parser_cocci_menhir.ml + cd $(TMP)/$(PACKAGE); rm todo_pos + cd $(TMP); tar cvfz $(PACKAGE).tgz --exclude=CVS $(PACKAGE) + rm -rf $(TMP)/$(PACKAGE) + + +bintar: all + rm -f $(TMP)/$(PACKAGE) + ln -s `pwd` $(TMP)/$(PACKAGE) + cd $(TMP); tar cvfz $(PACKAGE)-bin-x86.tgz $(BINSRC2) + rm -f $(TMP)/$(PACKAGE) + +staticbintar: all.opt + rm -f $(TMP)/$(PACKAGE) + ln -s `pwd` $(TMP)/$(PACKAGE) + make static + cd $(TMP); tar cvfz $(PACKAGE)-bin-x86-static.tgz $(BINSRC2) + rm -f $(TMP)/$(PACKAGE) + +# add ocaml version in name ? +bytecodetar: all + rm -f $(TMP)/$(PACKAGE) + ln -s `pwd` $(TMP)/$(PACKAGE) + make purebytecode + cd $(TMP); tar cvfz $(PACKAGE)-bin-bytecode-$(OCAMLVERSION).tgz $(BINSRC2) + rm -f $(TMP)/$(PACKAGE) + +clean:: + rm -f $(PACKAGE) + rm -f $(PACKAGE)-bin-x86.tgz + rm -f $(PACKAGE)-bin-x86-static.tgz + rm -f $(PACKAGE)-bin-bytecode-$(OCAMLVERSION).tgz + + + +TOLICENSIFY=ctl engine parsing_cocci popl popl09 python +licensify: + ocaml tools/licensify.ml + set -e; for i in $(TOLICENSIFY); do cd $$i; ocaml ../tools/licensify.ml; cd ..; done + +# When checking out the source from diku sometimes I have some "X in the future" +# error messages. +fixdates: + echo do 'touch **/*.*' + +#fixCVS: +# cvs update -d -P +# echo do 'rm -rf **/CVS' + +ocamlversion: + @echo $(OCAMLVERSION) + + +############################################################################## +# Pad specific rules +############################################################################## + +#TOP=/home/pad/mobile/project-coccinelle +WEBSITE=/home/pad/mobile/homepage/software/project-coccinelle + +website: + cp $(TMP)/$(PACKAGE).tgz $(WEBSITE) + cp $(TMP)/$(PACKAGE)-bin-x86.tgz $(WEBSITE) + cp $(TMP)/$(PACKAGE)-bin-x86-static.tgz $(WEBSITE) + cp $(TMP)/$(PACKAGE)-bin-bytecode-$(OCAMLVERSION).tgz $(WEBSITE) + + +#TXT=$(wildcard *.txt) +syncwiki: +# unison ~/public_html/wiki/wiki-LFS/data/pages/ docs/wiki/ +# set -e; for i in $(TXT); do unison $$i docs/wiki/$$i; done + +darcsweb: +# @echo pull from ~/public_html/darcs/c-coccinelle and c-commons and lib-xxx + + +############################################################################## +# Developer rules +############################################################################## + +test: $(TARGET) + ./$(TARGET) -testall + +testparsing: + ./$(TARGET) -D standard.h -parse_c -dir tests/ + + + +# -inline 0 to see all the functions in the profile. +# Can also use the profile framework in commons/ and run your program +# with -profile. +forprofiling: + $(MAKE) OPTFLAGS="-p -inline 0 " opt + +clean:: + rm -f gmon.out + +tags: + otags -no-mli-tags -r . + +dependencygraph: + find -name "*.ml" |grep -v "scripts" | xargs ocamldep -I commons -I globals -I ctl -I parsing_cocci -I parsing_c -I engine -I popl09 -I extra > /tmp/dependfull.depend + ocamldot -fullgraph /tmp/dependfull.depend > /tmp/dependfull.dot + dot -Tps /tmp/dependfull.dot > /tmp/dependfull.ps + +############################################################################## +# Misc rules +############################################################################## + +# each member of the project can have its own test.ml. this file is +# not under CVS. +test.ml: + echo "let foo_ctl () = failwith \"there is no foo_ctl formula\"" \ + > test.ml + +beforedepend:: test.ml + + +#INC=$(dir $(shell which ocaml)) +#INCX=$(INC:/=) +#INCY=$(dir $(INCX)) +#INCZ=$(INCY:/=)/lib/ocaml +# +#prim.o: prim.c +# gcc -c -o prim.o -I $(INCZ) prim.c + + +############################################################################## +# Generic ocaml rules +############################################################################## + +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) -c $< +.mli.cmi: + $(OCAMLC) -c $< +.ml.cmx: + $(OCAMLOPT) -c $< + +.ml.mldepend: + $(OCAMLC) -i $< + +clean:: + rm -f *.cm[iox] *.o *.annot + +clean:: + rm -f *~ .*~ *.exe #*# + +beforedepend:: + +depend:: beforedepend + $(OCAMLDEP) *.mli *.ml > .depend + set -e; for i in $(MAKESUBDIRS); do $(MAKE) -C $$i depend; done + +-include .depend diff --git a/Makefile.config b/Makefile.config new file mode 100644 index 0000000..c05b87e --- /dev/null +++ b/Makefile.config @@ -0,0 +1,16 @@ +# autogenerated by configure + +# Where to install the binary +BINDIR=/usr/local/bin + +# Where to install the man pages +MANDIR=/usr/local/man + +# Where to install the lib +LIBDIR=/usr/local/lib + +# Where to install the configuration files +SHAREDIR=/usr/local/share/coccinelle + +# Features +FEATURE_PYTHON=0 diff --git a/authors.txt b/authors.txt new file mode 100644 index 0000000..0cd3bff --- /dev/null +++ b/authors.txt @@ -0,0 +1,39 @@ +Here are the authors and maintainers of the different parts of coccinelle: + +* Julia Lawall + +- parsing_cocci/ (parsing SmPL, isomorphism handling) +- engine/ (ast_cocci to ctl, sgrep) +- ctl/ (symbolic model checker) +- popl/ popl09/ +- tools/ +- standard.iso + +* Yoann Padioleau + +- parsing_c/ (parsing C, unparsing C, type checking, control flow, C diff) +- engine/ (pattern matching and transforming, unparsing, ctl integration) +- cocci.ml (driver) +- main.ml, testing.ml +- emacs/cocci.el +- globals/ +- extra/ +- tools/ +- scripts/ +- commons/ (utility functions) +- standard.h + + +* Rene Rydhof Hansen + +- Original version of the model checker in ctl/ +- emacs/cocci-ediff.el +- scripts/extractor.awk + +* Henrik stuart + +- python/ (python SmPL extension and a coccinelle GUI) + +* All + +- tests/ demos/ diff --git a/bugs.txt b/bugs.txt new file mode 100644 index 0000000..be2f557 --- /dev/null +++ b/bugs.txt @@ -0,0 +1,2 @@ +Send a mail to julia@diku.dk or yoann.padioleau@gmail.com with [Bug-Cocci] as +a prefix in the subject of your mail. diff --git a/changes.txt b/changes.txt new file mode 100644 index 0000000..bbc8c07 --- /dev/null +++ b/changes.txt @@ -0,0 +1,18 @@ +-*- org -*- + +* 0.1 + +** first public release of the source code: + +** Features + - embeded python scripting + - position + +* beta + +** first public release of the binary + +* alpha + +** Features + - lots of features ... look at coccinelle research papers and tutorials. diff --git a/cocci.ml b/cocci.ml new file mode 100644 index 0000000..9953d1e --- /dev/null +++ b/cocci.ml @@ -0,0 +1,1413 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Common + +module CCI = Ctlcocci_integration +module TAC = Type_annoter_c + +(*****************************************************************************) +(* This file is a kind of driver. It gathers all the important functions + * from coccinelle in one place. The different entities in coccinelle are: + * - files + * - astc + * - astcocci + * - flow (contain nodes) + * - ctl (contain rule_elems) + * This file contains functions to transform one in another. + *) +(*****************************************************************************) + +(* --------------------------------------------------------------------- *) +(* C related *) +(* --------------------------------------------------------------------- *) +let cprogram_of_file file = + let (program2, _stat) = Parse_c.parse_print_error_heuristic file in + program2 + +let cprogram_of_file_cached file = + let (program2, _stat) = Parse_c.parse_cache file in + program2 + + +let cfile_of_program program2_with_ppmethod outf = + Unparse_c2.pp_program program2_with_ppmethod outf + +(* for memoization, contains only one entry, the one for the SP *) +let _hparse = Hashtbl.create 101 +let _hctl = Hashtbl.create 101 + +(* --------------------------------------------------------------------- *) +(* Cocci related *) +(* --------------------------------------------------------------------- *) +let sp_of_file2 file iso = + Common.memoized _hparse (file, iso) (fun () -> + Parse_cocci.process file iso false) +let sp_of_file file iso = + Common.profile_code "parse cocci" (fun () -> sp_of_file2 file iso) + + +(* --------------------------------------------------------------------- *) +(* Flow related *) +(* --------------------------------------------------------------------- *) +let print_flow flow = + Ograph_extended.print_ograph_mutable flow "/tmp/test.dot" true + + +let ast_to_flow_with_error_messages2 x = + let flowopt = + try Ast_to_flow.ast_to_control_flow x + with Ast_to_flow.Error x -> + Ast_to_flow.report_error x; + None + in + flowopt +> do_option (fun flow -> + (* This time even if there is a deadcode, we still have a + * flow graph, so I can try the transformation and hope the + * deadcode will not bother us. + *) + try Ast_to_flow.deadcode_detection flow + with Ast_to_flow.Error (Ast_to_flow.DeadCode x) -> + Ast_to_flow.report_error (Ast_to_flow.DeadCode x); + ); + flowopt +let ast_to_flow_with_error_messages a = + Common.profile_code "flow" (fun () -> ast_to_flow_with_error_messages2 a) + + +(* --------------------------------------------------------------------- *) +(* Ctl related *) +(* --------------------------------------------------------------------- *) +let ctls_of_ast2 ast ua pos = + List.map2 + (function ast -> function (ua,pos) -> + List.combine + (if !Flag_cocci.popl + then Popl.popl ast + else Asttoctl2.asttoctl ast ua pos) + (Asttomember.asttomember ast ua)) + ast (List.combine ua pos) + +let ctls_of_ast ast ua = + Common.profile_code "asttoctl2" (fun () -> ctls_of_ast2 ast ua) + +(*****************************************************************************) +(* Some debugging functions *) +(*****************************************************************************) + +(* the inputs *) + +let show_or_not_cfile2 cfile = + if !Flag_cocci.show_c then begin + Common.pr2_xxxxxxxxxxxxxxxxx (); + pr2 ("processing C file: " ^ cfile); + Common.pr2_xxxxxxxxxxxxxxxxx (); + Common.command2 ("cat " ^ cfile); + end +let show_or_not_cfile a = + Common.profile_code "show_xxx" (fun () -> show_or_not_cfile2 a) + +let show_or_not_cfiles cfiles = List.iter show_or_not_cfile cfiles + + +let show_or_not_cocci2 coccifile isofile = + if !Flag_cocci.show_cocci then begin + Common.pr2_xxxxxxxxxxxxxxxxx (); + pr2 ("processing semantic patch file: " ^ coccifile); + isofile +> (fun s -> pr2 ("with isos from: " ^ s)); + Common.pr2_xxxxxxxxxxxxxxxxx (); + Common.command2 ("cat " ^ coccifile); + pr2 ""; + end +let show_or_not_cocci a b = + Common.profile_code "show_xxx" (fun () -> show_or_not_cocci2 a b) + + +(* the output *) + +let show_or_not_diff2 cfile outfile show_only_minus = + if !Flag_cocci.show_diff then begin + match Common.fst(Compare_c.compare_default cfile outfile) with + Compare_c.Correct -> () (* diff only in spacing, etc *) + | _ -> + (* may need --strip-trailing-cr under windows *) + pr2 "diff = "; + + let line = + match !Flag_parsing_c.diff_lines with + | None -> "diff -u -p " ^ cfile ^ " " ^ outfile + | Some n -> "diff -U "^n^" -p "^cfile^" "^outfile in + let xs = + let res = Common.cmd_to_list line in + match (!Flag.patch,res) with + (* create something that looks like the output of patch *) + (Some prefix,minus_file::plus_file::rest) -> + let drop_prefix file = + if prefix = "" + then "/"^file + else + (match Str.split (Str.regexp prefix) file with + [base_file] -> base_file + | _ -> failwith "prefix not found in the old file name") in + let diff_line = + match List.rev(Str.split (Str.regexp " ") line) with + new_file::old_file::cmdrev -> + if !Flag.sgrep_mode2 + then + String.concat " " + (List.rev ("/tmp/nothing" :: old_file :: cmdrev)) + else + let old_base_file = drop_prefix old_file in + String.concat " " + (List.rev + (("b"^old_base_file)::("a"^old_base_file)::cmdrev)) + | _ -> failwith "bad command" in + let (minus_line,plus_line) = + if !Flag.sgrep_mode2 + then (minus_file,plus_file) + else + match (Str.split (Str.regexp "[ \t]") minus_file, + Str.split (Str.regexp "[ \t]") plus_file) with + ("---"::old_file::old_rest,"+++"::new_file::new_rest) -> + let old_base_file = drop_prefix old_file in + (String.concat " " + ("---"::("a"^old_base_file)::old_rest), + String.concat " " + ("+++"::("b"^old_base_file)::new_rest)) + | (l1,l2) -> + failwith + (Printf.sprintf "bad diff header lines: %s %s" + (String.concat ":" l1) (String.concat ":" l2)) in + diff_line::minus_line::plus_line::rest + | _ -> res in + xs +> List.iter (fun s -> + if s =~ "^\\+" && show_only_minus + then () + else pr s) + end +let show_or_not_diff a b c = + Common.profile_code "show_xxx" (fun () -> show_or_not_diff2 a b c) + + +(* the derived input *) + +let show_or_not_ctl_tex2 astcocci ctls = + if !Flag_cocci.show_ctl_tex then begin + Ctltotex.totex ("/tmp/__cocci_ctl.tex") astcocci ctls; + Common.command2 ("cd /tmp; latex __cocci_ctl.tex; " ^ + "dvips __cocci_ctl.dvi -o __cocci_ctl.ps;" ^ + "gv __cocci_ctl.ps &"); + end +let show_or_not_ctl_tex a b = + Common.profile_code "show_xxx" (fun () -> show_or_not_ctl_tex2 a b) + + + +let show_or_not_rule_name ast rulenb = + if !Flag_cocci.show_ctl_text or !Flag.show_trying or + !Flag_cocci.show_transinfo or !Flag_cocci.show_binding_in_out + then + begin + let name = + match ast with + Ast_cocci.CocciRule (nm, (deps, drops, exists), x, _) -> nm + | _ -> i_to_s rulenb in + Common.pr_xxxxxxxxxxxxxxxxx (); + pr (name ^ " = "); + Common.pr_xxxxxxxxxxxxxxxxx () + end + +let show_or_not_scr_rule_name rulenb = + if !Flag_cocci.show_ctl_text or !Flag.show_trying or + !Flag_cocci.show_transinfo or !Flag_cocci.show_binding_in_out + then + begin + let name = i_to_s rulenb in + Common.pr_xxxxxxxxxxxxxxxxx (); + pr ("script rule " ^ name ^ " = "); + Common.pr_xxxxxxxxxxxxxxxxx () + end + +let show_or_not_ctl_text2 ctl ast rulenb = + if !Flag_cocci.show_ctl_text then begin + + adjust_pp_with_indent (fun () -> + Format.force_newline(); + Pretty_print_cocci.print_plus_flag := true; + Pretty_print_cocci.print_minus_flag := true; + Pretty_print_cocci.unparse ast; + ); + + pr "CTL = "; + let (ctl,_) = ctl in + adjust_pp_with_indent (fun () -> + Format.force_newline(); + Pretty_print_engine.pp_ctlcocci + !Flag_cocci.show_mcodekind_in_ctl !Flag_cocci.inline_let_ctl ctl; + ); + pr ""; + end +let show_or_not_ctl_text a b c = + Common.profile_code "show_xxx" (fun () -> show_or_not_ctl_text2 a b c) + + + +(* running information *) + +let show_or_not_celem2 prelude celem = + if !Flag.show_trying then + (match celem with + | Ast_c.Definition ((funcs,_,_,_c),_) -> + pr2 (prelude ^ " function: " ^ funcs); + | Ast_c.Declaration + (Ast_c.DeclList ([(Some ((s, _),_), typ, sto, _local), _], _)) -> + pr2 (prelude ^ " variable " ^ s); + | _ -> + pr2 (prelude ^ " something else"); + ) +let show_or_not_celem a b = + Common.profile_code "show_xxx" (fun () -> show_or_not_celem2 a b) + + +let show_or_not_trans_info2 trans_info = + if !Flag_cocci.show_transinfo then begin + if null trans_info then pr2 "transformation info is empty" + else begin + pr2 "transformation info returned:"; + let trans_info = + List.sort (function (i1,_,_) -> function (i2,_,_) -> compare i1 i2) + trans_info + in + indent_do (fun () -> + trans_info +> List.iter (fun (i, subst, re) -> + pr2 ("transform state: " ^ (Common.i_to_s i)); + indent_do (fun () -> + adjust_pp_with_indent_and_header "with rule_elem: " (fun () -> + Pretty_print_cocci.print_plus_flag := true; + Pretty_print_cocci.print_minus_flag := true; + Pretty_print_cocci.rule_elem "" re; + ); + adjust_pp_with_indent_and_header "with binding: " (fun () -> + Pretty_print_engine.pp_binding subst; + ); + ) + ); + ) + end + end +let show_or_not_trans_info a = + Common.profile_code "show_xxx" (fun () -> show_or_not_trans_info2 a) + + + +let show_or_not_binding2 s binding = + if !Flag_cocci.show_binding_in_out then begin + adjust_pp_with_indent_and_header ("binding " ^ s ^ " = ") (fun () -> + Pretty_print_engine.pp_binding binding + ) + end +let show_or_not_binding a b = + Common.profile_code "show_xxx" (fun () -> show_or_not_binding2 a b) + + + +(*****************************************************************************) +(* Some helper functions *) +(*****************************************************************************) + +let worth_trying cfiles tokens = + (* drop the following line for a list of list by rules. since we don't + allow multiple minirules, all the tokens within a rule should be in + a single CFG entity *) + let tokens = Common.union_all tokens in + if not !Flag_cocci.windows && not (null tokens) + then + (* could also modify the code in get_constants.ml *) + let tokens = tokens +> List.map (fun s -> + match () with + | _ when s =~ "^[A-Za-z_][A-Za-z_0-9]*$" -> + "\\b" ^ s ^ "\\b" + + | _ when s =~ "^[A-Za-z_]" -> + "\\b" ^ s + + | _ when s =~ ".*[A-Za-z_]$" -> + s ^ "\\b" + | _ -> s + + ) in + let com = sprintf "egrep -q '(%s)' %s" (join "|" tokens) (join " " cfiles) + in + (match Sys.command com with + | 0 (* success *) -> true + | _ (* failure *) -> + (if !Flag.show_misc + then Printf.printf "grep failed: %s\n" com); + false (* no match, so not worth trying *) + ) + else true + +let check_macro_in_sp_and_adjust tokens = + let tokens = Common.union_all tokens in + tokens +> List.iter (fun s -> + if Hashtbl.mem !Parsing_hacks._defs s + then begin + pr2 "warning: macro in semantic patch was in macro definitions"; + pr2 ("disabling macro expansion for " ^ s); + Hashtbl.remove !Parsing_hacks._defs s + end + ) + + +let contain_loop gopt = + match gopt with + | Some g -> + g#nodes#tolist +> List.exists (fun (xi, node) -> + Control_flow_c.extract_is_loop node + ) + | None -> true (* means nothing, if no g then will not model check *) + + + +let sp_contain_typed_metavar_z toplevel_list_list = + let bind x y = x or y in + let option_default = false in + let mcode _ _ = option_default in + let donothing r k e = k e in + + let expression r k e = + match Ast_cocci.unwrap e with + | Ast_cocci.MetaExpr (_,_,_,Some t,_,_) -> true + | Ast_cocci.MetaExpr (_,_,_,_,Ast_cocci.LocalID,_) -> true + | _ -> k e + in + + let combiner = + Visitor_ast.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + donothing expression donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing + in + toplevel_list_list +> + List.exists + (function (nm,_,rule) -> + (List.exists combiner.Visitor_ast.combiner_top_level rule)) + + +let sp_contain_typed_metavar rules = + sp_contain_typed_metavar_z + (List.map + (function x -> + match x with + Ast_cocci.CocciRule (a,b,c,d) -> (a,b,c) + | _ -> failwith "error in filter") + (List.filter + (function x -> + match x with Ast_cocci.CocciRule _ -> true | _ -> false) + rules)) + + + +(* finding among the #include the one that we need to parse + * because they may contain useful type definition or because + * we may have to modify them + * + * For the moment we base in part our heuristic on the name of the file, e.g. + * serio.c is related we think to #include + *) + +let includes_to_parse xs = + if !Flag_cocci.no_includes + then [] + else + xs +> List.map (fun (file, cs) -> + let dir = Common.dirname file in + + cs +> Common.map_filter (fun (c,_info_item) -> + match c with + | Ast_c.Include ((x,ii),info_h_pos) -> + (match x with + | Ast_c.Local xs -> + let f = Filename.concat dir (Common.join "/" xs) in + (* for our tests, all the files are flat in the current dir *) + if not (Sys.file_exists f) && !Flag_cocci.relax_include_path + then + let attempt2 = Filename.concat dir (Common.last xs) in + if not (Sys.file_exists f) && !Flag_cocci.all_includes + then Some (Filename.concat !Flag_cocci.include_path + (Common.join "/" xs)) + else Some attempt2 + else Some f + + | Ast_c.NonLocal xs -> + if !Flag_cocci.all_includes || + Common.fileprefix (Common.last xs) = Common.fileprefix file + then + Some (Filename.concat !Flag_cocci.include_path + (Common.join "/" xs)) + else None + | Ast_c.Wierd _ -> None + ) + | _ -> None + ) + ) + +> List.concat + +> Common.uniq + +let rec interpret_dependencies local global = function + Ast_cocci.Dep s -> List.mem s local + | Ast_cocci.AntiDep s -> + (if !Flag_ctl.steps != None + then failwith "steps and ! dependency incompatible"); + not (List.mem s local) + | Ast_cocci.EverDep s -> List.mem s global + | Ast_cocci.NeverDep s -> + (if !Flag_ctl.steps != None + then failwith "steps and ! dependency incompatible"); + not (List.mem s global) + | Ast_cocci.AndDep(s1,s2) -> + (interpret_dependencies local global s1) && + (interpret_dependencies local global s2) + | Ast_cocci.OrDep(s1,s2) -> + (interpret_dependencies local global s1) or + (interpret_dependencies local global s2) + | Ast_cocci.NoDep -> true + +let rec print_dependencies local global = + let seen = ref [] in + let rec loop = function + Ast_cocci.Dep s | Ast_cocci.AntiDep s -> + if not (List.mem s !seen) + then + begin + if List.mem s local + then pr2 (s^" satisfied") + else pr2 (s^" not satisfied"); + seen := s :: !seen + end + | Ast_cocci.EverDep s | Ast_cocci.NeverDep s -> + if not (List.mem s !seen) + then + begin + if List.mem s global + then pr2 (s^" satisfied") + else pr2 (s^" not satisfied"); + seen := s :: !seen + end + | Ast_cocci.AndDep(s1,s2) -> + print_dependencies local global s1; + print_dependencies local global s2 + | Ast_cocci.OrDep(s1,s2) -> + print_dependencies local global s1; + print_dependencies local global s2 + | Ast_cocci.NoDep -> () in + loop + + + + +(* --------------------------------------------------------------------- *) +(* #include relative position in the file *) +(* --------------------------------------------------------------------- *) + +(* compute the set of new prefixes + * on + * "a/b/x"; (* in fact it is now a list of string so ["a";"b";"x"] *) + * "a/b/c/x"; + * "a/x"; + * "b/x"; + * it would give for the first element + * ""; "a"; "a/b"; "a/b/x" + * for the second + * "a/b/c/x" + * + * update: if the include is inside a ifdef a put nothing. cf -test incl. + * this is because we dont want code added inside ifdef. + *) + +let compute_new_prefixes xs = + xs +> Common.map_withenv (fun already xs -> + let subdirs_prefixes = Common.inits xs in + let new_first = subdirs_prefixes +> List.filter (fun x -> + not (List.mem x already) + ) + in + new_first, + new_first @ already + ) [] + +> fst + + +(* does via side effect on the ref in the Include in Ast_c *) +let rec update_include_rel_pos cs = + let only_include = cs +> Common.map_filter (fun c -> + match c with + | Ast_c.Include ((x,_),(aref, inifdef)) -> + (match x with + | Ast_c.Wierd _ -> None + | _ -> + if inifdef + then None + else Some (x, aref) + ) + | _ -> None + ) + in + let (locals, nonlocals) = + only_include +> Common.partition_either (fun (c, aref) -> + match c with + | Ast_c.Local x -> Left (x, aref) + | Ast_c.NonLocal x -> Right (x, aref) + | Ast_c.Wierd x -> raise Impossible + ) in + + update_rel_pos_bis locals; + update_rel_pos_bis nonlocals; + cs +and update_rel_pos_bis xs = + let xs' = List.map fst xs in + let the_first = compute_new_prefixes xs' in + let the_last = List.rev (compute_new_prefixes (List.rev xs')) in + let merged = Common.zip xs (Common.zip the_first the_last) in + merged +> List.iter (fun ((x, aref), (the_first, the_last)) -> + aref := Some + { + Ast_c.first_of = the_first; + Ast_c.last_of = the_last; + } + ) + + + + + + +(*****************************************************************************) +(* All the information needed around the C elements and Cocci rules *) +(*****************************************************************************) + +type toplevel_c_info = { + ast_c: Ast_c.toplevel; (* contain refs so can be modified *) + tokens_c: Parser_c.token list; + fullstring: string; + + flow: Control_flow_c.cflow option; (* it's the "fixed" flow *) + contain_loop: bool; + + env_typing_before: TAC.environment; + env_typing_after: TAC.environment; + + was_modified: bool ref; + + (* id: int *) +} + +type toplevel_cocci_info_script_rule = { + scr_ast_rule: string * (string * (string * string)) list * string; + language: string; + scr_dependencies: Ast_cocci.dependency; + scr_ruleid: int; + script_code: string; +} + +type toplevel_cocci_info_cocci_rule = { + ctl: Lib_engine.ctlcocci * (CCI.pred list list); + ast_rule: Ast_cocci.rule; + isexp: bool; (* true if + code is an exp, only for Flag.make_hrule *) + + rulename: string; + dependencies: Ast_cocci.dependency; + (* There are also some hardcoded rule names in parse_cocci.ml: + * let reserved_names = ["all";"optional_storage";"optional_qualifier"] + *) + dropped_isos: string list; + free_vars: Ast_cocci.meta_name list; + negated_pos_vars: Ast_cocci.meta_name list; + used_after: Ast_cocci.meta_name list; + positions: Ast_cocci.meta_name list; + + ruleid: int; + + was_matched: bool ref; +} + +type toplevel_cocci_info = + ScriptRuleCocciInfo of toplevel_cocci_info_script_rule + | CocciRuleCocciInfo of toplevel_cocci_info_cocci_rule + +type kind_file = Header | Source +type file_info = { + fname : string; + full_fname : string; + was_modified_once: bool ref; + asts: toplevel_c_info list; + fpath : string; + fkind : kind_file; +} + +let g_contain_typedmetavar = ref false + + +let last_env_toplevel_c_info xs = + (Common.last xs).env_typing_after + +let concat_headers_and_c ccs = + (List.concat (ccs +> List.map (fun x -> x.asts))) + +let for_unparser xs = + xs +> List.map (fun x -> + (x.ast_c, (x.fullstring, x.tokens_c)), Unparse_c2.PPviastr + ) + +(* --------------------------------------------------------------------- *) +let prepare_cocci ctls free_var_lists negated_pos_lists + used_after_lists positions_list astcocci = + + let gathered = Common.index_list_1 + (zip (zip (zip (zip (zip ctls astcocci) free_var_lists) + negated_pos_lists) used_after_lists) positions_list) + in + gathered +> List.map + (fun ((((((ctl_toplevel_list,ast),free_var_list),negated_pos_list), + used_after_list), + positions_list),rulenb) -> + + let is_script_rule r = + match r with Ast_cocci.ScriptRule _ -> true | _ -> false in + + if not (List.length ctl_toplevel_list = 1) && not (is_script_rule ast) + then failwith "not handling multiple minirules"; + + match ast with + Ast_cocci.ScriptRule (lang,deps,mv,code) -> + let r = + { + scr_ast_rule = (lang, mv, code); + language = lang; + scr_dependencies = deps; + scr_ruleid = rulenb; + script_code = code; + } + in ScriptRuleCocciInfo r + | Ast_cocci.CocciRule + (rulename,(dependencies,dropped_isos,z),restast,isexp) -> + CocciRuleCocciInfo ( + { + ctl = List.hd ctl_toplevel_list; + ast_rule = ast; + isexp = List.hd isexp; + rulename = rulename; + dependencies = dependencies; + dropped_isos = dropped_isos; + free_vars = List.hd free_var_list; + negated_pos_vars = List.hd negated_pos_list; + used_after = List.hd used_after_list; + positions = List.hd positions_list; + ruleid = rulenb; + was_matched = ref false; + }) + ) + + +(* --------------------------------------------------------------------- *) + +let build_info_program cprogram env = + let (cs, parseinfos) = Common.unzip cprogram in + let (cs, envs) = + Common.unzip (TAC.annotate_program env !g_contain_typedmetavar cs) in + + zip (zip cs parseinfos) envs +> List.map (fun ((c, parseinfo), (enva,envb))-> + let (fullstr, tokens) = parseinfo in + + let flow = + ast_to_flow_with_error_messages c +> Common.map_option (fun flow -> + let flow = Ast_to_flow.annotate_loop_nodes flow in + + (* remove the fake nodes for julia *) + let fixed_flow = CCI.fix_flow_ctl flow in + + if !Flag_cocci.show_flow then print_flow fixed_flow; + if !Flag_cocci.show_before_fixed_flow then print_flow flow; + + fixed_flow + ) + in + + { + ast_c = c; (* contain refs so can be modified *) + tokens_c = tokens; + fullstring = fullstr; + + flow = flow; + + contain_loop = contain_loop flow; + + env_typing_before = enva; + env_typing_after = envb; + + was_modified = ref false; + } + ) + + + +(* Optimisation. Try not unparse/reparse the whole file when have modifs *) +let rebuild_info_program cs file isexp = + cs +> List.map (fun c -> + if !(c.was_modified) + then + (match !Flag.make_hrule with + Some dir -> + Unparse_hrule.pp_program (c.ast_c, (c.fullstring, c.tokens_c)) + dir file isexp; + [] + | None -> + let file = Common.new_temp_file "cocci_small_output" ".c" in + cfile_of_program + [(c.ast_c, (c.fullstring, c.tokens_c)), Unparse_c2.PPnormal] + file; + + (* Common.command2 ("cat " ^ file); *) + let cprogram = cprogram_of_file file in + let xs = build_info_program cprogram c.env_typing_before in + + (* TODO: assert env has not changed, + * if yes then must also reparse what follows even if not modified. + * Do that only if contain_typedmetavar of course, so good opti. + *) + (* Common.list_init xs *) (* get rid of the FinalDef *) + xs) + else [c] + ) +> List.concat + + +let rebuild_info_c_and_headers ccs isexp = + ccs +> List.iter (fun c_or_h -> + if c_or_h.asts +> List.exists (fun c -> !(c.was_modified)) + then c_or_h.was_modified_once := true; + ); + ccs +> List.map (fun c_or_h -> + { c_or_h with + asts = rebuild_info_program c_or_h.asts c_or_h.full_fname isexp } + ) + + + + + + + +let prepare_c files = + let cprograms = List.map cprogram_of_file_cached files in + let includes = includes_to_parse (zip files cprograms) in + + (* todo?: may not be good to first have all the headers and then all the c *) + let all = + (includes +> List.map (fun hpath -> Right hpath)) + ++ + ((zip files cprograms) +> List.map (fun (file, asts) -> Left (file, asts))) + in + + let env = ref TAC.initial_env in + + let ccs = all +> Common.map_filter (fun x -> + match x with + | Right hpath -> + if not (Common.lfile_exists hpath) + then begin + pr2 ("TYPE: header " ^ hpath ^ " not found"); + None + end + else + let h_cs = cprogram_of_file_cached hpath in + let info_h_cs = build_info_program h_cs !env in + env := + if null info_h_cs + then !env + else last_env_toplevel_c_info info_h_cs + ; + Some { + fname = Common.basename hpath; + full_fname = hpath; + asts = info_h_cs; + was_modified_once = ref false; + fpath = hpath; + fkind = Header; + } + | Left (file, cprogram) -> + (* todo?: don't update env ? *) + let cs = build_info_program cprogram !env in + (* we do that only for the c, not for the h *) + ignore(update_include_rel_pos (cs +> List.map (fun x -> x.ast_c))); + Some { + fname = Common.basename file; + full_fname = file; + asts = cs; + was_modified_once = ref false; + fpath = file; + fkind = Source; + } + ) + in + ccs + + +(*****************************************************************************) +(* Processing the ctls and toplevel C elements *) +(*****************************************************************************) + +(* The main algorithm =~ + * The algorithm is roughly: + * for_all ctl rules in SP + * for_all minirule in rule (no more) + * for_all binding (computed during previous phase) + * for_all C elements + * match control flow of function vs minirule + * with the binding and update the set of possible + * bindings, and returned the possibly modified function. + * pretty print modified C elements and reparse it. + * + * + * On ne prends que les newbinding ou returned_any_state est vrai. + * Si ca ne donne rien, on prends ce qu'il y avait au depart. + * Mais au nouveau depart de quoi ? + * - si ca donne rien apres avoir traité toutes les fonctions avec ce binding ? + * - ou alors si ca donne rien, apres avoir traité toutes les fonctions + * avec tous les bindings du round d'avant ? + * + * Julia pense qu'il faut prendre la premiere solution. + * Example: on a deux environnements candidats, E1 et E2 apres avoir traité + * la regle ctl 1. On arrive sur la regle ctl 2. + * E1 ne donne rien pour la regle 2, on garde quand meme E1 pour la regle 3. + * E2 donne un match a un endroit et rend E2' alors on utilise ca pour + * la regle 3. + * + * I have not to look at used_after_list to decide to restart from + * scratch. I just need to look if the binding list is empty. + * Indeed, let's suppose that a SP have 3 regions/rules. If we + * don't find a match for the first region, then if this first + * region does not bind metavariable used after, that is if + * used_after_list is empty, then mysat(), even if does not find a + * match, will return a Left, with an empty transformation_info, + * and so current_binding will grow. On the contrary if the first + * region must bind some metavariables used after, and that we + * dont find any such region, then mysat() will returns lots of + * Right, and current_binding will not grow, and so we will have + * an empty list of binding, and we will catch such a case. + * + * opti: julia says that because the binding is + * determined by the used_after_list, the items in the list + * are kind of sorted, so could optimise the insert_set operations. + *) + + +(* r(ule), c(element in C code), e(nvironment) *) + +let rec apply_python_rule r cache newes e rules_that_have_matched + rules_that_have_ever_matched = + show_or_not_scr_rule_name r.scr_ruleid; + if not(interpret_dependencies rules_that_have_matched + !rules_that_have_ever_matched r.scr_dependencies) + then + begin + if !Flag.show_misc + then + begin + pr2 ("dependencies for script not satisfied:"); + print_dependencies rules_that_have_matched + !rules_that_have_ever_matched r.scr_dependencies; + show_or_not_binding "in environment" e + end; + (cache, (e, rules_that_have_matched)::newes) + end + else + begin + let (_, mv, _) = r.scr_ast_rule in + show_or_not_binding "in" e; + if List.for_all (Pycocci.contains_binding e) mv + then + begin + let relevant_bindings = + List.filter + (function ((re,rm),_) -> + List.exists (function (_,(r,m)) -> r = re && m = rm) mv) + e in + let new_cache = + if List.mem relevant_bindings cache + then cache + else + begin + Pycocci.build_classes (List.map (function (x,y) -> x) e); + Pycocci.construct_variables mv e; + let _ = Pycocci.pyrun_simplestring + ("import coccinelle\nfrom coccinelle "^ + "import *\ncocci = Cocci()\n" ^ + r.script_code) in + relevant_bindings :: cache + end in + if !Pycocci.inc_match + then (new_cache, (e, rules_that_have_matched)::newes) + else (new_cache, newes) + end + else (cache, (e, rules_that_have_matched)::newes) + end + +and apply_cocci_rule r rules_that_have_ever_matched es ccs = + Common.profile_code r.rulename (fun () -> + show_or_not_rule_name r.ast_rule r.ruleid; + show_or_not_ctl_text r.ctl r.ast_rule r.ruleid; + + let reorganized_env = + reassociate_positions r.free_vars r.negated_pos_vars !es in + + (* looping over the environments *) + let (_,newes (* envs for next round/rule *)) = + List.fold_left + (function (cache,newes) -> + function ((e,rules_that_have_matched),relevant_bindings) -> + if not(interpret_dependencies rules_that_have_matched + !rules_that_have_ever_matched r.dependencies) + then + begin + if !Flag.show_misc + then + begin + pr2 + ("dependencies for rule "^r.rulename^" not satisfied:"); + print_dependencies rules_that_have_matched + !rules_that_have_ever_matched r.dependencies; + show_or_not_binding "in environment" e + end; + (cache, + Common.union_set newes + [(e +> List.filter (fun (s,v) -> List.mem s r.used_after), + rules_that_have_matched)]) + end + else + let new_bindings = + try List.assoc relevant_bindings cache + with + Not_found -> + begin + show_or_not_binding "in" e; + show_or_not_binding "relevant in" relevant_bindings; + + let children_e = ref [] in + + (* looping over the functions and toplevel elements in + .c and .h *) + concat_headers_and_c !ccs +> List.iter (fun c -> + if c.flow <> None + then + (* does also some side effects on c and r *) + let processed = + process_a_ctl_a_env_a_toplevel r relevant_bindings + c in + match processed with + | None -> () + | Some newbindings -> + newbindings +> List.iter (fun newbinding -> + children_e := + Common.insert_set newbinding !children_e) + ); (* end iter cs *) + + !children_e + end in + let old_bindings_to_keep = + Common.nub + (e +> List.filter (fun (s,v) -> List.mem s r.used_after)) in + let new_e = + if null new_bindings + then + begin + (*use the old bindings, specialized to the used_after_list*) + if !Flag_ctl.partial_match + then + printf + "Empty list of bindings, I will restart from old env"; + [(old_bindings_to_keep,rules_that_have_matched)] + end + else + (* combine the new bindings with the old ones, and + specialize to the used_after_list *) + let old_variables = List.map fst old_bindings_to_keep in + (* have to explicitly discard the inherited variables + because we want the inherited value of the positions + variables not the extended one created by + reassociate_positions. want to reassociate freshly + according to the free variables of each rule. *) + let new_bindings_to_add = + Common.nub + (new_bindings +> + List.map + (List.filter + (fun (s,v) -> + List.mem s r.used_after && + not (List.mem s old_variables)))) in + List.map + (function new_binding_to_add -> + (Common.union_set + old_bindings_to_keep new_binding_to_add, + r.rulename::rules_that_have_matched)) + new_bindings_to_add in + ((relevant_bindings,new_bindings)::cache, + Common.union_set new_e newes)) + ([],[]) reorganized_env in (* end iter es *) + if !(r.was_matched) + then Common.push2 r.rulename rules_that_have_ever_matched; + + es := newes; + + (* apply the tagged modifs and reparse *) + if not !Flag.sgrep_mode2 + then ccs := rebuild_info_c_and_headers !ccs r.isexp + ) + +and bigloop2 rs ccs = + let es = ref [(Ast_c.emptyMetavarsBinding,[])] in + let ccs = ref ccs in + let rules_that_have_ever_matched = ref [] in + + (* looping over the rules *) + rs +> List.iter (fun r -> + match r with + ScriptRuleCocciInfo r -> + if !Flag_cocci.show_ctl_text then begin + Common.pr_xxxxxxxxxxxxxxxxx (); + pr ("script: " ^ r.language); + Common.pr_xxxxxxxxxxxxxxxxx (); + + adjust_pp_with_indent (fun () -> + Format.force_newline(); + let (l,mv,code) = r.scr_ast_rule in + let deps = r.scr_dependencies in + Pretty_print_cocci.unparse + (Ast_cocci.ScriptRule (l,deps,mv,code))); + end; + + if !Flag.show_misc then print_endline "RESULT ="; + + let (_, newes) = + List.fold_left + (function (cache, newes) -> + function (e, rules_that_have_matched) -> + match r.language with + "python" -> + apply_python_rule r cache newes e rules_that_have_matched + rules_that_have_ever_matched + | "test" -> + concat_headers_and_c !ccs +> List.iter (fun c -> + if c.flow <> None + then + Printf.printf "Flow: %s\r\nFlow!\r\n%!" c.fullstring); + (cache, newes) + | _ -> + Printf.printf "Unknown language: %s\n" r.language; + (cache, newes) + ) + ([],[]) !es in + + es := newes; + | CocciRuleCocciInfo r -> + apply_cocci_rule r rules_that_have_ever_matched es ccs); + + if !Flag.sgrep_mode2 + then begin + (* sgrep can lead to code that is not parsable, but we must + * still call rebuild_info_c_and_headers to pretty print the + * action (MINUS), so that later the diff will show what was + * matched by sgrep. But we don't want the parsing error message + * hence the following flag setting. So this code propably + * will generate a NotParsedCorrectly for the matched parts + * and the very final pretty print and diff will work + *) + Flag_parsing_c.verbose_parsing := false; + ccs := rebuild_info_c_and_headers !ccs false + end; + !ccs (* return final C asts *) + +and reassociate_positions free_vars negated_pos_vars envs = + (* issues: isolate the bindings that are relevant to a given rule. + separate out the position variables + associate all of the position variables for a given set of relevant + normal variable bindings with each set of relevant normal variable + bindings. Goal: if eg if@p (E) matches in two places, then both inherited + occurrences of E should see both bindings of p, not just its own. + Otherwise, a position constraint for something that matches in two + places will never be useful, because the position can always be + different from the other one. *) + let relevant = + List.map + (function (e,_) -> + List.filter (function (x,_) -> List.mem x free_vars) e) + envs in + let splitted_relevant = + (* separate the relevant variables into the non-position ones and the + position ones *) + List.map + (function r -> + List.fold_left + (function (non_pos,pos) -> + function (v,_) as x -> + if List.mem v negated_pos_vars + then (non_pos,x::pos) + else (x::non_pos,pos)) + ([],[]) r) + relevant in + let splitted_relevant = + List.map + (function (non_pos,pos) -> + (List.sort compare non_pos,List.sort compare pos)) + splitted_relevant in + let non_poss = + List.fold_left + (function non_pos -> + function (np,_) -> + if List.mem np non_pos then non_pos else np::non_pos) + [] splitted_relevant in + let extended_relevant = + (* extend the position variables with the values found at other identical + variable bindings *) + List.map + (function non_pos -> + let others = + List.filter + (function (other_non_pos,other_pos) -> + (* do we want equal? or just somehow compatible? eg non_pos + binds only E, but other_non_pos binds both E and E1 *) + non_pos = other_non_pos) + splitted_relevant in + (non_pos, + List.sort compare + (non_pos @ + (combine_pos negated_pos_vars + (List.map (function (_,x) -> x) others))))) + non_poss in + List.combine envs + (List.map (function (non_pos,_) -> List.assoc non_pos extended_relevant) + splitted_relevant) + +and combine_pos negated_pos_vars others = + List.map + (function posvar -> + (posvar, + Ast_c.MetaPosValList + (List.sort compare + (List.fold_left + (function positions -> + function other_list -> + try + match List.assoc posvar other_list with + Ast_c.MetaPosValList l1 -> + Common.union_set l1 positions + | _ -> failwith "bad value for a position variable" + with Not_found -> positions) + [] others)))) + negated_pos_vars + +and bigloop a b = + Common.profile_code "bigloop" (fun () -> bigloop2 a b) + + + + + +(* does side effects on C ast and on Cocci info rule *) +and process_a_ctl_a_env_a_toplevel2 r e c = + indent_do (fun () -> + show_or_not_celem "trying" c.ast_c; + let (trans_info, returned_any_states, newbindings) = + Common.save_excursion Flag_ctl.loop_in_src_code (fun () -> + Flag_ctl.loop_in_src_code := !Flag_ctl.loop_in_src_code||c.contain_loop; + + (***************************************) + (* !Main point! The call to the engine *) + (***************************************) + let model_ctl = CCI.model_for_ctl r.dropped_isos (Common.some c.flow) e + in CCI.mysat model_ctl r.ctl (r.used_after, e) + ) + in + if not returned_any_states + then None + else begin + show_or_not_celem "found match in" c.ast_c; + show_or_not_trans_info trans_info; + List.iter (show_or_not_binding "out") newbindings; + + r.was_matched := true; + + if not (null trans_info) + then begin + c.was_modified := true; + try + (* les "more than one var in a decl" et "already tagged token" + * font crasher coccinelle. Si on a 5 fichiers, donc on a 5 + * failed. Le try limite le scope des crashes pendant la + * trasformation au fichier concerne. *) + + (* modify ast via side effect *) + ignore(Transformation3.transform r.rulename r.dropped_isos + trans_info (Common.some c.flow)); + with Timeout -> raise Timeout | UnixExit i -> raise (UnixExit i) + end; + + Some newbindings + end + ) + +and process_a_ctl_a_env_a_toplevel a b c = + Common.profile_code "process_a_ctl_a_env_a_toplevel" + (fun () -> process_a_ctl_a_env_a_toplevel2 a b c) + + + +(*****************************************************************************) +(* The main function *) +(*****************************************************************************) + +let full_engine2 (coccifile, isofile) cfiles = + + show_or_not_cfiles cfiles; + show_or_not_cocci coccifile isofile; + Pycocci.set_coccifile coccifile; + + let isofile = + if not (Common.lfile_exists isofile) + then begin + pr2 ("warning: Can't find default iso file: " ^ isofile); + None + end + else Some isofile + in + + (* useful opti when use -dir *) + let (astcocci,free_var_lists,negated_pos_lists,used_after_lists, + positions_lists,toks,_) = + sp_of_file coccifile isofile + in + let ctls = + Common.memoized _hctl (coccifile, isofile) (fun () -> + ctls_of_ast astcocci used_after_lists positions_lists) + in + + let contain_typedmetavar = sp_contain_typed_metavar astcocci in + + (* optimisation allowing to launch coccinelle on all the drivers *) + if !Flag_cocci.worth_trying_opt && not (worth_trying cfiles toks) + then begin + pr2 ("not worth trying:" ^ Common.join " " cfiles); + cfiles +> List.map (fun s -> s, None) + end + else begin + + if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx(); + if !Flag.show_misc then pr "let's go"; + if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx(); + + g_contain_typedmetavar := contain_typedmetavar; + + check_macro_in_sp_and_adjust toks; + + let cocci_infos = + prepare_cocci ctls free_var_lists negated_pos_lists + used_after_lists positions_lists astcocci in + let c_infos = prepare_c cfiles in + + show_or_not_ctl_tex astcocci ctls; + + (* ! the big loop ! *) + let c_infos' = bigloop cocci_infos c_infos in + + if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx (); + if !Flag.show_misc then pr "Finished"; + if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx(); + + c_infos' +> List.map (fun c_or_h -> + if !(c_or_h.was_modified_once) + then begin + let outfile = Common.new_temp_file "cocci-output" ("-" ^ c_or_h.fname) + in + + if c_or_h.fkind = Header + then pr2 ("a header file was modified: " ^ c_or_h.fname); + + (* and now unparse everything *) + cfile_of_program (for_unparser c_or_h.asts) outfile; + + let show_only_minus = !Flag.sgrep_mode2 in + show_or_not_diff c_or_h.fpath outfile show_only_minus; + + (c_or_h.fpath, + if !Flag.sgrep_mode2 then None else Some outfile + ) + end + else + (c_or_h.fpath, None) + ); + end + +let full_engine a b = + Common.profile_code "full_engine" (fun () -> full_engine2 a b) + + +(*****************************************************************************) +(* check duplicate from result of full_engine *) +(*****************************************************************************) + +let check_duplicate_modif2 xs = + (* opti: let groups = Common.groupBy (fun (a,resa) (b,resb) -> a =$= b) xs *) + pr2 ("Check duplication for " ^ i_to_s (List.length xs) ^ " files"); + let groups = Common.group_assoc_bykey_eff xs in + groups +> Common.map_filter (fun (file, xs) -> + match xs with + | [] -> raise Impossible + | [res] -> Some (file, res) + | res::xs -> + match res with + | None -> + if not (List.for_all (fun res2 -> res2 = None) xs) + then begin + pr2 ("different modification result for " ^ file); + None + end + else Some (file, None) + | Some res -> + if not(List.for_all (fun res2 -> + match res2 with + | None -> false + | Some res2 -> + let diff = Common.cmd_to_list ("diff -u -b -B "^res^" "^res2) + in + null diff + ) xs) then begin + pr2 ("different modification result for " ^ file); + None + end + else Some (file, Some res) + + + ) +let check_duplicate_modif a = + Common.profile_code "check_duplicate" (fun () -> check_duplicate_modif2 a) + diff --git a/cocci.mli b/cocci.mli new file mode 100644 index 0000000..e47ccee --- /dev/null +++ b/cocci.mli @@ -0,0 +1,32 @@ +open Common + +(* full_engine takes (coccifile, isofile) and cfiles in parameters and + * returns a list associating to the input cfiles, and maybe header + * files that was also required to be modified, the files containing the + * result (in general files in /tmp). + * + * This function use memoisation internally, which is useful when + * use -dir to not redo twice the same work. So take care! + *) +val full_engine : + (filename * filename) -> filename list -> + (filename * filename option) list + +(* because of the #include "toto.c" and also because we may associate the + * same C file to multiple drivers because they share code, we can + * modify multiple times the same file when use -dir. This check + * remove duplicates and check that the modification are consistent + * among the different drivers. + *) +val check_duplicate_modif : + (filename * filename option) list -> (filename * filename option) list + +(* provides memoization *) +val sp_of_file : + filename (* coccifile *) -> filename option (* isofile *) -> + Ast_cocci.rule list * Ast_cocci.meta_name list list list * + Ast_cocci.meta_name list list list * + Ast_cocci.meta_name list list list * Ast_cocci.meta_name list list list * + string list list * + string option + diff --git a/commitmsg b/commitmsg new file mode 100644 index 0000000..f4b65dd --- /dev/null +++ b/commitmsg @@ -0,0 +1,6 @@ +Release coccinelle-0.1 + + * First public release of the source code: + * Features + - embeded python scripting + - position diff --git a/commons/.depend b/commons/.depend new file mode 100644 index 0000000..39a569b --- /dev/null +++ b/commons/.depend @@ -0,0 +1,96 @@ +oarray.cmi: osequence.cmi ocollection.cmi +oassoc.cmi: ocollection.cmi +oassoc_buffer.cmi: ocollection.cmi oassoc.cmi +oassocbdb.cmi: ocollection.cmi oassoc.cmi +oassocdbm.cmi: ocollection.cmi oassoc.cmi common.cmi +ocollection.cmi: objet.cmi +ograph.cmi: oset.cmi +ograph2way.cmi: oset.cmi ograph.cmi +ograph_extended.cmi: oset.cmi oassoc.cmi common.cmi +osequence.cmi: oassoc.cmi +oset.cmi: seti.cmo ocamlextra/setb.cmi ocamlextra/setPt.cmo ocollection.cmi +backtrace.cmo: common.cmi +backtrace.cmx: common.cmx +common.cmo: common.cmi +common.cmx: common.cmi +common_extra.cmo: common.cmi ocamlextra/ANSITerminal.cmi +common_extra.cmx: common.cmx ocamlextra/ANSITerminal.cmx +glimpse.cmo: common.cmi +glimpse.cmx: common.cmx +interfaces.cmo: common.cmi +interfaces.cmx: common.cmx +oarray.cmo: osequence.cmi common.cmi oarray.cmi +oarray.cmx: osequence.cmx common.cmx oarray.cmi +oassoc.cmo: ocollection.cmi oassoc.cmi +oassoc.cmx: ocollection.cmx oassoc.cmi +oassoc_buffer.cmo: ocamlextra/setb.cmi osetb.cmo oassocb.cmo oassoc.cmi \ + common.cmi oassoc_buffer.cmi +oassoc_buffer.cmx: ocamlextra/setb.cmx osetb.cmx oassocb.cmx oassoc.cmx \ + common.cmx oassoc_buffer.cmi +oassocb.cmo: oassoc.cmi ocamlextra/mapb.cmo common.cmi +oassocb.cmx: oassoc.cmx ocamlextra/mapb.cmx common.cmx +oassocbdb.cmo: oassoc.cmi ocamlextra/dumper.cmi common.cmi oassocbdb.cmi +oassocbdb.cmx: oassoc.cmx ocamlextra/dumper.cmx common.cmx oassocbdb.cmi +oassocdbm.cmo: oassoc.cmi common.cmi oassocdbm.cmi +oassocdbm.cmx: oassoc.cmx common.cmx oassocdbm.cmi +oassoch.cmo: oassoc.cmi ocamlextra/dumper.cmi common.cmi +oassoch.cmx: oassoc.cmx ocamlextra/dumper.cmx common.cmx +oassocid.cmo: oassoc.cmi common.cmi +oassocid.cmx: oassoc.cmx common.cmx +objet.cmo: common.cmi objet.cmi +objet.cmx: common.cmx objet.cmi +ocollection.cmo: objet.cmi common.cmi ocollection.cmi +ocollection.cmx: objet.cmx common.cmx ocollection.cmi +ofullcommon.cmo: oseti.cmo osetb.cmo oset.cmi ograph2way.cmi ograph.cmi \ + oassoch.cmo oassocb.cmo oassoc_buffer.cmi oassoc.cmi oarray.cmi \ + common.cmi +ofullcommon.cmx: oseti.cmx osetb.cmx oset.cmx ograph2way.cmx ograph.cmx \ + oassoch.cmx oassocb.cmx oassoc_buffer.cmx oassoc.cmx oarray.cmx \ + common.cmx +ograph.cmo: oset.cmi common.cmi ograph.cmi +ograph.cmx: oset.cmx common.cmx ograph.cmi +ograph2way.cmo: ocamlextra/setb.cmi osetb.cmo oset.cmi ograph.cmi \ + ocollection.cmi common.cmi ograph2way.cmi +ograph2way.cmx: ocamlextra/setb.cmx osetb.cmx oset.cmx ograph.cmx \ + ocollection.cmx common.cmx ograph2way.cmi +ograph_extended.cmo: ocamlextra/setb.cmi osetb.cmo oset.cmi ocollection.cmi \ + oassocb.cmo oassoc.cmi common.cmi ograph_extended.cmi +ograph_extended.cmx: ocamlextra/setb.cmx osetb.cmx oset.cmx ocollection.cmx \ + oassocb.cmx oassoc.cmx common.cmx ograph_extended.cmi +osequence.cmo: oassoc.cmi osequence.cmi +osequence.cmx: oassoc.cmx osequence.cmi +oset.cmo: seti.cmo ocamlextra/setb.cmi ocamlextra/setPt.cmo ocollection.cmi \ + common.cmi oset.cmi +oset.cmx: seti.cmx ocamlextra/setb.cmx ocamlextra/setPt.cmx ocollection.cmx \ + common.cmx oset.cmi +osetb.cmo: ocamlextra/setb.cmi oset.cmi ocollection.cmi +osetb.cmx: ocamlextra/setb.cmx oset.cmx ocollection.cmx +oseth.cmo: oset.cmi common.cmi +oseth.cmx: oset.cmx common.cmx +oseti.cmo: seti.cmo oset.cmi ocollection.cmi +oseti.cmx: seti.cmx oset.cmx ocollection.cmx +osetpt.cmo: ocamlextra/setPt.cmo oset.cmi ocollection.cmi +osetpt.cmx: ocamlextra/setPt.cmx oset.cmx ocollection.cmx +seti.cmo: common.cmi +seti.cmx: common.cmx +ocamlextra/ANSITerminal.cmo: ocamlextra/ANSITerminal.cmi +ocamlextra/ANSITerminal.cmx: ocamlextra/ANSITerminal.cmi +ocamlextra/dumper.cmo: ocamlextra/dumper.cmi +ocamlextra/dumper.cmx: ocamlextra/dumper.cmi +ocamlextra/dynArray.cmo: ocamlextra/enum.cmi ocamlextra/dynArray.cmi +ocamlextra/dynArray.cmx: ocamlextra/enum.cmx ocamlextra/dynArray.cmi +ocamlextra/enum.cmo: ocamlextra/enum.cmi +ocamlextra/enum.cmx: ocamlextra/enum.cmi +ocamlextra/parser_combinators.cmo: common.cmi \ + ocamlextra/parser_combinators.cmi +ocamlextra/parser_combinators.cmx: common.cmx \ + ocamlextra/parser_combinators.cmi +ocamlextra/setb.cmo: ocamlextra/setb.cmi +ocamlextra/setb.cmx: ocamlextra/setb.cmi +ocamlextra/suffix_tree.cmo: ocamlextra/suffix_tree.cmi +ocamlextra/suffix_tree.cmx: ocamlextra/suffix_tree.cmi +ocamlextra/suffix_tree_ext.cmo: ocamlextra/dynArray.cmi \ + ocamlextra/suffix_tree_ext.cmi +ocamlextra/suffix_tree_ext.cmx: ocamlextra/dynArray.cmx \ + ocamlextra/suffix_tree_ext.cmi +ocamlextra/dynArray.cmi: ocamlextra/enum.cmi diff --git a/commons/Makefile b/commons/Makefile new file mode 100644 index 0000000..c36c18f --- /dev/null +++ b/commons/Makefile @@ -0,0 +1,279 @@ +############################################################################## +# Variables +############################################################################## +TARGET=commons + +# note: if you add a file (a .mli or .ml), dont forget to redo a 'make depend' +MYSRC=common.ml common_extra.ml \ + interfaces.ml objet.ml \ + ocollection.ml \ + seti.ml \ + oset.ml oassoc.ml osequence.ml ograph.ml \ + oseti.ml oseth.ml osetb.ml osetpt.ml \ + oassocb.ml oassoch.ml oassoc_buffer.ml oassocid.ml \ + oarray.ml \ + ograph2way.ml ograph_extended.ml \ + ofullcommon.ml \ + glimpse.ml + +# src from other authors, got from the web or caml hump +SRC=ocamlextra/dumper.ml +SRC+=ocamlextra/ANSITerminal.ml +SRC+=ocamlextra/setb.ml ocamlextra/mapb.ml # defunctorized version of standard set/map +SRC+=ocamlextra/setPt.ml +SRC+=$(MYSRC) +SRC+=ocamlextra/enum.ml ocamlextra/dynArray.ml +SRC+=ocamlextra/parser_combinators.ml +SRC+=ocamlextra/suffix_tree.ml ocamlextra/suffix_tree_ext.ml + +SYSLIBS=str.cma unix.cma + +INCLUDEDIRS=ocamlextra +SUBDIR=ocamlextra + +#----------------------------------------------------------------------------- +# Other common (thin wrapper) libraries +#----------------------------------------------------------------------------- + +#gdbm +MYGDBMSRC=oassocdbm.ml +GDBMSYSLIBS=dbm.cma + +#berkeley db +BDBINCLUDES=-I ../ocamlbdb +MYBDBSRC=oassocbdb.ml +BDBSYSLIBS=bdb.cma + + +#ocamlgtk +GUIINCLUDES=-I +lablgtk2 -I +lablgtksourceview -I ../ocamlgtk/src +MYGUISRC=gui.ml +GUISYSLIBS=lablgtk.cma lablgtksourceview.cma + +#pycaml +PYINCLUDES=-I ../ocamlpython -I ../../ocamlpython +MYPYSRC=python.ml +PYSYSLIBS=python.cma + +#ocamlmpi +MPIINCLUDES=-I ../ocamlmpi -I ../../ocamlmpi -I +ocamlmpi +MYMPISRC=distribution.ml +MPISYSLIBS=mpi.cma + +#ocamlmpi +MPIINCLUDES=-I ../ocamlmpi -I ../../ocamlmpi -I +ocamlmpi +MYMPISRC=distribution.ml +MPISYSLIBS=mpi.cma + + +#----------------------------------------------------------------------------- +# Other stuff +#----------------------------------------------------------------------------- + +#backtrace +BACKTRACEINCLUDES=-I $(shell ocamlc -where) +MYBACKTRACESRC=backtrace.ml + +############################################################################## +# Generic variables +############################################################################## + +INCLUDES=$(INCLUDEDIRS:%=-I %) $(INCLUDESEXTRA) + +############################################################################## +# Generic ocaml variables +############################################################################## + +# This flag can also be used in subdirectories so don't change its name here. +# For profiling use: -p -inline 0 +OPTFLAGS= +#-thread + +# The OPTBIN variable is here to allow to use ocamlc.opt instead of +# ocaml, when it is available, which speeds up compilation. So +# if you want the fast version of the ocaml chain tools, set this var +# or setenv it to ".opt" in your startup script. +OPTBIN= #.opt + +OCAMLCFLAGS ?= -g -dtypes + +# The OCaml tools. +OCAMLC =ocamlc$(OPTBIN) $(OCAMLCFLAGS) $(INCLUDES) +OCAMLOPT=ocamlopt$(OPTBIN) $(OPTFLAGS) $(INCLUDES) +OCAMLLEX = ocamllex$(OPTBIN) +OCAMLYACC= ocamlyacc -v +OCAMLDEP = ocamldep$(OPTBIN) $(INCLUDES) +OCAMLMKTOP=ocamlmktop -g -custom $(INCLUDES) + +# if need C code +OCAMLMKLIB=ocamlmklib +CC=gcc + +############################################################################## +# Top rules +############################################################################## +LIB=$(TARGET).cma +OPTLIB=$(LIB:.cma=.cmxa) + +OBJS = $(SRC:.ml=.cmo) +OPTOBJS = $(SRC:.ml=.cmx) + + +all: $(LIB) +all.opt: $(OPTLIB) +opt: all.opt +top: $(TARGET).top + +$(LIB): $(OBJS) + $(OCAMLC) -a -o $@ $^ + +$(OPTLIB): $(OPTOBJS) + $(OCAMLOPT) -a -o $@ $^ + +$(TARGET).top: $(OBJS) + $(OCAMLMKTOP) -o $@ $(SYSLIBS) $^ + +clean:: + rm -f $(TARGET).top + +############################################################################## +# Other commons libs target +############################################################################## + +all_libs: gdbm bdb gui mpi backtrace + +gdbm: commons_gdbm.cma +gdbm.opt: commons_gdbm.cmxa + +commons_gdbm.cma: $(MYGDBMSRC:.ml=.cmo) + $(OCAMLC) -a -o $@ $^ + +commons_gdbm.cmxa: $(MYGDBMSRC:.ml=.cmx) + $(OCAMLOPT) -a -o $@ $^ + + +bdb: + $(MAKE) INCLUDESEXTRA="$(BDBINCLUDES)" commons_bdb.cma +bdb.opt: + $(MAKE) INCLUDESEXTRA="$(BDBINCLUDES)" commons_bdb.cmxa + +commons_bdb.cma: $(MYBDBSRC:.ml=.cmo) + $(OCAMLC) -a -o $@ $^ + +commons_bdb.cmxa: $(MYBDBSRC:.ml=.cmx) + $(OCAMLOPT) -a -o $@ $^ + + + +gui: + $(MAKE) INCLUDESEXTRA="$(GUIINCLUDES)" commons_gui.cma +gui.opt: + $(MAKE) INCLUDESEXTRA="$(GUIINCLUDES)" commons_gui.cmxa + +commons_gui.cma: $(MYGUISRC:.ml=.cmo) + $(OCAMLC) -a -o $@ $^ + +commons_gui.cmxa: $(MYGUISRC:.ml=.cmx) + $(OCAMLOPT) -a -o $@ $^ + + + +mpi: + $(MAKE) INCLUDESEXTRA="$(MPIINCLUDES)" commons_mpi.cma +mpi.opt: + $(MAKE) INCLUDESEXTRA="$(MPIINCLUDES)" commons_mpi.cmxa + +commons_mpi.cma: $(MYMPISRC:.ml=.cmo) + $(OCAMLC) -a -o $@ $^ + +commons_mpi.cmxa: $(MYMPISRC:.ml=.cmx) + $(OCAMLOPT) -a -o $@ $^ + +#alias +distribution: mpi +distribution.opt: mpi.opt + + + +python: + $(MAKE) INCLUDESEXTRA="$(PYINCLUDES)" commons_python.cma +python.opt: + $(MAKE) INCLUDESEXTRA="$(PYINCLUDES)" commons_python.cmxa + + +commons_python.cma: $(MYPYSRC:.ml=.cmo) + $(OCAMLC) -a -o $@ $^ + +commons_python.cmxa: $(MYPYSRC:.ml=.cmx) + $(OCAMLOPT) -a -o $@ $^ + + +backtrace: commons_backtrace.cma +backtrace.opt: commons_backtrace.cmxa + +backtrace_c.o: backtrace_c.c + $(CC) $(BACKTRACEINCLUDES) -c $^ + +commons_backtrace.cma: $(MYBACKTRACESRC:.ml=.cmo) backtrace_c.o + $(OCAMLMKLIB) -o commons_backtrace $^ + +commons_backtrace.cmxa: $(MYBACKTRACESRC:.ml=.cmx) backtrace_c.o + $(OCAMLMKLIB) -o commons_backtrace $^ + +clean:: + rm -f dllcommons_backtrace.so + + +############################################################################## +# Developer rules +############################################################################## + +tags: + otags -no-mli-tags -r . + +clean:: + rm -f gmon.out + +forprofiling: + $(MAKE) OPTFLAGS="-p -inline 0 " opt + +dependencygraph: + ocamldep *.mli *.ml > /tmp/dependfull.depend + ocamldot -fullgraph /tmp/dependfull.depend > /tmp/dependfull.dot + dot -Tps /tmp/dependfull.dot > /tmp/dependfull.ps + +dependencygraph2: + find -name "*.ml" |grep -v "scripts" | xargs ocamldep -I commons -I globals -I ctl -I parsing_cocci -I parsing_c -I engine -I popl -I extra > /tmp/dependfull.depend + ocamldot -fullgraph /tmp/dependfull.depend > /tmp/dependfull.dot + dot -Tps /tmp/dependfull.dot > /tmp/dependfull.ps + + +############################################################################## +# Generic rules +############################################################################## +.SUFFIXES: +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) -c $< +.mli.cmi: + $(OCAMLC) -c $< +.ml.cmx: + $(OCAMLOPT) -c $< + +clean:: + rm -f *.cm[iox] *.o *.a *.cma *.cmxa *.annot + rm -f *~ .*~ #*# + +clean:: + rm -f $(SUBDIR)/*.cm[iox] $(SUBDIR)/*.o $(SUBDIR)/*.a + rm -f $(SUBDIR)/*.cma $(SUBDIR)/*.cmxa $(SUBDIR)/*.annot + rm -f $(SUBDIR)/*~ $(SUBDIR)/.*~ #*# + +depend: + $(OCAMLDEP) *.mli *.ml $(SUBDIR)/*.ml $(SUBDIR)/*.mli > .depend + +distclean:: + rm -f .depend + +-include .depend diff --git a/commons/authors.txt b/commons/authors.txt new file mode 100644 index 0000000..985ce64 --- /dev/null +++ b/commons/authors.txt @@ -0,0 +1,5 @@ +Yoann Padioleau + +Maybe a few code was borrowed from pixel (pascal rigaux). + +See also credits.txt. diff --git a/commons/backtrace.ml b/commons/backtrace.ml new file mode 100644 index 0000000..85a61b3 --- /dev/null +++ b/commons/backtrace.ml @@ -0,0 +1,40 @@ +open Common + +(* This function is especially useful with lablgtk which intercepts + * the exception and forbid them to reach the toplevel, or with LFS + * where I can not allow any exception to stop mount.lfs. + * + * src: Jane Street Core library. + *) +external print : unit -> unit = "print_exception_backtrace_stub" "noalloc" + + +(* ---------------------------------------------------------------------- *) +(* testing *) +(* ---------------------------------------------------------------------- *) + +exception MyNot_Found + +let foo1 () = + if 1=1 + then raise MyNot_Found + else 2 + +let foo2 () = + foo1 () + 2 + +let test_backtrace () = + (try ignore(foo2 ()) + with exn -> + pr2 (Common.exn_to_s exn); + print(); + failwith "other exn" + ); + print_string "ok cool\n"; + () + +let actions () = + [ + "-test_backtrace", " ", + Common.mk_action_0_arg test_backtrace; + ] diff --git a/commons/backtrace_c.c b/commons/backtrace_c.c new file mode 100644 index 0000000..67103cc --- /dev/null +++ b/commons/backtrace_c.c @@ -0,0 +1,9 @@ +#include "caml/mlvalues.h" + +CAMLextern void caml_print_exception_backtrace(void); + +CAMLprim value print_exception_backtrace_stub(value /*__unused*/ unit) +{ + caml_print_exception_backtrace(); + return Val_unit; +} diff --git a/commons/common.ml b/commons/common.ml new file mode 100644 index 0000000..ee2b75e --- /dev/null +++ b/commons/common.ml @@ -0,0 +1,5300 @@ +(* Copyright (C) 1998-2008 Yoann Padioleau + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation, with the + * special exception on linking described in file license.txt. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file + * license.txt for more details. + *) + +(*****************************************************************************) +(* Notes *) +(*****************************************************************************) + + + +(* ---------------------------------------------------------------------- *) +(* Maybe could split common.ml and use include tricks as in ofullcommon.ml or + * Jane Street core lib. But then harder to bundle simple scripts like my + * make_full_linux_kernel.ml because would then need to pass all the files + * either to ocamlc or either to some #load. Also as the code of many + * functions depends on other functions from this common, it would + * be tedious to add those dependencies. Here simpler (have just the + * pb of the Prelude, but it's a small problem). + * + * pixel means code from Pascal Rigaux + * julia means code from Julia Lawall + *) +(* ---------------------------------------------------------------------- *) + +(*****************************************************************************) +(* We use *) +(*****************************************************************************) +(* + * modules: + * - Pervasives, of course + * - List + * - Str + * - Hashtbl + * - Format + * - Buffer + * - Unix and Sys + * - Arg + * + * functions: + * - =, <=, max min, abs, ... + * - List.rev, List.mem, List.partition, + * - List.fold*, List.concat, ... + * - Str.global_replace + * + * + * The Format library allows to hide passing an indent_level variable. + * You use as usual the print_string function except that there is + * this automatic indent_level variable handled for you (and maybe + * more services). src: julia in coccinelle unparse_cocci. + * + * Extra packages + * - ocamlbdb + * - ocamlgtk + * - ocamlgl + * - ocamlpython + * - ocamlagrep + * - ocamlfuse + * - ocamlmpi + * - ocamlcalendar + * + * Many functions were inspired by Haskell or Lisp librairies. + *) + +(*****************************************************************************) +(* Prelude *) +(*****************************************************************************) + +(* The following functions should be in their respective sections but + * because some functions in some sections use functions in other + * sections, and because I don't want to take care of the order of + * those sections, of those dependencies, I put the functions causing + * dependency problem here. C is better than caml on this with the + * ability to declare prototype, enabling some form of forward + * reference. *) + +let (+>) o f = f o +let (++) = (@) + +exception Timeout +exception UnixExit of int + +let rec (do_n: int -> (unit -> unit) -> unit) = fun i f -> + if i = 0 then () else (f(); do_n (i-1) f) +let rec (foldn: ('a -> int -> 'a) -> 'a -> int -> 'a) = fun f acc i -> + if i = 0 then acc else foldn f (f acc i) (i-1) + +let sum_int = List.fold_left (+) 0 + +(* could really call it 'for' :) *) +let fold_left_with_index f acc = + let rec fold_lwi_aux acc n = function + | [] -> acc + | x::xs -> fold_lwi_aux (f acc x n) (n+1) xs + in fold_lwi_aux acc 0 + + +let rec drop n xs = + match (n,xs) with + | (0,_) -> xs + | (_,[]) -> failwith "drop: not enough" + | (n,x::xs) -> drop (n-1) xs + +let rec enum_orig x n = if x = n then [n] else x::enum_orig (x+1) n + +let enum x n = + if not(x <= n) + then failwith (Printf.sprintf "bad values in enum, expect %d <= %d" x n); + let rec enum_aux acc x n = + if x = n then n::acc else enum_aux (x::acc) (x+1) n + in + List.rev (enum_aux [] x n) + +let rec take n xs = + match (n,xs) with + | (0,_) -> [] + | (_,[]) -> failwith "take: not enough" + | (n,x::xs) -> x::take (n-1) xs + + +let last_n n l = List.rev (take n (List.rev l)) +let last l = List.hd (last_n 1 l) + + +let (list_of_string: string -> char list) = function + "" -> [] + | s -> (enum 0 ((String.length s) - 1) +> List.map (String.get s)) + +let (lines: string -> string list) = fun s -> + let rec lines_aux = function + | [] -> [] + | [x] -> if x = "" then [] else [x] + | x::xs -> + x::lines_aux xs + in + Str.split_delim (Str.regexp "\n") s +> lines_aux + + +let push2 v l = + l := v :: !l + + + + + +let debugger = ref false + +let unwind_protect f cleanup = + if !debugger then f() else + try f () + with e -> begin cleanup e; raise e end + +let finalize f cleanup = + if !debugger then f() else + try + let res = f () in + cleanup (); + res + with e -> + cleanup (); + raise e + +let command2 s = ignore(Sys.command s) + + +let (matched: int -> string -> string) = fun i s -> + Str.matched_group i s + +let matched1 = fun s -> matched 1 s +let matched2 = fun s -> (matched 1 s, matched 2 s) +let matched3 = fun s -> (matched 1 s, matched 2 s, matched 3 s) +let matched4 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s) +let matched5 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s) +let matched6 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s, matched 6 s) +let matched7 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s, matched 6 s, matched 7 s) + +let (with_open_stringbuf: (((string -> unit) * Buffer.t) -> unit) -> string) = + fun f -> + let buf = Buffer.create 1000 in + let pr s = Buffer.add_string buf (s ^ "\n") in + f (pr, buf); + Buffer.contents buf + + +(*****************************************************************************) +(* Debugging/logging *) +(*****************************************************************************) + +(* I used this in coccinelle where the huge logging of stuff ask for + * a more organized solution that use more visual indentation hints. + * + * todo? could maybe use log4j instead ? or use Format module more + * consistently ? + *) + +let _tab_level_print = ref 0 +let _tab_indent = 5 + + +let _prefix_pr = ref "" + +let indent_do f = + _tab_level_print := !_tab_level_print + _tab_indent; + finalize f + (fun () -> _tab_level_print := !_tab_level_print - _tab_indent;) + + +let pr s = + print_string !_prefix_pr; + do_n !_tab_level_print (fun () -> print_string " "); + print_string s; + print_string "\n"; + flush stdout + +let pr_no_nl s = + print_string !_prefix_pr; + do_n !_tab_level_print (fun () -> print_string " "); + print_string s; + flush stdout + + +let pr2 s = + prerr_string !_prefix_pr; + do_n !_tab_level_print (fun () -> prerr_string " "); + prerr_string s; + prerr_string "\n"; + flush stderr + +let pr2_no_nl s = + prerr_string !_prefix_pr; + do_n !_tab_level_print (fun () -> prerr_string " "); + prerr_string s; + flush stderr + +let pr_xxxxxxxxxxxxxxxxx () = + pr "-----------------------------------------------------------------------" + +let pr2_xxxxxxxxxxxxxxxxx () = + pr2 "-----------------------------------------------------------------------" + + +let reset_pr_indent () = + _tab_level_print := 0 + +(* old: + * let pr s = (print_string s; print_string "\n"; flush stdout) + * let pr2 s = (prerr_string s; prerr_string "\n"; flush stderr) + *) + +(* ---------------------------------------------------------------------- *) + +(* I can not use the _xxx ref tech that I use for common_extra.ml here because + * ocaml don't like the polymorphism of Dumper mixed with refs. + * + * let (_dump_func : ('a -> string) ref) = ref + * (fun x -> failwith "no dump yet, have you included common_extra.cmo?") + * let (dump : 'a -> string) = fun x -> + * !_dump_func x + * + * So I have included directly dumper.ml in common.ml. It's more practical + * when want to give script that use my common.ml, I just have to give + * this file. + *) + +(* start of dumper.ml *) + +(* Dump an OCaml value into a printable string. + * By Richard W.M. Jones (rich@annexia.org). + * dumper.ml 1.2 2005/02/06 12:38:21 rich Exp + *) +open Printf +open Obj + +let rec dump r = + if is_int r then + string_of_int (magic r : int) + else ( (* Block. *) + let rec get_fields acc = function + | 0 -> acc + | n -> let n = n-1 in get_fields (field r n :: acc) n + in + let rec is_list r = + if is_int r then ( + if (magic r : int) = 0 then true (* [] *) + else false + ) else ( + let s = size r and t = tag r in + if t = 0 && s = 2 then is_list (field r 1) (* h :: t *) + else false + ) + in + let rec get_list r = + if is_int r then [] + else let h = field r 0 and t = get_list (field r 1) in h :: t + in + let opaque name = + (* XXX In future, print the address of value 'r'. Not possible in + * pure OCaml at the moment. + *) + "<" ^ name ^ ">" + in + + let s = size r and t = tag r in + + (* From the tag, determine the type of block. *) + if is_list r then ( (* List. *) + let fields = get_list r in + "[" ^ String.concat "; " (List.map dump fields) ^ "]" + ) + else if t = 0 then ( (* Tuple, array, record. *) + let fields = get_fields [] s in + "(" ^ String.concat ", " (List.map dump fields) ^ ")" + ) + + (* Note that [lazy_tag .. forward_tag] are < no_scan_tag. Not + * clear if very large constructed values could have the same + * tag. XXX *) + else if t = lazy_tag then opaque "lazy" + else if t = closure_tag then opaque "closure" + else if t = object_tag then ( (* Object. *) + let fields = get_fields [] s in + let clasz, id, slots = + match fields with h::h'::t -> h, h', t | _ -> assert false in + (* No information on decoding the class (first field). So just print + * out the ID and the slots. + *) + "Object #" ^ dump id ^ + " (" ^ String.concat ", " (List.map dump slots) ^ ")" + ) + else if t = infix_tag then opaque "infix" + else if t = forward_tag then opaque "forward" + + else if t < no_scan_tag then ( (* Constructed value. *) + let fields = get_fields [] s in + "Tag" ^ string_of_int t ^ + " (" ^ String.concat ", " (List.map dump fields) ^ ")" + ) + else if t = string_tag then ( + "\"" ^ String.escaped (magic r : string) ^ "\"" + ) + else if t = double_tag then ( + string_of_float (magic r : float) + ) + else if t = abstract_tag then opaque "abstract" + else if t = custom_tag then opaque "custom" + else if t = final_tag then opaque "final" + else failwith ("dump: impossible tag (" ^ string_of_int t ^ ")") + ) + +let dump v = dump (repr v) + +(* end of dumper.ml *) + +(* +let (dump : 'a -> string) = fun x -> + Dumper.dump x +*) + + +(* ---------------------------------------------------------------------- *) +let pr2_gen x = pr2 (dump x) + + + +(* ---------------------------------------------------------------------- *) + + +let _already_printed = Hashtbl.create 101 +let disable_pr2_once = ref false +let pr2_once s = + if !disable_pr2_once then pr2 s + else + if not (Hashtbl.mem _already_printed s) + then begin + Hashtbl.add _already_printed s true; + pr2 ("(ONCE) " ^ s); + end + + +(* ---------------------------------------------------------------------- *) +(* could also be in File section *) + +let redirect_stdout_stderr file f = + begin + let chan = open_out file in + let descr = Unix.descr_of_out_channel chan in + + let saveout = Unix.dup Unix.stdout in + let saveerr = Unix.dup Unix.stderr in + Unix.dup2 descr Unix.stdout; + Unix.dup2 descr Unix.stderr; + flush stdout; flush stderr; + f(); + flush stdout; flush stderr; + Unix.dup2 saveout Unix.stdout; + Unix.dup2 saveerr Unix.stderr; + close_out chan; + end + +let redirect_stdin file f = + begin + let chan = open_in file in + let descr = Unix.descr_of_in_channel chan in + + let savein = Unix.dup Unix.stdin in + Unix.dup2 descr Unix.stdin; + f(); + Unix.dup2 savein Unix.stdin; + close_in chan; + end + +let redirect_stdin_opt optfile f = + match optfile with + | None -> f() + | Some infile -> redirect_stdin infile f + + + +(* ---------------------------------------------------------------------- *) + +include Printf + +(* cf common.mli, fprintf, printf, eprintf, sprintf. + * also what is this ? + * val bprintf : Buffer.t -> ('a, Buffer.t, unit) format -> 'a + * val kprintf : (string -> 'a) -> ('b, unit, string, 'a) format4 -> 'b + *) + +(* ex of printf: + * printf "%02d" i + * for padding + *) + +let spf = sprintf + +(* ---------------------------------------------------------------------- *) + +let _chan = ref stderr +let start_log_file () = + let filename = (spf "/tmp/debugml%d:%d" (Unix.getuid()) (Unix.getpid())) in + pr2 (spf "now using %s for logging" filename); + _chan := open_out filename + + +let dolog s = output_string !_chan (s ^ "\n"); flush !_chan + +let verbose_level = ref 1 +let log s = if !verbose_level >= 1 then dolog s +let log2 s = if !verbose_level >= 2 then dolog s +let log3 s = if !verbose_level >= 3 then dolog s +let log4 s = if !verbose_level >= 4 then dolog s + +let if_log f = if !verbose_level >= 1 then f() +let if_log2 f = if !verbose_level >= 2 then f() +let if_log3 f = if !verbose_level >= 3 then f() +let if_log4 f = if !verbose_level >= 4 then f() + +(* ---------------------------------------------------------------------- *) + +let pause () = (pr2 "pause: type return"; ignore(read_line ())) + +(* src: from getopt from frish *) +let bip () = Printf.printf "\007"; flush stdout +let wait () = Unix.sleep 1 + +(* was used by fix_caml *) +let _trace_var = ref 0 +let add_var() = incr _trace_var +let dec_var() = decr _trace_var +let get_var() = !_trace_var + +let (print_n: int -> string -> unit) = fun i s -> + do_n i (fun () -> print_string s) +let (printerr_n: int -> string -> unit) = fun i s -> + do_n i (fun () -> prerr_string s) + +let _debug = ref true +let debugon () = _debug := true +let debugoff () = _debug := false +let debug f = if !_debug then f () else () + + + +(* now in prelude: + * let debugger = ref false + *) + + +(*****************************************************************************) +(* Profiling *) +(*****************************************************************************) + +let get_mem() = + command2("grep VmData /proc/" ^ string_of_int (Unix.getpid()) ^ "/status") + +let memory_stat () = + let stat = Gc.stat() in + let conv_mo x = x * 4 / 1000000 in + Printf.sprintf "maximal = %d Mo\n" (conv_mo stat.Gc.top_heap_words) ^ + Printf.sprintf "current = %d Mo\n" (conv_mo stat.Gc.heap_words) ^ + Printf.sprintf "lives = %d Mo\n" (conv_mo stat.Gc.live_words) + (* Printf.printf "fragments = %d Mo\n" (conv_mo stat.Gc.fragments); *) + +let timenow () = + "sys:" ^ (string_of_float (Sys.time ())) ^ " seconds" ^ + ":real:" ^ + (let tm = Unix.time () +> Unix.gmtime in + tm.Unix.tm_min +> string_of_int ^ " min:" ^ + tm.Unix.tm_sec +> string_of_int ^ ".00 seconds") + +let _count1 = ref 0 +let _count2 = ref 0 +let _count3 = ref 0 +let _count4 = ref 0 +let _count5 = ref 0 + +let count1 () = incr _count1 +let count2 () = incr _count2 +let count3 () = incr _count3 +let count4 () = incr _count4 +let count5 () = incr _count5 + +let profile_diagnostic_basic () = + Printf.sprintf + "count1 = %d\ncount2 = %d\ncount3 = %d\ncount4 = %d\ncount5 = %d\n" + !_count1 !_count2 !_count3 !_count4 !_count5 + + + +let time_func f = + (* let _ = Timing () in *) + let x = f () in + (* let _ = Timing () in *) + x + +(* ---------------------------------------------------------------------- *) + +type prof = PALL | PNONE | PSOME of string list +let profile = ref PNONE + +let check_profile category = + match !profile with + PALL -> true + | PNONE -> false + | PSOME l -> List.mem category l + +let _profile_table = ref (Hashtbl.create 100) +let profile_start category = failwith "todo" +let profile_end category = failwith "todo" + +(* subtil: don't forget to give all argumens to f, otherwise partial app + * and will profile nothing. + *) +let profile_code category f = + if not (check_profile category) + then f() + else begin + let t = Unix.gettimeofday () in + let res, prefix = + try Some (f ()), "" + with Timeout -> None, "*" + in + let category = prefix ^ category in (* add a '*' to indicate timeout func *) + let t' = Unix.gettimeofday () in + let (xtime, xcount) = + (try Hashtbl.find !_profile_table category + with Not_found -> + let xtime = ref 0.0 in + let xcount = ref 0 in + Hashtbl.add !_profile_table category (xtime, xcount); + (xtime, xcount) + ) in + xtime := !xtime +. (t' -. t); + xcount := !xcount + 1; + (match res with + | Some res -> res + | None -> raise Timeout + ); + end + +(* todo: also put % ? also add % to see if coherent numbers *) +let profile_diagnostic () = + if !profile = PNONE then "" else + let xs = + Hashtbl.fold (fun k v acc -> (k,v)::acc) !_profile_table [] + +> List.sort (fun (k1, (t1,n1)) (k2, (t2,n2)) -> compare t2 t1) + in + with_open_stringbuf (fun (pr,_) -> + pr "---------------------"; + pr "profiling result"; + pr "---------------------"; + xs +> List.iter (fun (k, (t,n)) -> + pr (sprintf "%-40s : %10.3f sec %10d count" k !t !n) + ) + ) + + + +let report_if_take_time timethreshold s f = + let t = Unix.gettimeofday () in + let res = f () in + let t' = Unix.gettimeofday () in + if (t' -. t > float_of_int timethreshold) + then pr2 (sprintf "NOTE: this code takes more than: %ds %s" timethreshold s); + res + +let profile_code2 category f = + profile_code category (fun () -> + if !profile = PALL + then pr2 ("starting: " ^ category); + let t = Unix.gettimeofday () in + let res = f () in + let t' = Unix.gettimeofday () in + if !profile = PALL + then pr2 (spf "ending: %s, %fs" category (t' -. t)); + res + ) + + +(*****************************************************************************) +(* Test *) +(*****************************************************************************) +let example b = assert b + +let _ex1 = example (enum 1 4 = [1;2;3;4]) + +let assert_equal a b = + if not (a = b) + then failwith ("assert_equal: those 2 values are not equal:\n\t" ^ + (dump a) ^ "\n\t" ^ (dump b) ^ "\n") + +let (example2: string -> bool -> unit) = fun s b -> + try assert b with x -> failwith s + +(*-------------------------------------------------------------------*) +let _list_bool = ref [] + +let (example3: string -> bool -> unit) = fun s b -> + _list_bool := (s,b)::(!_list_bool) + +(* could introduce a fun () otherwise the calculus is made at compile time + * and this can be long. This would require to redefine test_all. + * let (example3: string -> (unit -> bool) -> unit) = fun s func -> + * _list_bool := (s,func):: (!_list_bool) + * + * I would like to do as a func that take 2 terms, and make an = over it + * avoid to add this ugly fun (), but pb of type, cant do that :( + *) + + +let (test_all: unit -> unit) = fun () -> + List.iter (fun (s, b) -> + Printf.printf "%s: %s\n" s (if b then "passed" else "failed") + ) !_list_bool + +let (test: string -> unit) = fun s -> + Printf.printf "%s: %s\n" s + (if (List.assoc s (!_list_bool)) then "passed" else "failed") + +let _ex = example3 "++" ([1;2]++[3;4;5] = [1;2;3;4;5]) + +(*-------------------------------------------------------------------*) +(* Regression testing *) +(*-------------------------------------------------------------------*) + +(* cf end of file. It uses too many other common functions so I + * have put the code at the end of this file. + *) + + + +(* todo? take code from julien signoles in calendar-2.0.2/tests *) +(* + +(* Generic functions used in the tests. *) + +val reset : unit -> unit +val nb_ok : unit -> int +val nb_bug : unit -> int +val test : bool -> string -> unit +val test_exn : 'a Lazy.t -> string -> unit + + +let ok_ref = ref 0 +let ok () = incr ok_ref +let nb_ok () = !ok_ref + +let bug_ref = ref 0 +let bug () = incr bug_ref +let nb_bug () = !bug_ref + +let reset () = + ok_ref := 0; + bug_ref := 0 + +let test x s = + if x then ok () else begin Printf.printf "%s\n" s; bug () end;; + +let test_exn x s = + try + ignore (Lazy.force x); + Printf.printf "%s\n" s; + bug () + with _ -> + ok ();; +*) + + +(*****************************************************************************) +(* Quickcheck like (sfl) *) +(*****************************************************************************) + +(* Better than quickcheck, cos cant do a test_all_prop in haskell cos + * prop were functions, whereas here we have not prop_Unix x = ... but + * laws "unit" ... + * + * How to do without overloading ? objet ? can pass a generator as a + * parameter, mais lourd, prefer automatic inferring of the + * generator? But at the same time quickcheck does not do better cos + * we must explictly type the property. So between a + * prop_unit:: [Int] -> [Int] -> bool ... + * prop_unit x = reverse [x] == [x] + * and + * let _ = laws "unit" (fun x -> reverse [x] = [x]) (listg intg) + * there is no real differences. + * + * Yes I define typeg generator but quickcheck too, he must define + * class instance. I emulate the context Gen a => Gen [a] by making + * listg take as a param a type generator. Moreover I have not the pb of + * monad. I can do random independently, so my code is more simple + * I think than the haskell code of quickcheck. + * + * update: apparently Jane Street have copied some of my code for their + * Ounit_util.ml and quichcheck.ml in their Core library :) + *) + +(*---------------------------------------------------------------------------*) +(* generators *) +(*---------------------------------------------------------------------------*) +type 'a gen = unit -> 'a + +let (ig: int gen) = fun () -> + Random.int 10 +let (lg: ('a gen) -> ('a list) gen) = fun gen () -> + foldn (fun acc i -> (gen ())::acc) [] (Random.int 10) +let (pg: ('a gen) -> ('b gen) -> ('a * 'b) gen) = fun gen1 gen2 () -> + (gen1 (), gen2 ()) +let polyg = ig +let (ng: (string gen)) = fun () -> + "a" ^ (string_of_int (ig ())) + +let (oneofl: ('a list) -> 'a gen) = fun xs () -> + List.nth xs (Random.int (List.length xs)) +(* let oneofl l = oneof (List.map always l) *) + +let (oneof: (('a gen) list) -> 'a gen) = fun xs -> + List.nth xs (Random.int (List.length xs)) + +let (always: 'a -> 'a gen) = fun e () -> e + +let (frequency: ((int * ('a gen)) list) -> 'a gen) = fun xs -> + let sums = sum_int (List.map fst xs) in + let i = Random.int sums in + let rec freq_aux acc = function + | (x,g)::xs -> if i < acc+x then g else freq_aux (acc+x) xs + | _ -> failwith "frequency" + in + freq_aux 0 xs +let frequencyl l = frequency (List.map (fun (i,e) -> (i,always e)) l) + +(* +let b = oneof [always true; always false] () +let b = frequency [3, always true; 2, always false] () +*) + +(* cant do this: + * let rec (lg: ('a gen) -> ('a list) gen) = fun gen -> oneofl [[]; lg gen ()] + * nor + * let rec (lg: ('a gen) -> ('a list) gen) = fun gen -> oneof [always []; lg gen] + * + * because caml is not as lazy as haskell :( fix the pb by introducing a size + * limit. take the bounds/size as parameter. morover this is needed for + * more complex type. + * + * how make a bintreeg ?? we need recursion + * + * let rec (bintreeg: ('a gen) -> ('a bintree) gen) = fun gen () -> + * let rec aux n = + * if n = 0 then (Leaf (gen ())) + * else frequencyl [1, Leaf (gen ()); 4, Branch ((aux (n / 2)), aux (n / 2))] + * () + * in aux 20 + * + *) + + +(*---------------------------------------------------------------------------*) +(* property *) +(*---------------------------------------------------------------------------*) + +(* todo: a test_all_laws, better syntax (done already a little with ig in + * place of intg. En cas d'erreur, print the arg that not respect + * + * todo: with monitoring, as in haskell, laws = laws2, no need for 2 func, + * but hard i found + * + * todo classify, collect, forall + *) + + +(* return None when good, and Just the_problematic_case when bad *) +let (laws: string -> ('a -> bool) -> ('a gen) -> 'a option) = fun s func gen -> + let res = foldn (fun acc i -> let n = gen() in (n, func n)::acc) [] 1000 in + let res = List.filter (fun (x,b) -> not b) res in + if res = [] then None else Some (fst (List.hd res)) + +let rec (statistic_number: ('a list) -> (int * 'a) list) = function + | [] -> [] + | x::xs -> let (splitg, splitd) = List.partition (fun y -> y = x) xs in + (1+(List.length splitg), x)::(statistic_number splitd) + +(* in pourcentage *) +let (statistic: ('a list) -> (int * 'a) list) = fun xs -> + let stat_num = statistic_number xs in + let totals = sum_int (List.map fst stat_num) in + List.map (fun (i, v) -> ((i * 100) / totals), v) stat_num + +let (laws2: + string -> ('a -> (bool * 'b)) -> ('a gen) -> + ('a option * ((int * 'b) list ))) = + fun s func gen -> + let res = foldn (fun acc i -> let n = gen() in (n, func n)::acc) [] 1000 in + let stat = statistic (List.map (fun (x,(b,v)) -> v) res) in + let res = List.filter (fun (x,(b,v)) -> not b) res in + if res = [] then (None, stat) else (Some (fst (List.hd res)), stat) + + +(* +let b = laws "unit" (fun x -> reverse [x] = [x] )ig +let b = laws "app " (fun (xs,ys) -> reverse (xs++ys) = reverse ys++reverse xs)(pg (lg ig)(lg ig)) +let b = laws "rev " (fun xs -> reverse (reverse xs) = xs )(lg ig) +let b = laws "appb" (fun (xs,ys) -> reverse (xs++ys) = reverse xs++reverse ys)(pg (lg ig)(lg ig)) +let b = laws "max" (fun (x,y) -> x <= y ==> (max x y = y) )(pg ig ig) + +let b = laws2 "max" (fun (x,y) -> ((x <= y ==> (max x y = y)), x <= y))(pg ig ig) +*) + + +(* todo, do with coarbitrary ?? idea is that given a 'a, generate a 'b + * depending of 'a and gen 'b, that is modify gen 'b, what is important is + * that each time given the same 'a, we must get the same 'b !!! + *) + +(* +let (fg: ('a gen) -> ('b gen) -> ('a -> 'b) gen) = fun gen1 gen2 () -> +let b = laws "funs" (fun (f,g,h) -> x <= y ==> (max x y = y) )(pg ig ig) + *) + +(* +let one_of xs = List.nth xs (Random.int (List.length xs)) +let take_one xs = + if empty xs then failwith "Take_one: empty list" + else + let i = Random.int (List.length xs) in + List.nth xs i, filter_index (fun j _ -> i <> j) xs +*) + +(*****************************************************************************) +(* Persistence *) +(*****************************************************************************) + +let get_value filename = + let chan = open_in filename in + let x = input_value chan in (* <=> Marshal.from_channel *) + (close_in chan; x) + +let write_value valu filename = + let chan = open_out filename in + (output_value chan valu; (* <=> Marshal.to_channel *) + (* Marshal.to_channel chan valu [Marshal.Closures]; *) + close_out chan) + +let write_back func filename = + write_value (func (get_value filename)) filename + + + +(*****************************************************************************) +(* Counter *) +(*****************************************************************************) +let _counter = ref 0 +let counter () = (_counter := !_counter +1; !_counter) + +let _counter2 = ref 0 +let counter2 () = (_counter2 := !_counter2 +1; !_counter2) + +let _counter3 = ref 0 +let counter3 () = (_counter3 := !_counter3 +1; !_counter3) + +type timestamp = int + +(*****************************************************************************) +(* String_of *) +(*****************************************************************************) +(* To work with the macro system autogenerated string_of and print_ function + (kind of deriving a la haskell) *) + +(* int, bool, char, float, ref ?, string *) + +let string_of_string s = "\"" ^ s "\"" + +let string_of_list f xs = + "[" ^ (xs +> List.map f +> String.concat ";" ) ^ "]" + +let string_of_unit () = "()" + +let string_of_array f xs = + "[|" ^ (xs +> Array.to_list +> List.map f +> String.concat ";") ^ "|]" + +let string_of_option f = function + | None -> "None " + | Some x -> "Some " ^ (f x) + + + + +let print_bool x = print_string (if x then "True" else "False") + +let print_option pr = function + | None -> print_string "None" + | Some x -> print_string "Some ("; pr x; print_string ")" + +let print_list pr xs = + begin + print_string "["; + List.iter (fun x -> pr x; print_string ",") xs; + print_string "]"; + end + +(* specialised +let (string_of_list: char list -> string) = + List.fold_left (fun acc x -> acc^(Char.escaped x)) "" +*) + + +let rec print_between between fn = function + | [] -> () + | [x] -> fn x + | x::xs -> fn x; between(); print_between between fn xs + + + + +let adjust_pp_with_indent f = + Format.open_box !_tab_level_print; + (*Format.force_newline();*) + f(); + Format.close_box (); + Format.print_newline() + +let adjust_pp_with_indent_and_header s f = + Format.open_box (!_tab_level_print + String.length s); + do_n !_tab_level_print (fun () -> Format.print_string " "); + Format.print_string s; + f(); + Format.close_box (); + Format.print_newline() + + + +let pp_do_in_box f = Format.open_box 1; f(); Format.close_box () +let pp_do_in_zero_box f = Format.open_box 0; f(); Format.close_box () + +let pp_f_in_box f = + Format.open_box 1; + let res = f() in + Format.close_box (); + res + +let pp s = Format.print_string s + + + +(* julia: convert something printed using format to print into a string *) +let format_to_string f = + let o = open_out "/tmp/out" in + Format.set_formatter_out_channel o; + let _ = f() in + Format.print_flush(); + Format.set_formatter_out_channel stdout; + close_out o; + let i = open_in "/tmp/out" in + let lines = ref [] in + let rec loop _ = + let cur = input_line i in + lines := cur :: !lines; + loop() in + (try loop() with End_of_file -> ()); + close_in i; + String.concat "\n" (List.rev !lines) + + + +(*****************************************************************************) +(* Macro *) +(*****************************************************************************) + +(* put your macro in macro.ml4, and you can test it interactivly as in lisp *) +let macro_expand s = + let c = open_out "/tmp/ttttt.ml" in + begin + output_string c s; close_out c; + command2 ("ocamlc -c -pp 'camlp4o pa_extend.cmo q_MLast.cmo -impl' " ^ + "-I +camlp4 -impl macro.ml4"); + command2 "camlp4o ./macro.cmo pr_o.cmo /tmp/ttttt.ml"; + command2 "rm -f /tmp/ttttt.ml"; + end + +(* +let t = macro_expand "{ x + y | (x,y) <- [(1,1);(2,2);(3,3)] and x>2 and y<3}" +let x = { x + y | (x,y) <- [(1,1);(2,2);(3,3)] and x > 2 and y < 3} +let t = macro_expand "{1 .. 10}" +let x = {1 .. 10} +> List.map (fun i -> i) +let t = macro_expand "[1;2] to append to [2;4]" +let t = macro_expand "{x = 2; x = 3}" + +let t = macro_expand "type 'a bintree = Leaf of 'a | Branch of ('a bintree * 'a bintree)" +*) + + + +(*****************************************************************************) +(* Composition/Control *) +(*****************************************************************************) + +(* I like the obj.func object notation. In OCaml cant use '.' so I use +> + * + * update: it seems that F# agrees with me :) but they use |> + *) + +(* now in prelude: + * let (+>) o f = f o + *) +let (+!>) refo f = refo := f !refo +(* alternatives: + * let ((@): 'a -> ('a -> 'b) -> 'b) = fun a b -> b a + * let o f g x = f (g x) + *) + +let ($) f g x = g (f x) +let compose f g x = f (g x) +(* dont work :( let ( ° ) f g x = f(g(x)) *) + +(* trick to have something similar to the 1 `max` 4 haskell infix notation. + by Keisuke Nakano on the caml mailing list. +> let ( /* ) x y = y x +> and ( */ ) x y = x y +or + let ( <| ) x y = y x + and ( |> ) x y = x y + +> Then we can make an infix operator <| f |> for a binary function f. +*) + +let flip f = fun a b -> f b a + +let curry f x y = f (x,y) +let uncurry f (a,b) = f a b + +let id = fun x -> x + +let do_nothing () = () + +let rec applyn n f o = if n = 0 then o else applyn (n-1) f (f o) + +let forever f = + while true do + f(); + done + + +class ['a] shared_variable_hook (x:'a) = + object(self) + val mutable data = x + val mutable registered = [] + method set x = + begin + data <- x; + pr "refresh registered"; + registered +> List.iter (fun f -> f()); + end + method get = data + method modify f = self#set (f self#get) + method register f = + registered <- f :: registered + end + +(* src: from aop project. was called ptFix *) +let rec fixpoint trans elem = + let image = trans elem in + if (image = elem) + then elem (* point fixe *) + else fixpoint trans image + +(* le point fixe pour les objets. was called ptFixForObjetct *) +let rec fixpoint_for_object trans elem = + let image = trans elem in + if (image#equal elem) then elem (* point fixe *) + else fixpoint_for_object trans image + +let (add_hook: ('a -> ('a -> 'b) -> 'b) ref -> ('a -> ('a -> 'b) -> 'b) -> unit) = + fun var f -> + let oldvar = !var in + var := fun arg k -> f arg (fun x -> oldvar x k) + +let (add_hook_action: ('a -> unit) -> ('a -> unit) list ref -> unit) = + fun f hooks -> + push2 f hooks + +let (run_hooks_action: 'a -> ('a -> unit) list ref -> unit) = + fun obj hooks -> + !hooks +> List.iter (fun f -> try f obj with _ -> ()) + + +type 'a mylazy = (unit -> 'a) + +(* a la emacs *) +let save_excursion reference f = + let old = !reference in + let res = f() in + reference := old; + res + + + +let memoized h k f = + try Hashtbl.find h k + with Not_found -> + let v = f () in + begin + Hashtbl.add h k v; + v + end + +let once f = + let already = ref false in + (fun x -> + if not !already + then begin already := true; f x end + ) + +(* cache_file, cf below *) + +let before_leaving f x = + f x; + x + +(* finalize, cf prelude *) + + +(* cheat *) +let rec y f = fun x -> f (y f) x + +(*****************************************************************************) +(* Concurrency *) +(*****************************************************************************) + +(* from http://en.wikipedia.org/wiki/File_locking + * + * "When using file locks, care must be taken to ensure that operations + * are atomic. When creating the lock, the process must verify that it + * does not exist and then create it, but without allowing another + * process the opportunity to create it in the meantime. Various + * schemes are used to implement this, such as taking advantage of + * system calls designed for this purpose (but such system calls are + * not usually available to shell scripts) or by creating the lock file + * under a temporary name and then attempting to move it into place." + * + * => can't use 'if(not (file_exist xxx)) then create_file xxx' because + * file_exist/create_file are not in atomic section (classic problem). + * + * from man open: + * + * "O_EXCL When used with O_CREAT, if the file already exists it + * is an error and the open() will fail. In this context, a + * symbolic link exists, regardless of where it points to. + * O_EXCL is broken on NFS file systems; programs which + * rely on it for performing locking tasks will contain a + * race condition. The solution for performing atomic file + * locking using a lockfile is to create a unique file on + * the same file system (e.g., incorporating host- name and + * pid), use link(2) to make a link to the lockfile. If + * link(2) returns 0, the lock is successful. Otherwise, + * use stat(2) on the unique file to check if its link + * count has increased to 2, in which case the lock is also + * successful." + + *) + +exception FileAlreadyLocked + +(* Racy if lock file on NFS!!! But still racy with recent Linux ? *) +let acquire_file_lock filename = + pr2 ("Locking file: " ^ filename); + try + let _fd = Unix.openfile filename [Unix.O_CREAT;Unix.O_EXCL] 0o777 in + () + with Unix.Unix_error (e, fm, argm) -> + pr2 (spf "exn Unix_error: %s %s %s\n" (Unix.error_message e) fm argm); + raise FileAlreadyLocked + + +let release_file_lock filename = + pr2 ("Releasing file: " ^ filename); + Unix.unlink filename; + () + + + +(*****************************************************************************) +(* Error managment *) +(*****************************************************************************) + +exception Todo +exception Impossible +exception Here +exception ReturnExn + +exception WrongFormat of string + +(* old: let _TODO () = failwith "TODO", now via fix_caml with raise Todo *) + +let internal_error s = failwith ("internal error: "^s) +let error_cant_have x = internal_error ("cant have this case" ^(dump x)) +let myassert cond = if cond then () else failwith "assert error" + + + +(* before warning I was forced to do stuff like this: + * + * let (fixed_int_to_posmap: fixed_int -> posmap) = fun fixed -> + * let v = ((fix_to_i fixed) / (power 2 16)) in + * let _ = Printf.printf "coord xy = %d\n" v in + * v + * + * The need for printf make me force to name stuff :( + * How avoid ? use 'it' special keyword ? + * In fact dont have to name it, use +> (fun v -> ...) so when want + * erase debug just have to erase one line. + *) +let warning s v = (pr2 ("Warning: " ^ s ^ "; value = " ^ (dump v)); v) + + + + +let exn_to_s exn = + Printexc.to_string exn + + + +(* want or of merd, but cant cos cant put die ... in b (strict call) *) +let (|||) a b = try a with _ -> b + +(* emacs/lisp inspiration, (vouillon does that too in unison I think) *) + +(* now in Prelude: + * let unwind_protect f cleanup = ... + * let finalize f cleanup = ... + *) + + +(*****************************************************************************) +(* Environment *) +(*****************************************************************************) + +let check_stack = ref true +let check_stack_size limit = + if !check_stack then begin + pr2 "checking stack size (do ulimit -s 50000 if problem)"; + let rec aux i = + if i = limit + then 0 + else 1 + aux (i + 1) + in + assert(aux 0 = limit); + () + end + +let test_check_stack_size limit = + (* bytecode: 100000000 *) + (* native: 10000000 *) + check_stack_size (int_of_string limit) + + +(* only relevant in bytecode, in native the stacklimit is the os stacklimit + * (adjustable by ulimit -s) + *) +let _init_gc_stack = + Gc.set {(Gc.get ()) with Gc.stack_limit = 100 * 1024 * 1024} + + +(* if process a big set of files then dont want get overflow in the middle + * so for this we are ready to spend some extra time at the beginning that + * could save far more later. + *) +let check_stack_nbfiles nbfiles = + if nbfiles > 200 + then check_stack_size 10000000 + +(*****************************************************************************) +(* Arguments/options and command line (cocci and acomment) *) +(*****************************************************************************) + +(* + * Why define wrappers ? Arg not good enough ? Well the Arg.Rest is not that + * good and I need a way sometimes to get a list of argument. + * + * I could define maybe a new Arg.spec such as + * | String_list of (string list -> unit), but the action may require + * some flags to be set, so better to process this after all flags have + * been set by parse_options. So have to split. Otherwise it would impose + * an order of the options such as + * -verbose_parsing -parse_c file1 file2. and I really like to use bash + * history and add just at the end of my command a -profile for instance. + * + * + * Why want a -action arg1 arg2 arg3 ? (which in turn requires this + * convulated scheme ...) Why not use Arg.String action such as + * "-parse_c", Arg.String (fun file -> ...) ? + * I want something that looks like ocaml function but at the UNIX + * command line level. So natural to have this scheme instead of + * -taxo_file arg2 -sample_file arg3 -parse_c arg1. + * + * + * Why not use the toplevel ? because to debug ocamldebug is far superior + * to the toplevel (can go back, can go directly to a specific point, etc). + * I want a kind of testing at cmdline level. + * + * + * Why having variable flags ? Why use 'if !verbose_parsing then ...' ? + * why not use strings and do stuff like the following + * 'if (get_config "verbose_parsing") then ...' + * Because I want to make the interface for flags easier for the code + * that use it. The programmer should not be bothered wether this + * flag is set via args cmd line or a config file, so I want to make it + * as simple as possible, just use a global plain caml ref variable. + * + * Same spirit a little for the action. Instead of having function such as + * test_parsing_c, I could do it only via string. But I still prefer + * to have plain caml test functions. Also it makes it easier to call + * those functions from a toplevel for people who prefer the toplevel. + * + * + * So have flag_spec and action_spec. And in flag have debug_xxx flags, + * verbose_xxx flags and other flags. + * + * I would like to not have to separate the -xxx actions spec from the + * corresponding actions, but those actions may need more than one argument + * and so have to wait for parse_options, which in turn need the options + * spec, so circle. + * + * Also I dont want to mix code with data structures, so it's better that the + * options variable contain just a few stuff and have no side effects except + * setting global variables. + * + * Why not have a global variable such as Common.actions that + * other modules modify ? No, I prefer to do less stuff behind programmer's + * back so better to let the user merge the different options at call + * site, but at least make it easier by providing shortcut for set of options. + * + * + * + * + * todo? isn't unison or scott-mcpeak-lib-in-cil handles that kind of + * stuff better ? That is the need to localize command line argument + * while still being able to gathering them. Same for logging. + * Similiar to the type prof = PALL | PNONE | PSOME of string list. + * Same spirit of fine grain config in log4j ? + * + * todo? how mercurial/cvs/git manage command line options ? because they + * all have a kind of DSL around arguments with some common options, + * specific options, conventions, etc. + * + * + * todo? generate the corresponding noxxx options ? + * todo? generate list of options and show their value ? + * + * todo? make it possible to set this value via a config file ? + * + * + *) + +type arg_spec_full = Arg.key * Arg.spec * Arg.doc +type cmdline_options = arg_spec_full list + +(* the format is a list of triples: + * (title of section * (optional) explanation of sections * options) + *) +type options_with_title = string * string * arg_spec_full list +type cmdline_sections = options_with_title list + + +(* ---------------------------------------------------------------------- *) + +(* now I use argv as I like at the call sites to show that + * this function internally use argv. + *) +let parse_options options usage_msg argv = + let args = ref [] in + (try + Arg.parse_argv argv options (fun file -> args := file::!args) usage_msg; + args := List.rev !args; + !args + with + | Arg.Bad msg -> eprintf "%s" msg; exit 2 + | Arg.Help msg -> printf "%s" msg; exit 0 + ) + + + + +let usage usage_msg options = + Arg.usage (Arg.align options) usage_msg + + +(* for coccinelle *) + +(* If you don't want the -help and --help that are appended by Arg.align *) +let arg_align2 xs = + Arg.align xs +> List.rev +> drop 2 +> List.rev + + +let short_usage usage_msg ~short_opt = + usage usage_msg short_opt + +let long_usage usage_msg ~short_opt ~long_opt = + pr usage_msg; + pr ""; + let all_options_with_title = + (("main options", "", short_opt)::long_opt) in + all_options_with_title +> List.iter + (fun (title, explanations, xs) -> + pr title; + pr_xxxxxxxxxxxxxxxxx(); + if explanations <> "" + then begin pr explanations; pr "" end; + arg_align2 xs +> List.iter (fun (key,action,s) -> + pr (" " ^ key ^ s) + ); + pr ""; + ); + () + + +(* copy paste of Arg.parse. Don't want the default -help msg *) +let arg_parse2 l msg short_usage_fun = + let args = ref [] in + let f = (fun file -> args := file::!args) in + let l = Arg.align l in + (try begin + Arg.parse_argv Sys.argv l f msg; + args := List.rev !args; + !args + end + with + | Arg.Bad msg -> (* eprintf "%s" msg; exit 2; *) + let xs = lines msg in + (* take only head, it's where the error msg is *) + pr2 (List.hd xs); + short_usage_fun(); + raise (UnixExit (2)) + | Arg.Help msg -> (* printf "%s" msg; exit 0; *) + raise Impossible (* -help is specified in speclist *) + ) + + +(* ---------------------------------------------------------------------- *) +(* kind of unit testing framework, or toplevel like functionnality + * at shell command line. I realize than in fact It follows a current trend + * to have a main cmdline program where can then select different actions, + * as in cvs/hg/git where do hg , and the shell even + * use a curried syntax :) + * + * + * Not-perfect-but-basic-feels-right: an action + * spec looks like this: + * + * let actions () = [ + * "-parse_taxo", " ", + * Common.mk_action_1_arg test_parse_taxo; + * ... + * ] + * + * Not-perfect-but-basic-feels-right because for such functionality we + * need a way to transform a string into a caml function and pass arguments + * and the preceding design does exactly that, even if then the + * functions that use this design are not so convenient to use (there + * are 2 places where we need to pass those data, in the options and in the + * main dispatcher). + * + * Also it's not too much intrusive. Still have an + * action ref variable in the main.ml and can still use the previous + * simpler way to do where the match args with in main.ml do the + * dispatch. + * + * Use like this at option place: + * (Common.options_of_actions actionref (Test_parsing_c.actions())) ++ + * Use like this at dispatch action place: + * | xs when List.mem !action (Common.action_list all_actions) -> + * Common.do_action !action xs all_actions + * + *) + +type flag_spec = Arg.key * Arg.spec * Arg.doc +type action_spec = Arg.key * Arg.doc * action_func + and action_func = (string list -> unit) + +type cmdline_actions = action_spec list +exception WrongNumberOfArguments + +let options_of_actions action_ref actions = + actions +> List.map (fun (key, doc, _func) -> + (key, (Arg.Unit (fun () -> action_ref := key)), doc) + ) + +let (action_list: cmdline_actions -> Arg.key list) = fun xs -> + List.map (fun (a,b,c) -> a) xs + +let (do_action: Arg.key -> string list (* args *) -> cmdline_actions -> unit) = + fun key args xs -> + let assoc = xs +> List.map (fun (a,b,c) -> (a,c)) in + let action_func = List.assoc key assoc in + action_func args + + +(* todo? if have a function with default argument ? would like a + * mk_action_0_or_1_arg ? + *) + +let mk_action_0_arg f = + (function + | [] -> f () + | _ -> raise WrongNumberOfArguments + ) + +let mk_action_1_arg f = + (function + | [file] -> f file + | _ -> raise WrongNumberOfArguments + ) + +let mk_action_2_arg f = + (function + | [file1;file2] -> f file1 file2 + | _ -> raise WrongNumberOfArguments + ) + +let mk_action_3_arg f = + (function + | [file1;file2;file3] -> f file1 file2 file3 + | _ -> raise WrongNumberOfArguments + ) + +let mk_action_n_arg f = f + + +(*****************************************************************************) +(* Equality *) +(*****************************************************************************) + +(* Using the generic (=) is tempting, but it backfires, so better avoid it *) + +(* To infer all the code that use an equal, and that should be + * transformed, is not that easy, because (=) is used by many + * functions, such as List.find, List.mem, and so on. So the strategy + * is to turn what you were previously using into a function, because + * (=) return an exception when applied to a function. Then you simply + * use ocamldebug to infer where the code has to be transformed. + *) + +(* src: caml mailing list ? *) +let (=|=) : int -> int -> bool = (=) +let (=<=) : char -> char -> bool = (=) +let (=$=) : string -> string -> bool = (=) +let (=:=) : bool -> bool -> bool = (=) + +(* the evil generic (=). I define another symbol to more easily detect + * it, cos the '=' sign is syntaxically overloaded in caml. It is also + * used to define function. + *) +let (=*=) = (=) + +(* if really want to forbid to use '=' +let (=) = (=|=) +*) + + + + + + + + +(*###########################################################################*) +(* And now basic types *) +(*###########################################################################*) + + + +(*****************************************************************************) +(* Bool *) +(*****************************************************************************) +let (==>) b1 b2 = if b1 then b2 else true (* could use too => *) + +let (<=>) a b = if a = b then 0 else if a < b then -1 else 1 + +let xor a b = not (a = b) + + +(*****************************************************************************) +(* Char *) +(*****************************************************************************) + +let string_of_char c = String.make 1 c + +let is_single = String.contains ",;()[]{}_`" +let is_symbol = String.contains "!@#$%&*+./<=>?\\^|:-~" +let is_space = String.contains "\n\t " +let cbetween min max c = + (int_of_char c) <= (int_of_char max) && + (int_of_char c) >= (int_of_char min) +let is_upper = cbetween 'A' 'Z' +let is_lower = cbetween 'a' 'z' +let is_alpha c = is_upper c || is_lower c +let is_digit = cbetween '0' '9' + +let string_of_chars cs = cs +> List.map (String.make 1) +> String.concat "" + + + +(*****************************************************************************) +(* Num *) +(*****************************************************************************) + +(* since 3.08, div by 0 raise Div_by_rezo, and not anymore a hardware trap :)*) +let (/!) x y = if y = 0 then (log "common.ml: div by 0"; 0) else x / y + +(* now in prelude + * let rec (do_n: int -> (unit -> unit) -> unit) = fun i f -> + * if i = 0 then () else (f(); do_n (i-1) f) + *) + +(* now in prelude + * let rec (foldn: ('a -> int -> 'a) -> 'a -> int -> 'a) = fun f acc i -> + * if i = 0 then acc else foldn f (f acc i) (i-1) + *) + +let sum_float = List.fold_left (+.) 0.0 +let sum_int = List.fold_left (+) 0 + +let pi = 3.14159265358979323846 +let pi2 = pi /. 2.0 +let pi4 = pi /. 4.0 + +(* 180 = pi *) +let (deg_to_rad: float -> float) = fun deg -> + (deg *. pi) /. 180.0 + +let clampf = function + | n when n < 0.0 -> 0.0 + | n when n > 1.0 -> 1.0 + | n -> n + +let square x = x *. x + +let rec power x n = if n = 0 then 1 else x * power x (n-1) + +let between i min max = i > min && i < max + +let (between_strict: int -> int -> int -> bool) = fun a b c -> + a < b && b < c + + +let bitrange x p = let v = power 2 p in between x (-v) v + +(* descendant *) +let (prime1: int -> int option) = fun x -> + let rec prime1_aux n = + if n = 1 then None + else + if (x / n) * n = x then Some n else prime1_aux (n-1) + in if x = 1 then None else if x < 0 then failwith "negative" else prime1_aux (x-1) + +(* montant, better *) +let (prime: int -> int option) = fun x -> + let rec prime_aux n = + if n = x then None + else + if (x / n) * n = x then Some n else prime_aux (n+1) + in if x = 1 then None else if x < 0 then failwith "negative" else prime_aux 2 + +let sum xs = List.fold_left (+) 0 xs +let product = List.fold_left ( * ) 1 + + +let decompose x = + let rec decompose x = + if x = 1 then [] + else + (match prime x with + | None -> [x] + | Some n -> n::decompose (x / n) + ) + in assert (product (decompose x) = x); decompose x + +let mysquare x = x * x +let sqr a = a *. a + + +type compare = Equal | Inf | Sup +let (<=>) a b = if a = b then Equal else if a < b then Inf else Sup +let (<==>) a b = if a = b then 0 else if a < b then -1 else 1 + +type uint = int + + +let int_of_stringchar s = + fold_left_with_index (fun acc e i -> acc + (Char.code e*(power 8 i))) 0 (List.rev (list_of_string s)) + +let int_of_base s base = + fold_left_with_index (fun acc e i -> + let j = Char.code e - Char.code '0' in + if j >= base then failwith "not in good base" + else acc + (j*(power base i)) + ) + 0 (List.rev (list_of_string s)) + +let int_of_stringbits s = int_of_base s 2 +let _ = example (int_of_stringbits "1011" = 1*8 + 1*2 + 1*1) + +let int_of_octal s = int_of_base s 8 +let _ = example (int_of_octal "017" = 15) + +(* let int_of_hex s = int_of_base s 16, NONONONO cos 'A' - '0' does not give 10 !! *) + +let int_of_all s = + if String.length s >= 2 && (String.get s 0 = '0') && is_digit (String.get s 1) + then int_of_octal s else int_of_string s + + +let (+=) ref v = ref := !ref + v +let (-=) ref v = ref := !ref - v + +let pourcent x total = + (x * 100) / total +let pourcent_float x total = + ((float_of_int x) *. 100.0) /. (float_of_int total) + +let pourcent_float_of_floats x total = + (x *. 100.0) /. total + +(*****************************************************************************) +(* Numeric/overloading *) +(*****************************************************************************) + +type 'a numdict = + NumDict of (('a-> 'a -> 'a) * + ('a-> 'a -> 'a) * + ('a-> 'a -> 'a) * + ('a -> 'a));; + +let add (NumDict(a, m, d, n)) = a;; +let mul (NumDict(a, m, d, n)) = m;; +let div (NumDict(a, m, d, n)) = d;; +let neg (NumDict(a, m, d, n)) = n;; + +let numd_int = NumDict(( + ),( * ),( / ),( ~- ));; +let numd_float = NumDict(( +. ),( *. ), ( /. ),( ~-. ));; +let testd dict n = + let ( * ) x y = mul dict x y in + let ( / ) x y = div dict x y in + let ( + ) x y = add dict x y in + (* Now you can define all sorts of things in terms of *, /, + *) + let f num = (num * num) / (num + num) in + f n;; + + + +module ArithFloatInfix = struct + let (+..) = (+) + let (-..) = (-) + let (/..) = (/) + let ( *.. ) = ( * ) + + + let (+) = (+.) + let (-) = (-.) + let (/) = (/.) + let ( * ) = ( *. ) + + let (+=) ref v = ref := !ref + v + let (-=) ref v = ref := !ref - v + +end + + + +(*****************************************************************************) +(* Tuples *) +(*****************************************************************************) + +type 'a pair = 'a * 'a +type 'a triple = 'a * 'a * 'a + +let fst3 (x,_,_) = x +let snd3 (_,y,_) = y +let thd3 (_,_,z) = z + +let sndthd (a,b,c) = (b,c) + +let map_fst f (x, y) = f x, y +let map_snd f (x, y) = x, f y + +let pair f (x,y) = (f x, f y) + +(* for my ocamlbeautify script *) +let snd = snd +let fst = fst + +let double a = a,a +let swap (x,y) = (y,x) + + +let tuple_of_list1 = function [a] -> a | _ -> failwith "tuple_of_list1" +let tuple_of_list2 = function [a;b] -> a,b | _ -> failwith "tuple_of_list2" +let tuple_of_list3 = function [a;b;c] -> a,b,c | _ -> failwith "tuple_of_list3" +let tuple_of_list4 = function [a;b;c;d] -> a,b,c,d | _ -> failwith "tuple_of_list4" +let tuple_of_list5 = function [a;b;c;d;e] -> a,b,c,d,e | _ -> failwith "tuple_of_list5" +let tuple_of_list6 = function [a;b;c;d;e;f] -> a,b,c,d,e,f | _ -> failwith "tuple_of_list6" + + +(*****************************************************************************) +(* Maybe *) +(*****************************************************************************) + +(* type 'a maybe = Just of 'a | None *) + +type ('a,'b) either = Left of 'a | Right of 'b +type ('a, 'b, 'c) either3 = Left3 of 'a | Middle3 of 'b | Right3 of 'c + +let just = function + | (Some x) -> x + | _ -> failwith "just: pb" + +let some = just + + +let fmap f = function + | None -> None + | Some x -> Some (f x) +let map_option = fmap + +let do_option f = function + | None -> () + | Some x -> f x + +let optionise f = + try Some (f ()) with Not_found -> None + + + +(* pixel *) +let some_or = function + | None -> id + | Some e -> fun _ -> e + + +let partition_either f l = + let rec part_either left right = function + | [] -> (List.rev left, List.rev right) + | x :: l -> + (match f x with + | Left e -> part_either (e :: left) right l + | Right e -> part_either left (e :: right) l) in + part_either [] [] l + + +(* pixel *) +let rec filter_some = function + | [] -> [] + | None :: l -> filter_some l + | Some e :: l -> e :: filter_some l + +let map_filter f xs = xs +> List.map f +> filter_some + +let rec find_some p = function + | [] -> raise Not_found + | x :: l -> + match p x with + | Some v -> v + | None -> find_some p l + +(* same +let map_find f xs = + xs +> List.map f +> List.find (function Some x -> true | None -> false) + +> (function Some x -> x | None -> raise Impossible) +*) + + +(*****************************************************************************) +(* Regexp *) +(*****************************************************************************) + +(* put before String section because String section use some =~ *) + +(* let gsubst = global_replace *) + +(* Different from Perl a little. Must match the entire way. + * So "testBee" =~ "Bee" is wrong + * but "testBee" =~ ".*Bee" is right + * Can have the perl behavior if use Str.search_forward instead of + * Str.string_match. + *) + +let (==~) s re = Str.string_match re s 0 + +let _memo_compiled_regexp = Hashtbl.create 101 +let candidate_match_func s re = + (* old: Str.string_match (Str.regexp re) s 0 *) + let compile_re = + memoized _memo_compiled_regexp re (fun () -> Str.regexp re) + in + Str.string_match compile_re s 0 + +let match_func s re = + profile_code "Common.=~" (fun () -> candidate_match_func s re) + +let (=~) s re = + match_func s re + + + + + +let string_match_substring re s = + try let _i = Str.search_forward re s 0 in true + with Not_found -> false + +let (regexp_match: string -> string -> string) = fun s re -> + assert(s =~ re); + Str.matched_group 1 s + +(* beurk, side effect code, but hey, it is convenient *) +(* now in prelude + * let (matched: int -> string -> string) = fun i s -> + * Str.matched_group i s + * + * let matched1 = fun s -> matched 1 s + * let matched2 = fun s -> (matched 1 s, matched 2 s) + * let matched3 = fun s -> (matched 1 s, matched 2 s, matched 3 s) + * let matched4 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s) + * let matched5 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s) + * let matched6 = fun s -> (matched 1 s, matched 2 s, matched 3 s, matched 4 s, matched 5 s, matched 6 s) + *) + + + +let split sep s = Str.split (Str.regexp sep) s +let _ = example (split "/" "" = []) +let join sep xs = String.concat sep xs +let _ = example (join "/" ["toto"; "titi"; "tata"] = "toto/titi/tata") +(* +let rec join str = function + | [] -> "" + | [x] -> x + | x::xs -> x ^ str ^ (join str xs) +*) + + +let (split_list_regexp: string -> string list -> (string * string list) list) = + fun re xs -> + let rec split_lr_aux (heading, accu) = function + | [] -> [(heading, List.rev accu)] + | x::xs -> + if x =~ re + then (heading, List.rev accu)::split_lr_aux (x, []) xs + else split_lr_aux (heading, x::accu) xs + in + split_lr_aux ("__noheading__", []) xs + +> (fun xs -> if (List.hd xs) = ("__noheading__",[]) then List.tl xs else xs) + + + +let regexp_alpha = Str.regexp + "^[a-zA-Z_][A-Za-z_0-9]*$" + + +let all_match re s = + let regexp = Str.regexp re in + let res = ref [] in + let _ = Str.global_substitute regexp (fun _s -> + let substr = Str.matched_string s in + assert(substr ==~ regexp); (* @Effect: also use it's side effect *) + let paren_matched = matched1 substr in + push2 paren_matched res; + "" (* @Dummy *) + ) s in + List.rev !res + +let _ = example (all_match "\\(@[A-Za-z]+\\)" "ca va @Et toi @Comment" + = ["@Et";"@Comment"]) + + + +(*****************************************************************************) +(* Strings *) +(*****************************************************************************) + +let slength = String.length +let concat = String.concat + +(* ruby *) +let i_to_s = string_of_int +let s_to_i = int_of_string + + +(* strings take space in memory. Better when can share the space used by + similar strings *) +let _shareds = Hashtbl.create 100 +let (shared_string: string -> string) = fun s -> + try Hashtbl.find _shareds s + with Not_found -> (Hashtbl.add _shareds s s; s) + +let chop = function + | "" -> "" + | s -> String.sub s 0 (String.length s - 1) + + +let chop_dirsymbol = function + | s when s =~ "\\(.*\\)/$" -> matched1 s + | s -> s + + +let () s (i,j) = + String.sub s i (if j < 0 then String.length s - i + j + 1 else j - i) +(* let _ = example ( "tototati"(3,-2) = "otat" ) *) + +let () s i = String.get s i + +(* pixel *) +let rec split_on_char c s = + try + let sp = String.index s c in + String.sub s 0 sp :: + split_on_char c (String.sub s (sp+1) (String.length s - sp - 1)) + with Not_found -> [s] + + +let lowercase = String.lowercase + +let quote s = "\"" ^ s ^ "\"" + +(* easier to have this to be passed as hof, because ocaml dont have + * haskell "section" operators + *) +let null_string s = + s = "" + +let is_blank_string s = + s =~ "^\\([ \t]\\)*$" + +(* src: lablgtk2/examples/entrycompletion.ml *) +let is_string_prefix s1 s2 = + (String.length s1 <= String.length s2) && (String.sub s2 0 (String.length s1) = s1) + +let plural i s = + if i=1 + then Printf.sprintf "%d %s" i s + else Printf.sprintf "%d %ss" i s + +let showCodeHex xs = List.iter (fun i -> printf "%02x" i) xs + + +(* used by LFS *) +let size_mo_ko i = + let ko = (i / 1024) mod 1024 in + let mo = (i / 1024) / 1024 in + (if mo > 0 + then sprintf "%dMo%dKo" mo ko + else sprintf "%dKo" ko + ) + +let size_ko i = + let ko = i / 1024 in + sprintf "%dKo" ko + + + +(* done in summer 2007 for julia + * Reference: P216 of gusfeld book + * For two strings S1 and S2, D(i,j) is defined to be the edit distance of S1[1..i] to S2[1..j] + * So edit distance of S1 (of length n) and S2 (of length m) is D(n,m) + * + * Dynamic programming technique + * base: + * D(i,0) = i for all i (cos to go from S1[1..i] to 0 characteres of S2 you have to delete all characters from S1[1..i] + * D(0,j) = j for all j (cos j characters must be inserted) + * recurrence: + * D(i,j) = min([D(i-1, j)+1, D(i, j - 1 + 1), D(i-1, j-1) + t(i,j)]) + * where t(i,j) is equal to 1 if S1(i) != S2(j) and 0 if equal + * intuition = there is 4 possible action = deletion, insertion, substitution, or match + * so Lemma = + * + * D(i,j) must be one of the three + * D(i, j-1) + 1 + * D(i-1, j)+1 + * D(i-1, j-1) + + * t(i,j) + * + * + *) +let matrix_distance s1 s2 = + let n = (String.length s1) in + let m = (String.length s2) in + let mat = Array.make_matrix (n+1) (m+1) 0 in + let t i j = + if String.get s1 (i-1) = String.get s2 (j-1) + then 0 + else 1 + in + let min3 a b c = min (min a b) c in + + begin + for i = 0 to n do + mat.(i).(0) <- i + done; + for j = 0 to m do + mat.(0).(j) <- j; + done; + for i = 1 to n do + for j = 1 to m do + mat.(i).(j) <- + min3 (mat.(i).(j-1) + 1) (mat.(i-1).(j) + 1) (mat.(i-1).(j-1) + t i j) + done + done; + mat + end +let edit_distance s1 s2 = + (matrix_distance s1 s2).(String.length s1).(String.length s2) + + +let test = edit_distance "vintner" "writers" +let _ = assert (edit_distance "winter" "winter" = 0) +let _ = assert (edit_distance "vintner" "writers" = 5) + + +(*****************************************************************************) +(* Filenames *) +(*****************************************************************************) + +let dirname = Filename.dirname +let basename = Filename.basename + +type filename = string (* TODO could check that exist :) type sux *) + +module BasicType = struct + type filename = string +end + + +let (filesuffix: filename -> string) = fun s -> + (try regexp_match s ".+\\.\\([a-zA-Z0-9_]+\\)$" with _ -> "NOEXT") +let (fileprefix: filename -> string) = fun s -> + (try regexp_match s "\\(.+\\)\\.\\([a-zA-Z0-9_]+\\)?$" with _ -> s) + +let _ = example (filesuffix "toto.c" = "c") +let _ = example (fileprefix "toto.c" = "toto") + +(* +assert (s = fileprefix s ^ filesuffix s) + +let withoutExtension s = global_replace (regexp "\\..*$") "" s +let () = example "without" + (withoutExtension "toto.s.toto" = "toto") +*) + +let adjust_ext_if_needed filename ext = + if String.get ext 0 <> '.' + then failwith "I need an extension such as .c not just c"; + + if not (filename =~ (".*\\" ^ ext)) + then filename ^ ext + else filename + + + +let db_of_filename file = + dirname file, basename file + +let filename_of_db (basedir, file) = + Filename.concat basedir file + + + +let dbe_of_filename file = + (* raise Invalid_argument if no ext, so safe to use later the unsafe + * fileprefix and filesuffix functions. + *) + ignore(Filename.chop_extension file); + Filename.dirname file, + Filename.basename file +> fileprefix, + Filename.basename file +> filesuffix + +let filename_of_dbe (dir, base, ext) = + Filename.concat dir (base ^ "." ^ ext) + + +let dbe_of_filename_safe file = + try Left (dbe_of_filename file) + with Invalid_argument _ -> + Right (Filename.dirname file, Filename.basename file) + + +let dbe_of_filename_nodot file = + let (d,b,e) = dbe_of_filename file in + let d = if d = "." then "" else d in + d,b,e + + + + + +let replace_ext file oldext newext = + let (d,b,e) = dbe_of_filename file in + assert(e = oldext); + filename_of_dbe (d,b,newext) + + +let normalize_path file = + let (dir, filename) = Filename.dirname file, Filename.basename file in + let xs = split "/" dir in + let rec aux acc = function + | [] -> List.rev acc + | x::xs -> + (match x with + | "." -> aux acc xs + | ".." -> aux (List.tl acc) xs + | x -> aux (x::acc) xs + ) + in + let xs' = aux [] xs in + Filename.concat (join "/" xs') filename + + + +(* +let relative_to_absolute s = + if Filename.is_relative s + then + begin + let old = Sys.getcwd () in + Sys.chdir s; + let current = Sys.getcwd () in + Sys.chdir old; + s + end + else s +*) + +let relative_to_absolute s = + if Filename.is_relative s + then Sys.getcwd () ^ "/" ^ s + else s + + + +(* @Pre: prj_path must not contain regexp symbol *) +let filename_without_leading_path prj_path s = + let prj_path = chop_dirsymbol prj_path in + if s =~ ("^" ^ prj_path ^ "/\\(.*\\)$") + then matched1 s + else + failwith + (spf "cant find filename_without_project_path: %s %s" prj_path s) + + +(*****************************************************************************) +(* i18n *) +(*****************************************************************************) +type langage = + | English + | Francais + | Deutsch + +(* gettext ? *) + + +(*****************************************************************************) +(* Dates *) +(*****************************************************************************) + +type month = + | Jan | Feb | Mar | Apr | May | Jun + | Jul | Aug | Sep | Oct | Nov | Dec +type year = Year of int +type day = Day of int +type wday = Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday + +type date_dmy = DMY of day * month * year + +type hour = Hour of int +type minute = Min of int +type second = Sec of int + +type time_hms = HMS of hour * minute * second + +type full_date = date_dmy * time_hms + + +(* intervalle *) +type days = Days of int + +type time_dmy = TimeDMY of day * month * year + + +type float_time = float + + + +let check_date_dmy (DMY (day, month, year)) = + raise Todo + +let check_time_dmy (TimeDMY (day, month, year)) = + raise Todo + +let check_time_hms (HMS (x,y,a)) = + raise Todo + + + +(* ---------------------------------------------------------------------- *) + +(* older code *) +let int_to_month i = + assert (i <= 12 && i >= 1); + match i with + + | 1 -> "Jan" + | 2 -> "Feb" + | 3 -> "Mar" + | 4 -> "Apr" + | 5 -> "May" + | 6 -> "Jun" + | 7 -> "Jul" + | 8 -> "Aug" + | 9 -> "Sep" + | 10 -> "Oct" + | 11 -> "Nov" + | 12 -> "Dec" +(* + | 1 -> "January" + | 2 -> "February" + | 3 -> "March" + | 4 -> "April" + | 5 -> "May" + | 6 -> "June" + | 7 -> "July" + | 8 -> "August" + | 9 -> "September" + | 10 -> "October" + | 11 -> "November" + | 12 -> "December" +*) + | _ -> raise Impossible + + +let month_info = [ + 1 , Jan, "Jan", "January", 31; + 2 , Feb, "Feb", "February", 28; + 3 , Mar, "Mar", "March", 31; + 4 , Apr, "Apr", "April", 30; + 5 , May, "May", "May", 31; + 6 , Jun, "Jun", "June", 30; + 7 , Jul, "Jul", "July", 31; + 8 , Aug, "Aug", "August", 31; + 9 , Sep, "Sep", "September", 30; + 10 , Oct, "Oct", "October", 31; + 11 , Nov, "Nov", "November", 30; + 12 , Dec, "Dec", "December", 31; +] + +let week_day_info = [ + 0 , Sunday , "Sun" , "Dim" , "Sunday"; + 1 , Monday , "Mon" , "Lun" , "Monday"; + 2 , Tuesday , "Tue" , "Mar" , "Tuesday"; + 3 , Wednesday , "Wed" , "Mer" , "Wednesday"; + 4 , Thursday , "Thu" ,"Jeu" ,"Thursday"; + 5 , Friday , "Fri" , "Ven" , "Friday"; + 6 , Saturday , "Sat" ,"Sam" , "Saturday"; +] + +let i_to_month_h = + month_info +> List.map (fun (i,month,monthstr,mlong,days) -> i, month) +let s_to_month_h = + month_info +> List.map (fun (i,month,monthstr,mlong,days) -> monthstr, month) +let slong_to_month_h = + month_info +> List.map (fun (i,month,monthstr,mlong,days) -> mlong, month) +let month_to_s_h = + month_info +> List.map (fun (i,month,monthstr,mlong,days) -> month, monthstr) +let month_to_i_h = + month_info +> List.map (fun (i,month,monthstr,mlong,days) -> month, i) + +let i_to_wday_h = + week_day_info +> List.map (fun (i,day,dayen,dayfr,daylong) -> i, day) +let wday_to_en_h = + week_day_info +> List.map (fun (i,day,dayen,dayfr,daylong) -> day, dayen) +let wday_to_fr_h = + week_day_info +> List.map (fun (i,day,dayen,dayfr,daylong) -> day, dayfr) + +let month_of_string s = + List.assoc s s_to_month_h + +let month_of_string_long s = + List.assoc s slong_to_month_h + +let string_of_month s = + List.assoc s month_to_s_h + +let month_of_int i = + List.assoc i i_to_month_h + +let int_of_month m = + List.assoc m month_to_i_h + + +let wday_of_int i = + List.assoc i i_to_wday_h + +let string_en_of_wday wday = + List.assoc wday wday_to_en_h +let string_fr_of_wday wday = + List.assoc wday wday_to_fr_h + +(* ---------------------------------------------------------------------- *) + +let wday_str_of_int ~langage i = + let wday = wday_of_int i in + match langage with + | English -> string_en_of_wday wday + | Francais -> string_fr_of_wday wday + | Deutsch -> raise Todo + + + +let string_of_date_dmy (DMY (Day n, month, Year y)) = + (spf "%02d-%s-%d" n (string_of_month month) y) + + +let string_of_unix_time ?(langage=English) tm = + let y = tm.Unix.tm_year + 1900 in + let mon = string_of_month (month_of_int (tm.Unix.tm_mon + 1)) in + let d = tm.Unix.tm_mday in + let h = tm.Unix.tm_hour in + let min = tm.Unix.tm_min in + let s = tm.Unix.tm_sec in + + let wday = wday_str_of_int ~langage tm.Unix.tm_wday in + + spf "%02d/%03s/%04d (%s) %02d:%02d:%02d" d mon y wday h min s + +(* ex: 21/Jul/2008 (Lun) 21:25:12 *) +let unix_time_of_string s = + if s =~ + ("\\([0-9][0-9]\\)/\\(...\\)/\\([0-9][0-9][0-9][0-9]\\) " ^ + "\\(.*\\) \\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)") + then + let (sday, smonth, syear, _sday, shour, smin, ssec) = matched7 s in + + let y = s_to_i syear - 1900 in + let mon = + smonth +> month_of_string +> int_of_month +> (fun i -> i -1) + in + + let tm = Unix.localtime (Unix.time ()) in + { tm with + Unix.tm_year = y; + Unix.tm_mon = mon; + Unix.tm_mday = s_to_i sday; + Unix.tm_hour = s_to_i shour; + Unix.tm_min = s_to_i smin; + Unix.tm_sec = s_to_i ssec; + } + else failwith ("unix_time_of_string: " ^ s) + + + +let short_string_of_unix_time ?(langage=English) tm = + let y = tm.Unix.tm_year + 1900 in + let mon = string_of_month (month_of_int (tm.Unix.tm_mon + 1)) in + let d = tm.Unix.tm_mday in + let _h = tm.Unix.tm_hour in + let _min = tm.Unix.tm_min in + let _s = tm.Unix.tm_sec in + + let wday = wday_str_of_int ~langage tm.Unix.tm_wday in + + spf "%02d/%03s/%04d (%s)" d mon y wday + + +let string_of_unix_time_lfs time = + spf "%02d--%s--%d" + time.Unix.tm_mday + (int_to_month (time.Unix.tm_mon + 1)) + (time.Unix.tm_year + 1900) + + +(* ---------------------------------------------------------------------- *) +let string_of_floattime ?langage i = + let tm = Unix.localtime i in + string_of_unix_time ?langage tm + +let short_string_of_floattime ?langage i = + let tm = Unix.localtime i in + short_string_of_unix_time ?langage tm + +let floattime_of_string s = + let tm = unix_time_of_string s in + let (sec,_tm) = Unix.mktime tm in + sec + + +(* ---------------------------------------------------------------------- *) +let days_in_week_of_day day = + let tm = Unix.localtime day in + + let wday = tm.Unix.tm_wday in + let wday = if wday = 0 then 6 else wday -1 in + + let mday = tm.Unix.tm_mday in + + let start_d = mday - wday in + let end_d = mday + (6 - wday) in + + enum start_d end_d +> List.map (fun mday -> + Unix.mktime {tm with Unix.tm_mday = mday} +> fst + ) + +let first_day_in_week_of_day day = + List.hd (days_in_week_of_day day) + +let last_day_in_week_of_day day = + last (days_in_week_of_day day) + + +(* ---------------------------------------------------------------------- *) + +(* (modified) copy paste from ocamlcalendar/src/date.ml *) +let days_month = + [| 0; 31; 59; 90; 120; 151; 181; 212; 243; 273; 304; 334(*; 365*) |] + + +let rough_days_since_jesus (DMY (Day nday, month, Year year)) = + let n = + nday + + (days_month.(int_of_month month -1)) + + year * 365 + in + Days n + + + + +let rough_days_between_dates d1 d2 = + let (Days n1) = rough_days_since_jesus d1 in + let (Days n2) = rough_days_since_jesus d2 in + if (n2 < n1) + then pr2 (spf "wierd date, d1 < d2: %s vs %s " + (string_of_date_dmy d1) + (string_of_date_dmy d2)); + + Days (n2 - n1) + +let _ = example + (rough_days_between_dates + (DMY (Day 7, Jan, Year 1977)) + (DMY (Day 13, Jan, Year 1977)) = Days 6) + +(* because of rough days, it is a bit buggy, here it should return 1 *) +(* +let _ = assert_equal + (rough_days_between_dates + (DMY (Day 29, Feb, Year 1977)) + (DMY (Day 1, Mar , Year 1977))) + (Days 1) +*) + + +(* from julia, in gitsort.ml *) + +(* +let antimonths = + [(1,31);(2,28);(3,31);(4,30);(5,31); (6,6);(7,7);(8,31);(9,30);(10,31); + (11,30);(12,31);(0,31)] + +let normalize (year,month,day,hour,minute,second) = + if hour < 0 + then + let (day,hour) = (day - 1,hour + 24) in + if day = 0 + then + let month = month - 1 in + let day = List.assoc month antimonths in + let day = + if month = 2 && year / 4 * 4 = year && not (year / 100 * 100 = year) + then 29 + else day in + if month = 0 + then (year-1,12,day,hour,minute,second) + else (year,month,day,hour,minute,second) + else (year,month,day,hour,minute,second) + else (year,month,day,hour,minute,second) + +*) + + +let mk_date_dmy day month year = + let date = DMY (Day day, month_of_int month, Year year) in + (* check_date_dmy date *) + date + + +(* ---------------------------------------------------------------------- *) +(* conversion to unix.tm *) + +let dmy_to_unixtime (DMY (Day n, month, Year year)) = + let tm = { + Unix.tm_sec = 0; (** Seconds 0..60 *) + tm_min = 0; (** Minutes 0..59 *) + tm_hour = 12; (** Hours 0..23 *) + tm_mday = n; (** Day of month 1..31 *) + tm_mon = (int_of_month month -1); (** Month of year 0..11 *) + tm_year = year - 1900; (** Year - 1900 *) + tm_wday = 0; (** Day of week (Sunday is 0) *) + tm_yday = 0; (** Day of year 0..365 *) + tm_isdst = false; (** Daylight time savings in effect *) + } in + Unix.mktime tm + +let unixtime_to_dmy tm = + let n = tm.Unix.tm_mday in + let month = month_of_int (tm.Unix.tm_mon + 1) in + let year = tm.Unix.tm_year + 1900 in + + DMY (Day n, month, Year year) + + +let unixtime_to_floattime tm = + Unix.mktime tm +> fst + + +let sec_to_days sec = + let minfactor = 60 in + let hourfactor = 60 * 60 in + let dayfactor = 60 * 60 * 24 in + + let days = sec / dayfactor in + let hours = (sec mod dayfactor) / hourfactor in + let mins = (sec mod hourfactor) / minfactor in + let sec = (sec mod 60) in + (* old: Printf.sprintf "%d days, %d hours, %d minutes" days hours mins *) + (if days > 0 then plural days "day" ^ " " else "") ^ + (if hours > 0 then plural hours "hour" ^ " " else "") ^ + (if mins > 0 then plural mins "min" ^ " " else "") ^ + (spf "%dsec" sec) + +let sec_to_hours sec = + let minfactor = 60 in + let hourfactor = 60 * 60 in + + let hours = sec / hourfactor in + let mins = (sec mod hourfactor) / minfactor in + let sec = (sec mod 60) in + (* old: Printf.sprintf "%d days, %d hours, %d minutes" days hours mins *) + (if hours > 0 then plural hours "hour" ^ " " else "") ^ + (if mins > 0 then plural mins "min" ^ " " else "") ^ + (spf "%dsec" sec) + + + +let test_date_1 () = + let date = DMY (Day 17, Sep, Year 1991) in + let float, tm = dmy_to_unixtime date in + pr2 (spf "date: %.0f" float); + () + + +(* src: ferre in logfun/.../date.ml *) + +let day_secs : float = 86400. + +let today : unit -> float = fun () -> (Unix.time () ) +let yesterday : unit -> float = fun () -> (Unix.time () -. day_secs) +let tomorrow : unit -> float = fun () -> (Unix.time () +. day_secs) + +let lastweek : unit -> float = fun () -> (Unix.time () -. (7.0 *. day_secs)) +let lastmonth : unit -> float = fun () -> (Unix.time () -. (30.0 *. day_secs)) + + +let week_before : float_time -> float_time = fun d -> + (d -. (7.0 *. day_secs)) +let month_before : float_time -> float_time = fun d -> + (d -. (30.0 *. day_secs)) + +let week_after : float_time -> float_time = fun d -> + (d +. (7.0 *. day_secs)) + + + +(*****************************************************************************) +(* Lines/words/strings *) +(*****************************************************************************) + +(* now in prelude: + * let (list_of_string: string -> char list) = fun s -> + * (enum 0 ((String.length s) - 1) +> List.map (String.get s)) + *) + +let _ = example (list_of_string "abcd" = ['a';'b';'c';'d']) + +(* +let rec (list_of_stream: ('a Stream.t) -> 'a list) = +parser + | [< 'c ; stream >] -> c :: list_of_stream stream + | [<>] -> [] + +let (list_of_string: string -> char list) = + Stream.of_string $ list_of_stream +*) + +(* now in prelude: + * let (lines: string -> string list) = fun s -> ... + *) + +let (lines_with_nl: string -> string list) = fun s -> + let rec lines_aux = function + | [] -> [] + | [x] -> if x = "" then [] else [x ^ "\n"] (* old: [x] *) + | x::xs -> + let e = x ^ "\n" in + e::lines_aux xs + in + (time_func (fun () -> Str.split_delim (Str.regexp "\n") s)) +> lines_aux + +(* in fact better make it return always complete lines, simplify *) +(* Str.split, but lines "\n1\n2\n" dont return the \n and forget the first \n => split_delim better than split *) +(* +> List.map (fun s -> s ^ "\n") but add an \n even at the end => lines_aux *) +(* old: slow + let chars = list_of_string s in + chars +> List.fold_left (fun (acc, lines) char -> + let newacc = acc ^ (String.make 1 char) in + if char = '\n' + then ("", newacc::lines) + else (newacc, lines) + ) ("", []) + +> (fun (s, lines) -> List.rev (s::lines)) +*) + +(* CHECK: unlines (lines x) = x *) +let (unlines: string list -> string) = fun s -> + (String.concat "\n" s) ^ "\n" +let (words: string -> string list) = fun s -> + Str.split (Str.regexp "[ \t()\";]+") s +let (unwords: string list -> string) = fun s -> + String.concat "" s + +let (split_space: string -> string list) = fun s -> + Str.split (Str.regexp "[ \t\n]+") s + + +(* todo opti ? *) +let nblines s = + lines s +> List.length +let _ = example (nblines "" = 0) +let _ = example (nblines "toto" = 1) +let _ = example (nblines "toto\n" = 1) +let _ = example (nblines "toto\ntata" = 2) +let _ = example (nblines "toto\ntata\n" = 2) + +(*****************************************************************************) +(* Process/Files *) +(*****************************************************************************) +let cat_orig file = + let chan = open_in file in + let rec cat_orig_aux () = + try + (* cant do input_line chan::aux() cos ocaml eval from right to left ! *) + let l = input_line chan in + l :: cat_orig_aux () + with End_of_file -> [] in + cat_orig_aux() + +(* tail recursive efficient version *) +let cat file = + let chan = open_in file in + let rec cat_aux acc () = + (* cant do input_line chan::aux() cos ocaml eval from right to left ! *) + let (b, l) = try (true, input_line chan) with End_of_file -> (false, "") in + if b + then cat_aux (l::acc) () + else acc + in + cat_aux [] () +> List.rev +> (fun x -> close_in chan; x) + +let interpolate str = + begin + command2 ("printf \"%s\\n\" " ^ str ^ ">/tmp/caml"); + cat "/tmp/caml" + end + +(* could do a print_string but printf dont like print_string *) +let echo s = printf "%s" s; flush stdout; s + +let usleep s = for i = 1 to s do () done + +let sleep_little () = + (*old: *) + Unix.sleep 1 + (*ignore(Sys.command ("usleep " ^ !_sleep_time))*) + + +(* now in prelude: + * let command2 s = ignore(Sys.command s) + *) + +let do_in_fork f = + let pid = Unix.fork () in + if pid = 0 + then + begin + (* Unix.setsid(); *) + Sys.set_signal Sys.sigint (Sys.Signal_handle (fun _ -> + pr2 "being killed"; + Unix.kill 0 Sys.sigkill; + )); + f(); + exit 0; + end + else pid + + +let process_output_to_list2 = fun command -> + let chan = Unix.open_process_in command in + let res = ref ([] : string list) in + let rec process_otl_aux () = + let e = input_line chan in + res := e::!res; + process_otl_aux() in + try process_otl_aux () + with End_of_file -> + let stat = Unix.close_process_in chan in (List.rev !res,stat) +let cmd_to_list command = + let (l,_) = process_output_to_list2 command in l +let process_output_to_list = cmd_to_list +let cmd_to_list_and_status = process_output_to_list2 + +(* now in prelude: + * let command2 s = ignore(Sys.command s) + *) + +let command2_y_or_no cmd = + pr2 (cmd ^ " [y/n] ?"); + match read_line () with + | "y" | "yes" | "Y" -> command2 cmd; true + | "n" | "no" | "N" -> false + | _ -> failwith "answer by yes or no" + + + + +let mkdir ?(mode=0o770) file = + Unix.mkdir file mode + +let read_file_orig file = cat file +> unlines +let read_file file = + let ic = open_in file in + let size = in_channel_length ic in + let buf = String.create size in + really_input ic buf 0 size; + close_in ic; + buf + + +let write_file ~file s = + let chan = open_out file in + (output_string chan s; close_out chan) + +let filesize file = + (Unix.stat file).Unix.st_size + +let filemtime file = + (Unix.stat file).Unix.st_mtime + +(* opti? use wc -l ? *) +let nblines_file file = + cat file +> List.length + +let lfile_exists filename = + try + (match (Unix.lstat filename).Unix.st_kind with + | (Unix.S_REG | Unix.S_LNK) -> true + | _ -> false + ) + with Unix.Unix_error (Unix.ENOENT, _, _) -> false + +let is_directory file = + (Unix.stat file).Unix.st_kind = Unix.S_DIR + + +(* src: from chailloux et al book *) +let capsule_unix f args = + try (f args) + with Unix.Unix_error (e, fm, argm) -> + log (Printf.sprintf "exn Unix_error: %s %s %s\n" (Unix.error_message e) fm argm) + + +let (readdir_to_kind_list: string -> Unix.file_kind -> string list) = + fun path kind -> + Sys.readdir path + +> Array.to_list + +> List.filter (fun s -> + try + let stat = Unix.lstat (path ^ "/" ^ s) in + stat.Unix.st_kind = kind + with e -> + pr2 ("EXN pb stating file: " ^ s); + false + ) + +let (readdir_to_dir_list: string -> string list) = fun path -> + readdir_to_kind_list path Unix.S_DIR + +let (readdir_to_file_list: string -> string list) = fun path -> + readdir_to_kind_list path Unix.S_REG + +let (readdir_to_link_list: string -> string list) = fun path -> + readdir_to_kind_list path Unix.S_LNK + + +let (readdir_to_dir_size_list: string -> (string * int) list) = fun path -> + Sys.readdir path + +> Array.to_list + +> map_filter (fun s -> + let stat = Unix.lstat (path ^ "/" ^ s) in + if stat.Unix.st_kind = Unix.S_DIR + then Some (s, stat.Unix.st_size) + else None + ) + +(* could be in control section too *) + +(* Why a use_cache argument ? because sometimes want disable it but dont + * want put the cache_computation funcall in comment, so just easier to + * pass this extra option. + *) +let cache_computation2 ?(verbose=false) ?(use_cache=true) file ext_cache f = + if not use_cache + then f () + else begin + if not (Sys.file_exists file) + then failwith ("can't find: " ^ file); + let file_cache = (file ^ ext_cache) in + if Sys.file_exists file_cache && + filemtime file_cache >= filemtime file + then begin + if verbose then pr2 ("using cache: " ^ file_cache); + get_value file_cache + end + else begin + let res = f () in + write_value res file_cache; + res + end + end +let cache_computation ?verbose ?use_cache a b c = + profile_code "Common.cache_computation" (fun () -> + cache_computation2 ?verbose ?use_cache a b c) + + +let cache_computation_robust2 + file ext_cache + (need_no_changed_files, need_no_changed_variables) ext_depend + f = + if not (Sys.file_exists file) + then failwith ("can't find: " ^ file); + + let file_cache = (file ^ ext_cache) in + let dependencies_cache = (file ^ ext_depend) in + + let dependencies = + (* could do md5sum too *) + ((file::need_no_changed_files) +> List.map (fun f -> f, filemtime f), + need_no_changed_variables) + in + + if Sys.file_exists dependencies_cache && + get_value dependencies_cache = dependencies + then get_value file_cache + else begin + pr2 ("cache computation recompute " ^ file); + let res = f () in + write_value dependencies dependencies_cache; + write_value res file_cache; + res + end + +let cache_computation_robust a b c d e = + profile_code "Common.cache_computation_robust" (fun () -> + cache_computation_robust2 a b c d e) + + + + +(* dont forget that cmd_to_list call bash and so pattern may contain + * '*' symbols that will be expanded, so can do glob "*.c" + *) +let glob pattern = + cmd_to_list ("ls -1 " ^ pattern) + + +(* update: have added the -type f, so normally need less the sanity_check_xxx + * function below *) +let files_of_dir_or_files ext xs = + xs +> List.map (fun x -> + if is_directory x + then cmd_to_list ("find " ^ x ^" -noleaf -type f -name \"*." ^ext^"\"") + else [x] + ) +> List.concat + + +let files_of_dir_or_files_no_vcs ext xs = + xs +> List.map (fun x -> + if is_directory x + then + cmd_to_list + ("find " ^ x ^" -noleaf -type f -name \"*." ^ext^"\"" ^ + "| grep -v /.hg/ |grep -v /CVS/ | grep -v /.git/ |grep -v /_darcs/" + ) + else [x] + ) +> List.concat + + +let files_of_dir_or_files_no_vcs_post_filter regex xs = + xs +> List.map (fun x -> + if is_directory x + then + cmd_to_list + ("find " ^ x ^ + " -noleaf -type f | grep -v /.hg/ |grep -v /CVS/ | grep -v /.git/" + ) + +> List.filter (fun s -> s =~ regex) + else [x] + ) +> List.concat + + +let sanity_check_files_and_adjust ext files = + let files = files +> List.filter (fun file -> + if not (file =~ (".*\\."^ext)) + then begin + pr2 ("warning: seems not a ."^ext^" file"); + false + end + else + if is_directory file + then begin + pr2 (spf "warning: %s is a directory" file); + false + end + else true + ) in + files + + + + +(* taken from mlfuse, the predecessor of ocamlfuse *) +type rwx = [`R|`W|`X] list +let file_perm_of : u:rwx -> g:rwx -> o:rwx -> Unix.file_perm = + fun ~u ~g ~o -> + let to_oct l = + List.fold_left (fun acc p -> acc lor ((function `R -> 4 | `W -> 2 | `X -> 1) p)) 0 l in + let perm = + ((to_oct u) lsl 6) lor + ((to_oct g) lsl 3) lor + (to_oct o) + in + perm + + +(* pixel *) +let has_env var = + try + let _ = Sys.getenv var in true + with Not_found -> false + +(* emacs/lisp inspiration (eric cooper and yaron minsky use that too) *) +let (with_open_outfile: filename -> (((string -> unit) * out_channel) -> 'a) -> 'a) = + fun file f -> + let chan = open_out file in + let pr s = output_string chan s in + unwind_protect (fun () -> + let res = f (pr, chan) in + close_out chan; + res) + (fun e -> close_out chan) + +let (with_open_infile: filename -> ((in_channel) -> 'a) -> 'a) = fun file f -> + let chan = open_in file in + unwind_protect (fun () -> + let res = f chan in + close_in chan; + res) + (fun e -> close_in chan) + + +let (with_open_outfile_append: filename -> (((string -> unit) * out_channel) -> 'a) -> 'a) = + fun file f -> + let chan = open_out_gen [Open_creat;Open_append] 0o666 file in + let pr s = output_string chan s in + unwind_protect (fun () -> + let res = f (pr, chan) in + close_out chan; + res) + (fun e -> close_out chan) + + +(* now in prelude: + * exception Timeout + *) + +(* it seems that the toplevel block such signals, even with this explicit + * command :( + * let _ = Unix.sigprocmask Unix.SIG_UNBLOCK [Sys.sigalrm] + *) + +(* could be in Control section *) + +(* subtil: have to make sure that timeout is not intercepted before here, so + * avoid exn handle such as try (...) with _ -> cos timeout will not bubble up + * enough. In such case, add a case before such as + * with Timeout -> raise Timeout | _ -> ... + * + * question: can we have a signal and so exn when in a exn handler ? + *) +let timeout_function timeoutval = fun f -> + try + begin + Sys.set_signal Sys.sigalrm (Sys.Signal_handle (fun _ -> raise Timeout )); + ignore(Unix.alarm timeoutval); + let x = f() in + ignore(Unix.alarm 0); + x + end + with Timeout -> + begin + log "timeout (we abort)"; + raise Timeout; + end + | e -> + (* subtil: important to disable the alarm before relaunching the exn, + * otherwise the alarm is still running. + * + * robust?: and if alarm launched after the log (...) ? + * Maybe signals are disabled when process an exception handler ? + *) + begin + ignore(Unix.alarm 0); + (* log ("exn while in transaction (we abort too, even if ...) = " ^ + Printexc.to_string e); + *) + log "exn while in timeout_function"; + raise e + end + +let timeout_function_opt timeoutvalopt f = + match timeoutvalopt with + | None -> f() + | Some x -> timeout_function x f + + + +(* creation of tmp files, a la gcc *) + +let _temp_files_created = ref [] + +(* ex: new_temp_file "cocci" ".c" will give "/tmp/cocci-3252-434465.c" *) +let new_temp_file prefix suffix = + let processid = i_to_s (Unix.getpid ()) in + let tmp_file = Filename.temp_file (prefix ^ "-" ^ processid ^ "-") suffix in + push2 tmp_file _temp_files_created; + tmp_file + + +let save_tmp_files = ref false +let erase_temp_files () = + if not !save_tmp_files then begin + !_temp_files_created +> List.iter (fun s -> + (* pr2 ("erasing: " ^ s); *) + command2 ("rm -f " ^ s) + ); + _temp_files_created := [] + end + +(* now in prelude: exception UnixExit of int *) +let exn_to_real_unixexit f = + try f() + with UnixExit x -> exit x + + + + + + + +(*****************************************************************************) +(* List *) +(*****************************************************************************) + +(* pixel *) +let uncons l = (List.hd l, List.tl l) + +(* pixel *) +let safe_tl l = try List.tl l with _ -> [] + +let push l v = + l := v :: !l + +let rec zip xs ys = + match (xs,ys) with + | ([],[]) -> [] + | ([],_) -> failwith "zip: not same length" + | (_,[]) -> failwith "zip: not same length" + | (x::xs,y::ys) -> (x,y)::zip xs ys + +let rec zip_safe xs ys = + match (xs,ys) with + | ([],_) -> [] + | (_,[]) -> [] + | (x::xs,y::ys) -> (x,y)::zip_safe xs ys + +let rec unzip zs = + List.fold_right (fun e (xs, ys) -> + (fst e::xs), (snd e::ys)) zs ([],[]) + + +(* now in prelude + * let rec take n xs = + * match (n,xs) with + * | (0,_) -> [] + * | (_,[]) -> failwith "take: not enough" + * | (n,x::xs) -> x::take (n-1) xs + *) + +let rec take_safe n xs = + match (n,xs) with + | (0,_) -> [] + | (_,[]) -> [] + | (n,x::xs) -> x::take_safe (n-1) xs + +let rec take_until p = function + | [] -> [] + | x::xs -> if p x then [] else x::(take_until p xs) + +let take_while p = take_until (p $ not) + + +(* now in prelude: let rec drop n xs = ... *) +let _ = example (drop 3 [1;2;3;4] = [4]) + +let rec drop_while p = function + | [] -> [] + | x::xs -> if p x then drop_while p xs else x::xs + + +let rec drop_until p xs = + drop_while (fun x -> not (p x)) xs +let _ = example (drop_until (fun x -> x = 3) [1;2;3;4;5] = [3;4;5]) + + +let span p xs = (take_while p xs, drop_while p xs) + + +let rec (span: ('a -> bool) -> 'a list -> 'a list * 'a list) = + fun p -> function + | [] -> ([], []) + | x::xs -> + if p x then + let (l1, l2) = span p xs in + (x::l1, l2) + else ([], x::xs) +let _ = example ((span (fun x -> x <= 3) [1;2;3;4;1;2] = ([1;2;3],[4;1;2]))) + +let rec groupBy eq l = + match l with + | [] -> [] + | x::xs -> + let (xs1,xs2) = List.partition (fun x' -> eq x x') xs in + (x::xs1)::(groupBy eq xs2) + +let (exclude_but_keep_attached: ('a -> bool) -> 'a list -> ('a * 'a list) list)= + fun f xs -> + let rec aux_filter acc = function + | [] -> [] (* drop what was accumulated because nothing to attach to *) + | x::xs -> + if f x + then aux_filter (x::acc) xs + else (x, List.rev acc)::aux_filter [] xs + in + aux_filter [] xs +let _ = example + (exclude_but_keep_attached (fun x -> x = 3) [3;3;1;3;2;3;3;3] = + [(1,[3;3]);(2,[3])]) + + +let rec (split_when: ('a -> bool) -> 'a list -> 'a list * 'a * 'a list) = + fun p -> function + | [] -> raise Not_found + | x::xs -> + if p x then + [], x, xs + else + let (l1, a, l2) = split_when p xs in + (x::l1, a, l2) +let _ = example (split_when (fun x -> x = 3) [1;2;3;4;1;2] = ([1;2],3,[4;1;2])) + + +(* not so easy to come up with ... used in aComment for split_paragraph *) +let rec split_gen_when_aux f acc xs = + match xs with + | [] -> + if acc = [] + then [] + else [List.rev acc] + | (x::xs) -> + (match f (x::xs) with + | None -> + split_gen_when_aux f (x::acc) xs + | Some (rest) -> + let before = List.rev acc in + if before = [] + then split_gen_when_aux f [] rest + else before::split_gen_when_aux f [] rest + ) +(* could avoid introduce extra aux function by using ?(acc = []) *) +let split_gen_when f xs = + split_gen_when_aux f [] xs + + + +(* generate exception (Failure "tl") if there is no element satisfying p *) +let rec (skip_until: ('a list -> bool) -> 'a list -> 'a list) = fun p xs -> + if p xs then xs else skip_until p (List.tl xs) +let _ = example (skip_until (function 1::2::xs -> true | _ -> false) [1;3;4;1;2;4;5] = [1;2;4;5]) + +let rec skipfirst e = function + | [] -> [] + | e'::l when e = e' -> skipfirst e l + | l -> l + + +(* now in prelude: + * let rec enum x n = ... + *) + + +let index_list xs = + if xs = [] then [] (* enum 0 (-1) generate an exception *) + else zip xs (enum 0 ((List.length xs) -1)) + +let index_list_and_total xs = + let total = List.length xs in + if xs = [] then [] (* enum 0 (-1) generate an exception *) + else zip xs (enum 0 ((List.length xs) -1)) + +> List.map (fun (a,b) -> (a,b,total)) + +let index_list_1 xs = + xs +> index_list +> List.map (fun (x,i) -> x, i+1) + +let or_list = List.fold_left (||) false +let and_list = List.fold_left (&&) true + +let snoc x xs = xs @ [x] +let cons x xs = x::xs + +let head_middle_tail xs = + match xs with + | x::y::xs -> + let head = x in + let reversed = List.rev (y::xs) in + let tail = List.hd reversed in + let middle = List.rev (List.tl reversed) in + head, middle, tail + | _ -> failwith "head_middle_tail, too small list" + +let _ = assert_equal (head_middle_tail [1;2;3]) (1, [2], 3) +let _ = assert_equal (head_middle_tail [1;3]) (1, [], 3) + +(* now in prelude + * let (++) = (@) + *) + +(* let (++) = (@), could do that, but if load many times the common, then pb *) +(* let (++) l1 l2 = List.fold_right (fun x acc -> x::acc) l1 l2 *) + +let remove x xs = + let newxs = List.filter (fun y -> y <> x) xs in + assert (List.length newxs = List.length xs - 1); + newxs + + +let exclude p xs = + List.filter (fun x -> not (p x)) xs + +let foldl1 p = function x::xs -> List.fold_left p x xs | _ -> failwith "foldl1" + +let fold_k f lastk acc xs = + let rec fold_k_aux acc = function + | [] -> lastk acc + | x::xs -> + f acc x (fun acc -> fold_k_aux acc xs) + in + fold_k_aux acc xs + + +let rec list_init = function + | [] -> raise Not_found + | [x] -> [] + | x::y::xs -> x::(list_init (y::xs)) + +let rec list_last = function + | [] -> raise Not_found + | [x] -> x + | x::y::xs -> list_last (y::xs) + +(* pixel *) +(* now in prelude + * let last_n n l = List.rev (take n (List.rev l)) + * let last l = List.hd (last_n 1 l) + *) + +let rec join_gen a = function + | [] -> [] + | [x] -> [x] + | x::xs -> x::a::(join_gen a xs) + + +(* todo: foldl, foldr (a more consistent foldr) *) + +(* start pixel *) +let iter_index f l = + let rec iter_ n = function + | [] -> () + | e::l -> f e n ; iter_ (n+1) l + in iter_ 0 l + +let map_index f l = + let rec map_ n = function + | [] -> [] + | e::l -> f e n :: map_ (n+1) l + in map_ 0 l + + +(* pixel *) +let filter_index f l = + let rec filt i = function + | [] -> [] + | e::l -> if f i e then e :: filt (i+1) l else filt (i+1) l + in + filt 0 l + +(* pixel *) +let do_withenv doit f env l = + let r_env = ref env in + let l' = doit (fun e -> + let e', env' = f !r_env e in + r_env := env' ; e' + ) l in + l', !r_env + +(* now in prelude: + * let fold_left_with_index f acc = ... + *) + +let map_withenv f env e = do_withenv List.map f env e + +let rec collect_accu f accu = function + | [] -> accu + | e::l -> collect_accu f (List.rev_append (f e) accu) l + +let collect f l = List.rev (collect_accu f [] l) + +(* cf also List.partition *) + +let rec fpartition p l = + let rec part yes no = function + | [] -> (List.rev yes, List.rev no) + | x :: l -> + (match p x with + | None -> part yes (x :: no) l + | Some v -> part (v :: yes) no l) in + part [] [] l + +(* end pixel *) + +let rec removelast = function + | [] -> failwith "removelast" + | [_] -> [] + | e::l -> e :: removelast l + +let remove x = List.filter (fun y -> y != x) +let empty list = list = [] + + +let rec inits = function + | [] -> [[]] + | e::l -> [] :: List.map (fun l -> e::l) (inits l) + +let rec tails = function + | [] -> [[]] + | (_::xs) as xxs -> xxs :: tails xs + + +let reverse = List.rev +let rev = List.rev + +let nth = List.nth +let fold_left = List.fold_left +let rev_map = List.rev_map + +(* pixel *) +let rec fold_right1 f = function + | [] -> failwith "fold_right1" + | [e] -> e + | e::l -> f e (fold_right1 f l) + +let maximum l = foldl1 max l +let minimum l = foldl1 min l + +(* do a map tail recursive, and result is reversed, it is a tail recursive map => efficient *) +let map_eff_rev = fun f l -> + let rec map_eff_aux acc = + function + | [] -> acc + | x::xs -> map_eff_aux ((f x)::acc) xs + in + map_eff_aux [] l + +let acc_map f l = + let rec loop acc = function + [] -> List.rev acc + | x::xs -> loop ((f x)::acc) xs in + loop [] l + + +let rec (generate: int -> 'a -> 'a list) = fun i el -> + if i = 0 then [] + else el::(generate (i-1) el) + +let rec uniq = function + | [] -> [] + | e::l -> if List.mem e l then uniq l else e :: uniq l + +let rec all_assoc e = function + | [] -> [] + | (e',v) :: l when e=e' -> v :: all_assoc e l + | _ :: l -> all_assoc e l + +let prepare_want_all_assoc l = + List.map (fun n -> n, uniq (all_assoc n l)) (uniq (List.map fst l)) + +let rotate list = List.tl list ++ [(List.hd list)] + +let or_list = List.fold_left (||) false +let and_list = List.fold_left (&&) true + +let rec (return_when: ('a -> 'b option) -> 'a list -> 'b) = fun p -> function + | [] -> raise Not_found + | x::xs -> (match p x with None -> return_when p xs | Some b -> b) + +let rec splitAt n xs = + if n = 0 then ([],xs) + else + (match xs with + | [] -> ([],[]) + | (x::xs) -> let (a,b) = splitAt (n-1) xs in (x::a, b) + ) + +let pack n xs = + let rec pack_aux l i = function + | [] -> failwith "not on a boundary" + | [x] -> if i = n then [l++[x]] else failwith "not on a boundary" + | x::xs -> + if i = n + then (l++[x])::(pack_aux [] 1 xs) + else pack_aux (l++[x]) (i+1) xs + in + pack_aux [] 1 xs + +let min_with f = function + | [] -> raise Not_found + | e :: l -> + let rec min_with_ min_val min_elt = function + | [] -> min_elt + | e::l -> + let val_ = f e in + if val_ < min_val + then min_with_ val_ e l + else min_with_ min_val min_elt l + in min_with_ (f e) e l + +let two_mins_with f = function + | e1 :: e2 :: l -> + let rec min_with_ min_val min_elt min_val2 min_elt2 = function + | [] -> min_elt, min_elt2 + | e::l -> + let val_ = f e in + if val_ < min_val2 + then + if val_ < min_val + then min_with_ val_ e min_val min_elt l + else min_with_ min_val min_elt val_ e l + else min_with_ min_val min_elt min_val2 min_elt2 l + in + let v1 = f e1 in + let v2 = f e2 in + if v1 < v2 then min_with_ v1 e1 v2 e2 l else min_with_ v2 e2 v1 e1 l + | _ -> raise Not_found + +let grep_with_previous f = function + | [] -> [] + | e::l -> + let rec grep_with_previous_ previous = function + | [] -> [] + | e::l -> if f previous e then e :: grep_with_previous_ e l else grep_with_previous_ previous l + in e :: grep_with_previous_ e l + +let iter_with_previous f = function + | [] -> () + | e::l -> + let rec iter_with_previous_ previous = function + | [] -> () + | e::l -> f previous e ; iter_with_previous_ e l + in iter_with_previous_ e l + + +let iter_with_before_after f xs = + let rec aux before_rev after = + match after with + | [] -> () + | x::xs -> + f before_rev x xs; + aux (x::before_rev) xs + in + aux [] xs + + + +(* kind of cartesian product of x*x *) +let rec (get_pair: ('a list) -> (('a * 'a) list)) = function + | [] -> [] + | x::xs -> (List.map (fun y -> (x,y)) xs) ++ (get_pair xs) + + +(* retourne le rang dans une liste d'un element *) +let rang elem liste = + let rec rang_rec elem accu = function + | [] -> raise Not_found + | a::l -> if a = elem then accu + else rang_rec elem (accu+1) l in + rang_rec elem 1 liste + +(* retourne vrai si une liste contient des doubles *) +let rec doublon = function + | [] -> false + | a::l -> if List.mem a l then true + else doublon l + +let rec (insert_in: 'a -> 'a list -> 'a list list) = fun x -> function + | [] -> [[x]] + | y::ys -> (x::y::ys) :: (List.map (fun xs -> y::xs) (insert_in x ys)) +(* insert_in 3 [1;2] = [[3; 1; 2]; [1; 3; 2]; [1; 2; 3]] *) + +let rec (permutation: 'a list -> 'a list list) = function + | [] -> [] + | [x] -> [[x]] + | x::xs -> List.flatten (List.map (insert_in x) (permutation xs)) +(* permutation [1;2;3] = + * [[1; 2; 3]; [2; 1; 3]; [2; 3; 1]; [1; 3; 2]; [3; 1; 2]; [3; 2; 1]] + *) + + +let rec remove_elem_pos pos xs = + match (pos, xs) with + | _, [] -> failwith "remove_elem_pos" + | 0, x::xs -> xs + | n, x::xs -> x::(remove_elem_pos (n-1) xs) + +let rec insert_elem_pos (e, pos) xs = + match (pos, xs) with + | 0, xs -> e::xs + | n, x::xs -> x::(insert_elem_pos (e, (n-1)) xs) + | n, [] -> failwith "insert_elem_pos" + +let rec uncons_permut xs = + let indexed = index_list xs in + indexed +> List.map (fun (x, pos) -> (x, pos), remove_elem_pos pos xs) +let _ = + example + (uncons_permut ['a';'b';'c'] = + [('a', 0), ['b';'c']; + ('b', 1), ['a';'c']; + ('c', 2), ['a';'b'] + ]) + +let rec uncons_permut_lazy xs = + let indexed = index_list xs in + indexed +> List.map (fun (x, pos) -> + (x, pos), + lazy (remove_elem_pos pos xs) + ) + + + + +(* pixel *) +let rec map_flatten f l = + let rec map_flatten_aux accu = function + | [] -> accu + | e :: l -> map_flatten_aux (List.rev (f e) ++ accu) l + in List.rev (map_flatten_aux [] l) + + +let rec repeat e n = + let rec repeat_aux acc = function + | 0 -> acc + | n when n < 0 -> failwith "repeat" + | n -> repeat_aux (e::acc) (n-1) in + repeat_aux [] n + +let rec map2 f = function + | [] -> [] + | x::xs -> let r = f x in r::map2 f xs + +let rec map3 f l = + let rec map3_aux acc = function + | [] -> acc + | x::xs -> map3_aux (f x::acc) xs in + map3_aux [] l + +(* +let tails2 xs = map rev (inits (rev xs)) +let res = tails2 [1;2;3;4] +let res = tails [1;2;3;4] +let id x = x +*) + +let pack_sorted same xs = + let rec pack_s_aux acc xs = + match (acc,xs) with + | ((cur,rest),[]) -> cur::rest + | ((cur,rest), y::ys) -> + if same (List.hd cur) y then pack_s_aux (y::cur, rest) ys + else pack_s_aux ([y], cur::rest) ys + in pack_s_aux ([List.hd xs],[]) (List.tl xs) +> List.rev +let test = pack_sorted (=) [1;1;1;2;2;3;4] + + +let rec keep_best f = + let rec partition e = function + | [] -> e, [] + | e' :: l -> + match f(e,e') with + | None -> let (e'', l') = partition e l in e'', e' :: l' + | Some e'' -> partition e'' l + in function + | [] -> [] + | e::l -> + let (e', l') = partition e l in + e' :: keep_best f l' + +let rec sorted_keep_best f = function + | [] -> [] + | [a] -> [a] + | a :: b :: l -> + match f a b with + | None -> a :: sorted_keep_best f (b :: l) + | Some e -> sorted_keep_best f (e :: l) + + + +let (cartesian_product: 'a list -> 'b list -> ('a * 'b) list) = fun xs ys -> + xs +> List.map (fun x -> ys +> List.map (fun y -> (x,y))) + +> List.flatten + +let _ = assert_equal + (cartesian_product [1;2] ["3";"4";"5"]) + [1,"3";1,"4";1,"5"; 2,"3";2,"4";2,"5"] + +(*----------------------------------*) + +(* sur surEnsemble [p1;p2] [[p1;p2;p3] [p1;p2] ....] -> [[p1;p2;p3] ... *) +(* mais pas p2;p3 *) +(* (aop) *) +let surEnsemble liste_el liste_liste_el = + List.filter + (function liste_elbis -> + List.for_all (function el -> List.mem el liste_elbis) liste_el + ) liste_liste_el;; + + + +(*----------------------------------*) +(* combinaison/product/.... (aop) *) +(* 123 -> 123 12 13 23 1 2 3 *) +let rec realCombinaison = function + | [] -> [] + | [a] -> [[a]] + | a::l -> + let res = realCombinaison l in + let res2 = List.map (function x -> a::x) res in + res2 ++ res ++ [[a]] + +(* genere toutes les combinaisons possible de paire *) +(* par exemple combinaison [1;2;4] -> [1, 2; 1, 4; 2, 4] *) +let rec combinaison = function + | [] -> [] + | [a] -> [] + | [a;b] -> [(a, b)] + | a::b::l -> (List.map (function elem -> (a, elem)) (b::l)) ++ + (combinaison (b::l)) + +(*----------------------------------*) + +(* list of list(aop) *) +(* insere elem dans la liste de liste (si elem est deja present dans une de *) +(* ces listes, on ne fait rien *) +let rec insere elem = function + | [] -> [[elem]] + | a::l -> + if (List.mem elem a) then a::l + else a::(insere elem l) + +let rec insereListeContenant lis el = function + | [] -> [el::lis] + | a::l -> + if List.mem el a then + (List.append lis a)::l + else a::(insereListeContenant lis el l) + +(* fusionne les listes contenant et1 et et2 dans la liste de liste*) +let rec fusionneListeContenant (et1, et2) = function + | [] -> [[et1; et2]] + | a::l -> + (* si les deux sont deja dedans alors rien faire *) + if List.mem et1 a then + if List.mem et2 a then a::l + else + insereListeContenant a et2 l + else if List.mem et2 a then + insereListeContenant a et1 l + else a::(fusionneListeContenant (et1, et2) l) + +(*****************************************************************************) +(* Arrays *) +(*****************************************************************************) + +let array_find_index f a = + let rec array_find_index_ i = + if f a.(i) then i else array_find_index_ (i+1) + in + try array_find_index_ 0 with _ -> raise Not_found + + +type 'a matrix = 'a array array + +let map_matrix f mat = + mat +> Array.map (fun arr -> arr +> Array.map f) + + +(*****************************************************************************) +(* Fast array *) +(*****************************************************************************) +(* +module B_Array = Bigarray.Array2 +*) + +(* +open B_Array +open Bigarray +*) + + +(* for the string_of auto generation of camlp4 +val b_array_string_of_t : 'a -> 'b -> string +val bigarray_string_of_int16_unsigned_elt : 'a -> string +val bigarray_string_of_c_layout : 'a -> string +let b_array_string_of_t f a = "<>" +let bigarray_string_of_int16_unsigned_elt a = "<>" +let bigarray_string_of_c_layout a = "<>" + +*) + + +(*****************************************************************************) +(* Set. Have a look too at set*.mli *) +(*****************************************************************************) +type 'a set = 'a list + +let (empty_set: 'a set) = [] +let (insert_set: 'a -> 'a set -> 'a set) = fun x xs -> + if List.mem x xs + then (* let _ = print_string "warning insert: already exist" in *) + xs + else x::xs + +let (single_set: 'a -> 'a set) = fun x -> insert_set x empty_set +let (set: 'a list -> 'a set) = fun xs -> + xs +> List.fold_left (flip insert_set) empty_set + +let (exists_set: ('a -> bool) -> 'a set -> bool) = List.exists +let (forall_set: ('a -> bool) -> 'a set -> bool) = List.for_all +let (filter_set: ('a -> bool) -> 'a set -> 'a set) = List.filter +let (fold_set: ('a -> 'b -> 'a) -> 'a -> 'b set -> 'a) = List.fold_left +let (map_set: ('a -> 'b) -> 'a set -> 'b set) = List.map +let (member_set: 'a -> 'a set -> bool) = List.mem + +let find_set = List.find +let sort_set = List.sort +let iter_set = List.iter + +let (top_set: 'a set -> 'a) = List.hd + +let (inter_set: 'a set -> 'a set -> 'a set) = fun s1 s2 -> + s1 +> fold_set (fun acc x -> if member_set x s2 then insert_set x acc else acc) empty_set +let (union_set: 'a set -> 'a set -> 'a set) = fun s1 s2 -> + s2 +> fold_set (fun acc x -> if member_set x s1 then acc else insert_set x acc) s1 +let (minus_set: 'a set -> 'a set -> 'a set) = fun s1 s2 -> + s1 +> filter_set (fun x -> not (member_set x s2)) + + +let union_all l = List.fold_left union_set [] l + +let big_union_set f xs = xs +> map_set f +> fold_set union_set empty_set + +let (card_set: 'a set -> int) = List.length + +let (include_set: 'a set -> 'a set -> bool) = fun s1 s2 -> + (s1 +> forall_set (fun p -> member_set p s2)) + +let equal_set s1 s2 = include_set s1 s2 && include_set s2 s1 + +let (include_set_strict: 'a set -> 'a set -> bool) = fun s1 s2 -> + (card_set s1 < card_set s2) && (include_set s1 s2) + +let ($*$) = inter_set +let ($+$) = union_set +let ($-$) = minus_set +let ($?$) a b = profile_code "$?$" (fun () -> member_set a b) +let ($<$) = include_set_strict +let ($<=$) = include_set +let ($=$) = equal_set + +(* as $+$ but do not check for memberness, allow to have set of func *) +let ($@$) = fun a b -> a @ b + +let rec nub = function + [] -> [] + | x::xs -> if List.mem x xs then nub xs else x::(nub xs) + +(*****************************************************************************) +(* Set as normal list *) +(*****************************************************************************) +(* +let (union: 'a list -> 'a list -> 'a list) = fun l1 l2 -> + List.fold_left (fun acc x -> if List.mem x l1 then acc else x::acc) l1 l2 + +let insert_normal x xs = union xs [x] + +(* retourne lis1 - lis2 *) +let minus l1 l2 = List.filter (fun x -> not (List.mem x l2)) l1 + +let inter l1 l2 = List.fold_left (fun acc x -> if List.mem x l2 then x::acc else acc) [] l1 + +let union_list = List.fold_left union [] + +let uniq lis = + List.fold_left (function acc -> function el -> union [el] acc) [] lis + +(* pixel *) +let rec non_uniq = function + | [] -> [] + | e::l -> if mem e l then e :: non_uniq l else non_uniq l + +let rec inclu lis1 lis2 = + List.for_all (function el -> List.mem el lis2) lis1 + +let equivalent lis1 lis2 = + (inclu lis1 lis2) && (inclu lis2 lis1) + +*) + + +(*****************************************************************************) +(* Set as sorted list *) +(*****************************************************************************) +(* liste trie, cos we need to do intersection, and insertion (it is a set + cos when introduce has, if we create a new has => must do a recurse_rep + and another categ can have to this has => must do an union + *) +(* +let rec insert x = function + | [] -> [x] + | y::ys -> + if x = y then y::ys + else (if x < y then x::y::ys else y::(insert x ys)) + +(* same, suppose sorted list *) +let rec intersect x y = + match(x,y) with + | [], y -> [] + | x, [] -> [] + | x::xs, y::ys -> + if x = y then x::(intersect xs ys) + else + (if x < y then intersect xs (y::ys) + else intersect (x::xs) ys + ) +(* intersect [1;3;7] [2;3;4;7;8];; *) +*) + +(*****************************************************************************) +(* Assoc *) +(*****************************************************************************) +type ('a,'b) assoc = ('a * 'b) list + + +let (assoc_to_function: ('a, 'b) assoc -> ('a -> 'b)) = fun xs -> + xs +> List.fold_left (fun acc (k, v) -> + (fun k' -> + if k = k' then v else acc k' + )) (fun k -> failwith "no key in this assoc") +(* simpler: +let (assoc_to_function: ('a, 'b) assoc -> ('a -> 'b)) = fun xs -> + fun k -> List.assoc k xs +*) + +let (empty_assoc: ('a, 'b) assoc) = [] +let fold_assoc = List.fold_left +let insert_assoc = fun x xs -> x::xs +let map_assoc = List.map +let filter_assoc = List.filter + +let assoc = List.assoc +let keys xs = List.map fst xs + +let lookup = assoc + +(* assert unique key ?*) +let del_assoc key xs = xs +> List.filter (fun (k,v) -> k <> key) +let replace_assoc (key, v) xs = insert_assoc (key, v) (del_assoc key xs) + +let apply_assoc key f xs = + let old = assoc key xs in + replace_assoc (key, f old) xs + +let big_union_assoc f xs = xs +> map_assoc f +> fold_assoc union_set empty_set + +(* todo: pb normally can suppr fun l -> .... l but if do that, then strange type _a + => assoc_map is strange too => equal dont work +*) +let (assoc_reverse: (('a * 'b) list) -> (('b * 'a) list)) = fun l -> + List.map (fun(x,y) -> (y,x)) l + +let (assoc_map: (('a * 'b) list) -> (('a * 'b) list) -> (('a * 'a) list)) = + fun l1 l2 -> + let (l1bis, l2bis) = (assoc_reverse l1, assoc_reverse l2) in + List.map (fun (x,y) -> (y, List.assoc x l2bis )) l1bis + +let rec (lookup_list: 'a -> ('a , 'b) assoc list -> 'b) = fun el -> function + | [] -> raise Not_found + | (xs::xxs) -> try List.assoc el xs with Not_found -> lookup_list el xxs + +let (lookup_list2: 'a -> ('a , 'b) assoc list -> ('b * int)) = fun el xxs -> + let rec lookup_l_aux i = function + | [] -> raise Not_found + | (xs::xxs) -> + try let res = List.assoc el xs in (res,i) + with Not_found -> lookup_l_aux (i+1) xxs + in lookup_l_aux 0 xxs + +let _ = example (lookup_list2 "c" [["a",1;"b",2];["a",1;"b",3];["a",1;"c",7]] = (7,2)) + + +let assoc_option k l = + optionise (fun () -> List.assoc k l) + +(*****************************************************************************) +(* Assoc int -> xxx with binary tree. Have a look too at Mapb.mli *) +(*****************************************************************************) + +(* ex: type robot_list = robot_info IntMap.t *) +module IntMap = Map.Make + (struct + type t = int + let compare = compare + end) +let intmap_to_list m = IntMap.fold (fun id v acc -> (id, v) :: acc) m [] +let intmap_string_of_t f a = "" + +module IntIntMap = Map.Make + (struct + type t = int * int + let compare = compare +end) + +let intintmap_to_list m = IntIntMap.fold (fun id v acc -> (id, v) :: acc) m [] +let intintmap_string_of_t f a = "" + + +(*****************************************************************************) +(* Hash *) +(*****************************************************************************) + +(* il parait que better when choose a prime *) +let hcreate () = Hashtbl.create 401 +let hadd (k,v) h = Hashtbl.add h k v +let hmem k h = Hashtbl.mem h k +let hfind k h = Hashtbl.find h k +let hreplace (k,v) h = Hashtbl.replace h k v +let hiter = Hashtbl.iter +let hfold = Hashtbl.fold +let hremove k h = Hashtbl.remove h k + + +let hash_to_list h = + Hashtbl.fold (fun k v acc -> (k,v)::acc) h [] + +> List.sort compare + +let hash_to_list_unsorted h = + Hashtbl.fold (fun k v acc -> (k,v)::acc) h [] + +let hash_of_list xs = + let h = Hashtbl.create 101 in + begin + xs +> List.iter (fun (k, v) -> Hashtbl.add h k v); + h + end + +let _ = + let h = Hashtbl.create 101 in + Hashtbl.add h "toto" 1; + Hashtbl.add h "toto" 1; + assert(hash_to_list h = ["toto",1; "toto",1]) + + +let hfind_default key value_if_not_found h = + try Hashtbl.find h key + with Not_found -> + (Hashtbl.add h key (value_if_not_found ()); Hashtbl.find h key) + +(* not as easy as Perl $h->{key}++; but still possible *) +let hupdate_default key op value_if_not_found h = + let old = hfind_default key value_if_not_found h in + Hashtbl.replace h key (op old) + + +let hfind_option key h = + optionise (fun () -> Hashtbl.find h key) + + +(* see below: let hkeys h = ... *) + + +(*****************************************************************************) +(* Hash sets *) +(*****************************************************************************) + +type 'a hashset = ('a, bool) Hashtbl.t + + +let hash_hashset_add k e h = + match optionise (fun () -> Hashtbl.find h k) with + | Some hset -> Hashtbl.replace hset e true + | None -> + let hset = Hashtbl.create 11 in + begin + Hashtbl.add h k hset; + Hashtbl.replace hset e true; + end + +let hashset_to_set baseset h = + h +> hash_to_list +> List.map fst +> (fun xs -> baseset#fromlist xs) + +let hashset_to_list h = hash_to_list h +> List.map fst + +let hashset_of_list xs = + xs +> List.map (fun x -> x, true) +> hash_of_list + + + +let hkeys h = + let hkey = Hashtbl.create 101 in + h +> Hashtbl.iter (fun k v -> Hashtbl.replace hkey k true); + hashset_to_list hkey + + + +let group_assoc_bykey_eff xs = + let h = Hashtbl.create 101 in + xs +> List.iter (fun (k, v) -> Hashtbl.add h k v); + let keys = hkeys h in + keys +> List.map (fun k -> k, Hashtbl.find_all h k) + + +let test_group_assoc () = + let xs = enum 0 10000 +> List.map (fun i -> i_to_s i, i) in + let xs = ("0", 2)::xs in +(* let _ys = xs +> Common.groupBy (fun (a,resa) (b,resb) -> a =$= b) *) + let ys = xs +> group_assoc_bykey_eff + in + pr2_gen ys + + + + +let diff_two_say_set_eff xs1 xs2 = + let h1 = hashset_of_list xs1 in + let h2 = hashset_of_list xs2 in + + let hcommon = Hashtbl.create 101 in + let honly_in_h1 = Hashtbl.create 101 in + let honly_in_h2 = Hashtbl.create 101 in + + h1 +> Hashtbl.iter (fun k _ -> + if Hashtbl.mem h2 k + then Hashtbl.replace hcommon k true + else Hashtbl.add honly_in_h1 k true + ); + h2 +> Hashtbl.iter (fun k _ -> + if Hashtbl.mem h1 k + then Hashtbl.replace hcommon k true + else Hashtbl.add honly_in_h2 k true + ); + hashset_to_list hcommon, + hashset_to_list honly_in_h1, + hashset_to_list honly_in_h2 + + +(*****************************************************************************) +(* Stack *) +(*****************************************************************************) +type 'a stack = 'a list + +let (empty_stack: 'a stack) = [] +let (push: 'a -> 'a stack -> 'a stack) = fun x xs -> x::xs +let (top: 'a stack -> 'a) = List.hd +let (pop: 'a stack -> 'a stack) = List.tl + + +(* now in prelude: + * let push2 v l = l := v :: !l + *) + +let pop2 l = + let v = List.hd !l in + begin + l := List.tl !l; + v + end + + +(*****************************************************************************) +(* Binary tree *) +(*****************************************************************************) +type 'a bintree = Leaf of 'a | Branch of ('a bintree * 'a bintree) + + +(*****************************************************************************) +(* N-ary tree *) +(*****************************************************************************) + +(* no empty tree, must have one root at list *) +type 'a tree = Tree of 'a * ('a tree) list + +let rec (tree_iter: ('a -> unit) -> 'a tree -> unit) = fun f tree -> + match tree with + | Tree (node, xs) -> + f node; + xs +> List.iter (tree_iter f) + + +(*****************************************************************************) +(* N-ary tree with updatable childrens *) +(*****************************************************************************) + +(* Leaf can seem redundant, but sometimes want to directly see if + * a children is a leaf without looking if the list is empty. + *) +type ('a, 'b) treeref = + | NodeRef of 'a * ('a, 'b) treeref list ref + | LeafRef of 'b + +let rec (treeref_node_iter: + (('a * ('a, 'b) treeref list ref) -> unit) -> + ('a, 'b) treeref -> unit) = fun f tree -> + match tree with + | LeafRef _ -> () + | NodeRef (n, xs) -> + f (n, xs); + !xs +> List.iter (treeref_node_iter f) + + +let rec (treeref_node_iter_with_parents: + (('a * ('a, 'b) treeref list ref) -> ('a list) -> unit) -> + ('a, 'b) treeref -> unit) = fun f tree -> + let rec aux acc tree = + match tree with + | LeafRef _ -> () + | NodeRef (n, xs) -> + f (n, xs) acc ; + !xs +> List.iter (aux (n::acc)) + in + aux [] tree + + +let find_treeref f tree = + let res = ref [] in + + tree +> treeref_node_iter (fun (n, xs) -> + if f (n,xs) + then push2 (n, xs) res; + ); + match !res with + | [n,xs] -> NodeRef (n, xs) + | [] -> raise Not_found + | x::y::zs -> failwith "multi found" + +(*****************************************************************************) +(* Graph. Have a look too at Ograph_*.mli *) +(*****************************************************************************) +(* todo: generalise to put in common (need 'edge (and 'c ?), + * and take in param a display func, cos caml sux, no overloading of show :( + * Simple impelemntation. Can do also matrix, or adjacent list, or pointer(ref) + * todo: do some check (dont exist already, ...) + *) + +type 'node graph = ('node set) * (('node * 'node) set) + +let (add_node: 'a -> 'a graph -> 'a graph) = fun node (nodes, arcs) -> + (node::nodes, arcs) + +let (del_node: 'a -> 'a graph -> 'a graph) = fun node (nodes, arcs) -> + (nodes $-$ set [node], arcs) +(* could do more job: + let _ = assert (successors node (nodes, arcs) = empty) in + +> List.filter (fun (src, dst) -> dst != node)) +*) +let (add_arc: ('a * 'a) -> 'a graph -> 'a graph) = fun arc (nodes, arcs) -> + (nodes, set [arc] $+$ arcs) + +let (del_arc: ('a * 'a) -> 'a graph -> 'a graph) = fun arc (nodes, arcs) -> + (nodes, arcs +> List.filter (fun a -> not (arc = a))) + +let (successors: 'a -> 'a graph -> 'a set) = fun x (nodes, arcs) -> + arcs +> List.filter (fun (src, dst) -> src = x) +> List.map snd + +let (predecessors: 'a -> 'a graph -> 'a set) = fun x (nodes, arcs) -> + arcs +> List.filter (fun (src, dst) -> dst = x) +> List.map fst + +let (nodes: 'a graph -> 'a set) = fun (nodes, arcs) -> nodes + +(* pre: no cycle *) +let rec (fold_upward: ('b -> 'a -> 'b) -> 'a set -> 'b -> 'a graph -> 'b) = + fun f xs acc graph -> + match xs with + | [] -> acc + | x::xs -> (f acc x) + +> (fun newacc -> fold_upward f (graph +> predecessors x) newacc graph) + +> (fun newacc -> fold_upward f xs newacc graph) + (* TODO avoid already visited *) + +let empty_graph = ([], []) + + + +(* +let (add_arcs_toward: int -> (int list) -> 'a graph -> 'a graph) = fun i xs -> + function + (nodes, arcs) -> (nodes, (List.map (fun j -> (j,i) ) xs)++arcs) +let (del_arcs_toward: int -> (int list) -> 'a graph -> 'a graph)= fun i xs g -> + List.fold_left (fun acc el -> del_arc (el, i) acc) g xs +let (add_arcs_from: int -> (int list) -> 'a graph -> 'a graph) = fun i xs -> + function + (nodes, arcs) -> (nodes, (List.map (fun j -> (i,j) ) xs)++arcs) + + +let (del_node: (int * 'node) -> 'node graph -> 'node graph) = fun node -> + function (nodes, arcs) -> + let newnodes = List.filter (fun a -> not (node = a)) nodes in + if newnodes = nodes then (raise Not_found) else (newnodes, arcs) +let (replace_node: int -> 'node -> 'node graph -> 'node graph) = fun i n -> + function (nodes, arcs) -> + let newnodes = List.filter (fun (j,_) -> not (i = j)) nodes in + ((i,n)::newnodes, arcs) +let (get_node: int -> 'node graph -> 'node) = fun i -> function + (nodes, arcs) -> List.assoc i nodes + +let (get_free: 'a graph -> int) = function + (nodes, arcs) -> (maximum (List.map fst nodes))+1 +(* require no cycle !! + TODO if cycle check that we have already visited a node *) +let rec (succ_all: int -> 'a graph -> (int list)) = fun i -> function + (nodes, arcs) as g -> + let direct = succ i g in + union direct (union_list (List.map (fun i -> succ_all i g) direct)) +let rec (pred_all: int -> 'a graph -> (int list)) = fun i -> function + (nodes, arcs) as g -> + let direct = pred i g in + union direct (union_list (List.map (fun i -> pred_all i g) direct)) +(* require that the nodes are different !! *) +let rec (equal: 'a graph -> 'a graph -> bool) = fun g1 g2 -> + let ((nodes1, arcs1),(nodes2, arcs2)) = (g1,g2) in + try + (* do 2 things, check same length and to assoc *) + let conv = assoc_map nodes1 nodes2 in + List.for_all (fun (i1,i2) -> + List.mem (List.assoc i1 conv, List.assoc i2 conv) arcs2) + arcs1 + && (List.length arcs1 = List.length arcs2) + (* could think that only forall is needed, but need check same lenth too*) + with _ -> false + +let (display: 'a graph -> ('a -> unit) -> unit) = fun g display_func -> + let rec aux depth i = + print_n depth " "; + print_int i; print_string "->"; display_func (get_node i g); + print_string "\n"; + List.iter (aux (depth+2)) (succ i g) + in aux 0 1 + +let (display_dot: 'a graph -> ('a -> string) -> unit)= fun (nodes,arcs) func -> + let file = open_out "test.dot" in + output_string file "digraph misc {\n" ; + List.iter (fun (n, node) -> + output_int file n; output_string file " [label=\""; + output_string file (func node); output_string file " \"];\n"; ) nodes; + List.iter (fun (i1,i2) -> output_int file i1 ; output_string file " -> " ; + output_int file i2 ; output_string file " ;\n"; ) arcs; + output_string file "}\n" ; + close_out file; + let status = Unix.system "viewdot test.dot" in + () +(* todo: faire = graphe (int can change !!! => cant make simply =) + reassign number first !! + *) + +(* todo: mettre diff(modulo = !!) en rouge *) +let (display_dot2: 'a graph -> 'a graph -> ('a -> string) -> unit) = + fun (nodes1, arcs1) (nodes2, arcs2) func -> + let file = open_out "test.dot" in + output_string file "digraph misc {\n" ; + output_string file "rotate = 90;\n"; + List.iter (fun (n, node) -> + output_string file "100"; output_int file n; + output_string file " [label=\""; + output_string file (func node); output_string file " \"];\n"; ) nodes1; + List.iter (fun (n, node) -> + output_string file "200"; output_int file n; + output_string file " [label=\""; + output_string file (func node); output_string file " \"];\n"; ) nodes2; + List.iter (fun (i1,i2) -> + output_string file "100"; output_int file i1 ; output_string file " -> " ; + output_string file "100"; output_int file i2 ; output_string file " ;\n"; + ) + arcs1; + List.iter (fun (i1,i2) -> + output_string file "200"; output_int file i1 ; output_string file " -> " ; + output_string file "200"; output_int file i2 ; output_string file " ;\n"; ) + arcs2; +(* output_string file "500 -> 1001; 500 -> 2001}\n" ; *) + output_string file "}\n" ; + close_out file; + let status = Unix.system "viewdot test.dot" in + () + + +*) +(*****************************************************************************) +(* Generic op *) +(*****************************************************************************) +(* overloading *) + +let map = List.map (* note: really really slow, use rev_map if possible *) +let filter = List.filter +let fold = List.fold_left +let member = List.mem +let iter = List.iter +let find = List.find +let exists = List.exists +let forall = List.for_all +let big_union f xs = xs +> map f +> fold union_set empty_set +(* let empty = [] *) +let empty_list = [] +let sort = List.sort +let length = List.length +let null xs = match xs with [] -> true | _ -> false +let head = List.hd +let tail = List.tl +let is_singleton = fun xs -> List.length xs = 1 + +(*****************************************************************************) +(* Geometry (raytracer) *) +(*****************************************************************************) + +type vector = (float * float * float) +type point = vector +type color = vector (* color(0-1) *) + +(* todo: factorise *) +let (dotproduct: vector * vector -> float) = + fun ((x1,y1,z1),(x2,y2,z2)) -> (x1*.x2 +. y1*.y2 +. z1*.z2) +let (vector_length: vector -> float) = + fun (x,y,z) -> sqrt (square x +. square y +. square z) +let (minus_point: point * point -> vector) = + fun ((x1,y1,z1),(x2,y2,z2)) -> ((x1 -. x2),(y1 -. y2),(z1 -. z2)) +let (distance: point * point -> float) = + fun (x1, x2) -> vector_length (minus_point (x2,x1)) +let (normalise: vector -> vector) = + fun (x,y,z) -> + let len = vector_length (x,y,z) in (x /. len, y /. len, z /. len) +let (mult_coeff: vector -> float -> vector) = + fun (x,y,z) c -> (x *. c, y *. c, z *. c) +let (add_vector: vector -> vector -> vector) = + fun v1 v2 -> let ((x1,y1,z1),(x2,y2,z2)) = (v1,v2) in + (x1+.x2, y1+.y2, z1+.z2) +let (mult_vector: vector -> vector -> vector) = + fun v1 v2 -> let ((x1,y1,z1),(x2,y2,z2)) = (v1,v2) in + (x1*.x2, y1*.y2, z1*.z2) +let sum_vector = List.fold_left add_vector (0.0,0.0,0.0) + +(*****************************************************************************) +(* Pics (raytracer) *) +(*****************************************************************************) + +type pixel = (int * int * int) (* RGB *) + +(* required pixel list in row major order, line after line *) +let (write_ppm: int -> int -> (pixel list) -> string -> unit) = fun + width height xs filename -> + let chan = open_out filename in + begin + output_string chan "P6\n"; + output_string chan ((string_of_int width) ^ "\n"); + output_string chan ((string_of_int height) ^ "\n"); + output_string chan "255\n"; + List.iter (fun (r,g,b) -> + List.iter (fun byt -> output_byte chan byt) [r;g;b] + ) xs; + close_out chan + end + +let test_ppm1 () = write_ppm 100 100 + ((generate (50*100) (1,45,100)) ++ (generate (50*100) (1,1,100))) + "img.ppm" + +(*****************************************************************************) +(* Diff (lfs) *) +(*****************************************************************************) +type diff = Match | BnotinA | AnotinB + +let (diff: (int -> int -> diff -> unit)-> (string list * string list) -> unit)= + fun f (xs,ys) -> + let file1 = "/tmp/diff1-" ^ (string_of_int (Unix.getuid ())) in + let file2 = "/tmp/diff2-" ^ (string_of_int (Unix.getuid ())) in + let fileresult = "/tmp/diffresult-" ^ (string_of_int (Unix.getuid ())) in + write_file file1 (unwords xs); + write_file file2 (unwords ys); + command2 + ("diff --side-by-side -W 1 " ^ file1 ^ " " ^ file2 ^ " > " ^ fileresult); + let res = cat fileresult in + let a = ref 0 in + let b = ref 0 in + res +> List.iter (fun s -> + match s with + | ("" | " ") -> f !a !b Match; incr a; incr b; + | ">" -> f !a !b BnotinA; incr b; + | ("|" | "/" | "\\" ) -> + f !a !b BnotinA; f !a !b AnotinB; incr a; incr b; + | "<" -> f !a !b AnotinB; incr a; + | _ -> raise Impossible + ) +(* +let _ = + diff + ["0";"a";"b";"c";"d"; "f";"g";"h";"j";"q"; "z"] + [ "a";"b";"c";"d";"e";"f";"g";"i";"j";"k";"r";"x";"y";"z"] + (fun x y -> pr "match") + (fun x y -> pr "a_not_in_b") + (fun x y -> pr "b_not_in_a") +*) + +let (diff2: (int -> int -> diff -> unit) -> (string * string) -> unit) = + fun f (xstr,ystr) -> + write_file "/tmp/diff1" xstr; + write_file "/tmp/diff2" ystr; + command2 + ("diff --side-by-side --left-column -W 1 " ^ + "/tmp/diff1 /tmp/diff2 > /tmp/diffresult"); + let res = cat "/tmp/diffresult" in + let a = ref 0 in + let b = ref 0 in + res +> List.iter (fun s -> + match s with + | "(" -> f !a !b Match; incr a; incr b; + | ">" -> f !a !b BnotinA; incr b; + | "|" -> f !a !b BnotinA; f !a !b AnotinB; incr a; incr b; + | "<" -> f !a !b AnotinB; incr a; + | _ -> raise Impossible + ) + + +(*****************************************************************************) +(* Parsers (aop-colcombet) *) +(*****************************************************************************) + +let parserCommon lexbuf parserer lexer = + try + let result = parserer lexer lexbuf in + result + with Parsing.Parse_error -> + print_string "buf: "; print_string lexbuf.Lexing.lex_buffer; + print_string "\n"; + print_string "current: "; print_int lexbuf.Lexing.lex_curr_pos; + print_string "\n"; + raise Parsing.Parse_error + + +(* marche pas ca neuneu *) +(* +let getDoubleParser parserer lexer string = + let lexbuf1 = Lexing.from_string string in + let chan = open_in string in + let lexbuf2 = Lexing.from_channel chan in + (parserCommon lexbuf1 parserer lexer , parserCommon lexbuf2 parserer lexer ) +*) + +let getDoubleParser parserer lexer = + ( + (function string -> + let lexbuf1 = Lexing.from_string string in + parserCommon lexbuf1 parserer lexer + ), + (function string -> + let chan = open_in string in + let lexbuf2 = Lexing.from_channel chan in + parserCommon lexbuf2 parserer lexer + )) + + +(*****************************************************************************) +(* parser combinators *) +(*****************************************************************************) + +(* cf parser_combinators.ml + * + * Could also use ocaml stream. but not backtrack and forced to do LL, + * so combinators are better. + * + *) + + +(*****************************************************************************) +(* Parser related (cocci) *) +(*****************************************************************************) + +type parse_info = { + str: string; + charpos: int; + + line: int; + column: int; + file: filename; + } + +let fake_parse_info = { + charpos = -1; str = ""; + line = -1; column = -1; file = ""; +} + +let string_of_parse_info x = + spf "%s at %s:%d:%d" x.str x.file x.line x.column + + +let (info_from_charpos2: int -> filename -> (int * int * string)) = + fun charpos filename -> + + (* Currently lexing.ml does not handle the line number position. + * Even if there is some fields in the lexing structure, they are not + * maintained by the lexing engine :( So the following code does not work: + * let pos = Lexing.lexeme_end_p lexbuf in + * sprintf "at file %s, line %d, char %d" pos.pos_fname pos.pos_lnum + * (pos.pos_cnum - pos.pos_bol) in + * Hence this function to overcome the previous limitation. + *) + let chan = open_in filename in + let linen = ref 0 in + let posl = ref 0 in + let rec charpos_to_pos_aux () = + let s = (input_line chan) in + incr linen; + let s = s ^ "\n" in + if (!posl + slength s > charpos) + then begin + close_in chan; + (!linen, charpos - !posl, s) + end + else begin + posl := !posl + slength s; + charpos_to_pos_aux (); + end + in + let res = charpos_to_pos_aux () in + close_in chan; + res + +let info_from_charpos a b = + profile_code "Common.info_from_charpos" (fun () -> info_from_charpos2 a b) + + + +let (full_charpos_to_pos2: filename -> (int * int) array ) = fun filename -> + + let arr = Array.create (filesize filename + 2) (0,0) in + + let chan = open_in filename in + + let charpos = ref 0 in + let line = ref 0 in + + let rec full_charpos_to_pos_aux () = + try + let s = (input_line chan) in + incr line; + + (* '... +1 do' cos input_line dont return the trailing \n *) + for i = 0 to (slength s - 1) + 1 do + arr.(!charpos + i) <- (!line, i); + done; + charpos := !charpos + slength s + 1; + full_charpos_to_pos_aux(); + + with End_of_file -> + for i = !charpos to Array.length arr - 1 do + arr.(i) <- (!line, 0); + done; + (); + in + begin + full_charpos_to_pos_aux (); + close_in chan; + arr + end +let full_charpos_to_pos a = + profile_code "Common.full_charpos_to_pos" (fun () -> full_charpos_to_pos2 a) + +let test_charpos file = + full_charpos_to_pos file +> dump +> pr2 + + + +let complete_parse_info filename table x = + { x with + file = filename; + line = fst (table.(x.charpos)); + column = snd (table.(x.charpos)); + } + +(*---------------------------------------------------------------------------*) +(* Decalage is here to handle stuff such as cpp which include file and who + * can make shift. + *) +let (error_messagebis: filename -> (string * int) -> int -> string)= + fun filename (lexeme, lexstart) decalage -> + + let charpos = lexstart + decalage in + let tok = lexeme in + let (line, pos, linecontent) = info_from_charpos charpos filename in + sprintf "File \"%s\", line %d, column %d, charpos = %d + around = '%s', whole content = %s" + filename line pos charpos tok (chop linecontent) + +let error_message = fun filename (lexeme, lexstart) -> + try + error_messagebis filename (lexeme, lexstart) 0 + with End_of_file -> + begin + ("PB in Common.error_message, position " ^ i_to_s lexstart ^ + " given out of file:" ^ filename); + end + + + +let error_message_short = fun filename (lexeme, lexstart) -> + try + let charpos = lexstart in + let (line, pos, linecontent) = info_from_charpos charpos filename in + sprintf "File \"%s\", line %d" filename line + + with End_of_file -> + begin + ("PB in Common.error_message, position " ^ i_to_s lexstart ^ + " given out of file:" ^ filename); + end + + + +(*****************************************************************************) +(* Regression testing bis (cocci) *) +(*****************************************************************************) + +(* todo: keep also size of file, compute md5sum ? cos maybe the file + * has changed!. + * + * todo: could also compute the date, or some version info of the program, + * can record the first date when was found a OK, the last date where + * was ok, and then first date when found fail. So the + * Common.Ok would have more information that would be passed + * to the Common.Pb of date * date * date * string peut etre. + * + * todo? maybe use plain text file instead of marshalling. + *) + +type score_result = Ok | Pb of string +type score = (string (* usually a filename *), score_result) Hashtbl.t + +let empty_score () = (Hashtbl.create 101 : score) + + + +let regression_testing newscore best_score_file = + + pr2 ("regression file: "^ best_score_file); + let (bestscore : score) = + if not (Sys.file_exists best_score_file) + then write_value (empty_score()) best_score_file; + get_value best_score_file + in + let newbestscore = empty_score () in + + let allres = + (hash_to_list newscore +> List.map fst) + $+$ + (hash_to_list bestscore +> List.map fst) + in + begin + allres +> List.iter (fun res -> + match + optionise (fun () -> Hashtbl.find newscore res), + optionise (fun () -> Hashtbl.find bestscore res) + with + | None, None -> raise Impossible + | Some x, None -> + Printf.printf "new test file appeared: %s\n" res; + Hashtbl.add newbestscore res x; + | None, Some x -> + Printf.printf "old test file disappeared: %s\n" res; + | Some newone, Some bestone -> + (match newone, bestone with + | Ok, Ok -> + Hashtbl.add newbestscore res Ok + | Pb x, Ok -> + Printf.printf + "PBBBBBBBB: a test file does not work anymore!!! : %s\n" res; + Printf.printf "Error : %s\n" x; + Hashtbl.add newbestscore res Ok + | Ok, Pb x -> + Printf.printf "Great: a test file now works: %s\n" res; + Hashtbl.add newbestscore res Ok + | Pb x, Pb y -> + Hashtbl.add newbestscore res (Pb x); + if not (x = y) + then begin + Printf.printf + "Semipb: still error but not same error : %s\n" res; + Printf.printf "%s\n" (chop ("Old error: " ^ y)); + Printf.printf "New error: %s\n" x; + end + ) + ); + write_value newbestscore (best_score_file ^ ".old"); + write_value newbestscore best_score_file; + flush stdout; flush stderr; + end + +let string_of_score_result v = + match v with + | Ok -> "Ok" + | Pb s -> "Pb: " ^ s + +let print_score score = + score +> hash_to_list +> List.iter (fun (k, v) -> + pr2 (sprintf "% s --> %s" k (string_of_score_result v)) + ); + pr2 "--------------------------------"; + pr2 "total score"; + pr2 "--------------------------------"; + let total = hash_to_list score +> List.length in + let good = hash_to_list score +> List.filter + (fun (s, v) -> v = Ok) +> List.length + in + pr2 (sprintf "good = %d/%d" good total) + + +(*****************************************************************************) +(* Scope managment (cocci) *) +(*****************************************************************************) + +(* could also make a function Common.make_scope_functions that return + * the new_scope, del_scope, do_in_scope, add_env. Kind of functor :) + *) + +type ('a, 'b) scoped_env = ('a, 'b) assoc list + +(* +let rec lookup_env f env = + match env with + | [] -> raise Not_found + | []::zs -> lookup_env f zs + | (x::xs)::zs -> + match f x with + | None -> lookup_env f (xs::zs) + | Some y -> y + +let member_env_key k env = + try + let _ = lookup_env (fun (k',v) -> if k = k' then Some v else None) env in + true + with Not_found -> false + +*) + +let rec lookup_env k env = + match env with + | [] -> raise Not_found + | []::zs -> lookup_env k zs + | ((k',v)::xs)::zs -> + if k = k' + then v + else lookup_env k (xs::zs) + +let member_env_key k env = + match optionise (fun () -> lookup_env k env) with + | None -> false + | Some _ -> true + + +let new_scope scoped_env = scoped_env := []::!scoped_env +let del_scope scoped_env = scoped_env := List.tl !scoped_env + +let do_in_new_scope scoped_env f = + begin + new_scope scoped_env; + let res = f() in + del_scope scoped_env; + res + end + +let add_in_scope scoped_env def = + let (current, older) = uncons !scoped_env in + scoped_env := (def::current)::older + + + + + +(* note that ocaml hashtbl store also old value of a binding when add + * add a newbinding; that's why del_scope works + *) + +type ('a, 'b) scoped_h_env = { + scoped_h : ('a, 'b) Hashtbl.t; + scoped_list : ('a, 'b) assoc list; +} + +let empty_scoped_h_env () = { + scoped_h = Hashtbl.create 101; + scoped_list = [[]]; +} +let clone_scoped_h_env x = + { scoped_h = Hashtbl.copy x.scoped_h; + scoped_list = x.scoped_list; + } + +let rec lookup_h_env k env = + Hashtbl.find env.scoped_h k + +let member_h_env_key k env = + match optionise (fun () -> lookup_h_env k env) with + | None -> false + | Some _ -> true + + +let new_scope_h scoped_env = + scoped_env := {!scoped_env with scoped_list = []::!scoped_env.scoped_list} +let del_scope_h scoped_env = + begin + List.hd !scoped_env.scoped_list +> List.iter (fun (k, v) -> + Hashtbl.remove !scoped_env.scoped_h k + ); + scoped_env := {!scoped_env with scoped_list = + List.tl !scoped_env.scoped_list + } + end + +let do_in_new_scope_h scoped_env f = + begin + new_scope_h scoped_env; + let res = f() in + del_scope_h scoped_env; + res + end + +(* +let add_in_scope scoped_env def = + let (current, older) = uncons !scoped_env in + scoped_env := (def::current)::older +*) + +let add_in_scope_h x (k,v) = + begin + Hashtbl.add !x.scoped_h k v; + x := { !x with scoped_list = + ((k,v)::(List.hd !x.scoped_list))::(List.tl !x.scoped_list); + }; + end + +(*****************************************************************************) +(* Terminal *) +(*****************************************************************************) + +(* let ansi_terminal = ref true *) + +let (_execute_and_show_progress_func: (int (* length *) -> ((unit -> unit) -> unit) -> unit) ref) + = ref + (fun a b -> + failwith "no execute yet, have you included common_extra.cmo?" + ) + + + +let execute_and_show_progress len f = + !_execute_and_show_progress_func len f + + +(* now in common_extra.ml: + * let execute_and_show_progress len f = ... + *) + +(*****************************************************************************) +(* Random *) +(*****************************************************************************) + +let _init_random = Random.self_init () +(* +let random_insert i l = + let p = Random.int (length l +1) + in let rec insert i p l = + if (p = 0) then i::l else (hd l)::insert i (p-1) (tl l) + in insert i p l + +let rec randomize_list = function + [] -> [] + | a::l -> random_insert a (randomize_list l) +*) +let random_list xs = + List.nth xs (Random.int (length xs)) + +(* todo_opti: use fisher/yates algorithm. + * ref: http://en.wikipedia.org/wiki/Knuth_shuffle + * + * public static void shuffle (int[] array) + * { + * Random rng = new Random (); + * int n = array.length; + * while (--n > 0) + * { + * int k = rng.nextInt(n + 1); // 0 <= k <= n (!) + * int temp = array[n]; + * array[n] = array[k]; + * array[k] = temp; + * } + * } + + *) +let randomize_list xs = + let permut = permutation xs in + random_list permut + + + +let random_subset_of_list num xs = + let array = Array.of_list xs in + let len = Array.length array in + + let h = Hashtbl.create 101 in + let cnt = ref num in + while !cnt > 0 do + let x = Random.int len in + if not (Hashtbl.mem h (array.(x))) (* bugfix2: not just x :) *) + then begin + Hashtbl.add h (array.(x)) true; (* bugfix1: not just x :) *) + decr cnt; + end + done; + let objs = hash_to_list h +> List.map fst in + objs + + + +(*****************************************************************************) +(* Flags and actions *) +(*****************************************************************************) + +(* I put it inside a func as it can help to give a chance to + * change the globals before getting the options as some + * options sometimes may want to show the default value. + *) +let cmdline_flags_devel () = + [ + "-debugger", Arg.Set debugger , + " option to set if launched inside ocamldebug"; + "-profile", Arg.Unit (fun () -> profile := PALL), + " gather timing information about important functions"; + ] +let cmdline_flags_verbose () = + [ + "-verbose_level", Arg.Set_int verbose_level, + " guess what"; + "-disable_pr2_once", Arg.Set disable_pr2_once, + " to print more messages"; + ] + +let cmdline_flags_other () = + [ + "-nocheck_stack", Arg.Clear check_stack, + " "; + ] + +(* potentially other common options but not yet integrated: + + "-timeout", Arg.Set_int timeout, + " interrupt LFS or buggy external plugins"; + + (* can't be factorized because of the $ cvs stuff, we want the date + * of the main.ml file, not common.ml + *) + "-version", Arg.Unit (fun () -> + pr2 "version: _dollar_Date: 2008/06/14 00:54:22 _dollar_"; + raise (Common.UnixExit 0) + ), + " guess what"; + + "-shorthelp", Arg.Unit (fun () -> + !short_usage_func(); + raise (Common.UnixExit 0) + ), + " see short list of options"; + "-longhelp", Arg.Unit (fun () -> + !long_usage_func(); + raise (Common.UnixExit 0) + ), + "-help", Arg.Unit (fun () -> + !long_usage_func(); + raise (Common.UnixExit 0) + ), + " "; + "--help", Arg.Unit (fun () -> + !long_usage_func(); + raise (Common.UnixExit 0) + ), + " "; + +*) + +let cmdline_actions () = + [ + "-test_check_stack", " ", + mk_action_1_arg test_check_stack_size; + ] + + +(*****************************************************************************) +(* Postlude *) +(*****************************************************************************) +(* stuff put here cos of of forward definition limitation of ocaml *) + + +(* Infix trick, seen in jane street lib and harrop's code, and maybe in GMP *) +module Infix = struct + let (+>) = (+>) + let (==~) = (==~) + let (=~) = (=~) +end + + +let main_boilerplate f = + if not (!Sys.interactive) then + exn_to_real_unixexit (fun () -> + + Sys.set_signal Sys.sigint (Sys.Signal_handle (fun _ -> + pr2 "C-c intercepted, will do some cleaning before exiting"; + (* But if do some try ... with e -> and if do not reraise the exn, + * the bubble never goes at top and so I cant really C-c. + * + * A solution would be to not raise, but do the erase_temp_file in the + * syshandler, here, and then exit. + * The current solution is to not do some wild try ... with e + * by having in the exn handler a case: UnixExit x -> raise ... | e -> + *) + Sys.set_signal Sys.sigint Sys.Signal_default; + raise (UnixExit (-1)) + )); + + (* The finalize below makes it tedious to go back to exn when use + * 'back' in the debugger. Hence this special case. But the + * Common.debugger will be set in main(), so too late, so + * have to be quicker + *) + if Sys.argv +> Array.to_list +> List.exists (fun x -> x ="-debugger") + then debugger := true; + + finalize (fun ()-> + pp_do_in_zero_box (fun () -> + f(); (* <---- here it is *) + )) + (fun()-> + if !profile <> PNONE + then pr2 (profile_diagnostic ()); + erase_temp_files (); + ) + ) +(* let _ = if not !Sys.interactive then (main ()) *) + + +(*****************************************************************************) +(* Misc/test *) +(*****************************************************************************) + +let (generic_print: 'a -> string -> string) = fun v typ -> + write_value v "/tmp/generic_print"; + command2 + ("printf 'let (v:" ^ typ ^ ")= Common.get_value \"/tmp/generic_print\" " ^ + " in v;;' " ^ + " | calc.top > /tmp/result_generic_print"); + cat "/tmp/result_generic_print" + +> drop_while (fun e -> not (e =~ "^#.*")) +> tail + +> unlines + +> (fun s -> + if (s =~ ".*= \\(.+\\)") + then matched1 s + else "error in generic_print, not good format:" ^ s) + +(* let main () = pr (generic_print [1;2;3;4] "int list") *) + +class ['a] olist (ys: 'a list) = + object(o) + val xs = ys + method view = xs +(* method fold f a = List.fold_left f a xs *) + method fold : 'b. ('b -> 'a -> 'b) -> 'b -> 'b = + fun f accu -> List.fold_left f accu xs + end + + +(* let _ = write_value ((new setb[])#add 1) "/tmp/test" *) +let typing_sux_test () = + let x = Obj.magic [1;2;3] in + let f1 xs = List.iter print_int xs in + let f2 xs = List.iter print_string xs in + (f1 x; f2 x) + +(* let (test: 'a osetb -> 'a ocollection) = fun o -> (o :> 'a ocollection) *) +(* let _ = test (new osetb (Setb.empty)) *) diff --git a/commons/common.mli b/commons/common.mli new file mode 100644 index 0000000..a0cdac7 --- /dev/null +++ b/commons/common.mli @@ -0,0 +1,1792 @@ +(*###########################################################################*) +(* Globals *) +(*###########################################################################*) + +(* Some conventions: + * + * When I have some _xxx variables before some functions, it's + * because I want to show that those functions internally use a global + * variable. That does not mean I want people to modify this global. + * In fact they are kind of private, but I still want to show them. + * Maybe one day OCaml will have an effect type system so I don't need this. + * + * The variables that are called _init_xxx show the internal init + * side effect of the module (like static var trick used in C/C++) + * + * Why not split the functionnalities of this file in different files ? + * Because when I write ocaml script I want simply to load one + * file, common.ml, and that's it. Cf common_extra.ml for more on this. + *) + + +(*****************************************************************************) +(* Flags *) +(*****************************************************************************) +(* see the corresponding section for the use of those flags. See also + * the "Flags and actions" section at the end of this file. + *) + +(* if set then will not do certain finalize so faster to go back in replay *) +val debugger : bool ref + +type prof = PALL | PNONE | PSOME of string list +val profile : prof ref + +val verbose_level : int ref + +(* forbid pr2_once to do the once "optimisation" *) +val disable_pr2_once : bool ref + + + +(* works with new_temp_file *) +val save_tmp_files : bool ref + + + +(*****************************************************************************) +(* Module side effect *) +(*****************************************************************************) +(* + * I define a few unit tests via some let _ = example (... = ...). + * I also initialize the random seed, cf _init_random . + * I also set Gc.stack_size, cf _init_gc_stack . +*) + +(*****************************************************************************) +(* Semi globals *) +(*****************************************************************************) +(* cf the _xxx variables in this file *) + +(*###########################################################################*) +(* Basic features *) +(*###########################################################################*) + +type filename = string + +(* Trick in case you dont want to do an 'open Common' while still wanting + * more pervasive types than the one in Pervasives. Just do the selective + * open Common.BasicType. + *) +module BasicType : sig + type filename = string +end + +(* Same spirit. Trick found in Jane Street core lib, but originated somewhere + * else I think: the ability to open nested modules. *) +module Infix : sig + val ( +> ) : 'a -> ('a -> 'b) -> 'b + val ( =~ ) : string -> string -> bool + val ( ==~ ) : string -> Str.regexp -> bool +end + + +(* + * Another related trick, found via Jon Harrop to have an extended standard + * lib is to do something like + * + * module List = struct + * include List + * val map2 : ... + * end + * + * And then can put this "module extension" somewhere to open it. + *) + + + +(* This module defines the Timeout and UnixExit exceptions. + * You have to make sure that those exn are not intercepted. So + * avoid exn handler such as try (...) with _ -> cos Timeout will not bubble up + * enough. In such case, add a case before such as + * with Timeout -> raise Timeout | _ -> ... + * The same is true for UnixExit (see below). + *) + +(*****************************************************************************) +(* Debugging/logging *) +(*****************************************************************************) + +val _tab_level_print: int ref +val indent_do : (unit -> 'a) -> 'a +val reset_pr_indent : unit -> unit + +(* The following functions first indent _tab_level_print spaces. + * They also add the _prefix_pr, for instance used in MPI to show which + * worker is talking. + * + * The use of 2 in pr2 is because 2 is under UNIX the second descriptor + * which corresponds to stderr. + *) +val _prefix_pr : string ref +val pr : string -> unit +val pr2 : string -> unit +val pr_no_nl : string -> unit +val pr2_no_nl : string -> unit +val pr_xxxxxxxxxxxxxxxxx : unit -> unit +val pr2_xxxxxxxxxxxxxxxxx : unit -> unit + +(* use Dumper.dump *) +val pr2_gen: 'a -> unit +val dump: 'a -> string + +(* see flag: val disable_pr2_once : bool ref *) +val _already_printed : (string, bool) Hashtbl.t +val pr2_once : string -> unit + +val redirect_stdout_stderr : filename -> (unit -> unit) -> unit +val redirect_stdin : filename -> (unit -> unit) -> unit +val redirect_stdin_opt : filename option -> (unit -> unit) -> unit + +val fprintf : out_channel -> ('a, out_channel, unit) format -> 'a +val printf : ('a, out_channel, unit) format -> 'a +val eprintf : ('a, out_channel, unit) format -> 'a +val sprintf : ('a, unit, string) format -> 'a + +(* alias *) +val spf : ('a, unit, string) format -> 'a + +(* default = stderr *) +val _chan : out_channel ref +(* generate & use a /tmp/debugml-xxx file *) +val start_log_file : unit -> unit + +(* see flag: val verbose_level : int ref *) +val log : string -> unit +val log2 : string -> unit +val log3 : string -> unit +val log4 : string -> unit + +val if_log : (unit -> unit) -> unit +val if_log2 : (unit -> unit) -> unit +val if_log3 : (unit -> unit) -> unit +val if_log4 : (unit -> unit) -> unit + +val pause : unit -> unit + +(* was used by fix_caml *) +val _trace_var : int ref +val add_var : unit -> unit +val dec_var : unit -> unit +val get_var : unit -> int + +val print_n : int -> string -> unit +val printerr_n : int -> string -> unit + +val _debug : bool ref +val debugon : unit -> unit +val debugoff : unit -> unit +val debug : (unit -> unit) -> unit + +(* see flag: val debugger : bool ref *) + + +(*****************************************************************************) +(* Profiling (cpu/mem) *) +(*****************************************************************************) + +val get_mem : unit -> unit +val memory_stat : unit -> string + +val timenow : unit -> string + +val _count1 : int ref +val _count2 : int ref +val _count3 : int ref +val _count4 : int ref +val _count5 : int ref + +val count1 : unit -> unit +val count2 : unit -> unit +val count3 : unit -> unit +val count4 : unit -> unit +val count5 : unit -> unit +val profile_diagnostic_basic : unit -> string + +val time_func : (unit -> 'a) -> 'a + + + +(* see flag: type prof = PALL | PNONE | PSOME of string list *) +(* see flag: val profile : prof ref *) + +val _profile_table : (string, (float ref * int ref)) Hashtbl.t ref +val profile_code : string -> (unit -> 'a) -> 'a +val profile_diagnostic : unit -> string + +val report_if_take_time : int -> string -> (unit -> 'a) -> 'a + +(* similar to profile_code but print some information during execution too *) +val profile_code2 : string -> (unit -> 'a) -> 'a + +(*****************************************************************************) +(* Test *) +(*****************************************************************************) + +val example : bool -> unit +(* generate failwith when pb *) +val example2 : string -> bool -> unit +(* use Dumper to report when pb *) +val assert_equal : 'a -> 'a -> unit + +val _list_bool : (string * bool) list ref +val example3 : string -> bool -> unit +val test_all : unit -> unit + +(* regression testing *) +type score_result = Ok | Pb of string +type score = (string (* usually a filename *), score_result) Hashtbl.t +val empty_score : unit -> score +val regression_testing : + score -> filename (* old score file on disk (usually in /tmp) *) -> unit +val print_score : score -> unit + + +(* quickcheck spirit *) +type 'a gen = unit -> 'a + +(* quickcheck random generators *) +val ig : int gen +val lg : 'a gen -> 'a list gen +val pg : 'a gen -> 'b gen -> ('a * 'b) gen +val polyg : int gen +val ng : string gen + +val oneofl : 'a list -> 'a gen +val oneof : 'a gen list -> 'a gen +val always : 'a -> 'a gen +val frequency : (int * 'a gen) list -> 'a gen +val frequencyl : (int * 'a) list -> 'a gen + +val laws : string -> ('a -> bool) -> 'a gen -> 'a option + +(* example of use: + * let b = laws "unit" (fun x -> reverse [x] = [x]) ig + *) + +val statistic_number : 'a list -> (int * 'a) list +val statistic : 'a list -> (int * 'a) list + +val laws2 : + string -> ('a -> bool * 'b) -> 'a gen -> 'a option * (int * 'b) list + +(*****************************************************************************) +(* Persistence *) +(*****************************************************************************) + +(* just wrappers around Marshall *) +val get_value : filename -> 'a +val write_value : 'a -> filename -> unit +val write_back : ('a -> 'b) -> filename -> unit + +(*****************************************************************************) +(* Counter *) +(*****************************************************************************) +val _counter : int ref +val _counter2 : int ref +val _counter3 : int ref + +val counter : unit -> int +val counter2 : unit -> int +val counter3 : unit -> int + +type timestamp = int + +(*****************************************************************************) +(* String_of and (pretty) printing *) +(*****************************************************************************) + +val string_of_string : (string -> string) -> string +val string_of_list : ('a -> string) -> 'a list -> string +val string_of_unit : unit -> string +val string_of_array : ('a -> string) -> 'a array -> string +val string_of_option : ('a -> string) -> 'a option -> string + +val print_bool : bool -> unit +val print_option : ('a -> 'b) -> 'a option -> unit +val print_list : ('a -> 'b) -> 'a list -> unit +val print_between : (unit -> unit) -> ('a -> unit) -> 'a list -> unit + +(* use Format internally *) +val pp_do_in_box : (unit -> unit) -> unit +val pp_f_in_box : (unit -> 'a) -> 'a +val pp_do_in_zero_box : (unit -> unit) -> unit +val pp : string -> unit + +(* convert something printed using Format to print into a string *) +val format_to_string : (unit -> unit) (* printer *) -> string + +(* works with _tab_level_print enabling to mix some calls to pp, pr2 + * and indent_do to sometimes use advanced indentation pretty printing + * (with the pp* functions) and sometimes explicit and simple indendation + * printing (with pr* and indent_do) *) +val adjust_pp_with_indent : (unit -> unit) -> unit +val adjust_pp_with_indent_and_header : string -> (unit -> unit) -> unit + +(*****************************************************************************) +(* Macro *) +(*****************************************************************************) + +(* was working with my macro.ml4 *) +val macro_expand : string -> unit + +(*****************************************************************************) +(* Composition/Control *) +(*****************************************************************************) + +val ( +> ) : 'a -> ('a -> 'b) -> 'b +val ( +!> ) : 'a ref -> ('a -> 'a) -> unit +val ( $ ) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c + +val compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b +val flip : ('a -> 'b -> 'c) -> 'b -> 'a -> 'c + +val curry : ('a * 'b -> 'c) -> 'a -> 'b -> 'c +val uncurry : ('a -> 'b -> 'c) -> 'a * 'b -> 'c + +val id : 'a -> 'a +val do_nothing : unit -> unit + +val forever : (unit -> unit) -> unit + +val applyn : int -> ('a -> 'a) -> 'a -> 'a + +class ['a] shared_variable_hook : + 'a -> + object + val mutable data : 'a + val mutable registered : (unit -> unit) list + method get : 'a + method modify : ('a -> 'a) -> unit + method register : (unit -> unit) -> unit + method set : 'a -> unit + end + +val fixpoint : ('a -> 'a) -> 'a -> 'a +val fixpoint_for_object : ((< equal : 'a -> bool; .. > as 'a) -> 'a) -> 'a -> 'a + +val add_hook : ('a -> ('a -> 'b) -> 'b) ref -> ('a -> ('a -> 'b) -> 'b) -> unit +val add_hook_action : ('a -> unit) -> ('a -> unit) list ref -> unit +val run_hooks_action : 'a -> ('a -> unit) list ref -> unit + +type 'a mylazy = (unit -> 'a) + +(* emacs spirit *) +val save_excursion : 'a ref -> (unit -> 'b) -> 'b + +(* emacs spirit *) +val unwind_protect : (unit -> 'a) -> (exn -> 'b) -> 'a + +(* java spirit *) +val finalize : (unit -> 'a) -> (unit -> 'b) -> 'a + +val memoized : ('a, 'b) Hashtbl.t -> 'a -> (unit -> 'b) -> 'b + + +(* take file from which computation is done, an extension, and the function + * and will compute the function only once and then save result in + * file ^ extension + *) +val cache_computation : + ?verbose:bool -> ?use_cache:bool -> filename -> string (* extension *) -> + (unit -> 'a) -> 'a + +(* a more robust version where the client describes the dependencies of the + * computation so it will relaunch the computation in 'f' if needed. + *) +val cache_computation_robust : + filename -> + string (* extension for marshalled object *) -> + (filename list * 'x) -> + string (* extension for marshalled dependencies *) -> + (unit -> 'a) -> + 'a + + + +val once : ('a -> unit) -> ('a -> unit) + +val before_leaving : ('a -> unit) -> 'a -> 'a + +(* do some finalize, signal handling, unix exit conversion, etc *) +val main_boilerplate : (unit -> unit) -> unit + + +(* cf also the timeout function below that are control related too *) + + +(*****************************************************************************) +(* Concurrency *) +(*****************************************************************************) + +(* how ensure really atomic file creation ? hehe :) *) +exception FileAlreadyLocked +val acquire_file_lock : filename -> unit +val release_file_lock : filename -> unit + +(*****************************************************************************) +(* Error managment *) +(*****************************************************************************) +exception Todo +exception Impossible +exception Here +exception ReturnExn + +exception WrongFormat of string + + +val internal_error : string -> 'a +val myassert : bool -> unit +val warning : string -> 'a -> 'a +val error_cant_have : 'a -> 'b + +val exn_to_s : exn -> string + +(*****************************************************************************) +(* Environment *) +(*****************************************************************************) + +val check_stack_size: int -> unit +val check_stack_nbfiles: int -> unit + +(* internally common.ml set Gc. parameters *) +val _init_gc_stack : unit + +(*****************************************************************************) +(* Arguments and command line *) +(*****************************************************************************) + +type arg_spec_full = Arg.key * Arg.spec * Arg.doc +type cmdline_options = arg_spec_full list + + +type options_with_title = string * string * arg_spec_full list +type cmdline_sections = options_with_title list + + +(* A wrapper around Arg modules that have more logical argument order, + * and returns the remaining args. + *) +val parse_options : + cmdline_options -> Arg.usage_msg -> string array -> string list + +(* Another wrapper that does Arg.align automatically *) +val usage : Arg.usage_msg -> cmdline_options -> unit + + + +(* Work with the options_with_title type way to organize a long + * list of command line switches. + *) +val short_usage : + Arg.usage_msg -> short_opt:cmdline_options -> unit +val long_usage : + Arg.usage_msg -> short_opt:cmdline_options -> long_opt:cmdline_sections -> + unit + +(* With the options_with_title way, we don't want the default -help and --help + * so need adapter of Arg module, not just wrapper. + *) +val arg_align2 : cmdline_options -> cmdline_options +val arg_parse2 : + cmdline_options -> Arg.usage_msg -> (unit -> unit) (* short_usage func *) -> + string list + + + + + +(* The action lib. Useful to debug supart of your system. cf some of + * my main.ml for example of use. *) +type flag_spec = Arg.key * Arg.spec * Arg.doc +type action_spec = Arg.key * Arg.doc * action_func + and action_func = (string list -> unit) + +type cmdline_actions = action_spec list +exception WrongNumberOfArguments + +val mk_action_0_arg : (unit -> unit) -> action_func +val mk_action_1_arg : (string -> unit) -> action_func +val mk_action_2_arg : (string -> string -> unit) -> action_func +val mk_action_3_arg : (string -> string -> string -> unit) -> action_func + +val mk_action_n_arg : (string list -> unit) -> action_func + +val options_of_actions: + string ref (* the action ref *) -> cmdline_actions -> cmdline_options +val action_list: + cmdline_actions -> Arg.key list +val do_action: + Arg.key -> string list (* args *) -> cmdline_actions -> unit + +(*****************************************************************************) +(* Equality *) +(*****************************************************************************) + +(* Using the generic (=) is tempting, but it backfires, so better avoid it *) + +(* To infer all the code that use an equal, and that should be + * transformed, is not that easy, because (=) is used by many + * functions, such as List.find, List.mem, and so on. The strategy to find + * them is to turn what you were previously using into a function, because + * (=) return an exception when applied to a function, then you simply + * use ocamldebug to detect where the code has to be transformed by + * finding where the exception was launched from. + *) + +val (=|=) : int -> int -> bool +val (=<=) : char -> char -> bool +val (=$=) : string -> string -> bool +val (=:=) : bool -> bool -> bool + +val (=*=): 'a -> 'a -> bool + +(* if want to restrict the use of '=', uncomment this: + * + * val (=): int -> int -> bool + * + * But it will not forbid you to use caml functions like List.find, List.mem + * which internaly use this convenient but evolution-unfriendly (=) +*) + + + + +(*###########################################################################*) +(* And now basic types *) +(*###########################################################################*) + +(*****************************************************************************) +(* Bool *) +(*****************************************************************************) + +val ( ||| ) : 'a -> 'a -> 'a +val ( ==> ) : bool -> bool -> bool +val xor : 'a -> 'a -> bool + + +(*****************************************************************************) +(* Char *) +(*****************************************************************************) + +val string_of_char : char -> string +val string_of_chars : char list -> string + +val is_single : char -> bool +val is_symbol : char -> bool +val is_space : char -> bool +val is_upper : char -> bool +val is_lower : char -> bool +val is_alpha : char -> bool +val is_digit : char -> bool + +val cbetween : char -> char -> char -> bool + +(*****************************************************************************) +(* Num *) +(*****************************************************************************) + +val ( /! ) : int -> int -> int + +val do_n : int -> (unit -> unit) -> unit +val foldn : ('a -> int -> 'a) -> 'a -> int -> 'a + +val sum_float : float list -> float +val sum_int : int list -> int + +val pi : float +val pi2 : float +val pi4 : float + +val deg_to_rad : float -> float + +val clampf : float -> float + +val square : float -> float +val power : int -> int -> int + +val between : 'a -> 'a -> 'a -> bool +val between_strict : int -> int -> int -> bool +val bitrange : int -> int -> bool + +val prime1 : int -> int option +val prime : int -> int option + +val sum : int list -> int +val product : int list -> int + +val decompose : int -> int list + +val mysquare : int -> int +val sqr : float -> float + +type compare = Equal | Inf | Sup +val ( <=> ) : 'a -> 'a -> compare +val ( <==> ) : 'a -> 'a -> int + +type uint = int + +val int_of_stringchar : string -> int +val int_of_base : string -> int -> int +val int_of_stringbits : string -> int +val int_of_octal : string -> int +val int_of_all : string -> int + +(* useful but sometimes when want grep for all places where do modif, + * easier to have just code using ':=' and '<-' to do some modifications. + * In the same way avoid using {contents = xxx} to build some ref. + *) +val ( += ) : int ref -> int -> unit +val ( -= ) : int ref -> int -> unit + +val pourcent: int -> int -> int +val pourcent_float: int -> int -> float +val pourcent_float_of_floats: float -> float -> float + +(*****************************************************************************) +(* Numeric/overloading *) +(*****************************************************************************) + +type 'a numdict = + NumDict of + (('a -> 'a -> 'a) * ('a -> 'a -> 'a) * ('a -> 'a -> 'a) * ('a -> 'a)) +val add : 'a numdict -> 'a -> 'a -> 'a +val mul : 'a numdict -> 'a -> 'a -> 'a +val div : 'a numdict -> 'a -> 'a -> 'a +val neg : 'a numdict -> 'a -> 'a + +val numd_int : int numdict +val numd_float : float numdict + +val testd : 'a numdict -> 'a -> 'a + + +module ArithFloatInfix : sig + val (+) : float -> float -> float + val (-) : float -> float -> float + val (/) : float -> float -> float + val ( * ) : float -> float -> float + + + val (+..) : int -> int -> int + val (-..) : int -> int -> int + val (/..) : int -> int -> int + val ( *..) : int -> int -> int + + val (+=) : float ref -> float -> unit +end + +(*****************************************************************************) +(* Random *) +(*****************************************************************************) + +val _init_random : unit +val random_list : 'a list -> 'a +val randomize_list : 'a list -> 'a list +val random_subset_of_list : int -> 'a list -> 'a list + + +(*****************************************************************************) +(* Tuples *) +(*****************************************************************************) + +type 'a pair = 'a * 'a +type 'a triple = 'a * 'a * 'a + +val fst3 : 'a * 'b * 'c -> 'a +val snd3 : 'a * 'b * 'c -> 'b +val thd3 : 'a * 'b * 'c -> 'c + +val sndthd : 'a * 'b * 'c -> 'b * 'c + +val map_fst : ('a -> 'b) -> 'a * 'c -> 'b * 'c +val map_snd : ('a -> 'b) -> 'c * 'a -> 'c * 'b + +val pair : ('a -> 'b) -> 'a * 'a -> 'b * 'b + +val snd : 'a * 'b -> 'b (* alias *) +val fst : 'a * 'b -> 'a (* alias *) + +val double : 'a -> 'a * 'a +val swap : 'a * 'b -> 'b * 'a + +(* maybe a sign of bad programming if use those functions :) *) +val tuple_of_list1 : 'a list -> 'a +val tuple_of_list2 : 'a list -> 'a * 'a +val tuple_of_list3 : 'a list -> 'a * 'a * 'a +val tuple_of_list4 : 'a list -> 'a * 'a * 'a * 'a +val tuple_of_list5 : 'a list -> 'a * 'a * 'a * 'a * 'a +val tuple_of_list6 : 'a list -> 'a * 'a * 'a * 'a * 'a * 'a + +(*****************************************************************************) +(* Maybe *) +(*****************************************************************************) + +type ('a, 'b) either = Left of 'a | Right of 'b +type ('a, 'b, 'c) either3 = Left3 of 'a | Middle3 of 'b | Right3 of 'c + +val just : 'a option -> 'a +val some : 'a option -> 'a (* alias *) + +val fmap : ('a -> 'b) -> 'a option -> 'b option +val map_option : ('a -> 'b) -> 'a option -> 'b option (* alias *) + +val do_option : ('a -> unit) -> 'a option -> unit + +val optionise : (unit -> 'a) -> 'a option + +val some_or : 'a option -> 'a -> 'a + +val partition_either : + ('a -> ('b, 'c) either) -> 'a list -> 'b list * 'c list + +val filter_some : 'a option list -> 'a list +val map_filter : ('a -> 'b option) -> 'a list -> 'b list +val find_some : ('a -> 'b option) -> 'a list -> 'b + +(*****************************************************************************) +(* Strings *) +(*****************************************************************************) + +val slength : string -> int (* alias *) +val concat : string -> string list -> string (* alias *) + +val i_to_s : int -> string +val s_to_i : string -> int + +(* strings take space in memory. Better when can share the space used by + * similar strings. + *) +val _shareds : (string, string) Hashtbl.t +val shared_string : string -> string + +val chop : string -> string +val chop_dirsymbol : string -> string + +val ( ) : string -> int * int -> string +val ( ) : string -> int -> char + +val split_on_char : char -> string -> string list + +val lowercase : string -> string + +val quote : string -> string + +val null_string : string -> bool +val is_blank_string : string -> bool +val is_string_prefix : string -> string -> bool + + +val plural : int -> string -> string + +val showCodeHex : int list -> unit + +val size_mo_ko : int -> string +val size_ko : int -> string + +val edit_distance: string -> string -> int + +(*****************************************************************************) +(* Regexp *) +(*****************************************************************************) + +val regexp_alpha : Str.regexp + +val _memo_compiled_regexp : (string, Str.regexp) Hashtbl.t +val ( =~ ) : string -> string -> bool +val ( ==~ ) : string -> Str.regexp -> bool + + + +val regexp_match : string -> string -> string + +val matched : int -> string -> string + +(* not yet politypic functions in ocaml *) +val matched1 : string -> string +val matched2 : string -> string * string +val matched3 : string -> string * string * string +val matched4 : string -> string * string * string * string +val matched5 : string -> string * string * string * string * string +val matched6 : string -> string * string * string * string * string * string +val matched7 : string -> string * string * string * string * string * string * string + +val string_match_substring : Str.regexp -> string -> bool + +val split : string (* sep regexp *) -> string -> string list +val join : string (* sep *) -> string list -> string + +val split_list_regexp : string -> string list -> (string * string list) list + +val all_match : string (* regexp *) -> string -> string list + +(*****************************************************************************) +(* Filenames *) +(*****************************************************************************) + +(* now at beginning of this file: type filename = string *) +val dirname : string -> string +val basename : string -> string + +val filesuffix : filename -> string +val fileprefix : filename -> string + +val adjust_ext_if_needed : filename -> string -> filename + +(* db for dir, base *) +val db_of_filename : filename -> (string * filename) +val filename_of_db : (string * filename) -> filename + +(* dbe for dir, base, ext *) +val dbe_of_filename : filename -> string * string * string +val dbe_of_filename_nodot : filename -> string * string * string +(* Left (d,b,e) | Right (d,b) if file has no extension *) +val dbe_of_filename_safe : + filename -> (string * string * string, string * string) either + +val filename_of_dbe : string * string * string -> filename + +(* ex: replace_ext "toto.c" "c" "var" *) +val replace_ext: filename -> string -> string -> filename + +(* remove the ., .. *) +val normalize_path : filename -> filename + +val relative_to_absolute : filename -> filename + +val filename_without_leading_path : string -> filename -> filename + +(*****************************************************************************) +(* i18n *) +(*****************************************************************************) +type langage = + | English + | Francais + | Deutsch + +(*****************************************************************************) +(* Dates *) +(*****************************************************************************) + +(* can also use ocamlcalendar, but heavier, use many modules ... *) + +type month = + | Jan | Feb | Mar | Apr | May | Jun + | Jul | Aug | Sep | Oct | Nov | Dec +type year = Year of int +type day = Day of int + +type date_dmy = DMY of day * month * year + +type hour = Hour of int +type minute = Min of int +type second = Sec of int + +type time_hms = HMS of hour * minute * second + +type full_date = date_dmy * time_hms + + +(* intervalle *) +type days = Days of int + +type time_dmy = TimeDMY of day * month * year + + +(* from Unix *) +type float_time = float + + +val mk_date_dmy : int -> int -> int -> date_dmy + + +val check_date_dmy : date_dmy -> unit +val check_time_dmy : time_dmy -> unit +val check_time_hms : time_hms -> unit + +val int_to_month : int -> string +val int_of_month : month -> int +val month_of_string : string -> month +val month_of_string_long : string -> month +val string_of_month : month -> string + +val string_of_date_dmy : date_dmy -> string +val string_of_unix_time : ?langage:langage -> Unix.tm -> string +val short_string_of_unix_time : ?langage:langage -> Unix.tm -> string +val string_of_floattime: ?langage:langage -> float_time -> string +val short_string_of_floattime: ?langage:langage -> float_time -> string + +val floattime_of_string: string -> float_time + +val dmy_to_unixtime: date_dmy -> float_time * Unix.tm +val unixtime_to_dmy: Unix.tm -> date_dmy +val unixtime_to_floattime: Unix.tm -> float_time + +val sec_to_days : int -> string +val sec_to_hours : int -> string + +val today : unit -> float_time +val yesterday : unit -> float_time +val tomorrow : unit -> float_time + +val lastweek : unit -> float_time +val lastmonth : unit -> float_time + +val week_before: float_time -> float_time +val month_before: float_time -> float_time +val week_after: float_time -> float_time + +val days_in_week_of_day : float_time -> float_time list + +val first_day_in_week_of_day : float_time -> float_time +val last_day_in_week_of_day : float_time -> float_time + +val day_secs: float_time + +val rough_days_since_jesus : date_dmy -> days +val rough_days_between_dates : date_dmy -> date_dmy -> days + +val string_of_unix_time_lfs : Unix.tm -> string + + +(*****************************************************************************) +(* Lines/Words/Strings *) +(*****************************************************************************) + +val list_of_string : string -> char list + +val lines : string -> string list +val unlines : string list -> string + +val words : string -> string list +val unwords : string list -> string + +val split_space : string -> string list + +val lines_with_nl : string -> string list + +val nblines : string -> int + +(*****************************************************************************) +(* Process/Files *) +(*****************************************************************************) +val cat : filename -> string list +val cat_orig : filename -> string list + +val interpolate : string -> string list + +val echo : string -> string + +val usleep : int -> unit + +val process_output_to_list : string -> string list +val cmd_to_list : string -> string list (* alias *) +val cmd_to_list_and_status : string -> string list * Unix.process_status + +val command2 : string -> unit +val command2_y_or_no : string -> bool + +val do_in_fork : (unit -> unit) -> int + +val mkdir: ?mode:Unix.file_perm -> string -> unit + +val read_file : filename -> string +val write_file : file:filename -> string -> unit + +val filesize : filename -> int +val filemtime : filename -> float + +val nblines_file : filename -> int + +val lfile_exists : filename -> bool +val is_directory : filename -> bool + +val capsule_unix : ('a -> unit) -> 'a -> unit + +val readdir_to_kind_list : string -> Unix.file_kind -> string list +val readdir_to_dir_list : string -> string list +val readdir_to_file_list : string -> string list +val readdir_to_link_list : string -> string list +val readdir_to_dir_size_list : string -> (string * int) list + +val glob : string -> filename list +val files_of_dir_or_files : + string (* ext *) -> string list -> filename list +val files_of_dir_or_files_no_vcs : + string (* ext *) -> string list -> filename list +(* use a post filter =~ for the ext filtering *) +val files_of_dir_or_files_no_vcs_post_filter : + string (* regexp *) -> string list -> filename list + + +val sanity_check_files_and_adjust : + string (* ext *) -> string list -> filename list + + +type rwx = [ `R | `W | `X ] list +val file_perm_of : u:rwx -> g:rwx -> o:rwx -> Unix.file_perm + +val has_env : string -> bool + +(* scheme spirit. do a finalize so no leak. *) +val with_open_outfile : + filename -> ((string -> unit) * out_channel -> 'a) -> 'a +val with_open_infile : + filename -> (in_channel -> 'a) -> 'a +val with_open_outfile_append : + filename -> ((string -> unit) * out_channel -> 'a) -> 'a + +val with_open_stringbuf : + (((string -> unit) * Buffer.t) -> unit) -> string + +exception Timeout + +(* subtil: have to make sure that Timeout is not intercepted before here. So + * avoid exn handler such as try (...) with _ -> cos Timeout will not bubble up + * enough. In such case, add a case before such as + * with Timeout -> raise Timeout | _ -> ... + * + * The same is true for UnixExit (see below). + *) +val timeout_function : int -> (unit -> 'a) -> 'a + +val timeout_function_opt : int option -> (unit -> 'a) -> 'a + + +(* creation of /tmp files, a la gcc + * ex: new_temp_file "cocci" ".c" will give "/tmp/cocci-3252-434465.c" + *) +val _temp_files_created : string list ref +(* see flag: val save_tmp_files : bool ref *) +val new_temp_file : string (* prefix *) -> string (* suffix *) -> filename +val erase_temp_files : unit -> unit + +(* If the user use some exit 0 in his code, then no one can intercept this + * exit and do something before exiting. There is exn handler for exit 0 + * so better never use exit 0 but instead use an exception and just at + * the very toplevel transform this exn in a unix exit code. + * + * subtil: same problem than with Timeout. Do not intercept such exception + * with some blind try (...) with _ -> ... + *) +exception UnixExit of int +val exn_to_real_unixexit : (unit -> 'a) -> 'a + + + + + + + + +(*###########################################################################*) +(* And now collection-like types. See also ocollection.mli *) +(*###########################################################################*) + +(*****************************************************************************) +(* List *) +(*****************************************************************************) + +(* tail recursive efficient map (but that also reverse the element!) *) +val map_eff_rev : ('a -> 'b) -> 'a list -> 'b list +(* tail recursive efficient map, use accumulator *) +val acc_map : ('a -> 'b) -> 'a list -> 'b list + + +val zip : 'a list -> 'b list -> ('a * 'b) list +val zip_safe : 'a list -> 'b list -> ('a * 'b) list +val unzip : ('a * 'b) list -> 'a list * 'b list + +val take : int -> 'a list -> 'a list +val take_safe : int -> 'a list -> 'a list +val take_until : ('a -> bool) -> 'a list -> 'a list +val take_while : ('a -> bool) -> 'a list -> 'a list + +val drop : int -> 'a list -> 'a list +val drop_while : ('a -> bool) -> 'a list -> 'a list +val drop_until : ('a -> bool) -> 'a list -> 'a list + +val span : ('a -> bool) -> 'a list -> 'a list * 'a list + +val skip_until : ('a list -> bool) -> 'a list -> 'a list +val skipfirst : 'a -> 'a list -> 'a list + +(* cf also List.partition *) +val fpartition : ('a -> 'b option) -> 'a list -> 'b list * 'a list + +val groupBy : ('a -> 'a -> bool) -> 'a list -> 'a list list +val exclude_but_keep_attached: ('a -> bool) -> 'a list -> ('a * 'a list) list + +(* use hash internally to not be in O(n2) *) +val group_assoc_bykey_eff : ('a * 'b) list -> ('a * 'b list) list + +val splitAt : int -> 'a list -> 'a list * 'a list + +val split_when: ('a -> bool) -> 'a list -> 'a list * 'a * 'a list +val split_gen_when: ('a list -> 'a list option) -> 'a list -> 'a list list + +val pack : int -> 'a list -> 'a list list + + +val enum : int -> int -> int list +val repeat : 'a -> int -> 'a list +val generate : int -> 'a -> 'a list + + + +val index_list : 'a list -> ('a * int) list +val index_list_1 : 'a list -> ('a * int) list +val index_list_and_total : 'a list -> ('a * int * int) list + +val iter_index : ('a -> int -> 'b) -> 'a list -> unit +val map_index : ('a -> int -> 'b) -> 'a list -> 'b list +val filter_index : (int -> 'a -> bool) -> 'a list -> 'a list +val fold_left_with_index : ('a -> 'b -> int -> 'a) -> 'a -> 'b list -> 'a + +val nth : 'a list -> int -> 'a +val rang : 'a -> 'a list -> int + +val last_n : int -> 'a list -> 'a list + + + +val snoc : 'a -> 'a list -> 'a list +val cons : 'a -> 'a list -> 'a list +val uncons : 'a list -> 'a * 'a list +val safe_tl : 'a list -> 'a list +val head_middle_tail : 'a list -> 'a * 'a list * 'a +val last : 'a list -> 'a +val list_init : 'a list -> 'a list +val list_last : 'a list -> 'a +val removelast : 'a list -> 'a list + +val inits : 'a list -> 'a list list +val tails : 'a list -> 'a list list + + +val ( ++ ) : 'a list -> 'a list -> 'a list + +val foldl1 : ('a -> 'a -> 'a) -> 'a list -> 'a +val fold_k : ('a -> 'b -> ('a -> 'a) -> 'a) -> ('a -> 'a) -> 'a -> 'b list -> 'a +val fold_right1 : ('a -> 'a -> 'a) -> 'a list -> 'a +val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a + +val rev_map : ('a -> 'b) -> 'a list -> 'b list + +val join_gen : 'a -> 'a list -> 'a list + +val do_withenv : + (('a -> 'b) -> 'c -> 'd) -> ('e -> 'a -> 'b * 'e) -> 'e -> 'c -> 'd * 'e +val map_withenv : ('a -> 'b -> 'c * 'a) -> 'a -> 'b list -> 'c list * 'a + +val collect_accu : ('a -> 'b list) -> 'b list -> 'a list -> 'b list +val collect : ('a -> 'b list) -> 'a list -> 'b list + +val remove : 'a -> 'a list -> 'a list + +val exclude : ('a -> bool) -> 'a list -> 'a list + +(* Not like unix uniq command line tool that only delete contiguous repeated + * line. Here we delete any repeated line (here list element). + *) +val uniq : 'a list -> 'a list +val doublon : 'a list -> bool + +val reverse : 'a list -> 'a list (* alias *) +val rev : 'a list -> 'a list (* alias *) +val rotate : 'a list -> 'a list + +val map_flatten : ('a -> 'b list) -> 'a list -> 'b list + +val map2 : ('a -> 'b) -> 'a list -> 'b list +val map3 : ('a -> 'b) -> 'a list -> 'b list + + +val maximum : 'a list -> 'a +val minimum : 'a list -> 'a + +val min_with : ('a -> 'b) -> 'a list -> 'a +val two_mins_with : ('a -> 'b) -> 'a list -> 'a * 'a + +val all_assoc : 'a -> ('a * 'b) list -> 'b list +val prepare_want_all_assoc : ('a * 'b) list -> ('a * 'b list) list + +val or_list : bool list -> bool +val and_list : bool list -> bool + +val return_when : ('a -> 'b option) -> 'a list -> 'b + + +val grep_with_previous : ('a -> 'a -> bool) -> 'a list -> 'a list +val iter_with_previous : ('a -> 'a -> 'b) -> 'a list -> unit + +val iter_with_before_after : + ('a list -> 'a -> 'a list -> unit) -> 'a list -> unit + +val get_pair : 'a list -> ('a * 'a) list + +val permutation : 'a list -> 'a list list + +val remove_elem_pos : int -> 'a list -> 'a list +val insert_elem_pos : ('a * int) -> 'a list -> 'a list +val uncons_permut : 'a list -> (('a * int) * 'a list) list +val uncons_permut_lazy : 'a list -> (('a * int) * 'a list Lazy.t) list + + +val pack_sorted : ('a -> 'a -> bool) -> 'a list -> 'a list list + +val keep_best : ('a * 'a -> 'a option) -> 'a list -> 'a list +val sorted_keep_best : ('a -> 'a -> 'a option) -> 'a list -> 'a list + +val cartesian_product : 'a list -> 'b list -> ('a * 'b) list + +(* old stuff *) +val surEnsemble : 'a list -> 'a list list -> 'a list list +val realCombinaison : 'a list -> 'a list list +val combinaison : 'a list -> ('a * 'a) list +val insere : 'a -> 'a list list -> 'a list list +val insereListeContenant : 'a list -> 'a -> 'a list list -> 'a list list +val fusionneListeContenant : 'a * 'a -> 'a list list -> 'a list list + +(*****************************************************************************) +(* Arrays *) +(*****************************************************************************) + +val array_find_index : ('a -> bool) -> 'a array -> int + +type 'a matrix = 'a array array + +val map_matrix : ('a -> 'b) -> 'a matrix -> 'b matrix + +(*****************************************************************************) +(* Fast array *) +(*****************************************************************************) + +(* ?? *) + +(*****************************************************************************) +(* Set. But have a look too at set*.mli; it's better. Or use Hashtbl. *) +(*****************************************************************************) + +type 'a set = 'a list + +val empty_set : 'a set + +val insert_set : 'a -> 'a set -> 'a set +val single_set : 'a -> 'a set +val set : 'a list -> 'a set + +val exists_set : ('a -> bool) -> 'a set -> bool +val forall_set : ('a -> bool) -> 'a set -> bool + +val filter_set : ('a -> bool) -> 'a set -> 'a set +val fold_set : ('a -> 'b -> 'a) -> 'a -> 'b set -> 'a +val map_set : ('a -> 'b) -> 'a set -> 'b set + +val member_set : 'a -> 'a set -> bool +val find_set : ('a -> bool) -> 'a list -> 'a + +val sort_set : ('a -> 'a -> int) -> 'a list -> 'a list + +val iter_set : ('a -> unit) -> 'a list -> unit + +val top_set : 'a set -> 'a + +val inter_set : 'a set -> 'a set -> 'a set +val union_set : 'a set -> 'a set -> 'a set +val minus_set : 'a set -> 'a set -> 'a set + +val union_all : ('a set) list -> 'a set + +val big_union_set : ('a -> 'b set) -> 'a set -> 'b set +val card_set : 'a set -> int + +val include_set : 'a set -> 'a set -> bool +val equal_set : 'a set -> 'a set -> bool +val include_set_strict : 'a set -> 'a set -> bool + +(* could put them in Common.Infix *) +val ( $*$ ) : 'a set -> 'a set -> 'a set +val ( $+$ ) : 'a set -> 'a set -> 'a set +val ( $-$ ) : 'a set -> 'a set -> 'a set + +val ( $?$ ) : 'a -> 'a set -> bool +val ( $<$ ) : 'a set -> 'a set -> bool +val ( $<=$ ) : 'a set -> 'a set -> bool +val ( $=$ ) : 'a set -> 'a set -> bool + +val ( $@$ ) : 'a list -> 'a list -> 'a list + +val nub : 'a list -> 'a list + +(* use internally a hash and return + * - the common part, + * - part only in a, + * - part only in b + *) +val diff_two_say_set_eff : 'a list -> 'a list -> + 'a list * 'a list * 'a list + +(*****************************************************************************) +(* Set as normal list *) +(*****************************************************************************) + +(* cf above *) + +(*****************************************************************************) +(* Set as sorted list *) +(*****************************************************************************) + + +(*****************************************************************************) +(* Sets specialized *) +(*****************************************************************************) + +(* +module StringSet = Set.Make(struct type t = string let compare = compare end) +*) + + +(*****************************************************************************) +(* Assoc. But have a look too at Mapb.mli; it's better. Or use Hashtbl. *) +(*****************************************************************************) + +type ('a, 'b) assoc = ('a * 'b) list + +val assoc_to_function : ('a, 'b) assoc -> ('a -> 'b) + +val empty_assoc : ('a, 'b) assoc +val fold_assoc : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a +val insert_assoc : 'a -> 'a list -> 'a list +val map_assoc : ('a -> 'b) -> 'a list -> 'b list +val filter_assoc : ('a -> bool) -> 'a list -> 'a list + +val assoc : 'a -> ('a * 'b) list -> 'b + +val keys : ('a * 'b) list -> 'a list +val lookup : 'a -> ('a * 'b) list -> 'b + +val del_assoc : 'a -> ('a * 'b) list -> ('a * 'b) list +val replace_assoc : 'a * 'b -> ('a * 'b) list -> ('a * 'b) list +val apply_assoc : 'a -> ('b -> 'b) -> ('a * 'b) list -> ('a * 'b) list + +val big_union_assoc : ('a -> 'b set) -> 'a list -> 'b set + +val assoc_reverse : ('a * 'b) list -> ('b * 'a) list +val assoc_map : ('a * 'b) list -> ('a * 'b) list -> ('a * 'a) list + +val lookup_list : 'a -> ('a, 'b) assoc list -> 'b +val lookup_list2 : 'a -> ('a, 'b) assoc list -> 'b * int + +val assoc_option : 'a -> ('a, 'b) assoc -> 'b option + +(*****************************************************************************) +(* Assoc, specialized. *) +(*****************************************************************************) + +module IntMap : + sig + type key = int + type +'a t + val empty : 'a t + val is_empty : 'a t -> bool + val add : key -> 'a -> 'a t -> 'a t + val find : key -> 'a t -> 'a + val remove : key -> 'a t -> 'a t + val mem : key -> 'a t -> bool + val iter : (key -> 'a -> unit) -> 'a t -> unit + val map : ('a -> 'b) -> 'a t -> 'b t + val mapi : (key -> 'a -> 'b) -> 'a t -> 'b t + val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b + val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int + val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + end +val intmap_to_list : 'a IntMap.t -> (IntMap.key * 'a) list +val intmap_string_of_t : 'a -> 'b -> string + +module IntIntMap : + sig + type key = int * int + type +'a t + val empty : 'a t + val is_empty : 'a t -> bool + val add : key -> 'a -> 'a t -> 'a t + val find : key -> 'a t -> 'a + val remove : key -> 'a t -> 'a t + val mem : key -> 'a t -> bool + val iter : (key -> 'a -> unit) -> 'a t -> unit + val map : ('a -> 'b) -> 'a t -> 'b t + val mapi : (key -> 'a -> 'b) -> 'a t -> 'b t + val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b + val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int + val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + end +val intintmap_to_list : 'a IntIntMap.t -> (IntIntMap.key * 'a) list +val intintmap_string_of_t : 'a -> 'b -> string + + +(*****************************************************************************) +(* Hash *) +(*****************************************************************************) + +(* Note that Hashtbl keep old binding to a key so if want a hash + * of a list, then can use the Hashtbl as is. Use Hashtbl.find_all then + * to get the list of bindings + * + * Note that Hashtbl module use different convention :( the object is + * the first argument, not last as for List or Map. + *) + +(* obsolete: can use directly the Hashtbl module *) +val hcreate : unit -> ('a, 'b) Hashtbl.t +val hadd : 'a * 'b -> ('a, 'b) Hashtbl.t -> unit +val hmem : 'a -> ('a, 'b) Hashtbl.t -> bool +val hfind : 'a -> ('a, 'b) Hashtbl.t -> 'b +val hreplace : 'a * 'b -> ('a, 'b) Hashtbl.t -> unit +val hiter : ('a -> 'b -> unit) -> ('a, 'b) Hashtbl.t -> unit +val hfold : ('a -> 'b -> 'c -> 'c) -> ('a, 'b) Hashtbl.t -> 'c -> 'c +val hremove : 'a -> ('a, 'b) Hashtbl.t -> unit + + +val hfind_default : 'a -> (unit -> 'b) -> ('a, 'b) Hashtbl.t -> 'b +val hfind_option : 'a -> ('a, 'b) Hashtbl.t -> 'b option +val hupdate_default : + 'a -> ('b -> 'b) -> (unit -> 'b) -> ('a, 'b) Hashtbl.t -> unit + +val hash_to_list : ('a, 'b) Hashtbl.t -> ('a * 'b) list +val hash_to_list_unsorted : ('a, 'b) Hashtbl.t -> ('a * 'b) list +val hash_of_list : ('a * 'b) list -> ('a, 'b) Hashtbl.t + + +val hkeys : ('a, 'b) Hashtbl.t -> 'a list + +(*****************************************************************************) +(* Hash sets *) +(*****************************************************************************) + +type 'a hashset = ('a, bool) Hashtbl.t + + +(* common use of hashset, in a hash of hash *) +val hash_hashset_add : 'a -> 'b -> ('a, 'b hashset) Hashtbl.t -> unit + +val hashset_to_set : + < fromlist : ('a ) list -> 'c; .. > -> ('a, 'b) Hashtbl.t -> 'c + +val hashset_to_list : 'a hashset -> 'a list +val hashset_of_list : 'a list -> 'a hashset + + +(*****************************************************************************) +(* Stack *) +(*****************************************************************************) + +type 'a stack = 'a list +val empty_stack : 'a stack +val push : 'a -> 'a stack -> 'a stack +val top : 'a stack -> 'a +val pop : 'a stack -> 'a stack + +val push2 : 'a -> 'a stack ref -> unit +val pop2: 'a stack ref -> 'a + + +(*****************************************************************************) +(* Binary tree *) +(*****************************************************************************) +type 'a bintree = Leaf of 'a | Branch of ('a bintree * 'a bintree) + +(*****************************************************************************) +(* N-ary tree *) +(*****************************************************************************) + +(* no empty tree, must have one root at least *) +type 'a tree = Tree of 'a * ('a tree) list + +val tree_iter : ('a -> unit) -> 'a tree -> unit + + +(*****************************************************************************) +(* N-ary tree with updatable childrens *) +(*****************************************************************************) + +(* Leaf can seem redundant, but sometimes want to directly see if + * a children is a leaf without looking if the list is empty. + *) +type ('a, 'b) treeref = + | NodeRef of 'a * ('a, 'b) treeref list ref + | LeafRef of 'b + +val treeref_node_iter: + (('a * ('a, 'b) treeref list ref) -> unit) -> ('a, 'b) treeref -> unit +val treeref_node_iter_with_parents: + (('a * ('a, 'b) treeref list ref) -> ('a list) -> unit) -> + ('a, 'b) treeref -> unit + +val find_treeref: + (('a * ('a, 'b) treeref list ref) -> bool) -> + ('a, 'b) treeref -> ('a, 'b) treeref + + + + + +(*****************************************************************************) +(* Graph. But have a look too at Ograph_*.mli; it's better *) +(*****************************************************************************) + +type 'a graph = 'a set * ('a * 'a) set + +val add_node : 'a -> 'a graph -> 'a graph +val del_node : 'a -> 'a graph -> 'a graph + +val add_arc : 'a * 'a -> 'a graph -> 'a graph +val del_arc : 'a * 'a -> 'a graph -> 'a graph + +val successors : 'a -> 'a graph -> 'a set +val predecessors : 'a -> 'a graph -> 'a set + +val nodes : 'a graph -> 'a set + +val fold_upward : ('a -> 'b -> 'a) -> 'b set -> 'a -> 'b graph -> 'a + +val empty_graph : 'a list * 'b list + + +(*****************************************************************************) +(* Generic op *) +(*****************************************************************************) + +(* mostly alias to functions in List *) + +val map : ('a -> 'b) -> 'a list -> 'b list +val filter : ('a -> bool) -> 'a list -> 'a list +val fold : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a + +val member : 'a -> 'a list -> bool + +val iter : ('a -> unit) -> 'a list -> unit + +val find : ('a -> bool) -> 'a list -> 'a + +val exists : ('a -> bool) -> 'a list -> bool +val forall : ('a -> bool) -> 'a list -> bool + +val big_union : ('a -> 'b set) -> 'a list -> 'b set + +(* same than [] but easier to search for, because [] can also be a pattern *) +val empty_list : 'a list + +val sort : ('a -> 'a -> int) -> 'a list -> 'a list + +val length : 'a list -> int + +val null : 'a list -> bool + +val head : 'a list -> 'a +val tail : 'a list -> 'a list + +val is_singleton : 'a list -> bool + + + + + + + + + +(*###########################################################################*) +(* And now misc functions *) +(*###########################################################################*) + +(*****************************************************************************) +(* DB (LFS) *) +(*****************************************************************************) + +(* cf oassocbdb.ml or oassocdbm.ml *) + +(*****************************************************************************) +(* GUI (LFS, CComment, otimetracker) *) +(*****************************************************************************) + +(* cf ocamlgtk and my gui.ml *) + + +(*****************************************************************************) +(* Graphics (otimetracker) *) +(*****************************************************************************) + +(* cf ocamlgl and my opengl.ml *) + + + +(*****************************************************************************) +(* Geometry (ICFP raytracer) *) +(*****************************************************************************) + +type vector = float * float * float + +type point = vector +type color = vector + +val dotproduct : vector * vector -> float + +val vector_length : vector -> float + +val minus_point : point * point -> vector + +val distance : point * point -> float + +val normalise : vector -> vector + +val mult_coeff : vector -> float -> vector + +val add_vector : vector -> vector -> vector +val mult_vector : vector -> vector -> vector +val sum_vector : vector list -> vector + + +(*****************************************************************************) +(* Pics (ICFP raytracer) *) +(*****************************************************************************) +type pixel = int * int * int +val write_ppm : int -> int -> pixel list -> filename -> unit +val test_ppm1 : unit -> unit + +(*****************************************************************************) +(* Diff (LFS) *) +(*****************************************************************************) + +type diff = Match | BnotinA | AnotinB +val diff : (int -> int -> diff -> unit) -> string list * string list -> unit +val diff2 : (int -> int -> diff -> unit) -> string * string -> unit + +(*****************************************************************************) +(* Parsers (aop-colcombet) *) +(*****************************************************************************) + +val parserCommon : Lexing.lexbuf -> ('a -> Lexing.lexbuf -> 'b) -> 'a -> 'b +val getDoubleParser : + ('a -> Lexing.lexbuf -> 'b) -> 'a -> (string -> 'b) * (string -> 'b) + +(*****************************************************************************) +(* Parsers (cocci) *) +(*****************************************************************************) + + +(* Currently lexing.ml does not handle the line number position. + * Even if there is some fields in the lexing structure, they are not + * maintained by the lexing engine :( So the following code does not work: + * + * let pos = Lexing.lexeme_end_p lexbuf in + * sprintf "at file %s, line %d, char %d" pos.pos_fname pos.pos_lnum + * (pos.pos_cnum - pos.pos_bol) in + * + * Hence those functions to overcome the previous limitation. + *) + +type parse_info = { + str: string; + charpos: int; + + line: int; + column: int; + file: filename; + } +val fake_parse_info : parse_info +val string_of_parse_info : parse_info -> string + +(* array[i] will contain the (line x col) of the i char position *) +val full_charpos_to_pos : filename -> (int * int) array + +(* fill in the line and column field of parse_info that were not set + * during lexing because of limitations of ocamllex. *) +val complete_parse_info : + filename -> (int * int) array -> parse_info -> parse_info + +(* return line x col x str_line from a charpos. This function is quite + * expensive so don't use it to get the line x col from every token in + * a file. Instead use full_charpos_to_pos. + *) +val info_from_charpos : int -> filename -> (int * int * string) + +val error_message : filename -> (string * int) -> string +val error_message_short : filename -> (string * int) -> string + +(* add a 'decalage/shift' argument to handle stuff such as cpp which includes + * files and who can make shift. + *) +val error_messagebis : filename -> (string * int) -> int -> string + +(*****************************************************************************) +(* Scope managment (cocci) *) +(*****************************************************************************) + +(* for example of use, see the code used in coccinelle *) +type ('a, 'b) scoped_env = ('a, 'b) assoc list + +val lookup_env : 'a -> ('a, 'b) scoped_env -> 'b +val member_env_key : 'a -> ('a, 'b) scoped_env -> bool + +val new_scope : ('a, 'b) scoped_env ref -> unit +val del_scope : ('a, 'b) scoped_env ref -> unit + +val do_in_new_scope : ('a, 'b) scoped_env ref -> (unit -> unit) -> unit + +val add_in_scope : ('a, 'b) scoped_env ref -> 'a * 'b -> unit + + + + +(* for example of use, see the code used in coccinelle *) +type ('a, 'b) scoped_h_env = { + scoped_h : ('a, 'b) Hashtbl.t; + scoped_list : ('a, 'b) assoc list; +} +val empty_scoped_h_env : unit -> ('a, 'b) scoped_h_env +val clone_scoped_h_env : ('a, 'b) scoped_h_env -> ('a, 'b) scoped_h_env + +val lookup_h_env : 'a -> ('a, 'b) scoped_h_env -> 'b +val member_h_env_key : 'a -> ('a, 'b) scoped_h_env -> bool + +val new_scope_h : ('a, 'b) scoped_h_env ref -> unit +val del_scope_h : ('a, 'b) scoped_h_env ref -> unit + +val do_in_new_scope_h : ('a, 'b) scoped_h_env ref -> (unit -> unit) -> unit + +val add_in_scope_h : ('a, 'b) scoped_h_env ref -> 'a * 'b -> unit + +(*****************************************************************************) +(* Terminal (LFS) *) +(*****************************************************************************) + +val _execute_and_show_progress_func : + (int (* length *) -> ((unit -> unit) -> unit) -> unit) ref +val execute_and_show_progress : + int (* length *) -> ((unit -> unit) -> unit) -> unit + +(*****************************************************************************) +(* Flags and actions *) +(*****************************************************************************) + +val cmdline_flags_devel : unit -> cmdline_options +val cmdline_flags_verbose : unit -> cmdline_options +val cmdline_flags_other : unit -> cmdline_options + +(*****************************************************************************) +(* Misc/test *) +(*****************************************************************************) + +val generic_print : 'a -> string -> string + +class ['a] olist : + 'a list -> + object + val xs : 'a list + method fold : ('b -> 'a -> 'b) -> 'b -> 'b + method view : 'a list + end + +val typing_sux_test : unit -> unit + diff --git a/commons/common_extra.ml b/commons/common_extra.ml new file mode 100644 index 0000000..8111afa --- /dev/null +++ b/commons/common_extra.ml @@ -0,0 +1,31 @@ +(* I put those functions here and not in common.ml to try to avoid + * as much as possible dependencies in common.ml so I can more easily + * make ocaml script that just do a load common.ml without the need + * to load many other files (like dumper.ml, or ANSITerminal.ml and + * other recursive dependencies). + * + * Note that you can still use the functions below from an open Common. + * You don't need to do a 'open Common_extra'; loading the commons.cma is + * enough to make the connexions. + *) + + + +let execute_and_show_progress len f = + let _count = ref 0 in + (* kind of continuation passed to f *) + let continue_pourcentage () = + incr _count; + ANSITerminal.set_cursor 1 (-1); + ANSITerminal.printf [] "%d / %d" !_count len; flush stdout; + in + ANSITerminal.printf [] "0 / %d" len; flush stdout; + f continue_pourcentage; + Common.pr2 "" + +let set_link () = + Common._execute_and_show_progress_func := execute_and_show_progress + + +let _init_execute = + set_link () diff --git a/commons/copyright.txt b/commons/copyright.txt new file mode 100644 index 0000000..f3bd2d8 --- /dev/null +++ b/commons/copyright.txt @@ -0,0 +1,17 @@ +Copyright (C) 1998-2008 Yoann Padioleau + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License (LGPL) + version 2.1 as published by the Free Software Foundation, with the + special exception on linking described in file license.txt. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file + license.txt for more details. + + +The contents of some files in this directory was derived from external +sources with compatible licenses. The original copyright and license +notice was preserved in the affected files. + diff --git a/commons/credits.txt b/commons/credits.txt new file mode 100644 index 0000000..bf674e2 --- /dev/null +++ b/commons/credits.txt @@ -0,0 +1,8 @@ + +Thanks to + - Richard Jones for his dumper module, + - Brian Hurt and Nicolas Cannasse for their dynArray module, + - Troestler Christophe for his ANSITerminal module, + - Sebastien ferre for his suffix tree module + + - Jane street for the backtrace module diff --git a/commons/glimpse.ml b/commons/glimpse.ml new file mode 100644 index 0000000..afe2a44 --- /dev/null +++ b/commons/glimpse.ml @@ -0,0 +1,110 @@ +open Common + +(*****************************************************************************) +(* Glimpse *) +(*****************************************************************************) +(* was first used for LFS, then a little for cocci, and then for aComment *) + +let check_have_glimpse () = + let xs = + Common.cmd_to_list ("glimpse -V") +> Common.exclude Common.null_string in + (match xs with + | ["This is glimpse version 4.18.2, 2006."] -> () + | ["This is glimpse version 4.18.5, 2006."] -> () + | _ -> failwith "glimpse not found or bad version" + ) + + +(* + * note: + * - -o or -b for glimpseindex => bigger index, faster search + * - no need to use -b with our way to use glimpse + * cos we use -l so dont need to know what is the place of the word + * in the file + * - -f is for incremental indexing. Handle when files are deleted ? + * I think that not that bad cos yes certainly in the index there will + * have some no-more-valid pointers, but as glimpse actually then do + * a real search on the file, he will see that dont exist anymore and + * so using -f is slower but very very little slower + * - for -z the order is important in .glimpse_filters => put + * the case of compressed file first + * - -F receive the list of files to index from stdin + * - -H target index dir + * + * + * Note que glimpseindex index pas forcement tous les fichiers texte. + * Si le fichier texte est trop petit, contient par exemple un seul mot, + * alors il l'indexe pas. Si veut indexer quand meme, il faudrait ajouter + * l'option -E + * + * command2 "echo '*_backup' > glimpse/.glimpse_exclude"; + * command2 "echo '*_backup,v' >> glimpse/.glimpse_exclude"; + * + * ex: glimpseindex -o -H . home + * + *) +let glimpseindex ext dir indexdir = + check_have_glimpse (); + Common.command2(spf "mkdir -p %s" indexdir); + Common.command2 + (spf "find %s -name \"*.%s\" | glimpseindex -o -H %s -F" + dir ext indexdir + ); + () + + +type glimpse_search = + (* -i insensitive search *) + | GlimpseCaseInsensitive + (* -w match on complete words. But not always good idea, for instance + * if file contain chazarain_j then dont work with -w + *) + | GlimpseWholeWord + +let default_glimpse_search = [GlimpseWholeWord] + + + +let s_of_glimpse_search = function + | GlimpseCaseInsensitive -> "-i" + | GlimpseWholeWord -> "-w" + +let s_of_glimpse_options xs = + xs +> List.map s_of_glimpse_search +> Common.join " " + + +(* note: + * - -y dont ask for prompt + * - -N allow far faster search as it does not actually search the file + * => when pdf/ps files no filtering done of them => far faster. + * the -N fait pas un grep, donc si file deteled ou modified entre temps, + * bah il le voit pas. Ca veut dire aussi que si y'a pas -N, et bien + * glimpse fait des grep si le fichier a ete modifié entre temps pour + * toujours filer quelque chose de valide (pas de false positive, mais + * y'a quand meme peut etre des miss). Est ce qu'il utilise la date du + * fichier pour eviter de faire des grep inutile ? + * the -N can actually return wrong result. cos a file may + * contain "peter norvig" + * => better to not use -N at first + * + * - -N also just show the filename on output + * - -l show just the filename too, but the files are still searched so + * at least no false positives. + * - if use -z for glimpseindex, dont forget the -z too for glimpse + * - -W for boolean and queries to not be done on line level but file level + * + * query langage: good;bad for conjunction. good,bad for disjunction. + * + * ex: glimpse -y -H . -N -W -w pattern;pattern2 + * + *) +let glimpse query ?(options= default_glimpse_search) dir = + let str_options = s_of_glimpse_options options in + let res = + Common.cmd_to_list + (spf "glimpse -y -H %s -N -W %s '%s'" dir str_options query) in + res + +(* grep -i -l -I *) +let grep query = + raise Todo diff --git a/commons/interfaces.ml b/commons/interfaces.ml new file mode 100644 index 0000000..bbef599 --- /dev/null +++ b/commons/interfaces.ml @@ -0,0 +1,194 @@ +open Common.BasicType + +(*****************************************************************************) +(* TypeClass via module signature. *) +(*****************************************************************************) +(* + * Use this not so much for functors, I hate functors, but + * more to force me to have consistent naming of stuff. + * + * It's related to objet.ml in some way, but use a different scheme. + * + * src: (strongly) inspired by Jane Street core lib, which in turn + * may have been strongly inspired by Java Interfaces or Haskell + * TypeClass. + * + * + * + * Example of use in .mli: + * + * open Interfaces + * include Stringable with type stringable = t + * include Comparable with type comparable = t + * + * Example of use in .ml: + * + * type xxx + * type stringable = xxx + * let of_string = bool_of_string + * let to_string = string_of_bool + * + * + * No this file is not about (graphical) user interface. See gui.ml for that. + * + * + * todo? but as in type class, or object, can not have default method + * with this scheme ? + *) + + + +(*****************************************************************************) +(* Basic *) +(*****************************************************************************) + +(* note: less need for cloneable, copyable as in Java. Only needed + * when use ref, but refs should be avoided anyway so better not to + * encourage it. + * + * Often found this in haskell: + * + * data x = ... deriving (Read, Show, Eq, Ord, Enum, Bounded) + * + * Apparently this is what is considered basic by haskell. + *) + + +module type Check_able = sig + type checkable + val invariant: checkable -> unit (* raise exception *) +end + + + +(* Normally should not use the '=' of ocaml. cf common.mli on this issue. *) +module type Eq_able = sig + type eqable + val equal : eqable -> eqable -> bool + (* Jane Street have far more (complex) stuff for this typeclass *) + + val (=*=): eqable -> eqable -> bool +end + + + +(* Same, should not use compare normally, dangerous when evolve code. + * Called Ord in haskell. Inherit Eq normally. + *) +module type Compare_able = sig + type compareable + val compare: compareable -> compareable -> bool +end +(* Jane street have also some binable, sexpable *) + + +(* Haskell have lots of related type class after Num such as + * Real, Fractional, Integral, RealFrac, Floating, RealFloat + *) +module type Num_able = sig + type numable + (* +, -, etc *) +end + + + +(*****************************************************************************) +(* Show/read related *) +(*****************************************************************************) + + +(* Called show/read in haskell *) +module type String_able = sig + type stringable + val of_string : string -> stringable + val to_string : stringable -> string +end + +module type Debug_able = sig + type debugable + val debug: debugable -> string +end + + +module type XML_able = sig + type xmlable + val of_xml: string -> xmlable + val to_xml: xmlable -> string +end +(* Jane street have also some BIN_able, and SEXP_able (but no sex_able) *) + +module type File_able = sig + type fileable + val load: filename -> fileable + val save: fileable -> filename -> unit +end + +(* a.k.a Marshall_able *) +module type Serialize_able = sig + type serializeable + val serialize: serializeable -> string + val unserialize: string -> serializeable +end + + +module type Open_able = sig + type openable + val openfile: filename -> openable + val close: openable -> unit +end + +(*****************************************************************************) +(* Other *) +(*****************************************************************************) + +(* This is related to ocollection.ml in some way, but use a different scheme *) + +(* Require Constructor class ? So can not do it ? apparently can. Note the + * 'b which is not declareted but seems to pose no problem to ocamlc. + *) +module type Map_able = sig + type 'a mapable + val map: ('a -> 'b) -> 'a mapable -> 'b mapable +end + +module type Iter_able = sig + type 'a iterable + val iter: ('a -> unit) -> 'a iterable -> unit +end + + +(* testable ? actionable ? *) + +(* *) + +(* monad ? functor *) + + + +(*****************************************************************************) +(* Idea taken from Jane Street Core library, slightly changed. + * + * It's another way to organize data structures, module instead of objects. + * It's also the Java way. + * + * It makes some code looks a little bit like Haskell* typeclass. + * + *) + +(* In Jane Street they put each interface in its own file but then have to + * do that: + * + * module type Stringable = Stringable.S + * module type Comparable = Comparable.S + * module type Floatable = Floatable.S + * module type Hashable = Hashable.S + * module type Infix_comparators = Comparable.Infix + * module type Monad = Monad.S + * module type Robustly_comparable = Robustly_comparable.S + * module type Setable = Setable.S + * module type Sexpable = Sexpable.S + * module type Binable = Binable.S + * + * And I dont like having too much files, especially as all those xxable + * end with able, not start, so don't see them together in the directory. + *) diff --git a/commons/license.txt b/commons/license.txt new file mode 100644 index 0000000..67b72ca --- /dev/null +++ b/commons/license.txt @@ -0,0 +1,520 @@ +The Library is distributed under the terms of the GNU Lesser General +Public License version 2.1 (included below). + +As a special exception to the GNU Lesser General Public License, you +may link, statically or dynamically, a "work that uses the Library" +with a publicly distributed version of the Library to produce an +executable file containing portions of the Library, and distribute that +executable file under terms of your choice, without any of the additional +requirements listed in clause 6 of the GNU Lesser General Public License. +By "a publicly distributed version of the Library", we mean either the +unmodified Library as distributed by the authors, or a modified version +of the Library that is distributed under the conditions defined in clause +3 of the GNU Lesser General Public License. This exception does not +however invalidate any other reasons why the executable file might be +covered by the GNU Lesser General Public License. + +--------------------------------------------------------------------------- + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/commons/oarray.ml b/commons/oarray.ml new file mode 100644 index 0000000..875ff51 --- /dev/null +++ b/commons/oarray.ml @@ -0,0 +1,45 @@ +open Common + +open Osequence + +(* growing array ? initialise with None, + * and generate exception when not defined or have an arraydefault + * update: can use dynArray ? + *) + +(* !!take care!!, this is not a pure data structure *) +class ['a] oarray n el = +object(o: 'o) + inherit ['a] osequence + + val data = Array.make n el + + method empty = raise Todo + method add (i,v) = + Array.set data i v; + o + + method iter f = + Array.iteri (curry f) data + method view = raise Todo + + method assoc i = + Array.get data i + + method null = raise Todo + method nth = raise Todo + method mem = raise Todo + method last = raise Todo + method first = raise Todo + method delkey = raise Todo + method del = raise Todo + method fromlist = raise Todo + method length = + Array.length data + + (* method create: int -> 'a -> 'o = + raise Todo + *) + (* method put: make more explicit the fact that array do side effect *) +end + diff --git a/commons/oarray.mli b/commons/oarray.mli new file mode 100644 index 0000000..cec6952 --- /dev/null +++ b/commons/oarray.mli @@ -0,0 +1,28 @@ +(* !!take care!!, this is not a pure data structure *) + +class ['a] oarray : int -> 'a -> +object ('o) + inherit ['a] Osequence.osequence + + (* ocollection concrete instantiation of virtual methods *) + method empty : 'o + method add : (int * 'a) -> 'o + + method iter : (int * 'a -> unit) -> unit + method view : (int * 'a, 'o) Ocollection.view + + method del : (int * 'a) -> 'o + method mem : int * 'a -> bool + method null : bool + + + (* oassoc concrete instantiation of virtual methods *) + method assoc : int -> 'a + method delkey : int -> 'o + + (* osequence concrete instantiation of virtual methods *) + method first : 'a + method last : 'a + method nth : int -> 'a + +end diff --git a/commons/oassoc.ml b/commons/oassoc.ml new file mode 100644 index 0000000..b64241e --- /dev/null +++ b/commons/oassoc.ml @@ -0,0 +1,40 @@ +open Ocollection + +(* assoc, also called map or dictionnary *) +class virtual ['a,'b] oassoc = +object(o: 'o) + inherit ['a * 'b] ocollection + + method virtual assoc: 'a -> 'b + method virtual delkey: 'a -> 'o + + (* pre: must be in *) + method replkey: ('a * 'b) -> 'o = + fun (k,v) -> o#add (k,v) + + (* pre: must not be in *) + (* method add: ('a * 'b) -> 'o = *) + + (* method virtual keys: 'a oset *) + + method find: 'a -> 'b = fun k -> + o#assoc k + + method haskey: 'a -> bool = fun k -> + try (ignore(o#assoc k); true) + with Not_found -> false + + method apply: 'a -> ('b -> 'b) -> 'o = fun k f -> + let old = o#assoc k in + o#replkey (k, f old) + + (* apply default, assoc_default, take in class parameters a default value *) + method apply_with_default: 'a -> ('b -> 'b) -> (unit -> 'b) -> 'o = + fun k f default -> + let old = + try o#assoc k + with Not_found -> default () + in + o#replkey (k, f old) + +end diff --git a/commons/oassoc.mli b/commons/oassoc.mli new file mode 100644 index 0000000..50b533b --- /dev/null +++ b/commons/oassoc.mli @@ -0,0 +1,17 @@ + +class virtual ['a, 'b] oassoc : +object ('o) + inherit ['a * 'b] Ocollection.ocollection + + method virtual assoc : 'a -> 'b + method virtual delkey : 'a -> 'o + + method find : 'a -> 'b + + method haskey : 'a -> bool + method replkey : 'a * 'b -> 'o + + method apply : 'a -> ('b -> 'b) -> 'o + method apply_with_default : 'a -> ('b -> 'b) -> (unit -> 'b) -> 'o + +end diff --git a/commons/oassoc_buffer.ml b/commons/oassoc_buffer.ml new file mode 100644 index 0000000..b9f63a5 --- /dev/null +++ b/commons/oassoc_buffer.ml @@ -0,0 +1,124 @@ +open Common + +open Oassoc + +open Oassocb +open Osetb + +(* todo: limit number of entries, and erase all (then better do a ltu) + * todo: another cache that behave as in lfs1, + * every 100 operation do a flush + * + * todo: choose between oassocb and oassoch ? + *) + +(* !!take care!!: this class has side effect, not a pure oassoc *) +(* can not make it pure, cos the assoc have side effect on the cache *) +class ['a,'b] oassoc_buffer max cached = +object(o) + inherit ['a,'b] oassoc + + val counter = ref 0 + val cache = ref (new oassocb []) + val dirty = ref (new osetb Setb.empty) + val wrapped = ref cached + + method private myflush = + !dirty#iter (fun k -> + wrapped := !wrapped#add (k, !cache#assoc k) + ); + dirty := (new osetb Setb.empty); + cache := (new oassocb []); + counter := 0; + + method misc_op_hook2 = o#myflush + + method empty = + raise Todo + method add (k,v) = + cache := !cache#add (k,v); + dirty := !dirty#add k; + incr counter; + if !counter > max then o#myflush; + o + + method iter f = + o#myflush; (* bugfix: have to flush !!! *) + !wrapped#iter f + + + method length = + o#myflush; + !wrapped#length + + method view = + raise Todo + + method del (k,v) = + cache := !cache#del (k,v); + (* TODO as for delkey, do a try over wrapped *) + wrapped := !wrapped#del (k,v); + dirty := !dirty#del k; + o + method mem e = raise Todo + method null = raise Todo + + method assoc k = + try !cache#assoc k + with Not_found -> + (* may launch Not_found, but this time, dont catch it *) + let v = !wrapped#assoc k in + begin + cache := !cache#add (k,v); + (* otherwise can use too much mem *) + incr counter; + if !counter > max then o#myflush; + v + end + + method delkey k = + cache := !cache#delkey k; + (* sometimes have not yet flushed, so may not be yet in, (could + * also flush in place of doing try). + * + * TODO would be better to see if was in cache (in case mean that + * perhaps not flushed and do try and in other case just cos del + * (without try) cos forcement flushed ou was an error *) + begin + try wrapped := !wrapped#delkey k + with Not_found -> () + end; + dirty := !dirty#del k; + o + +end + + +(* +class ['a,'b] oassoc_cache cache cached max = + object(o) + inherit ['a,'b] oassoc + + val full = ref 0 + val max = max + val cache = cache + val cached = cached + val lru = TODO + + val data = Hashtbl.create 100 + + method empty = raise Todo + method add (k,v) = (Hashtbl.add data k v; o) + method iter f = cached#iter f + method view = raise Todo + + method del (k,v) = (cache#del (k,v); cached#del (k,v); o) + method mem e = raise Todo + method null = raise Todo + + method assoc k = Hashtbl.find data k + method delkey k = (cache#delkey (k,v); cached#del (k,v); o) +end +*) + + diff --git a/commons/oassoc_buffer.mli b/commons/oassoc_buffer.mli new file mode 100644 index 0000000..3b4712b --- /dev/null +++ b/commons/oassoc_buffer.mli @@ -0,0 +1,28 @@ +(* !!take care!!: this classe have side effect, not a pure oassoc *) +class ['a, 'b] oassoc_buffer : + int -> + (< add : 'a * 'b -> 'd; assoc : 'a -> 'b; del : 'a * 'b -> 'd; + delkey : 'a -> 'd; iter : ('a * 'b -> unit) -> unit; length : int; .. > + as 'd) -> +object ('o) + inherit ['a,'b] Oassoc.oassoc + + (* ocollection concrete instantiation of virtual methods *) + method empty : 'o + method add : 'a * 'b -> 'o + + method iter : ('a * 'b -> unit) -> unit + method view : ('a * 'b, 'o) Ocollection.view + + method del : 'a * 'b -> 'o + method mem : 'a * 'b -> bool + method null : bool + + (* oassoc concrete instantiation of virtual methods *) + method assoc : 'a -> 'b + method delkey : 'a -> 'o + + (* ugly, from objet class, extension trick *) + method private myflush : unit + method misc_op_hook2 : unit +end diff --git a/commons/oassocb.ml b/commons/oassocb.ml new file mode 100644 index 0000000..f218b46 --- /dev/null +++ b/commons/oassocb.ml @@ -0,0 +1,24 @@ +open Common + +open Oassoc + +class ['a,'b] oassocb xs = + object(o) + inherit ['a,'b] oassoc + + val data = Mapb.empty + + method empty = {< data = Mapb.empty >} + method add (k,v) = {< data = Mapb.add k v data >} + method replkey (k,v) = {< data = Mapb.add k v (Mapb.remove k data) >} + method iter f = Mapb.iter (curry f) data + method view = raise Todo + + method del (k,v) = {< data = Mapb.remove k data >} + method mem e = raise Todo + method null = (Mapb.height data = 0) + + method assoc k = Mapb.find k data + method delkey k = {< data = Mapb.remove k data >} +end + diff --git a/commons/oassocbdb.ml b/commons/oassocbdb.ml new file mode 100644 index 0000000..17dea84 --- /dev/null +++ b/commons/oassocbdb.ml @@ -0,0 +1,119 @@ +open Common + +open Bdb + +open Oassoc + +(* !!take care!!: this class does side effect, not a pure oassoc + * + * The fv/unv are to give the opportunity to translate the value from + * the dbm, before marshalling. Cf oassocdbm.mli for more about this. + * + * Quite similar to oassocdbm.ml. New: Take transact argument. + *) +class ['a,'b] oassoc_btree db namedb transact (*fkey unkey*) fv unv = +let namedb = if namedb = "" then "" else "(" ^ namedb ^ ")" in +object(o) + inherit ['a,'b] oassoc + + val data = db + + method empty = + raise Todo + + method private add2 (k,v) = + (* pr2 (fkey k); *) + (* pr2 (debugv v); *) + + (* try Db.del data None + (Marshal.to_string k []) [] + with Not_found -> ()); + *) + let k' = Marshal.to_string k [] in + let v' = Marshal.to_string (fv v) [Marshal.Closures] in (* still clos? *) + Db.put data (transact()) k' v' []; + (* minsky wrapper ? Db.put data ~txn:(transact()) ~key:k' ~data:v' *) + o + method add x = + Common.profile_code ("Btree.add" ^ namedb) (fun () -> o#add2 x) + + (* bugfix: if not tail call (because of a try for instance), + * then strange behaviour in native mode + *) + method private iter2 f = + let dbc = Cursor.db_cursor db (transact()) [] in + (* minsky wrapper? Cursor.create ~writecursor:false ~txn:(transact()) db *) + let rec aux dbc = + if + (try + let a = Cursor.dbc_get dbc [Cursor.DB_NEXT] in + (* minsky ? Cursor.get dbc Cursor.NEXT [] *) + let key = (* unkey *) Marshal.from_string (fst a) 0 in + let valu = unv (Marshal.from_string (snd a) 0) in + f (key, valu); + true + with Failure "ending" -> false + ) + then aux dbc + else () + + in + aux dbc; + Cursor.dbc_close dbc (* minsky Cursor.close dbc *) + + method iter x = + Common.profile_code ("Btree.iter" ^ namedb) (fun () -> o#iter2 x) + + method view = + raise Todo + + + + method private length2 = + let dbc = Cursor.db_cursor db (transact()) [] in + + let count = ref 0 in + let rec aux dbc = + if ( + try + let _a = Cursor.dbc_get dbc [Cursor.DB_NEXT] in + incr count; + true + with Failure "ending" -> false + ) + then aux dbc + else () + + in + aux dbc; + Cursor.dbc_close dbc; + !count + + method length = + Common.profile_code ("Btree.length" ^ namedb) (fun () -> o#length2) + + + method del (k,v) = raise Todo + method mem e = raise Todo + method null = raise Todo + + method private assoc2 k = + try + let k' = Marshal.to_string k [] in + let vget = Db.get data (transact()) k' [] in + (* minsky ? Db.get data ~txn:(transact() *) + unv (Marshal.from_string vget 0) + with Not_found -> + log3 ("pb assoc with k = " ^ (Dumper.dump k)); + raise Not_found + method assoc x = + Common.profile_code ("Btree.assoc" ^ namedb) (fun () -> o#assoc2 x) + + method private delkey2 k = + let k' = Marshal.to_string k [] in + Db.del data (transact()) k' []; + o + method delkey x = + Common.profile_code ("Btree.delkey" ^ namedb) (fun () -> o#delkey2 x) + +end diff --git a/commons/oassocbdb.mli b/commons/oassocbdb.mli new file mode 100644 index 0000000..7978e80 --- /dev/null +++ b/commons/oassocbdb.mli @@ -0,0 +1,25 @@ +(* !!take care!!: this class does side effect, not a pure oassoc *) +class ['a,'b] oassoc_btree : + Bdb.db -> + string (* db name, for profiling *) -> + (unit -> Bdb.dbtxn option) (* transaction handler *) -> + ('b -> 'e) -> ('e -> 'b) (* marshaller/unmarshaller wrappers *) -> +object('o) + inherit ['a,'b] Oassoc.oassoc + + (* ocollection concrete instantiation of virtual methods *) + method empty : 'o + method add : 'a * 'b -> 'o + + method iter : ('a * 'b -> unit) -> unit + method view : ('a * 'b, 'o) Ocollection.view + + method del : 'a * 'b -> 'o + method mem : 'a * 'b -> bool + method null : bool + + (* oassoc concrete instantiation of virtual methods *) + method assoc : 'a -> 'b + method delkey : 'a -> 'o + +end diff --git a/commons/oassocdbm.ml b/commons/oassocdbm.ml new file mode 100644 index 0000000..30a11ab --- /dev/null +++ b/commons/oassocdbm.ml @@ -0,0 +1,72 @@ +open Common + +open Oassoc + +(* !!take care!!: this class does side effect, not a pure oassoc. + * + * The fv/unv are here to give the opportunity to translate the value + * from the dbm, before marshalling. This is useful for instance if you + * want to store objects such as oset. Indeed we cant marshall + * conveniently functions/closures, and so objects (you can but you can + * load them back only from the same binary, which limits the + * practicallibity of the approach). You have to translate them to + * traditionnal data structures before marshalling them, and you have + * to rebuild the object from the traditionnal data structure when you + * get them from the dbm. Hence fv/unv. You can do the same for the key + * with fkey/unkey, but as key are usually simple data structures, + * there is less need for them, so I have commented them. *) +class ['a,'b] oassocdbm xs db (*fkey unkey*) fv unv = +object(o) + inherit ['a,'b] oassoc + + val db = db + + method empty = raise Todo + method add (k,v) = + (* pr2 (fkey k); *) + (* pr2 (debugv v); *) + + (* try Db.del data None + (Marshal.to_string k []) [] + with Not_found -> ()); + *) + let k' = Marshal.to_string k [] in + let v' = (Marshal.to_string (fv v) [(*Marshal.Closures*)]) in + (try Dbm.add db k' v' + with _ -> Dbm.replace db k' v' + ); + o + + method iter f = + db +> Dbm.iter (fun key data -> + let k' = (* unkey *) Marshal.from_string key 0 in + let v' = unv (Marshal.from_string data 0) in + f (k', v') + ) + + method view = raise Todo + + method del (k,v) = raise Todo + method mem e = raise Todo + method null = raise Todo + + method assoc k = + let k' = Marshal.to_string k [] in + unv (Marshal.from_string (Dbm.find db k') 0) + + method delkey k = + let k' = Marshal.to_string k [] in + try + Dbm.remove db k'; + o + with Dbm.Dbm_error "dbm_delete" -> + raise Not_found +end + + +let create_dbm metapath dbname = + let x_db = Dbm.opendbm (metapath^dbname) [Dbm.Dbm_create;Dbm.Dbm_rdwr] 0o777 + in + let assoc = new oassocdbm [] x_db id id in + x_db, assoc + diff --git a/commons/oassocdbm.mli b/commons/oassocdbm.mli new file mode 100644 index 0000000..447669a --- /dev/null +++ b/commons/oassocdbm.mli @@ -0,0 +1,28 @@ +(* !!take care!!: this class does side effect, not a pure oassoc *) +class ['a, 'b] oassocdbm : + 'd -> + Dbm.t -> + ('b -> 'e) -> + ('e -> 'b) -> +object ('o) + inherit ['a,'b] Oassoc.oassoc + + (* ocollection concrete instantiation of virtual methods *) + method empty : 'o + method add : 'a * 'b -> 'o + + method iter : ('a * 'b -> unit) -> unit + method view : ('a * 'b, 'o) Ocollection.view + + method del : 'a * 'b -> 'o + method mem : 'a * 'b -> bool + method null : bool + + (* oassoc concrete instantiation of virtual methods *) + method assoc : 'a -> 'b + method delkey : 'a -> 'o + +end + +val create_dbm : + Common.filename -> string -> Dbm.t * ('a, 'b) oassocdbm diff --git a/commons/oassoch.ml b/commons/oassoch.ml new file mode 100644 index 0000000..43cdb07 --- /dev/null +++ b/commons/oassoch.ml @@ -0,0 +1,34 @@ +open Common + +open Oassoc + +(* !!take care!!: this class does side effect, not a pure oassoc *) +class ['a,'b] oassoch xs = + let h = Common.hash_of_list xs in + object(o) + inherit ['a,'b] oassoc + + val data = h + + method empty = {< data = Hashtbl.create 101 >} + method add (k,v) = (Hashtbl.replace data k v; o) (* not add cos add make iter sux *) + + (* redefine replkey to be more efficient than default. With hash, don't need + to delkey before add, replace do both action directly. + *) + method replkey (k,v) = (Hashtbl.replace data k v; o) + method iter f = Hashtbl.iter (curry f) data + method view = raise Todo + + method del (k,v) = (Hashtbl.remove data k; o) + method mem e = raise Todo + method null = (try (Hashtbl.iter (fun k v -> raise ReturnExn) data; false) with ReturnExn -> true) + + method assoc k = + try + Hashtbl.find data k + with Not_found -> (log3 ("pb assoc with k = " ^ (Dumper.dump k)); raise Not_found) + + method delkey k = (Hashtbl.remove data k; o) +end + diff --git a/commons/oassocid.ml b/commons/oassocid.ml new file mode 100644 index 0000000..58171aa --- /dev/null +++ b/commons/oassocid.ml @@ -0,0 +1,20 @@ +open Common +open Oassoc + +(* just a class that behave as fun x -> x *) +class ['a] oassoc_id xs = + object(o) + inherit ['a,'a] oassoc + + method empty = {< >} + method add (k,v) = {< >} + method iter f = raise Todo + method view = raise Todo + + method del (k,v) = {< >} + method mem e = raise Todo + method null = raise Todo + + method assoc k = k + method delkey k = {< >} +end diff --git a/commons/objet.ml b/commons/objet.ml new file mode 100644 index 0000000..273b0f4 --- /dev/null +++ b/commons/objet.ml @@ -0,0 +1,29 @@ +open Common + +(* TypeClass via objects. Cf also now interfaces.ml + * + * todo? get more inspiration from Java to put fundamental interfaces + * here ? such as cloneable, equaable, showable, debugable, etc + *) + +class virtual objet = +object(o:'o) + method invariant: unit -> unit = fun () -> + raise Todo + (* method check: unit -> unit = fun () -> + assert(o#invariant()); + *) + + method of_string: string -> unit = + raise Todo + method to_string: unit -> string = + raise Todo + method debug: unit -> unit = + raise Todo + + method misc_op_hook: unit -> 'o = + raise Todo + + method misc_op_hook2: unit = + () +end diff --git a/commons/objet.mli b/commons/objet.mli new file mode 100644 index 0000000..aa88493 --- /dev/null +++ b/commons/objet.mli @@ -0,0 +1,18 @@ +class virtual objet : +object('o) + method invariant: unit -> unit + (* method check: unit -> unit *) + + method of_string: string -> unit + method to_string: unit -> string + method debug: unit -> unit + + (* ugly (but convenient): those methods allow to extend an interface without + * changing its interface. For instance in oassocbtree I want to + * provide a method to commit, but doing so will mean break the interface + * of oassoc. But if provide the commit code via a misc_op_hook, then + * I will not break the interface. + *) + method misc_op_hook: unit -> 'o + method misc_op_hook2: unit +end diff --git a/commons/ocamlextra/ANSITerminal.ml b/commons/ocamlextra/ANSITerminal.ml new file mode 100644 index 0000000..8fcfa4a --- /dev/null +++ b/commons/ocamlextra/ANSITerminal.ml @@ -0,0 +1,219 @@ +(* File: ANSITerminal.ml + Allow colors, cursor movements, erasing,... under Unix and DOS shells. + ********************************************************************* + + Copyright 2004 by Troestler Christophe + Christophe.Troestler(at)umh.ac.be + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + version 2.1 as published by the Free Software Foundation, with the + special exception on linking described in file LICENSE. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file + LICENSE for more details. +*) +(** See the file ctlseqs.html (unix) + and (for DOS) http://www.ka.net/jmenees/Dos/Ansi.htm + *) + + +open Printf + +(* Erasing *) + +type loc = Above | Below | Screen + +let erase = function + | Above -> print_string "\027[1J" + | Below -> print_string "\027[0J" + | Screen -> print_string "\027[2J" + + +(* Cursor *) + +let set_cursor x y = + if x <= 0 then (if y > 0 then printf "\027[%id" y) + else (* x > 0 *) if y <= 0 then printf "\027[%iG" x + else printf "\027[%i;%iH" y x + +let move_cursor x y = + if x > 0 then printf "\027[%iC" x + else if x < 0 then printf "\027[%iD" (-x); + if y > 0 then printf "\027[%iB" y + else if y < 0 then printf "\027[%iA" (-y) + +let save_cursor () = print_string "\027[s" +let restore_cursor () = print_string "\027[u" + +(* Scrolling *) + +let scroll lines = + if lines > 0 then printf "\027[%iS" lines + else if lines < 0 then printf "\027[%iT" (- lines) + +(* Colors *) + +let autoreset = ref true + +let set_autoreset b = autoreset := b + + +type color = + Black | Red | Green | Yellow | Blue | Magenta | Cyan | White | Default + +type style = + | Reset | Bold | Underlined | Blink | Inverse | Hidden + | Foreground of color + | Background of color + +let black = Foreground Black +let red = Foreground Red +let green = Foreground Green +let yellow = Foreground Yellow +let blue = Foreground Blue +let magenta = Foreground Magenta +let cyan = Foreground Cyan +let white = Foreground White +let default = Foreground Default + +let on_black = Background Black +let on_red = Background Red +let on_green = Background Green +let on_yellow = Background Yellow +let on_blue = Background Blue +let on_magenta = Background Magenta +let on_cyan = Background Cyan +let on_white = Background White +let on_default = Background Default + +let style_to_string = function + | Reset -> "0" + | Bold -> "1" + | Underlined -> "4" + | Blink -> "5" + | Inverse -> "7" + | Hidden -> "8" + | Foreground Black -> "30" + | Foreground Red -> "31" + | Foreground Green -> "32" + | Foreground Yellow -> "33" + | Foreground Blue -> "34" + | Foreground Magenta -> "35" + | Foreground Cyan -> "36" + | Foreground White -> "37" + | Foreground Default -> "39" + | Background Black -> "40" + | Background Red -> "41" + | Background Green -> "42" + | Background Yellow -> "43" + | Background Blue -> "44" + | Background Magenta -> "45" + | Background Cyan -> "46" + | Background White -> "47" + | Background Default -> "49" + + +let print_string style txt = + print_string "\027["; + let s = String.concat ";" (List.map style_to_string style) in + print_string s; + print_string "m"; + print_string txt; + if !autoreset then print_string "\027[0m" + + +let printf style = kprintf (print_string style) + + + +(* On DOS & windows, to enable the ANSI sequences, ANSI.SYS should be + loaded in C:\CONFIG.SYS with a line of the type + + DEVICE = C:\DOS\ANSI.SYS + DEVICEHIGH=C:\WINDOWS\COMMAND\ANSI.SYS + + This routine checks whether the line is present and, if not, it + inserts it and tells the user to reboot. + + On WINNT, one will create a ANSI.NT in the user dir and a + command.com link on the desktop (with Configfilename = our ANSI.NT) + and tell the user to use it. + + REM: that does NOT work under winxp because OCaml programs are not + considered to run in DOS mode only... + + http://support.microsoft.com/default.aspx?scid=kb;en-us;816179 + http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/console_functions.asp +*) + + +(* let is_readable file = *) +(* try close_in(open_in file); true *) +(* with Sys_error _ -> false *) + +(* let config_sys = "C:\\CONFIG.SYS" *) +(* exception OK *) + +(* let win9x () = *) +(* (\* Locate ANSI.SYS *\) *) +(* let ansi_sys = List.find is_readable [ *) +(* "C:\\DOS\\ANSI.SYS"; *) +(* "C:\\WINDOWS\\COMMAND\\ANSI.SYS"; ] in *) +(* (\* Parse CONFIG.SYS to see wether it has the right line *\) *) +(* try *) +(* let re = Str.regexp_case_fold *) +(* ("^DEVICE\\(HIGH\\)?[ \t]*=[ \t]*" ^ ansi_sys ^ "[ \t]*$") in *) +(* let fh = open_in config_sys in *) +(* begin try *) +(* while true do *) +(* if Str.string_match re (input_line fh) 0 then raise OK *) +(* done *) +(* with *) +(* | End_of_file -> *) +(* (\* Correct line not found: add it *\) *) +(* close_in fh; *) +(* raise(Sys_error "win9x") *) +(* | OK -> close_in fh (\* Correct line found, keep going *\) *) +(* end *) +(* with Sys_error _ -> *) +(* (\* config_sys not does not exists or does not contain the right line. *\) *) +(* let fh = open_out_gen [Open_wronly; Open_append; Open_creat; Open_text] *) +(* 0x777 config_sys in *) +(* output_string fh ("DEVICEHIGH=" ^ ansi_sys ^ "\n"); *) +(* close_out fh; *) +(* prerr_endline "Please restart your computer and rerun the program."; *) +(* exit 1 *) + + + +(* let winnt home = *) +(* (\* Locate ANSI.SYS *\) *) +(* let system = *) +(* try Sys.getenv "SystemRoot" *) +(* with Not_found -> "C:\\WINDOWS" in *) +(* let ansi_sys = *) +(* List.find is_readable (List.map (fun s -> Filename.concat system s) *) +(* [ "SYSTEM32\\ANSI.SYS"; ]) in *) +(* (\* Create an ANSI.SYS file in the user dir *\) *) +(* let ansi_nt = Filename.concat home "ANSI.NT" in *) +(* let fh = open_out ansi_nt in *) +(* output_string fh "dosonly\ndevice="; *) +(* output_string fh ansi_sys; *) +(* output_string fh "\ndevice=%SystemRoot%\\system32\\himem.sys *) +(* files=40 *) +(* dos=high, umb *) +(* " ; *) +(* close_out fh; *) +(* (\* Make a command.com link on the desktop *\) *) +(* let fh = open_out (Filename.concat home "command.lnk") in *) +(* close_out fh *) + + +(* let () = *) +(* if Sys.os_type = "Win32" then begin *) +(* try winnt(Sys.getenv "USERPROFILE") (\* WinNT, Win2000, WinXP *\) *) +(* with Not_found -> win9x() (\* Win9x *\) *) +(* end *) diff --git a/commons/ocamlextra/ANSITerminal.mli b/commons/ocamlextra/ANSITerminal.mli new file mode 100644 index 0000000..dd203b3 --- /dev/null +++ b/commons/ocamlextra/ANSITerminal.mli @@ -0,0 +1,107 @@ +(* File: ANSITerminal.mli + + Copyright 2004 Troestler Christophe + Christophe.Troestler(at)umh.ac.be + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + version 2.1 as published by the Free Software Foundation, with the + special exception on linking described in file LICENSE. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file + LICENSE for more details. +*) +(** This module offers basic control of ANSI compliant terminals. + + @author Christophe Troestler + @version 0.3 +*) + +(** {2 Color} *) + +type color = + | Black | Red | Green | Yellow | Blue | Magenta | Cyan | White + | Default (** Default color of the terminal *) + +(** Various styles for the text. [Blink] and [Hidden] may not work on + every terminal. *) +type style = + | Reset + | Bold | Underlined | Blink | Inverse | Hidden + | Foreground of color + | Background of color + +val black : style (** Shortcut for [Foreground Black] *) +val red : style (** Shortcut for [Foreground Red] *) +val green : style (** Shortcut for [Foreground Green] *) +val yellow : style (** Shortcut for [Foreground Yellow] *) +val blue : style (** Shortcut for [Foreground Blue] *) +val magenta : style (** Shortcut for [Foreground Magenta] *) +val cyan : style (** Shortcut for [Foreground Cyan] *) +val white : style (** Shortcut for [Foreground White] *) +val default : style (** Shortcut for [Foreground Default] *) + +val on_black : style (** Shortcut for [Background Black] *) +val on_red : style (** Shortcut for [Background Red] *) +val on_green : style (** Shortcut for [Background Green] *) +val on_yellow : style (** Shortcut for [Background Yellow] *) +val on_blue : style (** Shortcut for [Background Blue] *) +val on_magenta : style (** Shortcut for [Background Magenta] *) +val on_cyan : style (** Shortcut for [Background Cyan] *) +val on_white : style (** Shortcut for [Background White] *) +val on_default : style (** Shortcut for [Background Default] *) + +val set_autoreset : bool -> unit + (** Turns the autoreset feature on and off. It defaults to on. *) + +val print_string : style list -> string -> unit + (** [print_string attr txt] prints the string [txt] with the + attibutes [attr]. After printing, the attributes are + automatically reseted to the defaults, unless autoreset is turned + off. *) + +val printf : style list -> ('a, unit, string, unit) format4 -> 'a + (** [printf attr format arg1 ... argN] prints the arguments + [arg1],...,[argN] according to [format] with the attibutes [attr]. + After printing, the attributes are automatically reseted to the + defaults, unless autoreset is turned off. *) + + +(** {2 Erasing} *) + +type loc = Above | Below | Screen + +val erase : loc -> unit + (** [erase Above] erases everything before the position of the cursor. + [erase Below] erases everything after the position of the cursor. + [erase Screen] erases the whole screen. + *) + + +(** {2 Cursor} *) + +val set_cursor : int -> int -> unit + (** [set_cursor x y] puts the cursor at position [(x,y)], [x] + indicating the column (the leftmost one being 1) and [y] being the + line (the topmost one being 1). If [x <= 0], the [x] coordinate + is unchanged; if [y <= 0], the [y] coordinate is unchanged. *) + +val move_cursor : int -> int -> unit + (** [move_cursor x y] moves the cursor by [x] columns (to the right + if [x > 0], to the left if [x < 0]) and by [y] lines (downwards if + [y > 0] and upwards if [y < 0]). *) + +val save_cursor : unit -> unit + (** [save_cursor()] saves the current position of the cursor. *) +val restore_cursor : unit -> unit + (** [restore_cursor()] replaces the cursor to the position saved + with [save_cursor()]. *) + + +(** {2 Scrolling} *) + +val scroll : int -> unit + (** [scroll n] scrolls the terminal by [n] lines, up (creating new + lines at the bottom) if [n > 0] and down if [n < 0]. *) diff --git a/commons/ocamlextra/dumper.ml b/commons/ocamlextra/dumper.ml new file mode 100644 index 0000000..1540da0 --- /dev/null +++ b/commons/ocamlextra/dumper.ml @@ -0,0 +1,85 @@ +(* Dump an OCaml value into a printable string. + * By Richard W.M. Jones (rich@annexia.org). + * dumper.ml 1.2 2005/02/06 12:38:21 rich Exp + *) + +open Printf +open Obj + +let rec dump r = + if is_int r then + string_of_int (magic r : int) + else ( (* Block. *) + let rec get_fields acc = function + | 0 -> acc + | n -> let n = n-1 in get_fields (field r n :: acc) n + in + let rec is_list r = + if is_int r then ( + if (magic r : int) = 0 then true (* [] *) + else false + ) else ( + let s = size r and t = tag r in + if t = 0 && s = 2 then is_list (field r 1) (* h :: t *) + else false + ) + in + let rec get_list r = + if is_int r then [] + else let h = field r 0 and t = get_list (field r 1) in h :: t + in + let opaque name = + (* XXX In future, print the address of value 'r'. Not possible in + * pure OCaml at the moment. + *) + "<" ^ name ^ ">" + in + + let s = size r and t = tag r in + + (* From the tag, determine the type of block. *) + if is_list r then ( (* List. *) + let fields = get_list r in + "[" ^ String.concat "; " (List.map dump fields) ^ "]" + ) + else if t = 0 then ( (* Tuple, array, record. *) + let fields = get_fields [] s in + "(" ^ String.concat ", " (List.map dump fields) ^ ")" + ) + + (* Note that [lazy_tag .. forward_tag] are < no_scan_tag. Not + * clear if very large constructed values could have the same + * tag. XXX *) + else if t = lazy_tag then opaque "lazy" + else if t = closure_tag then opaque "closure" + else if t = object_tag then ( (* Object. *) + let fields = get_fields [] s in + let clasz, id, slots = + match fields with h::h'::t -> h, h', t | _ -> assert false in + (* No information on decoding the class (first field). So just print + * out the ID and the slots. + *) + "Object #" ^ dump id ^ + " (" ^ String.concat ", " (List.map dump slots) ^ ")" + ) + else if t = infix_tag then opaque "infix" + else if t = forward_tag then opaque "forward" + + else if t < no_scan_tag then ( (* Constructed value. *) + let fields = get_fields [] s in + "Tag" ^ string_of_int t ^ + " (" ^ String.concat ", " (List.map dump fields) ^ ")" + ) + else if t = string_tag then ( + "\"" ^ String.escaped (magic r : string) ^ "\"" + ) + else if t = double_tag then ( + string_of_float (magic r : float) + ) + else if t = abstract_tag then opaque "abstract" + else if t = custom_tag then opaque "custom" + else if t = final_tag then opaque "final" + else failwith ("dump: impossible tag (" ^ string_of_int t ^ ")") + ) + +let dump v = dump (repr v) diff --git a/commons/ocamlextra/dumper.mli b/commons/ocamlextra/dumper.mli new file mode 100644 index 0000000..d74853b --- /dev/null +++ b/commons/ocamlextra/dumper.mli @@ -0,0 +1,6 @@ +(* Dump an OCaml value into a printable string. + * By Richard W.M. Jones (rich@annexia.org). + * dumper.mli 1.1 2005/02/03 23:07:47 rich Exp + *) + +val dump : 'a -> string diff --git a/commons/ocamlextra/dynArray.ml b/commons/ocamlextra/dynArray.ml new file mode 100644 index 0000000..a3ea6c8 --- /dev/null +++ b/commons/ocamlextra/dynArray.ml @@ -0,0 +1,448 @@ +(* + * DynArray - Resizeable Ocaml arrays + * Copyright (C) 2003 Brian Hurt + * Copyright (C) 2003 Nicolas Cannasse + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version, + * with the special exception on linking described in file LICENSE. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) + +type resizer_t = currslots:int -> oldlength:int -> newlength:int -> int + +type 'a intern + +external ilen : 'a intern -> int = "%obj_size" +let idup (x : 'a intern) = if ilen x = 0 then x else (Obj.magic (Obj.dup (Obj.repr x)) : 'a intern) +let imake tag len = (Obj.magic (Obj.new_block tag len) : 'a intern) +external iget : 'a intern -> int -> 'a = "%obj_field" +external iset : 'a intern -> int -> 'a -> unit = "%obj_set_field" + +type 'a t = { + mutable arr : 'a intern; + mutable len : int; + mutable resize: resizer_t; +} + +exception Invalid_arg of int * string * string + +let invalid_arg n f p = raise (Invalid_arg (n,f,p)) + +let length d = d.len + +let exponential_resizer ~currslots ~oldlength ~newlength = + let rec doubler x = if x >= newlength then x else doubler (x * 2) in + let rec halfer x = if x / 2 < newlength then x else halfer (x / 2) in + if newlength = 1 then + 1 + else if currslots = 0 then + doubler 1 + else if currslots < newlength then + doubler currslots + else + halfer currslots + +let step_resizer step = + if step <= 0 then invalid_arg step "step_resizer" "step"; + (fun ~currslots ~oldlength ~newlength -> + if currslots < newlength || newlength < (currslots - step) + then + (newlength + step - (newlength mod step)) + else + currslots) + +let conservative_exponential_resizer ~currslots ~oldlength ~newlength = + let rec doubler x = if x >= newlength then x else doubler (x * 2) in + let rec halfer x = if x / 2 < newlength then x else halfer (x / 2) in + if currslots < newlength then begin + if newlength = 1 then + 1 + else if currslots = 0 then + doubler 1 + else + doubler currslots + end else if oldlength < newlength then + halfer currslots + else + currslots + +let default_resizer = conservative_exponential_resizer + +let changelen (d : 'a t) newlen = + let oldsize = ilen d.arr in + let r = d.resize + ~currslots:oldsize + ~oldlength:d.len + ~newlength:newlen + in + (* We require the size to be at least large enough to hold the number + * of elements we know we need! + *) + let newsize = if r < newlen then newlen else r in + if newsize <> oldsize then begin + let newarr = imake 0 newsize in + let cpylen = (if newlen < d.len then newlen else d.len) in + for i = 0 to cpylen - 1 do + iset newarr i (iget d.arr i); + done; + d.arr <- newarr; + end; + d.len <- newlen + +let compact d = + if d.len <> ilen d.arr then begin + let newarr = imake 0 d.len in + for i = 0 to d.len - 1 do + iset newarr i (iget d.arr i) + done; + d.arr <- newarr; + end + +let create() = + { + resize = default_resizer; + len = 0; + arr = imake 0 0; + } + +let make initsize = + if initsize < 0 then invalid_arg initsize "make" "size"; + { + resize = default_resizer; + len = 0; + arr = imake 0 initsize; + } + +let init initlen f = + if initlen < 0 then invalid_arg initlen "init" "len"; + let arr = imake 0 initlen in + for i = 0 to initlen-1 do + iset arr i (f i) + done; + { + resize = default_resizer; + len = initlen; + arr = arr; + } + +let set_resizer d resizer = + d.resize <- resizer + +let get_resizer d = + d.resize + +let empty d = + d.len = 0 + +let get d idx = + if idx < 0 || idx >= d.len then invalid_arg idx "get" "index"; + iget d.arr idx + +let last d = + if d.len = 0 then invalid_arg 0 "last" ""; + iget d.arr (d.len - 1) + +let set d idx v = + if idx < 0 || idx >= d.len then invalid_arg idx "set" "index"; + iset d.arr idx v + +let insert d idx v = + if idx < 0 || idx > d.len then invalid_arg idx "insert" "index"; + if d.len = ilen d.arr then changelen d (d.len + 1) else d.len <- d.len + 1; + if idx < d.len - 1 then begin + for i = d.len - 1 downto idx do + iset d.arr (i+1) (iget d.arr i) + done; + end; + iset d.arr idx v + +let add d v = + if d.len = ilen d.arr then changelen d (d.len + 1) else d.len <- d.len + 1; + iset d.arr (d.len - 1) v + +let delete d idx = + if idx < 0 || idx >= d.len then invalid_arg idx "delete" "index"; + let oldsize = ilen d.arr in + (* we don't call changelen because we want to blit *) + let r = d.resize + ~currslots:oldsize + ~oldlength:d.len + ~newlength:(d.len - 1) + in + let newsize = (if r < d.len - 1 then d.len - 1 else r) in + if oldsize <> newsize then begin + let newarr = imake 0 newsize in + for i = 0 to idx - 1 do + iset newarr i (iget d.arr i); + done; + for i = idx to d.len - 2 do + iset newarr i (iget d.arr (i+1)); + done; + d.arr <- newarr; + end else begin + for i = idx to d.len - 2 do + iset d.arr i (iget d.arr (i+1)); + done; + iset d.arr (d.len - 1) (Obj.magic 0) + end; + d.len <- d.len - 1 + + +let delete_range d idx len = + if len < 0 then invalid_arg len "delete_range" "length"; + if idx < 0 || idx + len > d.len then invalid_arg idx "delete_range" "index"; + let oldsize = ilen d.arr in + (* we don't call changelen because we want to blit *) + let r = d.resize + ~currslots:oldsize + ~oldlength:d.len + ~newlength:(d.len - len) + in + let newsize = (if r < d.len - len then d.len - len else r) in + if oldsize <> newsize then begin + let newarr = imake 0 newsize in + for i = 0 to idx - 1 do + iset newarr i (iget d.arr i); + done; + for i = idx to d.len - len - 1 do + iset newarr i (iget d.arr (i+len)); + done; + d.arr <- newarr; + end else begin + for i = idx to d.len - len - 1 do + iset d.arr i (iget d.arr (i+len)); + done; + for i = d.len - len to d.len - 1 do + iset d.arr i (Obj.magic 0) + done; + end; + d.len <- d.len - len + +let clear d = + d.len <- 0; + d.arr <- imake 0 0 + +let delete_last d = + if d.len <= 0 then invalid_arg 0 "delete_last" ""; + (* erase for GC, in case changelen don't resize our array *) + iset d.arr (d.len - 1) (Obj.magic 0); + changelen d (d.len - 1) + +let rec blit src srcidx dst dstidx len = + if len < 0 then invalid_arg len "blit" "len"; + if srcidx < 0 || srcidx + len > src.len then invalid_arg srcidx "blit" "source index"; + if dstidx < 0 || dstidx > dst.len then invalid_arg dstidx "blit" "dest index"; + let newlen = dstidx + len in + if newlen > ilen dst.arr then begin + (* this case could be inlined so we don't blit on just-copied elements *) + changelen dst newlen + end else begin + if newlen > dst.len then dst.len <- newlen; + end; + (* same array ! we need to copy in reverse order *) + if src.arr == dst.arr && dstidx > srcidx then + for i = len - 1 downto 0 do + iset dst.arr (dstidx+i) (iget src.arr (srcidx+i)); + done + else + for i = 0 to len - 1 do + iset dst.arr (dstidx+i) (iget src.arr (srcidx+i)); + done + +let append src dst = + blit src 0 dst dst.len src.len + +let to_list d = + let rec loop idx accum = + if idx < 0 then accum else loop (idx - 1) (iget d.arr idx :: accum) + in + loop (d.len - 1) [] + +let to_array d = + if d.len = 0 then begin + (* since the empty array is an atom, we don't care if float or not *) + [||] + end else begin + let arr = Array.make d.len (iget d.arr 0) in + for i = 1 to d.len - 1 do + Array.unsafe_set arr i (iget d.arr i) + done; + arr; + end + +let of_list lst = + let size = List.length lst in + let arr = imake 0 size in + let rec loop idx = function + | h :: t -> iset arr idx h; loop (idx + 1) t + | [] -> () + in + loop 0 lst; + { + resize = default_resizer; + len = size; + arr = arr; + } + +let of_array src = + let size = Array.length src in + let is_float = Obj.tag (Obj.repr src) = Obj.double_array_tag in + let arr = (if is_float then begin + let arr = imake 0 size in + for i = 0 to size - 1 do + iset arr i (Array.unsafe_get src i); + done; + arr + end else + (* copy the fields *) + idup (Obj.magic src : 'a intern)) + in + { + resize = default_resizer; + len = size; + arr = arr; + } + +let copy src = + { + resize = src.resize; + len = src.len; + arr = idup src.arr; + } + +let sub src start len = + if len < 0 then invalid_arg len "sub" "len"; + if start < 0 || start + len > src.len then invalid_arg start "sub" "start"; + let arr = imake 0 len in + for i = 0 to len - 1 do + iset arr i (iget src.arr (i+start)); + done; + { + resize = src.resize; + len = len; + arr = arr; + } + +let iter f d = + for i = 0 to d.len - 1 do + f (iget d.arr i) + done + +let iteri f d = + for i = 0 to d.len - 1 do + f i (iget d.arr i) + done + +let filter f d = + let l = d.len in + let a = imake 0 l in + let a2 = d.arr in + let p = ref 0 in + for i = 0 to l - 1 do + let x = iget a2 i in + if f x then begin + iset a !p x; + incr p; + end; + done; + d.len <- !p; + d.arr <- a + +let index_of f d = + let rec loop i = + if i >= d.len then + raise Not_found + else + if f (iget d.arr i) then + i + else + loop (i+1) + in + loop 0 + +let map f src = + let arr = imake 0 src.len in + for i = 0 to src.len - 1 do + iset arr i (f (iget src.arr i)) + done; + { + resize = src.resize; + len = src.len; + arr = arr; + } + +let mapi f src = + let arr = imake 0 src.len in + for i = 0 to src.len - 1 do + iset arr i (f i (iget src.arr i)) + done; + { + resize = src.resize; + len = src.len; + arr = arr; + } + +let fold_left f x a = + let rec loop idx x = + if idx >= a.len then x else loop (idx + 1) (f x (iget a.arr idx)) + in + loop 0 x + +let fold_right f a x = + let rec loop idx x = + if idx < 0 then x + else loop (idx - 1) (f (iget a.arr idx) x) + in + loop (a.len - 1) x + +let enum d = + let rec make start = + let idxref = ref 0 in + let next () = + if !idxref >= d.len then + raise Enum.No_more_elements + else + let retval = iget d.arr !idxref in + incr idxref; + retval + and count () = + if !idxref >= d.len then 0 + else d.len - !idxref + and clone () = + make !idxref + in + Enum.make ~next:next ~count:count ~clone:clone + in + make 0 + +let of_enum e = + if Enum.fast_count e then begin + let c = Enum.count e in + let arr = imake 0 c in + Enum.iteri (fun i x -> iset arr i x) e; + { + resize = default_resizer; + len = c; + arr = arr; + } + end else + let d = make 0 in + Enum.iter (add d) e; + d + +let unsafe_get a n = + iget a.arr n + +let unsafe_set a n x = + iset a.arr n x diff --git a/commons/ocamlextra/dynArray.mli b/commons/ocamlextra/dynArray.mli new file mode 100644 index 0000000..a2542aa --- /dev/null +++ b/commons/ocamlextra/dynArray.mli @@ -0,0 +1,281 @@ +(* + * DynArray - Resizeable Ocaml arrays + * Copyright (C) 2003 Brian Hurt + * Copyright (C) 2003 Nicolas Cannasse + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version, + * with the special exception on linking described in file LICENSE. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) + +(** Dynamic arrays. + + A dynamic array is equivalent to a OCaml array that will resize itself + when elements are added or removed, except that floats are boxed and + that no initialization element is required. +*) + +type 'a t + +exception Invalid_arg of int * string * string +(** When an operation on an array fails, [Invalid_arg] is raised. The + integer is the value that made the operation fail, the first string + contains the function name that has been called and the second string + contains the parameter name that made the operation fail. +*) + +(** {6 Array creation} *) + +val create : unit -> 'a t +(** [create()] returns a new empty dynamic array. *) + +val make : int -> 'a t +(** [make count] returns an array with some memory already allocated so + up to [count] elements can be stored into it without resizing. *) + +val init : int -> (int -> 'a) -> 'a t +(** [init n f] returns an array of [n] elements filled with values + returned by [f 0 , f 1, ... f (n-1)]. *) + +(** {6 Array manipulation functions} *) + +val empty : 'a t -> bool +(** Return true if the number of elements in the array is 0. *) + +val length : 'a t -> int +(** Return the number of elements in the array. *) + +val get : 'a t -> int -> 'a +(** [get darr idx] gets the element in [darr] at index [idx]. If [darr] has + [len] elements in it, then the valid indexes range from [0] to [len-1]. *) + +val last : 'a t -> 'a +(** [last darr] returns the last element of [darr]. *) + +val set : 'a t -> int -> 'a -> unit +(** [set darr idx v] sets the element of [darr] at index [idx] to value + [v]. The previous value is overwritten. *) + +val insert : 'a t -> int -> 'a -> unit +(** [insert darr idx v] inserts [v] into [darr] at index [idx]. All elements + of [darr] with an index greater than or equal to [idx] have their + index incremented (are moved up one place) to make room for the new + element. *) + +val add : 'a t -> 'a -> unit +(** [add darr v] appends [v] onto [darr]. [v] becomes the new + last element of [darr]. *) + +val append : 'a t -> 'a t -> unit +(** [append src dst] adds all elements of [src] to the end of [dst]. *) + +val delete : 'a t -> int -> unit +(** [delete darr idx] deletes the element of [darr] at [idx]. All elements + with an index greater than [idx] have their index decremented (are + moved down one place) to fill in the hole. *) + +val delete_last : 'a t -> unit +(** [delete_last darr] deletes the last element of [darr]. This is equivalent + of doing [delete darr ((length darr) - 1)]. *) + +val delete_range : 'a t -> int -> int -> unit +(** [delete_range darr p len] deletes [len] elements starting at index [p]. + All elements with an index greater than [p+len] are moved to fill + in the hole. *) + +val clear : 'a t -> unit +(** remove all elements from the array and resize it to 0. *) + +val blit : 'a t -> int -> 'a t -> int -> int -> unit +(** [blit src srcidx dst dstidx len] copies [len] elements from [src] + starting with index [srcidx] to [dst] starting at [dstidx]. *) + +val compact : 'a t -> unit +(** [compact darr] ensures that the space allocated by the array is minimal.*) + +(** {6 Array copy and conversion} *) + +val to_list : 'a t -> 'a list +(** [to_list darr] returns the elements of [darr] in order as a list. *) + +val to_array : 'a t -> 'a array +(** [to_array darr] returns the elements of [darr] in order as an array. *) + +val enum : 'a t -> 'a Enum.t +(** [enum darr] returns the enumeration of [darr] elements. *) + +val of_list : 'a list -> 'a t +(** [of_list lst] returns a dynamic array with the elements of [lst] in + it in order. *) + +val of_array : 'a array -> 'a t +(** [of_array arr] returns an array with the elements of [arr] in it + in order. *) + +val of_enum : 'a Enum.t -> 'a t +(** [of_enum e] returns an array that holds, in order, the elements of [e]. *) + +val copy : 'a t -> 'a t +(** [copy src] returns a fresh copy of [src], such that no modification of + [src] affects the copy, or vice versa (all new memory is allocated for + the copy). *) + +val sub : 'a t -> int -> int -> 'a t +(** [sub darr start len] returns an array holding the subset of [len] + elements from [darr] starting with the element at index [idx]. *) + +(** {6 Array functional support} *) + +val iter : ('a -> unit) -> 'a t -> unit +(** [iter f darr] calls the function [f] on every element of [darr]. It + is equivalent to [for i = 0 to length darr - 1 do f (get darr i) done;] *) + +val iteri : (int -> 'a -> unit) -> 'a t -> unit +(** [iter f darr] calls the function [f] on every element of [darr]. It + is equivalent to [for i = 0 to length darr - 1 do f i (get darr i) done;] + *) + +val map : ('a -> 'b) -> 'a t -> 'b t +(** [map f darr] applies the function [f] to every element of [darr] + and creates a dynamic array from the results - similar to [List.map] or + [Array.map]. *) + +val mapi : (int -> 'a -> 'b) -> 'a t -> 'b t +(** [mapi f darr] applies the function [f] to every element of [darr] + and creates a dynamic array from the results - similar to [List.mapi] or + [Array.mapi]. *) + +val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a +(** [fold_left f x darr] computes + [f ( ... ( f ( f (get darr 0) x) (get darr 1) ) ... ) (get darr n-1)], + similar to [Array.fold_left] or [List.fold_left]. *) + +val fold_right : ('a -> 'b -> 'b) -> 'a t -> 'b -> 'b +(** [fold_right f darr x] computes + [ f (get darr 0) (f (get darr 1) ( ... ( f (get darr n-1) x ) ... ) ) ] + similar to [Array.fold_right] or [List.fold_right]. *) + +val index_of : ('a -> bool) -> 'a t -> int +(** [index_of f darr] returns the index of the first element [x] in darr such + as [f x] returns [true] or raise [Not_found] if not found. *) + +val filter : ('a -> bool) -> 'a t -> unit + +(** {6 Array resizers} *) + +type resizer_t = currslots:int -> oldlength:int -> newlength:int -> int +(** The type of a resizer function. + + Resizer functions are called whenever elements are added to + or removed from the dynamic array to determine what the current number of + storage spaces in the array should be. The three named arguments + passed to a resizer are the current number of storage spaces in + the array, the length of the array before the elements are + added or removed, and the length the array will be after the + elements are added or removed. If elements are being added, newlength + will be larger than oldlength, if elements are being removed, + newlength will be smaller than oldlength. If the resizer function + returns exactly oldlength, the size of the array is only changed when + adding an element while there is not enough space for it. + + By default, all dynamic arrays are created with the [default_resizer]. + When a dynamic array is created from another dynamic array (using [copy], + [map] , etc. ) the resizer of the copy will be the same as the original + dynamic array resizer. To change the resizer, use the [set_resizer] + function. +*) + +val set_resizer : 'a t -> resizer_t -> unit +(** Change the resizer for this array. *) + +val get_resizer : 'a t -> resizer_t +(** Get the current resizer function for a given array *) + +val default_resizer : resizer_t +(** The default resizer function the library is using - in this version + of DynArray, this is the [exponential_resizer] but should change in + next versions. *) + +val exponential_resizer : resizer_t +(** The exponential resizer- The default resizer except when the resizer + is being copied from some other darray. + + [exponential_resizer] works by doubling or halving the number of + slots until they "fit". If the number of slots is less than the + new length, the number of slots is doubled until it is greater + than the new length (or Sys.max_array_size is reached). + + If the number of slots is more than four times the new length, + the number of slots is halved until it is less than four times the + new length. + + Allowing darrays to fall below 25% utilization before shrinking them + prevents "thrashing". Consider the case where the caller is constantly + adding a few elements, and then removing a few elements, causing + the length to constantly cross above and below a power of two. + Shrinking the array when it falls below 50% would causing the + underlying array to be constantly allocated and deallocated. + A few elements would be added, causing the array to be reallocated + and have a usage of just above 50%. Then a few elements would be + remove, and the array would fall below 50% utilization and be + reallocated yet again. The bulk of the array, untouched, would be + copied and copied again. By setting the threshold at 25% instead, + such "thrashing" only occurs with wild swings- adding and removing + huge numbers of elements (more than half of the elements in the array). + + [exponential_resizer] is a good performing resizer for most + applications. A list allocates 2 words for every element, while an + array (with large numbers of elements) allocates only 1 word per + element (ignoring unboxed floats). On insert, [exponential_resizer] + keeps the amount of wasted "extra" array elements below 50%, meaning + that less than 2 words per element are used. Even on removals + where the amount of wasted space is allowed to rise to 75%, that + only means that darray is using 4 words per element. This is + generally not a significant overhead. + + Furthermore, [exponential_resizer] minimizes the number of copies + needed- appending n elements into an empty darray with initial size + 0 requires between n and 2n elements of the array be copied- O(n) + work, or O(1) work per element (on average). A similar argument + can be made that deletes from the end of the array are O(1) as + well (obviously deletes from anywhere else are O(n) work- you + have to move the n or so elements above the deleted element down). + +*) + +val step_resizer : int -> resizer_t +(** The stepwise resizer- another example of a resizer function, this + time of a parameterized resizer. + + The resizer returned by [step_resizer step] returns the smallest + multiple of [step] larger than [newlength] if [currslots] is less + then [newlength]-[step] or greater than [newlength]. + + For example, to make an darray with a step of 10, a length + of len, and a null of null, you would do: + [make] ~resizer:([step_resizer] 10) len null +*) + +val conservative_exponential_resizer : resizer_t +(** [conservative_exponential_resizer] is an example resizer function + which uses the oldlength parameter. It only shrinks the array + on inserts- no deletes shrink the array, only inserts. It does + this by comparing the oldlength and newlength parameters. Other + than that, it acts like [exponential_resizer]. +*) + +(** {6 Unsafe operations} **) + +val unsafe_get : 'a t -> int -> 'a +val unsafe_set : 'a t -> int -> 'a -> unit diff --git a/commons/ocamlextra/enum.ml b/commons/ocamlextra/enum.ml new file mode 100644 index 0000000..063ab15 --- /dev/null +++ b/commons/ocamlextra/enum.ml @@ -0,0 +1,376 @@ +(* + * Enum - Enumeration over abstract collection of elements. + * Copyright (C) 2003 Nicolas Cannasse + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version, + * with the special exception on linking described in file LICENSE. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) + +type 'a t = { + mutable count : unit -> int; + mutable next : unit -> 'a; + mutable clone : unit -> 'a t; + mutable fast : bool; +} + +(* raised by 'next' functions, should NOT go outside the API *) +exception No_more_elements + +let _dummy () = assert false + +let make ~next ~count ~clone = + { + count = count; + next = next; + clone = clone; + fast = true; + } + +let rec init n f = + if n < 0 then invalid_arg "Enum.init"; + let count = ref n in + { + count = (fun () -> !count); + next = (fun () -> + match !count with + | 0 -> raise No_more_elements + | _ -> + decr count; + f (n - 1 - !count)); + clone = (fun () -> init !count f); + fast = true; + } + +let rec empty () = + { + count = (fun () -> 0); + next = (fun () -> raise No_more_elements); + clone = (fun () -> empty()); + fast = true; + } + +type 'a _mut_list = { + hd : 'a; + mutable tl : 'a _mut_list; +} + +let force t = + let rec clone enum count = + let enum = ref !enum + and count = ref !count in + { + count = (fun () -> !count); + next = (fun () -> + match !enum with + | [] -> raise No_more_elements + | h :: t -> decr count; enum := t; h); + clone = (fun () -> + let enum = ref !enum + and count = ref !count in + clone enum count); + fast = true; + } + in + let count = ref 0 in + let _empty = Obj.magic [] in + let rec loop dst = + let x = { hd = t.next(); tl = _empty } in + incr count; + dst.tl <- x; + loop x + in + let enum = ref _empty in + (try + enum := { hd = t.next(); tl = _empty }; + incr count; + loop !enum; + with No_more_elements -> ()); + let tc = clone (Obj.magic enum) count in + t.clone <- tc.clone; + t.next <- tc.next; + t.count <- tc.count; + t.fast <- true + +let from f = + let e = { + next = f; + count = _dummy; + clone = _dummy; + fast = false; + } in + e.count <- (fun () -> force e; e.count()); + e.clone <- (fun () -> force e; e.clone()); + e + +let from2 next clone = + let e = { + next = next; + count = _dummy; + clone = clone; + fast = false; + } in + e.count <- (fun () -> force e; e.count()); + e + +let get t = + try + Some (t.next()) + with + No_more_elements -> None + +let push t e = + let rec make t = + let fnext = t.next in + let fcount = t.count in + let fclone = t.clone in + let next_called = ref false in + t.next <- (fun () -> + next_called := true; + t.next <- fnext; + t.count <- fcount; + t.clone <- fclone; + e); + t.count <- (fun () -> + let n = fcount() in + if !next_called then n else n+1); + t.clone <- (fun () -> + let tc = fclone() in + if not !next_called then make tc; + tc); + in + make t + +let peek t = + match get t with + | None -> None + | Some x -> + push t x; + Some x + +let junk t = + try + ignore(t.next()) + with + No_more_elements -> () + +let is_empty t = + if t.fast then + t.count() = 0 + else + peek t = None + +let count t = + t.count() + +let fast_count t = + t.fast + +let clone t = + t.clone() + +let iter f t = + let rec loop () = + f (t.next()); + loop(); + in + try + loop(); + with + No_more_elements -> () + +let iteri f t = + let rec loop idx = + f idx (t.next()); + loop (idx+1); + in + try + loop 0; + with + No_more_elements -> () + +let iter2 f t u = + let push_t = ref None in + let rec loop () = + push_t := None; + let e = t.next() in + push_t := Some e; + f e (u.next()); + loop () + in + try + loop () + with + No_more_elements -> + match !push_t with + | None -> () + | Some e -> + push t e + +let iter2i f t u = + let push_t = ref None in + let rec loop idx = + push_t := None; + let e = t.next() in + push_t := Some e; + f idx e (u.next()); + loop (idx + 1) + in + try + loop 0 + with + No_more_elements -> + match !push_t with + | None -> () + | Some e -> push t e + +let fold f init t = + let acc = ref init in + let rec loop() = + acc := f (t.next()) !acc; + loop() + in + try + loop() + with + No_more_elements -> !acc + +let foldi f init t = + let acc = ref init in + let rec loop idx = + acc := f idx (t.next()) !acc; + loop (idx + 1) + in + try + loop 0 + with + No_more_elements -> !acc + +let fold2 f init t u = + let acc = ref init in + let push_t = ref None in + let rec loop() = + push_t := None; + let e = t.next() in + push_t := Some e; + acc := f e (u.next()) !acc; + loop() + in + try + loop() + with + No_more_elements -> + match !push_t with + | None -> !acc + | Some e -> + push t e; + !acc + +let fold2i f init t u = + let acc = ref init in + let push_t = ref None in + let rec loop idx = + push_t := None; + let e = t.next() in + push_t := Some e; + acc := f idx e (u.next()) !acc; + loop (idx + 1) + in + try + loop 0 + with + No_more_elements -> + match !push_t with + | None -> !acc + | Some e -> + push t e; + !acc + +let find f t = + let rec loop () = + let x = t.next() in + if f x then x else loop() + in + try + loop() + with + No_more_elements -> raise Not_found + +let rec map f t = + { + count = t.count; + next = (fun () -> f (t.next())); + clone = (fun () -> map f (t.clone())); + fast = t.fast; + } + +let rec mapi f t = + let idx = ref (-1) in + { + count = t.count; + next = (fun () -> incr idx; f !idx (t.next())); + clone = (fun () -> mapi f (t.clone())); + fast = t.fast; + } + +let rec filter f t = + let rec next() = + let x = t.next() in + if f x then x else next() + in + from2 next (fun () -> filter f (t.clone())) + +let rec filter_map f t = + let rec next () = + match f (t.next()) with + | None -> next() + | Some x -> x + in + from2 next (fun () -> filter_map f (t.clone())) + +let rec append ta tb = + let t = { + count = (fun () -> ta.count() + tb.count()); + next = _dummy; + clone = (fun () -> append (ta.clone()) (tb.clone())); + fast = ta.fast && tb.fast; + } in + t.next <- (fun () -> + try + ta.next() + with + No_more_elements -> + (* add one indirection because tb can mute *) + t.next <- (fun () -> tb.next()); + t.count <- (fun () -> tb.count()); + t.clone <- (fun () -> tb.clone()); + t.fast <- tb.fast; + t.next() + ); + t + +let rec concat t = + let concat_ref = ref _dummy in + let rec concat_next() = + let tn = t.next() in + concat_ref := (fun () -> + try + tn.next() + with + No_more_elements -> + concat_next()); + !concat_ref () + in + concat_ref := concat_next; + from2 (fun () -> !concat_ref ()) (fun () -> concat (t.clone())) diff --git a/commons/ocamlextra/enum.mli b/commons/ocamlextra/enum.mli new file mode 100644 index 0000000..a7175fd --- /dev/null +++ b/commons/ocamlextra/enum.mli @@ -0,0 +1,201 @@ +(* + * Enum - enumeration over abstract collection of elements. + * Copyright (C) 2003 Nicolas Cannasse + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version, + * with the special exception on linking described in file LICENSE. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) + +(** Enumeration over abstract collection of elements. + + Enumerations are entirely functional and most of the operations do not + actually require the allocation of data structures. Using enumerations + to manipulate data is therefore efficient and simple. All data structures in + ExtLib such as lists, arrays, etc. have support to convert from and to + enumerations. +*) + + +type 'a t + +(** {6 Final functions} + + These functions consume the enumeration until + it ends or an exception is raised by the first + argument function. +*) + +val iter : ('a -> unit) -> 'a t -> unit +(** [iter f e] calls the function [f] with each elements of [e] in turn. *) + +val iter2 : ('a -> 'b -> unit) -> 'a t -> 'b t -> unit +(** [iter2 f e1 e2] calls the function [f] with the next elements of [e] and + [e2] repeatedly until one of the two enumerations ends. *) + +val fold : ('a -> 'b -> 'b) -> 'b -> 'a t -> 'b +(** [fold f v e] returns v if e is empty, + otherwise [f (... (f (f v a1) a2) ...) aN] where a1..N are + the elements of [e]. +*) + +val fold2 : ('a -> 'b -> 'c -> 'c) -> 'c -> 'a t -> 'b t -> 'c +(** [fold2] is similar to [fold] but will fold over two enumerations at the + same time until one of the two enumerations ends. *) + +(** Indexed functions : these functions are similar to previous ones + except that they call the function with one additional argument which + is an index starting at 0 and incremented after each call to the function. *) + +val iteri : (int -> 'a -> unit) -> 'a t -> unit + +val iter2i : ( int -> 'a -> 'b -> unit) -> 'a t -> 'b t -> unit + +val foldi : (int -> 'a -> 'b -> 'b) -> 'b -> 'a t -> 'b + +val fold2i : (int -> 'a -> 'b -> 'c -> 'c) -> 'c -> 'a t -> 'b t -> 'c + +(** {6 Useful functions} *) + +val find : ('a -> bool) -> 'a t -> 'a +(** [find f e] returns the first element [x] of [e] such that [f x] returns + [true], consuming the enumeration up to and including the + found element, or, raises [Not_found] if no such element exists + in the enumeration, consuming the whole enumeration in the search. + + Since [find] consumes a prefix of the enumeration, it can be used several + times on the same enumeration to find the next element. *) + +val is_empty : 'a t -> bool +(** [is_empty e] returns true if [e] does not contains any element. *) + +val peek : 'a t -> 'a option +(** [peek e] returns [None] if [e] is empty or [Some x] where [x] is + the next element of [e]. The element is not removed from the enumeration. *) + +val get : 'a t -> 'a option +(** [get e] returns [None] if [e] is empty or [Some x] where [x] is + the next element of [e], in which case the element is removed from the enumeration. *) + +val push : 'a t -> 'a -> unit +(** [push e x] will add [x] at the beginning of [e]. *) + +val junk : 'a t -> unit +(** [junk e] removes the first element from the enumeration, if any. *) + +val clone : 'a t -> 'a t +(** [clone e] creates a new enumeration that is copy of [e]. If [e] + is consumed by later operations, the clone will not get affected. *) + +val force : 'a t -> unit +(** [force e] forces the application of all lazy functions and the + enumeration of all elements, exhausting the enumeration. + + An efficient intermediate data structure + of enumerated elements is constructed and [e] will now enumerate over + that data structure. *) + +(** {6 Lazy constructors} + + These functions are lazy which means that they will create a new modified + enumeration without actually enumerating any element until they are asked + to do so by the programmer (using one of the functions above). + + When the resulting enumerations of these functions are consumed, the + underlying enumerations they were created from are also consumed. *) + +val map : ('a -> 'b) -> 'a t -> 'b t +(** [map f e] returns an enumeration over [(f a1, f a2, ... , f aN)] where + a1...N are the elements of [e]. *) + +val mapi : (int -> 'a -> 'b) -> 'a t -> 'b t +(** [mapi] is similar to [map] except that [f] is passed one extra argument + which is the index of the element in the enumeration, starting from 0. *) + +val filter : ('a -> bool) -> 'a t -> 'a t +(** [filter f e] returns an enumeration over all elements [x] of [e] such + as [f x] returns [true]. *) + +val filter_map : ('a -> 'b option) -> 'a t -> 'b t +(** [filter_map f e] returns an enumeration over all elements [x] such as + [f y] returns [Some x] , where [y] is an element of [e]. *) + +val append : 'a t -> 'a t -> 'a t +(** [append e1 e2] returns an enumeration that will enumerate over all + elements of [e1] followed by all elements of [e2]. *) + +val concat : 'a t t -> 'a t +(** [concat e] returns an enumeration over all elements of all enumerations + of [e]. *) + +(** {6 Constructors} + + In this section the word {i shall} denotes a semantic + requirement. The correct operation + of the functions in this interface are conditional + on the client meeting these requirements. +*) + +exception No_more_elements +(** This exception {i shall} be raised by the [next] function of [make] + or [from] when no more elements can be enumerated, it {i shall not} + be raised by any function which is an argument to any + other function specified in the interface. +*) + +val empty : unit -> 'a t +(** The empty enumeration : contains no element *) + +val make : next:(unit -> 'a) -> count:(unit -> int) -> clone:(unit -> 'a t) -> 'a t +(** This function creates a fully defined enumeration. + {ul {li the [next] function {i shall} return the next element of the + enumeration or raise [No_more_elements] if the underlying data structure + does not have any more elements to enumerate.} + {li the [count] function {i shall} return the actual number of remaining + elements in the enumeration.} + {li the [clone] function {i shall} create a clone of the enumeration + such as operations on the original enumeration will not affect the + clone. }} + + For some samples on how to correctly use [make], you can have a look + at implementation of [ExtList.enum]. +*) + +val from : (unit -> 'a) -> 'a t +(** [from next] creates an enumeration from the [next] function. + [next] {i shall} return the next element of the enumeration or raise + [No_more_elements] when no more elements can be enumerated. Since the + enumeration definition is incomplete, a call to [clone] or [count] will + result in a call to [force] that will enumerate all elements in order to + return a correct value. *) + +val init : int -> (int -> 'a) -> 'a t +(** [init n f] creates a new enumeration over elements + [f 0, f 1, ..., f (n-1)] *) + +(** {6 Counting} *) + +val count : 'a t -> int +(** [count e] returns the number of remaining elements in [e] without + consuming the enumeration. + +Depending of the underlying data structure that is implementing the +enumeration functions, the count operation can be costly, and even sometimes +can cause a call to [force]. *) + +val fast_count : 'a t -> bool +(** For users worried about the speed of [count] you can call the [fast_count] + function that will give an hint about [count] implementation. Basically, if + the enumeration has been created with [make] or [init] or if [force] has + been called on it, then [fast_count] will return true. *) diff --git a/commons/ocamlextra/mapb.ml b/commons/ocamlextra/mapb.ml new file mode 100644 index 0000000..5bd1ea7 --- /dev/null +++ b/commons/ocamlextra/mapb.ml @@ -0,0 +1,144 @@ +(*pad: same than for Setb, module Make(Ord: OrderedType) = struct *) + +(***********************************************************************) +(* *) +(* Objective Caml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU Library General Public License, with *) +(* the special exception on linking described in file ../LICENSE. *) +(* *) +(***********************************************************************) + +(* map.ml 1.15 2004/04/23 10:01:33 xleroy Exp *) + + +(* + type key = Ord.t + + type 'a t = + Empty + | Node of 'a t * key * 'a * 'a t * int +*) + type ('key, 'v) t = + Empty + | Node of ('key, 'v) t * 'key * 'v * ('key, 'v) t * int + + let empty = Empty + + let height = function + Empty -> 0 + | Node(_,_,_,_,h) -> h + + let create l x d r = + let hl = height l and hr = height r in + Node(l, x, d, r, (if hl >= hr then hl + 1 else hr + 1)) + + let bal l x d r = + let hl = match l with Empty -> 0 | Node(_,_,_,_,h) -> h in + let hr = match r with Empty -> 0 | Node(_,_,_,_,h) -> h in + if hl > hr + 2 then begin + match l with + Empty -> invalid_arg "Map.bal" + | Node(ll, lv, ld, lr, _) -> + if height ll >= height lr then + create ll lv ld (create lr x d r) + else begin + match lr with + Empty -> invalid_arg "Map.bal" + | Node(lrl, lrv, lrd, lrr, _)-> + create (create ll lv ld lrl) lrv lrd (create lrr x d r) + end + end else if hr > hl + 2 then begin + match r with + Empty -> invalid_arg "Map.bal" + | Node(rl, rv, rd, rr, _) -> + if height rr >= height rl then + create (create l x d rl) rv rd rr + else begin + match rl with + Empty -> invalid_arg "Map.bal" + | Node(rll, rlv, rld, rlr, _) -> + create (create l x d rll) rlv rld (create rlr rv rd rr) + end + end else + Node(l, x, d, r, (if hl >= hr then hl + 1 else hr + 1)) + + let rec add x data = function + Empty -> + Node(Empty, x, data, Empty, 1) + | Node(l, v, d, r, h) -> + let c = compare x v in + if c = 0 then + Node(l, x, data, r, h) + else if c < 0 then + bal (add x data l) v d r + else + bal l v d (add x data r) + + let rec find x = function + Empty -> + raise Not_found + | Node(l, v, d, r, _) -> + let c = compare x v in + if c = 0 then d + else find x (if c < 0 then l else r) + + let rec mem x = function + Empty -> + false + | Node(l, v, d, r, _) -> + let c = compare x v in + c = 0 || mem x (if c < 0 then l else r) + + let rec min_binding = function + Empty -> raise Not_found + | Node(Empty, x, d, r, _) -> (x, d) + | Node(l, x, d, r, _) -> min_binding l + + let rec remove_min_binding = function + Empty -> invalid_arg "Map.remove_min_elt" + | Node(Empty, x, d, r, _) -> r + | Node(l, x, d, r, _) -> bal (remove_min_binding l) x d r + + let merge t1 t2 = + match (t1, t2) with + (Empty, t) -> t + | (t, Empty) -> t + | (_, _) -> + let (x, d) = min_binding t2 in + bal t1 x d (remove_min_binding t2) + + let rec remove x = function + Empty -> + Empty + | Node(l, v, d, r, h) -> + let c = compare x v in + if c = 0 then + merge l r + else if c < 0 then + bal (remove x l) v d r + else + bal l v d (remove x r) + + let rec iter f = function + Empty -> () + | Node(l, v, d, r, _) -> + iter f l; f v d; iter f r + + let rec map f = function + Empty -> Empty + | Node(l, v, d, r, h) -> Node(map f l, v, f d, map f r, h) + + let rec mapi f = function + Empty -> Empty + | Node(l, v, d, r, h) -> Node(mapi f l, v, f v d, mapi f r, h) + + let rec fold f m accu = + match m with + Empty -> accu + | Node(l, v, d, r, _) -> + fold f l (f v d (fold f r accu)) diff --git a/commons/ocamlextra/parser_combinators.ml b/commons/ocamlextra/parser_combinators.ml new file mode 100644 index 0000000..0e44cb8 --- /dev/null +++ b/commons/ocamlextra/parser_combinators.ml @@ -0,0 +1,370 @@ +(*****************************************************************************) +(* *) +(*****************************************************************************) +(* src: Jon Harrop. + * + * "Certain applications are extremely well suited to functional + * programming and parsing is one of them. Specifically, the ability to + * write functional combinators that allow parsers for everything from + * integers up to symbolic expressions to be composed is more general + * and provides more opportunity for code reuse than the use of + * conventional parser generators such as ocamllex and ocamlyacc. This + * article explains how parser combinators may be designed and + * implemented in OCaml, using the standard example of a calculator." + * + * Based on haskell articles I guess like meijer functional pearl or + * graham hutton articles. Also maybe based on haskell parsec. + * + * pad: a few bugfix. I also put more restrictive and descriptive types. + * pad: I remember having coded such a library, maybe not in ocaml. + * Or maybe it was during a "TP compilation" at INSA ? I remember having + * a generic lexer. Or maybe it was genlex ? + * + * + * + * + * alternatives: genlex + parser extension of ocaml (streams). + * cf genlex doc: + * + * Example: a lexer suitable for a desk calculator is obtained by + * let lexer = make_lexer ["+";"-";"*";"/";"let";"="; "("; ")"] + * let parse_expr = parser + * [< 'Int n >] -> n + * | [< 'Kwd "("; n = parse_expr; 'Kwd ")" >] -> n + * | [< n1 = parse_expr; n2 = parse_remainder n1 >] -> n2 + * and parse_remainder n1 = parser + * [< 'Kwd "+"; n2 = parse_expr >] -> n1+n2 + * | ... + * type token = + * | Kwd of string + * | Ident of string + * | Int of int + * | Float of float + * | String of string + * | Char of char + * + * + * Cf also ocaml manual + * let rec parse_expr = parser + * [< e1 = parse_mult; e = parse_more_adds e1 >] -> e + * and parse_more_adds e1 = parser + * [< 'Kwd "+"; e2 = parse_mult; e = parse_more_adds (Sum(e1, e2)) >] -> e + * | [< 'Kwd "-"; e2 = parse_mult; e = parse_more_adds (Diff(e1, e2)) >] -> e + * | [< >] -> e1 + * and parse_mult = parser + * [< e1 = parse_simple; e = parse_more_mults e1 >] -> e + * and parse_more_mults e1 = parser + * [< 'Kwd "*"; e2 = parse_simple; e = parse_more_mults (Prod(e1, e2)) >] -> e + * | [< 'Kwd "/"; e2 = parse_simple; e = parse_more_mults (Quot(e1, e2)) >] -> e + * | [< >] -> e1 + * and parse_simple = parser + * [< 'Ident s >] -> Var s + * | [< 'Int i >] -> Const(float i) + * | [< 'Float f >] -> Const f + * | [< 'Kwd "("; e = parse_expr; 'Kwd ")" >] -> e;; + * But see how they are forced to use a LL(1) grammar which denatures the + * grammar "parse_more_xxx" + * + *) + +(*****************************************************************************) +(* Parser Combinators *) +(*****************************************************************************) + +(* src: Jon Harrop. pad: a few bugfix *) + +type ('a, 'b) genp = 'a list -> 'b * 'a list +let val_of_parser = fst + +(* lexer = parser of char list *) +(* type 'a lexer = (char, 'a) genp *) + +(* grammer = parser ot tokens *) +(* type 'a p = (token, 'a) genp *) + + +(* pad: could also do it by returning a Maybe and use monad *) +let ( ||| ) p1 p2 s = + try + p1 s + with Not_found -> + p2 s + +let ( +++ ) p1 p2 s = + let e1, s = p1 s in + let e2, s = p2 s in + (e1, e2), s + +let rec many p s = + try + let e, s = p s in + let es, s = many p s in + e::es, s + with Not_found -> + [], s + + +let ( >| ) p k i = + let e, s = p i in + k e, s + +(* was called 'some', but confusing *) +let pred p = function + | h::t when p h -> h, t + | _ -> raise Not_found + +let a x = pred (( = ) x) + +let several p = many (pred p) + + +module Abstr : sig + type t + val x : t + end = struct + type t = int + let x = 0 + end + +let fin = function + | [] as t -> Abstr.x, t + | _ -> raise Not_found + + +(*****************************************************************************) +(* Lexing *) +(*****************************************************************************) +(* a generic lexer *) + +let digit = function + | '0'..'9' -> true + | _ -> false + +let alpha = function + | 'a'..'z' | 'A'..'Z' -> true + | _ -> false + + +let symbol = function + | '(' | ')' + | '{' | '}' + | '[' | ']' + | '<' | '>' + | '+' | '-' | '*' | '/' + | '&' | '|' | '!' + + | '=' | '~' | '@' + -> true + | _ -> false + +let space = function + | ' ' | '\t' | '\n' -> true + | _ -> false + +let stringquote = function + | '"' -> true + | _ -> false + +let quote = function + | '\'' -> true + | _ -> false + + +let alphanum c = digit c || alpha c + + +let alphanum_underscore c = digit c || alpha c || (c = '_') +let alphanum_minus c = digit c || alpha c || (c = '-') +let alphanum_under_minus c = digit c || alpha c || (c = '-') || (c = '_') + + + +let (+>) o f = f o +let string_of_chars cs = + cs +> List.map (String.make 1) +> String.concat "" + + +let collect(h, t) = + String.concat "" (List.map (String.make 1) (h::t)) + +let collectbis(xs) = + String.concat "" (List.map (String.make 1) (xs)) + +let list_of_string string = + let list = ref [] in + String.iter (fun c -> list := c :: !list) string; + List.rev !list + + +(*****************************************************************************) +(* still generic *) +(*****************************************************************************) + +type token = + | IDENT of string + | KWD of string + | INT of string + | SYM of string + | STR of string + +let string_of_token = function + | IDENT string -> "IDENT:" ^ string + | KWD string -> "KWD:" ^ string + | INT string -> "INT:" ^ string + | SYM string -> "SYM:" ^ string + | STR string -> "STR:" ^ string + + +type lexer = (char, token) genp + + +let rawnumber = + pred digit +++ several digit >| fun x -> INT(collect x) +let rawident = + pred alpha +++ several alphanum >| fun x -> IDENT(collect x) +let rawsymbol = + pred symbol +++ several symbol >| fun x -> SYM(collect x) + +let rawkeyword = + let p c = not(space c) && not(digit c) in + pred p +++ several p >| fun x -> KWD(collect x) + + +(* todo: handle antislash *) +let rawstring = + pred stringquote +++ + several (fun c -> not (stringquote c)) +++ + pred stringquote + >| (fun ((c1, cs), c3) -> + let s = string_of_chars cs in + STR s (* exclude the marker *) + ) + + +let lex_gen tokenf str = + let alltoks = (many tokenf) +++ fin >| fst in + val_of_parser (alltoks (list_of_string str)) + +let parse_gen tokenf grammarf p string = + val_of_parser (grammarf (lex_gen tokenf string)) + +(*****************************************************************************) +(* not generic anymore *) +(*****************************************************************************) +(* the order is important if some "rules" overlap, as in ocamllex *) +let token = + (rawident ||| rawnumber ||| rawkeyword) +++ several space >| fst + +(* pad: bugfix: was not defined in jon harrop article *) +let tokens = many token + +let alltokens = + tokens +++ fin >| fst + +let lex (string : string) = + val_of_parser (alltokens (list_of_string string)) + + + +let test1 () = + Common.example + (lex "a x^2 + b x + c" + = + [IDENT "a"; IDENT "x"; KWD "^"; INT "2"; KWD "+"; IDENT "b"; IDENT "x"; + KWD "+"; IDENT "c"] + ) + +(*****************************************************************************) +(* Parsing *) +(*****************************************************************************) + +type expr = + | Int of int + | Var of string + | Add of expr * expr + | Mul of expr * expr + +type 'a pparser = (token, 'a) genp + +(* +open Format;; +# let rec print_expr ff = function + | Int n -> fprintf ff "%d" n + | Var x -> fprintf ff "%s" x + | Add(f, g) -> + fprintf ff "%a + %a" print_expr f print_expr g + | Mul(f, g) -> + fprintf ff "%a %a" print_mul f print_mul g + and print_mul ff = function + | Add _ as e -> fprintf ff "(%a)" print_expr e + | e -> fprintf ff "%a" print_expr e +#install_printer print_expr +*) + +let ident = function + | IDENT x :: t -> x, t + | _ -> raise Not_found + +let int = function + | INT n :: t -> n, t + | _ -> raise Not_found + +let string = function + | STR x :: t -> x, t + | _ -> raise Not_found + +(* src: Jon Harrop + * "This style of parsing, known as recursive descent parsing , has one + * important caveat. If a rule tries to match itself immediately, even if + * that is succeeded by other parsers, then the resulting program will go + * into an infinite loops with the parser for that rule calling itself + * indefinitely until a stack overflow occurs. Consequently, our + * implementation of the factor parser is careful to parse an atom first, + * and term calls factor first, to avoid this problem." + * + * pad: bugfix, added the KWD "*". + *) + +(* pad: I think I remembered you cant eta-factorize the parameter + * when you use mutually recursive + *) +let rec atom s = + ( + (int >| fun n -> Int(int_of_string n)) + ||| + (ident >| fun x -> Var x) + ||| + (a (KWD "(") +++ term +++ a (KWD ")") >| fun ((_, e), _) -> e) + ) s +and factor s = + ( + (atom +++ a (KWD "*") +++ factor >| fun ((f, _), g) -> Mul (f,g)) + ||| + atom + ) s +and term s = + ( + (factor +++ a (KWD "+") +++ term >| fun ((f, _), g) -> Add (f,g)) + ||| + factor + ) s + + +let expr = + term +++ fin >| fst + +let parse p string = + val_of_parser(p(lex string)) + +(* +parse expr "a x x + b x + c" +*) + + +(*****************************************************************************) + +module Infix = struct + let (|||) = (|||) + let (+++) = (+++) + let (>|) = (>|) +end diff --git a/commons/ocamlextra/parser_combinators.mli b/commons/ocamlextra/parser_combinators.mli new file mode 100644 index 0000000..791218c --- /dev/null +++ b/commons/ocamlextra/parser_combinators.mli @@ -0,0 +1,154 @@ +(*****************************************************************************) +(* src: Jon Harrop. + * + * "Certain applications are extremely well suited to functional + * programming and parsing is one of them. Specifically, the ability to + * write functional combinators that allow parsers for everything from + * integers up to symbolic expressions to be composed is more general + * and provides more opportunity for code reuse than the use of + * conventional parser generators such as ocamllex and ocamlyacc. This + * article explains how parser combinators may be designed and + * implemented in OCaml, using the standard example of a calculator." + * + * pad: a few bugfixes. I also put more restrictive and descriptive types. + * + *) + +(*****************************************************************************) + +(* A generic parser takes a list of stuff (either char for lexical + * parser or tokens for grammar parser) and return something and the + * remaing list of stuff. *) +type ('a, 'b) genp = 'a list -> 'b * 'a list +val val_of_parser : 'b * 'a list -> 'b + +(* lexer = parser of char list *) +(* type 'a lexer = (char, 'a) genp *) + +(* grammer = parser ot tokens *) +(* type 'a pparser = (token, 'a) genp *) + + +val ( ||| ) : ('a, 'b) genp -> ('a, 'b) genp -> ('a, 'b) genp +(* ('a -> 'b) -> ('a -> 'b) -> 'a -> 'b *) +val ( +++ ) : ('a, 'b) genp -> ('a, 'c) genp -> ('a, 'b * 'c) genp +(* ('a -> 'b * 'c) -> ('c -> 'd * 'e) -> 'a -> ('b * 'd) * 'e *) + +val many : ('a, 'b) genp -> ('a, 'b list) genp +(* ('a -> 'b * 'a) -> 'a -> 'b list * 'a *) + +val ( >| ) : ('a, 'b) genp -> ('b -> 'c) -> ('a, 'c) genp +(* ('a -> 'b * 'c) -> ('b -> 'd) -> 'a -> 'd * 'c *) + +(* was called 'some', but confusing *) +val pred : ('a -> bool) -> ('a, 'a) genp +(* ('a -> bool) -> 'a list -> 'a * 'a list *) + +val a : 'a -> ('a, 'a) genp +(* 'a -> 'a list -> 'a * 'a list *) + +val several : ('a -> bool) -> ('a, 'a list) genp +(* ('a -> bool) -> 'a list -> 'a list * 'a list *) + + +module Abstr : sig + type t + val x : t +end + +val fin : ('a, Abstr.t) genp +(* 'a list -> Abstr.t * 'b list *) + + +val digit : char -> bool +val alpha : char -> bool +val symbol : char -> bool +val alphanum : char -> bool +val space : char -> bool + +val alphanum_underscore : char -> bool +val alphanum_minus : char -> bool +val alphanum_under_minus : char -> bool + +val collect : char * char list -> string +val list_of_string : string -> char list + + +(*****************************************************************************) +type token = + | IDENT of string + | KWD of string + | INT of string + | SYM of string + | STR of string + +val string_of_token : token -> string + +type lexer = (char, token) genp + +val rawident : lexer +(* char list -> token * char list *) +val rawnumber : lexer +(* char list -> token * char list *) + +val rawsymbol : lexer + +(* not space, not digit *) +val rawkeyword : lexer +(* char list -> token * char list *) + +val rawstring : lexer + +val lex_gen : lexer -> string -> token list + +(*****************************************************************************) +val token : lexer +(* char list -> token * char list *) +val tokens : (char, token list) genp +(* char list -> token list * char list *) + +val alltokens : (char, token list) genp +(* char list -> token list * 'a list *) + +val lex : string -> token list + + +(*****************************************************************************) +(* cant use parser as it's a reseverd word *) +type 'a pparser = (token, 'a) genp + +val ident : string pparser +(* token list -> string * token list *) +val int : string pparser +(* token list -> string * token list *) +val string : string pparser + +type expr = + | Int of int + | Var of string + | Add of expr * expr + | Mul of expr * expr + +val atom : expr pparser +(* token list -> expr * token list *) +val factor : expr pparser +(* token list -> expr * token list *) +val term : expr pparser +(* token list -> expr * token list *) +val expr : expr pparser +(* token list -> expr * 'a list *) + +val parse : 'a pparser -> string -> 'a +(* (token list -> 'a * 'b) -> string -> 'a *) + + +(*****************************************************************************) + +module Infix : sig + val ( ||| ) : ('a, 'b) genp -> ('a, 'b) genp -> ('a, 'b) genp + (* ('a -> 'b) -> ('a -> 'b) -> 'a -> 'b *) + val ( +++ ) : ('a, 'b) genp -> ('a, 'c) genp -> ('a, 'b * 'c) genp + (* ('a -> 'b * 'c) -> ('c -> 'd * 'e) -> 'a -> ('b * 'd) * 'e *) + val ( >| ) : ('a, 'b) genp -> ('b -> 'c) -> ('a, 'c) genp + (* ('a -> 'b * 'c) -> ('b -> 'd) -> 'a -> 'd * 'c *) +end diff --git a/commons/ocamlextra/setPt.ml b/commons/ocamlextra/setPt.ml new file mode 100644 index 0000000..3df6944 --- /dev/null +++ b/commons/ocamlextra/setPt.ml @@ -0,0 +1,346 @@ +(* + * Ptset: Sets of integers implemented as Patricia trees. + * Copyright (C) 2000 Jean-Christophe FILLIATRE + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2, as published by the Free Software Foundation. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU Library General Public License version 2 for more details + * (enclosed in the file LGPL). + *) + +(*i ptset.ml 1.8 2001/06/28 07:05:55 filliatr Exp i*) + +(*s Sets of integers implemented as Patricia trees, following Chris + Okasaki and Andrew Gill's paper {\em Fast Mergeable Integer Maps} + ({\tt\small http://www.cs.columbia.edu/\~{}cdo/papers.html\#ml98maps}). + Patricia trees provide faster operations than standard library's + module [Set], and especially very fast [union], [subset], [inter] + and [diff] operations. *) + +(*s The idea behind Patricia trees is to build a {\em trie} on the + binary digits of the elements, and to compact the representation + by branching only one the relevant bits (i.e. the ones for which + there is at least on element in each subtree). We implement here + {\em little-endian} Patricia trees: bits are processed from + least-significant to most-significant. The trie is implemented by + the following type [t]. [Empty] stands for the empty trie, and + [Leaf k] for the singleton [k]. (Note that [k] is the actual + element.) [Branch (m,p,l,r)] represents a branching, where [p] is + the prefix (from the root of the trie) and [m] is the branching + bit (a power of 2). [l] and [r] contain the subsets for which the + branching bit is respectively 0 and 1. Invariant: the trees [l] + and [r] are not empty. *) + +(*i*) +type elt = int +(*i*) + +type t = + | Empty + | Leaf of int + | Branch of int * int * t * t + +(*s Example: the representation of the set $\{1,4,5\}$ is + $$\mathtt{Branch~(0,~1,~Leaf~4,~Branch~(1,~4,~Leaf~1,~Leaf~5))}$$ + The first branching bit is the bit 0 (and the corresponding prefix + is [0b0], not of use here), with $\{4\}$ on the left and $\{1,5\}$ on the + right. Then the right subtree branches on bit 2 (and so has a branching + value of $2^2 = 4$), with prefix [0b01 = 1]. *) + +(*s Empty set and singletons. *) + +let empty = Empty + +let is_empty = function Empty -> true | _ -> false + +let singleton k = Leaf k + +(*s Testing the occurrence of a value is similar to the search in a + binary search tree, where the branching bit is used to select the + appropriate subtree. *) + +let zero_bit k m = (k land m) == 0 + +let rec mem k = function + | Empty -> false + | Leaf j -> k == j + | Branch (_, m, l, r) -> mem k (if zero_bit k m then l else r) + +(*s The following operation [join] will be used in both insertion and + union. Given two non-empty trees [t0] and [t1] with longest common + prefixes [p0] and [p1] respectively, which are supposed to + disagree, it creates the union of [t0] and [t1]. For this, it + computes the first bit [m] where [p0] and [p1] disagree and create + a branching node on that bit. Depending on the value of that bit + in [p0], [t0] will be the left subtree and [t1] the right one, or + the converse. Computing the first branching bit of [p0] and [p1] + uses a nice property of twos-complement representation of integers. *) + +let lowest_bit x = x land (-x) + +let branching_bit p0 p1 = lowest_bit (p0 lxor p1) + +let mask p m = p land (m-1) + +let join (p0,t0,p1,t1) = + let m = branching_bit p0 p1 in + if zero_bit p0 m then + Branch (mask p0 m, m, t0, t1) + else + Branch (mask p0 m, m, t1, t0) + +(*s Then the insertion of value [k] in set [t] is easily implemented + using [join]. Insertion in a singleton is just the identity or a + call to [join], depending on the value of [k]. When inserting in + a branching tree, we first check if the value to insert [k] + matches the prefix [p]: if not, [join] will take care of creating + the above branching; if so, we just insert [k] in the appropriate + subtree, depending of the branching bit. *) + +let match_prefix k p m = (mask k m) == p + +let add k t = + let rec ins = function + | Empty -> Leaf k + | Leaf j as t -> + if j == k then t else join (k, Leaf k, j, t) + | Branch (p,m,t0,t1) as t -> + if match_prefix k p m then + if zero_bit k m then + Branch (p, m, ins t0, t1) + else + Branch (p, m, t0, ins t1) + else + join (k, Leaf k, p, t) + in + ins t + +(*s The code to remove an element is basically similar to the code of + insertion. But since we have to maintain the invariant that both + subtrees of a [Branch] node are non-empty, we use here the + ``smart constructor'' [branch] instead of [Branch]. *) + +let branch = function + | (_,_,Empty,t) -> t + | (_,_,t,Empty) -> t + | (p,m,t0,t1) -> Branch (p,m,t0,t1) + +let remove k t = + let rec rmv = function + | Empty -> Empty + | Leaf j as t -> if k == j then Empty else t + | Branch (p,m,t0,t1) as t -> + if match_prefix k p m then + if zero_bit k m then + branch (p, m, rmv t0, t1) + else + branch (p, m, t0, rmv t1) + else + t + in + rmv t + +(*s One nice property of Patricia trees is to support a fast union + operation (and also fast subset, difference and intersection + operations). When merging two branching trees we examine the + following four cases: (1) the trees have exactly the same + prefix; (2/3) one prefix contains the other one; and (4) the + prefixes disagree. In cases (1), (2) and (3) the recursion is + immediate; in case (4) the function [join] creates the appropriate + branching. *) + +let rec merge = function + | Empty, t -> t + | t, Empty -> t + | Leaf k, t -> add k t + | t, Leaf k -> add k t + | (Branch (p,m,s0,s1) as s), (Branch (q,n,t0,t1) as t) -> + if m == n && match_prefix q p m then + (* The trees have the same prefix. Merge the subtrees. *) + Branch (p, m, merge (s0,t0), merge (s1,t1)) + else if m < n && match_prefix q p m then + (* [q] contains [p]. Merge [t] with a subtree of [s]. *) + if zero_bit q m then + Branch (p, m, merge (s0,t), s1) + else + Branch (p, m, s0, merge (s1,t)) + else if m > n && match_prefix p q n then + (* [p] contains [q]. Merge [s] with a subtree of [t]. *) + if zero_bit p n then + Branch (q, n, merge (s,t0), t1) + else + Branch (q, n, t0, merge (s,t1)) + else + (* The prefixes disagree. *) + join (p, s, q, t) + +let union s t = merge (s,t) + +(*s When checking if [s1] is a subset of [s2] only two of the above + four cases are relevant: when the prefixes are the same and when the + prefix of [s1] contains the one of [s2], and then the recursion is + obvious. In the other two cases, the result is [false]. *) + +let rec subset s1 s2 = match (s1,s2) with + | Empty, _ -> true + | _, Empty -> false + | Leaf k1, _ -> mem k1 s2 + | Branch _, Leaf _ -> false + | Branch (p1,m1,l1,r1), Branch (p2,m2,l2,r2) -> + if m1 == m2 && p1 == p2 then + subset l1 l2 && subset r1 r2 + else if m1 > m2 && match_prefix p1 p2 m2 then + if zero_bit p1 m2 then + subset l1 l2 && subset r1 l2 + else + subset l1 r2 && subset r1 r2 + else + false + +(*s To compute the intersection and the difference of two sets, we + still examine the same four cases as in [merge]. The recursion is + then obvious. *) + +let rec inter s1 s2 = match (s1,s2) with + | Empty, _ -> Empty + | _, Empty -> Empty + | Leaf k1, _ -> if mem k1 s2 then s1 else Empty + | _, Leaf k2 -> if mem k2 s1 then s2 else Empty + | Branch (p1,m1,l1,r1), Branch (p2,m2,l2,r2) -> + if m1 == m2 && p1 == p2 then + merge (inter l1 l2, inter r1 r2) + else if m1 < m2 && match_prefix p2 p1 m1 then + inter (if zero_bit p2 m1 then l1 else r1) s2 + else if m1 > m2 && match_prefix p1 p2 m2 then + inter s1 (if zero_bit p1 m2 then l2 else r2) + else + Empty + +let rec diff s1 s2 = match (s1,s2) with + | Empty, _ -> Empty + | _, Empty -> s1 + | Leaf k1, _ -> if mem k1 s2 then Empty else s1 + | _, Leaf k2 -> remove k2 s1 + | Branch (p1,m1,l1,r1), Branch (p2,m2,l2,r2) -> + if m1 == m2 && p1 == p2 then + merge (diff l1 l2, diff r1 r2) + else if m1 < m2 && match_prefix p2 p1 m1 then + if zero_bit p2 m1 then + merge (diff l1 s2, r1) + else + merge (l1, diff r1 s2) + else if m1 > m2 && match_prefix p1 p2 m2 then + if zero_bit p1 m2 then diff s1 l2 else diff s1 r2 + else + s1 + +(*s All the following operations ([cardinal], [iter], [fold], [for_all], + [exists], [filter], [partition], [choose], [elements]) are + implemented as for any other kind of binary trees. *) + +let rec cardinal = function + | Empty -> 0 + | Leaf _ -> 1 + | Branch (_,_,t0,t1) -> cardinal t0 + cardinal t1 + +let rec iter f = function + | Empty -> () + | Leaf k -> f k + | Branch (_,_,t0,t1) -> iter f t0; iter f t1 + +let rec fold f s accu = match s with + | Empty -> accu + | Leaf k -> f k accu + | Branch (_,_,t0,t1) -> fold f t0 (fold f t1 accu) + +let rec for_all p = function + | Empty -> true + | Leaf k -> p k + | Branch (_,_,t0,t1) -> for_all p t0 && for_all p t1 + +let rec exists p = function + | Empty -> false + | Leaf k -> p k + | Branch (_,_,t0,t1) -> exists p t0 || exists p t1 + +let filter p s = + let rec filt acc = function + | Empty -> acc + | Leaf k -> if p k then add k acc else acc + | Branch (_,_,t0,t1) -> filt (filt acc t0) t1 + in + filt Empty s + +let partition p s = + let rec part (t,f as acc) = function + | Empty -> acc + | Leaf k -> if p k then (add k t, f) else (t, add k f) + | Branch (_,_,t0,t1) -> part (part acc t0) t1 + in + part (Empty, Empty) s + +let rec choose = function + | Empty -> raise Not_found + | Leaf k -> k + | Branch (_, _,t0,_) -> choose t0 (* we know that [t0] is non-empty *) + +let elements s = + let rec elements_aux acc = function + | Empty -> acc + | Leaf k -> k :: acc + | Branch (_,_,l,r) -> elements_aux (elements_aux acc l) r + in + elements_aux [] s + +(*s There is no way to give an efficient implementation of [min_elt] + and [max_elt], as with binary search trees. The following + implementation is a traversal of all elements, barely more + efficient than [fold min t (choose t)] (resp. [fold max t (choose + t)]). Note that we use the fact that there is no constructor + [Empty] under [Branch] and therefore always a minimal + (resp. maximal) element there. *) + +let rec min_elt = function + | Empty -> raise Not_found + | Leaf k -> k + | Branch (_,_,s,t) -> min (min_elt s) (min_elt t) + +let rec max_elt = function + | Empty -> raise Not_found + | Leaf k -> k + | Branch (_,_,s,t) -> max (max_elt s) (max_elt t) + +(*s Another nice property of Patricia trees is to be independent of the + order of insertion. As a consequence, two Patricia trees have the + same elements if and only if they are structurally equal. *) + +let equal = (=) + +let compare = compare + +(*i*) +let make l = List.fold_right add l empty +(*i*) + +(*s Additional functions w.r.t to [Set.S]. *) + +let rec intersect s1 s2 = match (s1,s2) with + | Empty, _ -> false + | _, Empty -> false + | Leaf k1, _ -> mem k1 s2 + | _, Leaf k2 -> mem k2 s1 + | Branch (p1,m1,l1,r1), Branch (p2,m2,l2,r2) -> + if m1 == m2 && p1 == p2 then + intersect l1 l2 || intersect r1 r2 + else if m1 < m2 && match_prefix p2 p1 m1 then + intersect (if zero_bit p2 m1 then l1 else r1) s2 + else if m1 > m2 && match_prefix p1 p2 m2 then + intersect s1 (if zero_bit p1 m2 then l2 else r2) + else + false diff --git a/commons/ocamlextra/setb.ml b/commons/ocamlextra/setb.ml new file mode 100644 index 0000000..debfcfd --- /dev/null +++ b/commons/ocamlextra/setb.ml @@ -0,0 +1,302 @@ +(*pad: taken from set.ml from stdlib ocaml, functor sux: module Make(Ord: OrderedType) = *) +(* with some addons such as from list *) + + +(***********************************************************************) +(* *) +(* Objective Caml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU Library General Public License, with *) +(* the special exception on linking described in file ../LICENSE. *) +(* *) +(***********************************************************************) + +(* set.ml 1.18.4.1 2004/11/03 21:19:49 doligez Exp *) + +(* Sets over ordered types *) + +(* pad: + type elt = Ord.t + type t = Empty | Node of t * elt * t * int + and subst all Ord.compare with just compare +*) + type 'elt t = Empty | Node of 'elt t * 'elt * 'elt t * int + + (* Sets are represented by balanced binary trees (the heights of the + children differ by at most 2 *) + + let height = function + Empty -> 0 + | Node(_, _, _, h) -> h + + (* Creates a new node with left son l, value v and right son r. + We must have all elements of l < v < all elements of r. + l and r must be balanced and | height l - height r | <= 2. + Inline expansion of height for better speed. *) + + let create l v r = + let hl = match l with Empty -> 0 | Node(_,_,_,h) -> h in + let hr = match r with Empty -> 0 | Node(_,_,_,h) -> h in + Node(l, v, r, (if hl >= hr then hl + 1 else hr + 1)) + + (* Same as create, but performs one step of rebalancing if necessary. + Assumes l and r balanced and | height l - height r | <= 3. + Inline expansion of create for better speed in the most frequent case + where no rebalancing is required. *) + + let bal l v r = + let hl = match l with Empty -> 0 | Node(_,_,_,h) -> h in + let hr = match r with Empty -> 0 | Node(_,_,_,h) -> h in + if hl > hr + 2 then begin + match l with + Empty -> invalid_arg "Set.bal" + | Node(ll, lv, lr, _) -> + if height ll >= height lr then + create ll lv (create lr v r) + else begin + match lr with + Empty -> invalid_arg "Set.bal" + | Node(lrl, lrv, lrr, _)-> + create (create ll lv lrl) lrv (create lrr v r) + end + end else if hr > hl + 2 then begin + match r with + Empty -> invalid_arg "Set.bal" + | Node(rl, rv, rr, _) -> + if height rr >= height rl then + create (create l v rl) rv rr + else begin + match rl with + Empty -> invalid_arg "Set.bal" + | Node(rll, rlv, rlr, _) -> + create (create l v rll) rlv (create rlr rv rr) + end + end else + Node(l, v, r, (if hl >= hr then hl + 1 else hr + 1)) + + (* Insertion of one element *) + + let rec add x = function + Empty -> Node(Empty, x, Empty, 1) + | Node(l, v, r, _) as t -> + let c = compare x v in + if c = 0 then t else + if c < 0 then bal (add x l) v r else bal l v (add x r) + + (* Same as create and bal, but no assumptions are made on the + relative heights of l and r. *) + + let rec join l v r = + match (l, r) with + (Empty, _) -> add v r + | (_, Empty) -> add v l + | (Node(ll, lv, lr, lh), Node(rl, rv, rr, rh)) -> + if lh > rh + 2 then bal ll lv (join lr v r) else + if rh > lh + 2 then bal (join l v rl) rv rr else + create l v r + + (* Smallest and greatest element of a set *) + + let rec min_elt = function + Empty -> raise Not_found + | Node(Empty, v, r, _) -> v + | Node(l, v, r, _) -> min_elt l + + let rec max_elt = function + Empty -> raise Not_found + | Node(l, v, Empty, _) -> v + | Node(l, v, r, _) -> max_elt r + + (* Remove the smallest element of the given set *) + + let rec remove_min_elt = function + Empty -> invalid_arg "Set.remove_min_elt" + | Node(Empty, v, r, _) -> r + | Node(l, v, r, _) -> bal (remove_min_elt l) v r + + (* Merge two trees l and r into one. + All elements of l must precede the elements of r. + Assume | height l - height r | <= 2. *) + + let merge t1 t2 = + match (t1, t2) with + (Empty, t) -> t + | (t, Empty) -> t + | (_, _) -> bal t1 (min_elt t2) (remove_min_elt t2) + + (* Merge two trees l and r into one. + All elements of l must precede the elements of r. + No assumption on the heights of l and r. *) + + let concat t1 t2 = + match (t1, t2) with + (Empty, t) -> t + | (t, Empty) -> t + | (_, _) -> join t1 (min_elt t2) (remove_min_elt t2) + + (* Splitting. split x s returns a triple (l, present, r) where + - l is the set of elements of s that are < x + - r is the set of elements of s that are > x + - present is false if s contains no element equal to x, + or true if s contains an element equal to x. *) + + let rec split x = function + Empty -> + (Empty, false, Empty) + | Node(l, v, r, _) -> + let c = compare x v in + if c = 0 then (l, true, r) + else if c < 0 then + let (ll, pres, rl) = split x l in (ll, pres, join rl v r) + else + let (lr, pres, rr) = split x r in (join l v lr, pres, rr) + + (* Implementation of the set operations *) + + let empty = Empty + + let is_empty = function Empty -> true | _ -> false + + let rec mem x = function + Empty -> false + | Node(l, v, r, _) -> + let c = compare x v in + c = 0 || mem x (if c < 0 then l else r) + + let singleton x = Node(Empty, x, Empty, 1) + + let rec remove x = function + Empty -> Empty + | Node(l, v, r, _) -> + let c = compare x v in + if c = 0 then merge l r else + if c < 0 then bal (remove x l) v r else bal l v (remove x r) + + let rec union s1 s2 = + match (s1, s2) with + (Empty, t2) -> t2 + | (t1, Empty) -> t1 + | (Node(l1, v1, r1, h1), Node(l2, v2, r2, h2)) -> + if h1 >= h2 then + if h2 = 1 then add v2 s1 else begin + let (l2, _, r2) = split v1 s2 in + join (union l1 l2) v1 (union r1 r2) + end + else + if h1 = 1 then add v1 s2 else begin + let (l1, _, r1) = split v2 s1 in + join (union l1 l2) v2 (union r1 r2) + end + + let rec inter s1 s2 = + match (s1, s2) with + (Empty, t2) -> Empty + | (t1, Empty) -> Empty + | (Node(l1, v1, r1, _), t2) -> + match split v1 t2 with + (l2, false, r2) -> + concat (inter l1 l2) (inter r1 r2) + | (l2, true, r2) -> + join (inter l1 l2) v1 (inter r1 r2) + + let rec diff s1 s2 = + match (s1, s2) with + (Empty, t2) -> Empty + | (t1, Empty) -> t1 + | (Node(l1, v1, r1, _), t2) -> + match split v1 t2 with + (l2, false, r2) -> + join (diff l1 l2) v1 (diff r1 r2) + | (l2, true, r2) -> + concat (diff l1 l2) (diff r1 r2) + + let rec compare_aux l1 l2 = + match (l1, l2) with + ([], []) -> 0 + | ([], _) -> -1 + | (_, []) -> 1 + | (Empty :: t1, Empty :: t2) -> + compare_aux t1 t2 + | (Node(Empty, v1, r1, _) :: t1, Node(Empty, v2, r2, _) :: t2) -> + let c = compare v1 v2 in + if c <> 0 then c else compare_aux (r1::t1) (r2::t2) + | (Node(l1, v1, r1, _) :: t1, t2) -> + compare_aux (l1 :: Node(Empty, v1, r1, 0) :: t1) t2 + | (t1, Node(l2, v2, r2, _) :: t2) -> + compare_aux t1 (l2 :: Node(Empty, v2, r2, 0) :: t2) + + let compare s1 s2 = + compare_aux [s1] [s2] + + let equal s1 s2 = + compare s1 s2 = 0 + + let rec subset s1 s2 = + match (s1, s2) with + Empty, _ -> + true + | _, Empty -> + false + | Node (l1, v1, r1, _), (Node (l2, v2, r2, _) as t2) -> + let c = Pervasives.compare v1 v2 in + if c = 0 then + subset l1 l2 && subset r1 r2 + else if c < 0 then + subset (Node (l1, v1, Empty, 0)) l2 && subset r1 t2 + else + subset (Node (Empty, v1, r1, 0)) r2 && subset l1 t2 + + let rec iter f = function + Empty -> () + | Node(l, v, r, _) -> iter f l; f v; iter f r + + let rec fold f s accu = + match s with + Empty -> accu + | Node(l, v, r, _) -> fold f l (f v (fold f r accu)) + + let rec for_all p = function + Empty -> true + | Node(l, v, r, _) -> p v && for_all p l && for_all p r + + let rec exists p = function + Empty -> false + | Node(l, v, r, _) -> p v || exists p l || exists p r + + let filter p s = + let rec filt accu = function + | Empty -> accu + | Node(l, v, r, _) -> + filt (filt (if p v then add v accu else accu) l) r in + filt Empty s + + let partition p s = + let rec part (t, f as accu) = function + | Empty -> accu + | Node(l, v, r, _) -> + part (part (if p v then (add v t, f) else (t, add v f)) l) r in + part (Empty, Empty) s + + let rec cardinal = function + Empty -> 0 + | Node(l, v, r, _) -> cardinal l + 1 + cardinal r + + let rec elements_aux accu = function + Empty -> accu + | Node(l, v, r, _) -> elements_aux (v :: elements_aux accu r) l + + let elements s = + elements_aux [] s + + let choose = min_elt + +(* pad: *) +let (from_list: 'a list -> 'a t) = fun xs -> + List.fold_left (fun a e -> add e a) empty xs + + + diff --git a/commons/ocamlextra/setb.mli b/commons/ocamlextra/setb.mli new file mode 100644 index 0000000..b59c8d9 --- /dev/null +++ b/commons/ocamlextra/setb.mli @@ -0,0 +1,159 @@ +(*pad: taken from set.ml from stdlib ocaml, functor sux: module Make(Ord: OrderedType) = *) +(* with some addons such as from list *) +(***********************************************************************) +(* *) +(* Objective Caml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU Library General Public License, with *) +(* the special exception on linking described in file ../LICENSE. *) +(* *) +(***********************************************************************) + +(* set.mli 1.32 2004/04/23 10:01:54 xleroy Exp $ *) + +(** Sets over ordered types. + + This module implements the set data structure, given a total ordering + function over the set elements. All operations over sets + are purely applicative (no side-effects). + The implementation uses balanced binary trees, and is therefore + reasonably efficient: insertion and membership take time + logarithmic in the size of the set, for instance. +*) +(* pad: +module type OrderedType = + sig + type t + (** The type of the set elements. *) + val compare : t -> t -> int + (** A total ordering function over the set elements. + This is a two-argument function [f] such that + [f e1 e2] is zero if the elements [e1] and [e2] are equal, + [f e1 e2] is strictly negative if [e1] is smaller than [e2], + and [f e1 e2] is strictly positive if [e1] is greater than [e2]. + Example: a suitable ordering function is the generic structural + comparison function {!Pervasives.compare}. *) + end +(** Input signature of the functor {!Set.Make}. *) +*) +(* +module type S = + sig +*) + (* type elt *) + (** The type of the set elements. *) + + type 'elt t + (** The type of sets. *) + + val empty: 'elt t + (** The empty set. *) + + val is_empty: 'elt t -> bool + (** Test whether a set is empty or not. *) + + val mem: 'elt -> 'elt t -> bool + (** [mem x s] tests whether [x] belongs to the set [s]. *) + + val add: 'elt -> 'elt t -> 'elt t + (** [add x s] returns a set containing all elements of [s], + plus [x]. If [x] was already in [s], [s] is returned unchanged. *) + + val singleton: 'elt -> 'elt t + (** [singleton x] returns the one-element set containing only [x]. *) + + val remove: 'elt -> 'elt t -> 'elt t + (** [remove x s] returns a set containing all elements of [s], + except [x]. If [x] was not in [s], [s] is returned unchanged. *) + + val union: 'elt t -> 'elt t -> 'elt t + (** Set union. *) + + val inter: 'elt t -> 'elt t -> 'elt t + (** Set intersection. *) + + (** Set difference. *) + val diff: 'elt t -> 'elt t -> 'elt t + + val compare: 'elt t -> 'elt t -> int + (** Total ordering between sets. Can be used as the ordering function + for doing sets of sets. *) + + val equal: 'elt t -> 'elt t -> bool + (** [equal s1 s2] tests whether the sets [s1] and [s2] are + equal, that is, contain equal elements. *) + + val subset: 'elt t -> 'elt t -> bool + (** [subset s1 s2] tests whether the set [s1] is a subset of + the set [s2]. *) + + val iter: ('elt -> unit) -> 'elt t -> unit + (** [iter f s] applies [f] in turn to all elements of [s]. + The elements of [s] are presented to [f] in increasing order + with respect to the ordering over the type of the elements. *) + + val fold: ('elt -> 'a -> 'a) -> 'elt t -> 'a -> 'a + (** [fold f s a] computes [(f xN ... (f x2 (f x1 a))...)], + where [x1 ... xN] are the elements of [s], in increasing order. *) + + val for_all: ('elt -> bool) -> 'elt t -> bool + (** [for_all p s] checks if all elements of the set + satisfy the predicate [p]. *) + + val exists: ('elt -> bool) -> 'elt t -> bool + (** [exists p s] checks if at least one element of + the set satisfies the predicate [p]. *) + + val filter: ('elt -> bool) -> 'elt t -> 'elt t + (** [filter p s] returns the set of all elements in [s] + that satisfy predicate [p]. *) + + val partition: ('elt -> bool) -> 'elt t -> 'elt t * 'elt t + (** [partition p s] returns a pair of sets [(s1, s2)], where + [s1] is the set of all the elements of [s] that satisfy the + predicate [p], and [s2] is the set of all the elements of + [s] that do not satisfy [p]. *) + + val cardinal: 'elt t -> int + (** Return the number of elements of a set. *) + + val elements: 'elt t -> 'elt list + (** Return the list of all elements of the given set. + The returned list is sorted in increasing order with respect + to the ordering [Ord.compare], where [Ord] is the argument + given to {!Set.Make}. *) + + val min_elt: 'elt t -> 'elt + (** Return the smallest element of the given set + (with respect to the [Ord.compare] ordering), or raise + [Not_found] if the set is empty. *) + + val max_elt: 'elt t -> 'elt + (** Same as {!Set.S.min_elt}, but returns the largest element of the + given set. *) + + val choose: 'elt t -> 'elt + (** Return one element of the given set, or raise [Not_found] if + the set is empty. Which element is chosen is unspecified, + but equal elements will be chosen for equal sets. *) + + val split: 'elt -> 'elt t -> 'elt t * bool * 'elt t + (** [split x s] returns a triple [(l, present, r)], where + [l] is the set of elements of [s] that are + strictly less than [x]; + [r] is the set of elements of [s] that are + strictly greater than [x]; + [present] is [false] if [s] contains no element equal to [x], + or [true] if [s] contains an element equal to [x]. *) +(* + end +(** Output signature of the functor {!Set.Make}. *) + +module Make (Ord : OrderedType) : S with type elt = Ord.t +(** Functor building an implementation of the set structure + given a totally ordered type. *) +*) diff --git a/commons/ocamlextra/suffix_tree.ml b/commons/ocamlextra/suffix_tree.ml new file mode 100644 index 0000000..5c606ce --- /dev/null +++ b/commons/ocamlextra/suffix_tree.ml @@ -0,0 +1,318 @@ +(* made by Sebastien Ferre *) + +(* type of nodes in suffix trees *) +type node = { + seqid : int; (* sequence index in which the positions start and final are defined *) + mutable start : int; (* start and final position of the word labelling the node *) + final : int ref; + mutable link : node; (* suffix link *) + v : node_value + } +and node_value = + | Children of (char,node) Hashtbl.t (* for non-leaves: children nodes *) + (* for the key '\000', all values are relevant (use Hashtbl.find_all) *) + | Index of int (* for leaves: position of recognized suffix *) + +(* type of suffix trees *) +type t = string array * node + +(* the initial root node *) +let empty : unit -> node = + fun () -> + let rec root = {seqid= -1; start=0; final=ref (-1); link=root; v=Children (Hashtbl.create 2)} in + root + + +(* -------------------------------------------------------------------------------- + Operations on substrings of sequences + -------------------------------------------------------------------------------- *) + +type subseq = string * int * int (* (seq, pos, len) *) + +let subseq_empty = ("",0,0) (* non-significant subseq *) + +let subseq_is_empty (s,pos,len) = len = 0 + +let subseq_get (s,pos,len) i = s.[pos+i] + +let subseq_length (s,pos,len) = len + +let subseq_sub (s,pos,len) pos' len' = (s,pos+pos',len') + +let subseq_extend (s,pos,len) = (s,pos,len+1) + +(* ------------------------------------------------------------------------------- + Operations on implicit nodes (explicit, implicit, child : node * subseq * node) + the snd node [child] is significant only when [implicit] is not the empty string, + and is the child that recognizes [implicit] starting from [explicit]. [implicit] is + defined by a sequence, a start and a length. + ------------------------------------------------------------------------------- *) + +let eq_char c1 c2 = + c1<>'\000' & c1=c2 (* ensures that 2 terminal symbols '\000' are pairwise different (for GST only, not necessary for ST) *) + +(* returns the child node that recognizes [implicit] from the node [explicit] *) +let get_child seqar (explicit,implicit) = + if subseq_is_empty implicit + then explicit + else + let c = subseq_get implicit 0 in + if c = '\000' + then raise Not_found + else + match explicit.v with + | Children h -> Hashtbl.find h c + | Index _ -> raise Not_found + (* List.find (fun child -> eq_char seqar.(child.seqid).[child.start] c) explicit.children *) + +(* ensures that implicit does not span over another node below [explicit] *) +let rec canonical seqar (explicit,implicit,child) = + if subseq_is_empty implicit + then (explicit,implicit,child) + else + let l = !(child.final) - child.start + 1 in + let a = subseq_length implicit in + if a < l + then (explicit,implicit,child) + else + let implicit' = subseq_sub implicit l (a-l) in + canonical seqar (child, implicit', get_child seqar (child,implicit')) + +(* test whether an implicit node is the root node *) +let is_root root (explicit,implicit,_) = + explicit == root & subseq_is_empty implicit + +(* test whether the extension of an implicit node by [seqar.(k).[i]] is still recognized in the GST, + and if yes, returns the implicit node extended by 1 position, otherwise returns [None]. *) +let has_child seqar (explicit,implicit,child) (k,i) = + let a = subseq_length implicit in + if a <> 0 then + if eq_char seqar.(child.seqid).[child.start+a] seqar.(k).[i] + then Some (explicit, subseq_extend implicit, child) + else None + else + try + let implicit' = (seqar.(k),i,1) in + Some (explicit, implicit', get_child seqar (explicit,implicit')) + with Not_found -> None + +(* -------------------------------- + creation of new nodes and leaves + -------------------------------- *) + +let add_leaf (seqar,root) node seqid start final_ref index = + match node.v with + | Children h -> + Hashtbl.add h + seqar.(seqid).[start] + {seqid=seqid; start=start; final=final_ref; link=root; v=(Index index)} + | Index _ -> raise (Invalid_argument "Suffix_tree.add_leaf: 2nd argument must not be a leaf") + +(* make explicit an implicit node by inserting a new node between [explicit] and [child] *) +let insert_node (seqar,root) (explicit,implicit,child) = + let a = subseq_length implicit in + if a = 0 + then explicit + else + match explicit.v with + | Children h -> + let c_child_old = seqar.(child.seqid).[child.start] in + let c_child_new = seqar.(child.seqid).[child.start+a] in + let n' = { + seqid = child.seqid; + start = child.start; + final = ref (child.start+a-1); + link = root; + v = Children (let h' = Hashtbl.create (Hashtbl.length h) in Hashtbl.add h' c_child_new child; h') + } in + child.start <- child.start+a; + Hashtbl.replace h c_child_old n'; + n' + | Index _ -> raise (Invalid_argument "Suffix_tree.insert_node: first part of 2nd argument must not be a leaf") + +(* add a suffix link from [pred_opt] (if defined) to [explicit] *) +let add_link root pred_opt explicit = + (*if explicit != root then*) (* create a new suffix link *) + match pred_opt with + | Some n -> (*if n.link = None then*) n.link <- explicit + | None -> () + +(* ------------ + suffix links + ------------ *) + +(* get the node refered by the suffix link at [n] *) +(* +let suffix_link (root : node) (n : node) : node = + match n.link with + | None -> root (* by default, the suffix link points to the root node *) + | Some n' -> n' +*) + +(* extend suffix_link for implicit nodes *) +let link (seqar,root) = function (* TODO *) + | (explicit,implicit,_) when subseq_is_empty implicit -> + let explicit' = explicit.link (*suffix_link root explicit*) in + (explicit', subseq_empty, explicit') + | (explicit,implicit,_) -> + if explicit == root + then + let implicit' = subseq_sub implicit 1 (subseq_length implicit - 1) in + canonical seqar (root, implicit', get_child seqar (root,implicit')) + else + let explicit' = explicit.link (*suffix_link root explicit*) in + canonical seqar (explicit', implicit, get_child seqar (explicit',implicit)) + +(* -------------------------------------------------------------- + GST update for the new character c at position i in sequence k + -------------------------------------------------------------- *) + +(* state for 'update' *) +type res = { + terminal : int ref; + mutable startj : int; + mutable startnode : node * subseq * node + } + +let rec update (seqar,root) (k,i) res pred_opt = + (* c = seqar.(k).[i] *) + match has_child seqar res.startnode (k,i) with + | Some extended_startnode -> (* startnode can be extended by [c] *) + let explicit, implicit, _ = res.startnode in + assert (pred_opt = None or subseq_is_empty implicit); + (* if a link has been followed after node creation, then we are on an explicit node *) + add_link root pred_opt explicit; + res.startnode <- canonical seqar extended_startnode + | None -> (* startnode cannot be extended by [c] ... *) + let n' = insert_node (seqar,root) res.startnode in (* ... so we insert a new node ... *) + add_link root pred_opt n'; (* ... a suffix link from the last created node (if defined) ... *) + if seqar.(k).[res.startj] <> '\000' then + add_leaf (seqar,root) n' k i res.terminal res.startj; (* ... and a new leaf for the suffix at position [res.startj] *) + res.startj <- res.startj + 1; (* prepare for the next suffix *) + if not (is_root root res.startnode) + then begin (* while [res.startnode] is not the root, and cannot be extended by [c] ... *) + res.startnode <- link (seqar,root) res.startnode; (* ... follow the suffix link to find the next suffix ... *) + update (seqar,root) (k,i) res (Some n') end (* ... and loop on [update] *) + +(* ------------------------------- + implementing the .mli interface + ------------------------------- *) + +let make : string list -> t = + fun l_seq -> + let l = List.length l_seq in + let seqar = Array.make l "" in + let root = empty () in + let st = (seqar, root) in + ignore (List.fold_left + (fun k seq -> (* for every sequence/string [seq], numbered [k] ... *) + seqar.(k) <- seq ^ String.make 1 '\000'; (* add a terminal symbol ... *) + let res = {terminal=ref (-1); startj=0; startnode=(root,subseq_empty,root)} in (* initialize for [update] ... *) + for i = 0 to String.length seqar.(k) - 1 do (* for every position [i] in the sequence ... *) + incr res.terminal; (* increment the leaves final position ... *) + update st (k,i) res None (* call [update] for updating the suffix tree with the character at position [i] *) + done; + k+1) + 0 l_seq); + st + +let string (seqar,root : t) (k : int) = + let seq = seqar.(k) in + String.sub seq 0 (String.length seq - 1) (* removing the terminal symbol *) + +let string_list (seqar,root : t) = + List.map (fun seq -> String.sub seq 0 (String.length seq - 1)) (Array.to_list seqar) + +let root (seq,root : t) = root + +let word (seqar,root) node = + if node == root + then "" + else String.sub seqar.(node.seqid) node.start (!(node.final) - node.start + (match node.v with Children _ -> 1 | Index _ -> 0)) + +let children (gst : t) node = + match node.v with + | Children h -> + Hashtbl.fold (fun c n l -> n::l) h [] + | Index _ -> [] + +let index (seq,root) node : int * int = + match node.v with + | Children _ -> raise (Invalid_argument "Suffix_tree.index: 2nd argument must be a leaf") + | Index i -> (node.seqid, i) + +let linked_node (seqar,root : t) (n : node) : node = + n.link (*suffix_link root n*) + +let rec implicit_node (seqar,node : t) (word : string) = + let (explicit, (s,i,len), child) = implicit_node_aux (seqar,node) (word,0,String.length word) in + (explicit, String.sub s i len, child) +and implicit_node_aux (seqar,node) implicit = + let w = subseq_length implicit in + let child = get_child seqar (node,implicit) in + let l = !(child.final) - child.start + 1 in + let a = ref 1 in + while !a < l & !a < w & eq_char seqar.(child.seqid).[child.start + !a] (subseq_get implicit !a) do + incr a + done; (* [!a] is the first mismatch position, or the length of [child] label *) + if !a < w then + if !a < l + then raise Not_found + else implicit_node_aux (seqar,child) (subseq_sub implicit !a (w - !a)) + else (node,implicit,child) + +(* +let rec synthesized (seqar,root : t) (f : 'a list -> node -> 'a) = + synthesized_node (seqar,root) f root +and synthesized_node st f node = + f (List.map (synthesized_node st f) (children st node)) node +*) + +(* general fold *) +let rec fold : t -> ('h -> node -> bool) -> ('h -> node -> 'h) -> ('s list -> 'h -> node -> 's) -> 'h -> 's = + fun gst f h s init -> + fold_node gst f h s init (root gst) +and fold_node gst f h s h_node node = + s + (List.map + (fun child -> fold_node gst f h s (h h_node child) child) + (List.filter (f h_node) (children gst node))) + h_node + node + +(* synthesized attributes only *) +let fold_s_node gst s node = fold_node gst (fun _ _ -> true) (fun _ _ -> ()) (fun l _ n -> s l n) () node +let fold_s gst s = fold_s_node gst s (root gst) + +(* filtering and synthesizing, no inheritance *) +let fold_fs gst f s = fold gst (fun _ n -> f n) (fun _ _ -> ()) (fun l _ n -> s l n) () + + +type tree = Node of string * tree list | Leaf of string * (int * int) + +let readable gst = + fold_s gst + (fun l n -> + let w = word gst n in + if l=[] + then Leaf (w, index gst n) + else Node (w, l)) + +(* applications of suffix trees *) + +let exact_matches : t -> string -> (int * int) list = + fun gst word -> + try + let explicit, implicit, child = implicit_node gst word in + fold_s_node gst + (fun l n -> if l=[] then [index gst n] else List.concat l) + child + with Not_found -> [] + + + +let contained_string gst word = + List.map (fun (i,j) -> Array.get (fst gst) i) (exact_matches gst word) + + + diff --git a/commons/ocamlextra/suffix_tree.mli b/commons/ocamlextra/suffix_tree.mli new file mode 100644 index 0000000..545cccd --- /dev/null +++ b/commons/ocamlextra/suffix_tree.mli @@ -0,0 +1,90 @@ +(** + Generalized suffix trees (GSTs). + + Computes generalized suffix trees from list of strings. A terminal symbol is + implicitly added to them, but is not returned in the word labeling nodes and + leaves. This should allow a rather transparent handling of GSTs. + + Node-based accesses are provided (sequences, root, children, suffix links, + node labels, index), as well as a functional for synthesizing attributes from + a GST. A readable representation of GSTs is derived from the later. +*) +(* made by Sebastien Ferre *) + +type node + (** Type of nodes in GSTs. *) + +type t + (** Type of GSTs. *) + +val make : string list -> t + (** [make l_str] computes a GST based on the set of strings given in [l_str]. *) + +val string_list : t -> string list + (** [string_list gst] returns the list of strings from which [gst] was computed. *) + +val string : t -> int -> string + (** [string gst k] returns the sequence number [k] (starting from 0). *) + +val root : t -> node + (** [root gst] returns the root node of the gst. *) + +val word : t -> node -> string + (** [word gst n] returns the word labeling node [n] in [gst]. *) + +val children : t -> node -> node list + (** [children gst n] returns a list of the children nodes of [n] in [gst]. *) + +val linked_node : t -> node -> node + (** [linked_node gst n] returns the node pointed by the suffix link from [n] in [gst]. *) + +val index : t -> node -> int * int + (** [index gst n] returns the index of a leaf [n] in [gst]. + This index is a pair [(k,i)], where [k] is the number of the sequence (as used by [string]), and + [i] is the position of the related suffix (starting from [0] as usual in strings). + @raise Invalid_argument "Suffix_tree.index: not a leaf" if [n] is not a leaf (has some child). *) + +val implicit_node : t -> string -> node * string * node + (** [implicit_node gst word] returns an implicit_node [(node,word',child)], where [node] is the lowest + node in the suffix tre such that the concatenation of the word recognized by [node] and [word'] is + equal to [word], if [word'] is not the empty string, then [child] is the child node of [node], whose + label has [word'] as a prefix. + @raise Not_found when [word] is not a substring of [string_list gst]. *) + + +val fold : t -> ('h -> node -> bool) -> ('h -> node -> 'h) -> ('s list -> 'h -> node -> 's) -> 'h -> 's + (** [fold gst filter herit synth init] computes some attribute(s) over a GST by using the 3 functions + [filter], [herit], [synth], and the initial value [init] inherited by the root node. ['h] is the type + of inherited attributes, and ['s] is the type of synthesized attributes, and so the type of the result. + + The meaning of 3 functions is as follows: + - [filter h child] returns [true] if the node [child] must be explored given the inherited value of the current + node (parent of [child]), + - [herit h child] returns the value inherited by [child] given the inherited value of the current node + (parent of [child]), + - [synth l h node] returns the synthesized value of the current node, given its inherited value [h], and + the list [l] of synthesized values of explored children of [node] (according to [filter]). + + *) + +val fold_node : t -> ('h -> node -> bool) -> ('h -> node -> 'h) -> ('s list -> 'h -> node -> 's) -> 'h -> node -> 's + (** Same as [fold], except the computation starts and finishes at the last argument node. *) + +val fold_s : t -> ('s list -> node -> 's) -> 's + (** [fold_s gst synth] is equivalent to [fold gst filter herit synth init], where there is no filtering, and + no inherited values: purely synthetic. *) + +val fold_s_node : t -> ('s list -> node -> 's) -> node -> 's + (** Same as [fold_s], except the computation starts and finishes at the last argument node. *) + +val fold_fs : t -> (node -> bool) -> ('s list -> node -> 's) -> 's + (** [fold_fs gst filter synth] is equivalent to [fold gst filter herit synth init], where there is no inherited + values. *) + +type tree = Node of string * tree list | Leaf of string * (int * int) +val readable : t -> tree + (** [readable gst] returns a (more) readable representation of [gst]. + Each node and leaf is decorated by its word label, and leaves are + also decorated by their index. *) + +val exact_matches : t -> string -> (int * int) list diff --git a/commons/ocamlextra/suffix_tree_ext.ml b/commons/ocamlextra/suffix_tree_ext.ml new file mode 100644 index 0000000..fd5b8c8 --- /dev/null +++ b/commons/ocamlextra/suffix_tree_ext.ml @@ -0,0 +1,335 @@ +(* made by Sebastien Ferre *) + +(* type of nodes in suffix trees *) +type node = { + seqid : int; (* sequence index in which the positions start and final are defined *) + mutable start : int; (* start and final position of the word labelling the node *) + final : int ref; + mutable link : node; (* suffix link *) + v : node_value + } +and node_value = + | Children of (char,node) Hashtbl.t (* for non-leaves: children nodes *) + (* for the key '\000', all values are relevant (use Hashtbl.find_all) *) + | Index of int (* for leaves: position of recognized suffix *) + +(* type of suffix trees *) +type t = string DynArray.t * node + +(* the initial root node *) +let empty : unit -> node = + fun () -> + let rec root = {seqid= -1; start=0; final=ref (-1); link=root; v=Children (Hashtbl.create 2)} in + root + + +(* -------------------------------------------------------------------------------- + Operations on substrings of sequences + -------------------------------------------------------------------------------- *) + +type subseq = string * int * int (* (seq, pos, len) *) + +let subseq_empty = ("",0,0) (* non-significant subseq *) + +let subseq_is_empty (s,pos,len) = len = 0 + +let subseq_get (s,pos,len) i = s.[pos+i] + +let subseq_length (s,pos,len) = len + +let subseq_sub (s,pos,len) pos' len' = (s,pos+pos',len') + +let subseq_extend (s,pos,len) = (s,pos,len+1) + +(* ------------------------------------------------------------------------------- + Operations on implicit nodes (explicit, implicit, child : node * subseq * node) + the snd node [child] is significant only when [implicit] is not the empty string, + and is the child that recognizes [implicit] starting from [explicit]. [implicit] is + defined by a sequence, a start and a length. + ------------------------------------------------------------------------------- *) + +let eq_char c1 c2 = + c1<>'\000' & c1=c2 (* ensures that 2 terminal symbols '\000' are pairwise different (for GST only, not necessary for ST) *) + +(* returns the child node that recognizes [implicit] from the node [explicit] *) +let get_child seqar (explicit,implicit) = + if subseq_is_empty implicit + then explicit + else + let c = subseq_get implicit 0 in + if c = '\000' + then raise Not_found + else + match explicit.v with + | Children h -> Hashtbl.find h c + | Index _ -> raise Not_found + (* List.find (fun child -> eq_char seqar.(child.seqid).[child.start] c) explicit.children *) + +(* ensures that implicit does not span over another node below [explicit] *) +let rec canonical seqar (explicit,implicit,child) = + if subseq_is_empty implicit + then (explicit,implicit,child) + else + let l = !(child.final) - child.start + 1 in + let a = subseq_length implicit in + if a < l + then (explicit,implicit,child) + else + let implicit' = subseq_sub implicit l (a-l) in + canonical seqar (child, implicit', get_child seqar (child,implicit')) + +(* test whether an implicit node is the root node *) +let is_root root (explicit,implicit,_) = + explicit == root & subseq_is_empty implicit + +(* test whether the extension of an implicit node by [seqar.(k).[i]] is still recognized in the GST, + and if yes, returns the implicit node extended by 1 position, otherwise returns [None]. *) +let has_child seqar (explicit,implicit,child) (k,i) = + let a = subseq_length implicit in + if a <> 0 then + if eq_char (DynArray.get seqar (child.seqid)).[child.start+a] (DynArray.get seqar k).[i] + then Some (explicit, subseq_extend implicit, child) + else None + else + try + let implicit' = ((DynArray.get seqar k),i,1) in + Some (explicit, implicit', get_child seqar (explicit,implicit')) + with Not_found -> None + +(* -------------------------------- + creation of new nodes and leaves + -------------------------------- *) + +let add_leaf (seqar,root) node seqid start final_ref index = + match node.v with + | Children h -> + Hashtbl.add h + (DynArray.get seqar (seqid)).[start] + {seqid=seqid; start=start; final=final_ref; link=root; v=(Index index)} + | Index _ -> raise (Invalid_argument "Suffix_tree.add_leaf: 2nd argument must not be a leaf") + +(* make explicit an implicit node by inserting a new node between [explicit] and [child] *) +let insert_node (seqar,root) (explicit,implicit,child) = + let a = subseq_length implicit in + if a = 0 + then explicit + else + match explicit.v with + | Children h -> + let c_child_old = (DynArray.get seqar (child.seqid)).[child.start] in + let c_child_new = (DynArray.get seqar (child.seqid)).[child.start+a] in + let n' = { + seqid = child.seqid; + start = child.start; + final = ref (child.start+a-1); + link = root; + v = Children (let h' = Hashtbl.create (Hashtbl.length h) in Hashtbl.add h' c_child_new child; h') + } in + child.start <- child.start+a; + Hashtbl.replace h c_child_old n'; + n' + | Index _ -> raise (Invalid_argument "Suffix_tree.insert_node: first part of 2nd argument must not be a leaf") + +(* add a suffix link from [pred_opt] (if defined) to [explicit] *) +let add_link root pred_opt explicit = + (*if explicit != root then*) (* create a new suffix link *) + match pred_opt with + | Some n -> (*if n.link = None then*) n.link <- explicit + | None -> () + +(* ------------ + suffix links + ------------ *) + +(* get the node refered by the suffix link at [n] *) +(* +let suffix_link (root : node) (n : node) : node = + match n.link with + | None -> root (* by default, the suffix link points to the root node *) + | Some n' -> n' +*) + +(* extend suffix_link for implicit nodes *) +let link (seqar,root) = function (* TODO *) + | (explicit,implicit,_) when subseq_is_empty implicit -> + let explicit' = explicit.link (*suffix_link root explicit*) in + (explicit', subseq_empty, explicit') + | (explicit,implicit,_) -> + if explicit == root + then + let implicit' = subseq_sub implicit 1 (subseq_length implicit - 1) in + canonical seqar (root, implicit', get_child seqar (root,implicit')) + else + let explicit' = explicit.link (*suffix_link root explicit*) in + canonical seqar (explicit', implicit, get_child seqar (explicit',implicit)) + +(* -------------------------------------------------------------- + GST update for the new character c at position i in sequence k + -------------------------------------------------------------- *) + +(* state for 'update' *) +type res = { + terminal : int ref; + mutable startj : int; + mutable startnode : node * subseq * node + } + +let rec update (seqar,root) (k,i) res pred_opt = + (* c = seqar.(k).[i] *) + match has_child seqar res.startnode (k,i) with + | Some extended_startnode -> (* startnode can be extended by [c] *) + let explicit, implicit, _ = res.startnode in + assert (pred_opt = None or subseq_is_empty implicit); + (* if a link has been followed after node creation, then we are on an explicit node *) + add_link root pred_opt explicit; + res.startnode <- canonical seqar extended_startnode + | None -> (* startnode cannot be extended by [c] ... *) + let n' = insert_node (seqar,root) res.startnode in (* ... so we insert a new node ... *) + add_link root pred_opt n'; (* ... a suffix link from the last created node (if defined) ... *) + if (DynArray.get seqar (k)).[res.startj] <> '\000' then + add_leaf (seqar,root) n' k i res.terminal res.startj; (* ... and a new leaf for the suffix at position [res.startj] *) + res.startj <- res.startj + 1; (* prepare for the next suffix *) + if not (is_root root res.startnode) + then begin (* while [res.startnode] is not the root, and cannot be extended by [c] ... *) + res.startnode <- link (seqar,root) res.startnode; (* ... follow the suffix link to find the next suffix ... *) + update (seqar,root) (k,i) res (Some n') end (* ... and loop on [update] *) + +(* ------------------------------- + implementing the .mli interface + ------------------------------- *) + +let make : string list -> t = + fun l_seq -> + let l = List.length l_seq in + let seqar = Array.make l "" in + let seqar = DynArray.of_array seqar in + let root = empty () in + let st = (seqar, root) in + ignore (List.fold_left + (fun k seq -> (* for every sequence/string [seq], numbered [k] ... *) + DynArray.set seqar k (seq ^ String.make 1 '\000'); + let res = {terminal=ref (-1); startj=0; startnode=(root,subseq_empty,root)} in (* initialize for [update] ... *) + for i = 0 to String.length (DynArray.get seqar k) - 1 do (* for every position [i] in the sequence ... *) + incr res.terminal; (* increment the leaves final position ... *) + update st (k,i) res None (* call [update] for updating the suffix tree with the character at position [i] *) + done; + k+1) + 0 l_seq); + st + + +let add (s: string) (seqar,root : t) = + let k = DynArray.length seqar in + DynArray.add seqar s; + let st = (seqar, root) in + let seq = s in + begin + DynArray.set seqar k (seq ^ String.make 1 '\000'); + let res = {terminal=ref (-1); startj=0; startnode=(root,subseq_empty,root)} in (* initialize for [update] ... *) + for i = 0 to String.length (DynArray.get seqar k) - 1 do (* for every position [i] in the sequence ... *) + incr res.terminal; (* increment the leaves final position ... *) + update st (k,i) res None (* call [update] for updating the suffix tree with the character at position [i] *) + done; + end + + +let string (seqar,root : t) (k : int) = + let seq = (DynArray.get seqar (k)) in + String.sub seq 0 (String.length seq - 1) (* removing the terminal symbol *) + +let string_list (seqar,root : t) = + List.map (fun seq -> String.sub seq 0 (String.length seq - 1)) (DynArray.to_list seqar) + +let root (seq,root : t) = root + +let word (seqar,root) node = + if node == root + then "" + else String.sub (DynArray.get seqar (node.seqid)) node.start (!(node.final) - node.start + (match node.v with Children _ -> 1 | Index _ -> 0)) + +let children (gst : t) node = + match node.v with + | Children h -> + Hashtbl.fold (fun c n l -> n::l) h [] + | Index _ -> [] + +let index (seq,root) node : int * int = + match node.v with + | Children _ -> raise (Invalid_argument "Suffix_tree.index: 2nd argument must be a leaf") + | Index i -> (node.seqid, i) + +let linked_node (seqar,root : t) (n : node) : node = + n.link (*suffix_link root n*) + +let rec implicit_node (seqar,node : t) (word : string) = + let (explicit, (s,i,len), child) = implicit_node_aux (seqar,node) (word,0,String.length word) in + (explicit, String.sub s i len, child) +and implicit_node_aux (seqar,node) implicit = + let w = subseq_length implicit in + let child = get_child seqar (node,implicit) in + let l = !(child.final) - child.start + 1 in + let a = ref 1 in + while !a < l & !a < w & eq_char (DynArray.get seqar (child.seqid)).[child.start + !a] (subseq_get implicit !a) do + incr a + done; (* [!a] is the first mismatch position, or the length of [child] label *) + if !a < w then + if !a < l + then raise Not_found + else implicit_node_aux (seqar,child) (subseq_sub implicit !a (w - !a)) + else (node,implicit,child) + +(* +let rec synthesized (seqar,root : t) (f : 'a list -> node -> 'a) = + synthesized_node (seqar,root) f root +and synthesized_node st f node = + f (List.map (synthesized_node st f) (children st node)) node +*) + +(* general fold *) +let rec fold : t -> ('h -> node -> bool) -> ('h -> node -> 'h) -> ('s list -> 'h -> node -> 's) -> 'h -> 's = + fun gst f h s init -> + fold_node gst f h s init (root gst) +and fold_node gst f h s h_node node = + s + (List.map + (fun child -> fold_node gst f h s (h h_node child) child) + (List.filter (f h_node) (children gst node))) + h_node + node + +(* synthesized attributes only *) +let fold_s_node gst s node = fold_node gst (fun _ _ -> true) (fun _ _ -> ()) (fun l _ n -> s l n) () node +let fold_s gst s = fold_s_node gst s (root gst) + +(* filtering and synthesizing, no inheritance *) +let fold_fs gst f s = fold gst (fun _ n -> f n) (fun _ _ -> ()) (fun l _ n -> s l n) () + + +type tree = Node of string * tree list | Leaf of string * (int * int) + +let readable gst = + fold_s gst + (fun l n -> + let w = word gst n in + if l=[] + then Leaf (w, index gst n) + else Node (w, l)) + +(* applications of suffix trees *) + +let exact_matches : t -> string -> (int * int) list = + fun gst word -> + try + let explicit, implicit, child = implicit_node gst word in + fold_s_node gst + (fun l n -> if l=[] then [index gst n] else List.concat l) + child + with Not_found -> [] + + + +let contained_string gst word = + List.map (fun (i,j) -> DynArray.get (fst gst) i) (exact_matches gst word) + + + diff --git a/commons/ocamlextra/suffix_tree_ext.mli b/commons/ocamlextra/suffix_tree_ext.mli new file mode 100644 index 0000000..0185d92 --- /dev/null +++ b/commons/ocamlextra/suffix_tree_ext.mli @@ -0,0 +1,98 @@ +(** + Generalized suffix trees (GSTs). + + Computes generalized suffix trees from list of strings. A terminal symbol is + implicitly added to them, but is not returned in the word labeling nodes and + leaves. This should allow a rather transparent handling of GSTs. + + Node-based accesses are provided (sequences, root, children, suffix links, + node labels, index), as well as a functional for synthesizing attributes from + a GST. A readable representation of GSTs is derived from the later. + +*) +(* made by Sebastien Ferre *) + +(* extension by Yoann Padioleau: the function add, allowing to extend a gst + (internally use now a DynArray instead of an Array) +*) + +type node + (** Type of nodes in GSTs. *) + +type t + (** Type of GSTs. *) + +val make : string list -> t + (** [make l_str] computes a GST based on the set of strings given in [l_str]. *) + +val add : string -> t -> unit + (** [add l_str gst] add a new string in the GST. Does it via a side effect. *) + +val string_list : t -> string list + (** [string_list gst] returns the list of strings from which [gst] was computed. *) + +val string : t -> int -> string + (** [string gst k] returns the sequence number [k] (starting from 0). *) + +val root : t -> node + (** [root gst] returns the root node of the gst. *) + +val word : t -> node -> string + (** [word gst n] returns the word labeling node [n] in [gst]. *) + +val children : t -> node -> node list + (** [children gst n] returns a list of the children nodes of [n] in [gst]. *) + +val linked_node : t -> node -> node + (** [linked_node gst n] returns the node pointed by the suffix link from [n] in [gst]. *) + +val index : t -> node -> int * int + (** [index gst n] returns the index of a leaf [n] in [gst]. + This index is a pair [(k,i)], where [k] is the number of the sequence (as used by [string]), and + [i] is the position of the related suffix (starting from [0] as usual in strings). + @raise Invalid_argument "Suffix_tree.index: not a leaf" if [n] is not a leaf (has some child). *) + +val implicit_node : t -> string -> node * string * node + (** [implicit_node gst word] returns an implicit_node [(node,word',child)], where [node] is the lowest + node in the suffix tre such that the concatenation of the word recognized by [node] and [word'] is + equal to [word], if [word'] is not the empty string, then [child] is the child node of [node], whose + label has [word'] as a prefix. + @raise Not_found when [word] is not a substring of [string_list gst]. *) + + +val fold : t -> ('h -> node -> bool) -> ('h -> node -> 'h) -> ('s list -> 'h -> node -> 's) -> 'h -> 's + (** [fold gst filter herit synth init] computes some attribute(s) over a GST by using the 3 functions + [filter], [herit], [synth], and the initial value [init] inherited by the root node. ['h] is the type + of inherited attributes, and ['s] is the type of synthesized attributes, and so the type of the result. + + The meaning of 3 functions is as follows: + - [filter h child] returns [true] if the node [child] must be explored given the inherited value of the current + node (parent of [child]), + - [herit h child] returns the value inherited by [child] given the inherited value of the current node + (parent of [child]), + - [synth l h node] returns the synthesized value of the current node, given its inherited value [h], and + the list [l] of synthesized values of explored children of [node] (according to [filter]). + + *) + +val fold_node : t -> ('h -> node -> bool) -> ('h -> node -> 'h) -> ('s list -> 'h -> node -> 's) -> 'h -> node -> 's + (** Same as [fold], except the computation starts and finishes at the last argument node. *) + +val fold_s : t -> ('s list -> node -> 's) -> 's + (** [fold_s gst synth] is equivalent to [fold gst filter herit synth init], where there is no filtering, and + no inherited values: purely synthetic. *) + +val fold_s_node : t -> ('s list -> node -> 's) -> node -> 's + (** Same as [fold_s], except the computation starts and finishes at the last argument node. *) + +val fold_fs : t -> (node -> bool) -> ('s list -> node -> 's) -> 's + (** [fold_fs gst filter synth] is equivalent to [fold gst filter herit synth init], where there is no inherited + values. *) + +type tree = Node of string * tree list | Leaf of string * (int * int) +val readable : t -> tree + (** [readable gst] returns a (more) readable representation of [gst]. + Each node and leaf is decorated by its word label, and leaves are + also decorated by their index. *) + +val exact_matches : t -> string -> (int * int) list diff --git a/commons/ocollection.ml b/commons/ocollection.ml new file mode 100644 index 0000000..6869f4b --- /dev/null +++ b/commons/ocollection.ml @@ -0,0 +1,107 @@ +open Common + +(*****************************************************************************) +(* Collection *) +(*****************************************************************************) +(* + * The derived classes of collections: + * - sequence(next, nth): array, list, stack, queue, and mixed + * (fast cons, fast snoc, fast append, cf okasaki) + * - set(union): setl, setb, seti, seth + * - assoc(find): assocl, mapb, hash, btree, multimap (mais bof, can do + * with map of set) + * - graph: graph1way, graph2way, graphref, graphmatrix? + * + * Some features/notes: + * - views a la wadler to make it cool (I hate get/set). + * - take list in parameters to be able to construct value as is easily + * - take the comparaison function in parameters (=> functorial set made cool) + * make l [], h [], ... as in perl, and pass the func from pervasive + * in oo form (list, ...) + * - pure/impure: could put 2 interface, with one that show that inpure + * by making the operation return unit, but simpler to have one interface. + * - the core method and default method (via virtual classes) + * better to use virtual than typeclass, virtual play both roles: + * an interface and default code + * + * - pb binary methods: use tosetb tricks, or via (not safe) Obj.magic. + * - array/list are both a sequence _and_ a dictionnary, so are both + * a collection(a) and a collection(i,a) at the same time. But cant do that. + * So for array, I see it mainly as an assoc => favor assoc, and + * for list, I see it mainly as a collection => favor collection + * + * ??mixins: comparable, iterator, via virtual class in ocaml + * ?? kind of haskell class + default value + * + * ?? persistence, caching, peut prendre en param le type de map qu'il cache, + * comme en perl, evite du marshalling kan wrapped = bdb. + * + * ?? lazy wrapper, how avoid complexity of having to define each time + * a hashP, hashC, hashL, hashPCL, ... ? + * + * ?? I define those classes cos their name are cool, say what is intended to + * do with + * + * todo: cf book on algo, a la rivest/sedgewick + * todo: recreate collection hierarchy, inspire smalltalk ? haskell ? merd ? + * todo: put a clean sequence (inherit collection) and make array a special + * class + * todo: make ostack (FIFO), oqueue (LIFO) + * + * + * influences: okasaki, merd (pixel), java classes, smalltalk classes + *) + +(*---------------------------------------------------------------------------*) +type ('a, 'b) view = Empty | Cons of 'a * 'b + +class virtual ['a] ocollection = +object(o: 'o) + inherit Objet.objet + + method virtual empty: 'o + method virtual add: 'a -> 'o + + method virtual iter: ('a -> unit) -> unit + method virtual view: ('a, 'o) view + + (* no need virtual, but better to redefine for efficiency *) + method virtual del: 'a -> 'o (* can do default with: view+iter *) + method virtual mem: 'a -> bool (* can do default with: mem(tolist) *) + method virtual null: bool (* can do default with: lenght(tolist)= 0 *) + + + + method fold: 'b. ('b -> 'a -> 'b) -> 'b -> 'b = fun f a -> + let a = ref a in + o#iter (fun e -> a := f !a e); + !a + + method tolist: 'a list = + List.rev (o#fold (fun acc e -> e::acc) []) + method fromlist: 'a list -> 'o = + fun xs -> xs +> List.fold_left (fun o e -> o#add e) o#empty + + method length: int = + (* oldsimple: o#tolist +> List.length *) + (* opti: *) + let count = ref 0 in + o#iter (fun e -> incr count); + !count + + method exists: ('a -> bool) -> bool = fun f -> + o#tolist +> List.exists f + + method filter: ('a -> bool) -> 'o = fun f -> + (* iter and call add from empty, or del *) + o#tolist +> List.filter f +> o#fromlist + + (* forall, fold, map *) + + method getone: 'a = + match o#view with Cons (e,tl) -> e | Empty -> failwith "no head" + method others: 'o = + match o#view with Cons (e,tl) -> tl | Empty -> failwith "no tail" + +end + diff --git a/commons/ocollection.mli b/commons/ocollection.mli new file mode 100644 index 0000000..03d2d83 --- /dev/null +++ b/commons/ocollection.mli @@ -0,0 +1,34 @@ +type ('a, 'b) view = + | Empty + | Cons of 'a * 'b + +class virtual ['a] ocollection : +object ('o) + inherit Objet.objet + + method virtual empty : 'o + method virtual add : 'a -> 'o + + method virtual iter : ('a -> unit) -> unit + method virtual view : ('a, 'o) view + + (* no need virtual, but better to force redefine for efficiency *) + method virtual del : 'a -> 'o + method virtual mem : 'a -> bool + method virtual null : bool + + + + method fold : ('c -> 'a -> 'c) -> 'c -> 'c + + method fromlist : 'a list -> 'o + method tolist : 'a list + + method exists : ('a -> bool) -> bool + method filter : ('a -> bool) -> 'o + + method length : int + + method getone : 'a + method others : 'o +end diff --git a/commons/ofullcommon.ml b/commons/ofullcommon.ml new file mode 100644 index 0000000..8f00d99 --- /dev/null +++ b/commons/ofullcommon.ml @@ -0,0 +1,23 @@ +(* Do a 'open Fullcommon' to access most of the functions in commons/ + * without needing to qualify them. + * + * update: Jane Street use a similar trick, to have a more complete + * Pervasives, but for far more. They can define a module Std that + * correspond to old std lib and a module Std_internal that instead + * include all their extensions over the standard lib (a more complete + * List module, Arg, etc) +*) + +include Common + +include Oset +include Oassoc +include Oarray +include Ograph + +include Osetb +include Oassoch +include Oassocb +include Oseti +include Ograph2way +include Oassoc_buffer diff --git a/commons/ograph.ml b/commons/ograph.ml new file mode 100644 index 0000000..e97cdb7 --- /dev/null +++ b/commons/ograph.ml @@ -0,0 +1,30 @@ +open Common + +(* todo: + * invariant succesors/predecessors + * see c++ library, GTL ... + * (cf paper from ASTL, cf paper from jfla05 on ocamlgraph) + *) + +class virtual ['a] ograph = +object(o: 'o) + method virtual empty: 'o + + method virtual add_node: 'a -> 'o + method virtual del_node: 'a -> 'o + + method virtual add_arc: ('a * 'a) -> 'o + method virtual del_arc: ('a * 'a) -> 'o + + method virtual successors: 'a -> 'a Oset.oset + method virtual predecessors: 'a -> 'a Oset.oset + + method virtual nodes: 'a Oset.oset + + method virtual ancestors: 'a Oset.oset -> 'a Oset.oset + method virtual children: 'a Oset.oset -> 'a Oset.oset + method virtual brothers: 'a -> 'a Oset.oset + + method mydebug: ('a * 'a list) list = + (o#nodes)#tolist +> map (fun a -> (a, (o#successors a)#tolist)) +end diff --git a/commons/ograph.mli b/commons/ograph.mli new file mode 100644 index 0000000..6352095 --- /dev/null +++ b/commons/ograph.mli @@ -0,0 +1,21 @@ +class virtual ['a] ograph : +object ('o) + method virtual empty : 'o + + method virtual add_node : 'a -> 'o + method virtual del_node : 'a -> 'o + + method virtual add_arc : 'a * 'a -> 'o + method virtual del_arc : 'a * 'a -> 'o + + + method virtual nodes : 'a Oset.oset + method virtual predecessors : 'a -> 'a Oset.oset + method virtual successors : 'a -> 'a Oset.oset + + method virtual ancestors : 'a Oset.oset -> 'a Oset.oset + method virtual brothers : 'a -> 'a Oset.oset + method virtual children : 'a Oset.oset -> 'a Oset.oset + + method mydebug : ('a * 'a list) list +end diff --git a/commons/ograph2way.ml b/commons/ograph2way.ml new file mode 100644 index 0000000..3434080 --- /dev/null +++ b/commons/ograph2way.ml @@ -0,0 +1,86 @@ +open Common + +open Ocollection +open Oset +open Ograph + +open Osetb + +(* graph2way prend en parametre le type de finitemap et set a prendre + * todo? add_arc doit ramer, car del la key, puis add => + * better to have a ref to a set + * todo: efficient graph: with pointers and a tag: visited + * => need keep global value visited_counter + * check(that node is in, ...), display + * + * pourrait remettre val nods, a la place de les calculer. mais bon + * s'en sert pas vraiment car y'a pas de notion d'identifiant de noeud + * et de label. + * + * invariant: key in pred is also in succ (completness) and value in + * either table is a key also + *) +class ['a] ograph2way asucc apred (*f1*) f2 = +object(o) + inherit ['a] ograph + + val succ = asucc (* f1() ## new oassocb [] *) + val pred = apred (* f1() ## new oassocb [] *) + (* val nods = anodes ##f2() ## new osetb [] *) + + method empty = raise Todo (*{< succ = f1() ;(* new oassocb []; *) + pred = f1(); (* new oassocb []; *) + (* nods = f2(); ##new osetb []; *) + >}*) + + method add_node e = {< (* nods = nods#add e; *) + pred = pred#add (e, f2() );(* new osetb []); *) + succ = succ#add (e, f2() );(* new osetb []); *) + >} + method del_node e = {< (* nods = nods#del e; *) + pred = pred#delkey e; + succ = succ#delkey e; + >} + method add_arc (a,b) = {< + succ = succ#replkey (a, (succ#find a)#add b); + pred = pred#replkey (b, (pred#find b)#add a); + >} + method del_arc (a,b) = {< + succ = succ#replkey (a, (succ#find a)#del b); + pred = pred#replkey (b, (pred#find b)#del a); + >} + method successors e = succ#find e + method predecessors e = pred#find e + method nodes = (* nods *) + (* could take pred, same *) + (* caml typing sux, arrive pas a faire: pred#fold (fun a (k,v) -> a#add k) (new osetb Setb.empty) *) + let a = ref (new osetb Setb.empty) in + succ#iter (fun (k,v) -> a := !a#add k); + !a + + + + method ancestors xs = + let rec aux xs acc = + match xs#view with (* could be done with an iter *) + | Empty -> acc + | Cons(x, xs) -> (acc#add x) + +> (fun newacc -> aux (o#predecessors x) newacc) + +> (fun newacc -> aux xs newacc) + in aux xs (f2()) (* (new osetb []) *) + + method children xs = + let rec aux xs acc = + match xs#view with (* could be done with an iter *) + | Empty -> acc + | Cons(x, xs) -> (acc#add x) + +> (fun newacc -> aux (o#successors x) newacc) + +> (fun newacc -> aux xs newacc) + in aux xs (f2()) (* (new osetb []) *) + + + method brothers x = + let parents = o#predecessors x in + (parents#fold (fun acc e -> acc $++$ o#successors e) (f2()))#del x + +end diff --git a/commons/ograph2way.mli b/commons/ograph2way.mli new file mode 100644 index 0000000..fec5d24 --- /dev/null +++ b/commons/ograph2way.mli @@ -0,0 +1,33 @@ + +class ['a] ograph2way : + (< add : 'a * 'a Oset.oset -> 'c; delkey : 'a -> 'c; + find : 'a -> 'a Oset.oset; iter : ('a * 'd -> unit) -> 'e; + replkey : 'a * 'a Oset.oset -> 'c; .. > + as 'c) -> + (< add : 'a * 'a Oset.oset -> 'f; delkey : 'a -> 'f; + find : 'a -> 'a Oset.oset; replkey : 'a * 'a Oset.oset -> 'f; .. > + as 'f) -> + (unit -> 'a Oset.oset) -> +object ('o) + inherit ['a] Ograph.ograph + val pred : 'f + val succ : 'c + + (* ograph concrete instantiation of virtual methods *) + method empty : 'o + + method add_node : 'a -> 'o + method del_node : 'a -> 'o + + method add_arc : 'a * 'a -> 'o + method del_arc : 'a * 'a -> 'o + + method nodes : 'a Oset.oset + method predecessors : 'a -> 'a Oset.oset + method successors : 'a -> 'a Oset.oset + + method ancestors : 'a Oset.oset -> 'a Oset.oset + method brothers : 'a -> 'a Oset.oset + method children : 'a Oset.oset -> 'a Oset.oset + +end diff --git a/commons/ograph_extended.ml b/commons/ograph_extended.ml new file mode 100644 index 0000000..a11d494 --- /dev/null +++ b/commons/ograph_extended.ml @@ -0,0 +1,268 @@ +open Common + +open Ocollection +open Oset +open Oassoc +(* open Ograph *) + +open Oassocb +open Osetb + +(* + * graph structure: + * - node: index -> nodevalue + * - arc: (index * index) * edgevalue + * + * invariant: key in pred is also in succ (completness) and value in + * either assoc is a key also. + * + * How ? matrix ? but no growing array :( + * + * When need index ? Must have an index when can't just use nodevalue + * as a key, cos sometimes may have 2 times the same key, but it must + * be 2 different nodes. For instance in program f(); f(); we want 2 + * nodes, one per f(); hence the index. If each node is different, + * then no problem, can omit index. + * + * todo?: prend en parametre le type de finitemap et set a prendre + * todo?: add_arc doit ramer, car del la key, puis add => better to + * have a ref to a set. + * + * opti: graph with pointers and a tag visited => need keep global value + * visited_counter. check(that node is in, ...), display. + * opti: when the graph structure is stable, have a method compact, that + * transforms that in a matrix (assert that all number between 0 and + * free_index are used, or do some defrag-like-move/renaming). + * + *) + +type nodei = int + +class ['a,'b] ograph_extended = + let build_assoc () = new oassocb [] in (* opti?: = oassoch *) + let build_set () = new osetb Setb.empty in + + object(o) + (* inherit ['a] ograph *) + + val free_index = 0 + + val succ = build_assoc() + val pred = build_assoc() + val nods = build_assoc() + + method add_node (e: 'a) = + let i = free_index in + ({< + nods = nods#add (i, e); + pred = pred#add (i, build_set() ); + succ = succ#add (i, build_set() ); + free_index = i + 1; + >}, i) + + method add_nodei i (e: 'a) = + ({< + nods = nods#add (i, e); + pred = pred#add (i, build_set() ); + succ = succ#add (i, build_set() ); + free_index = (max free_index i) + 1; + >}, i) + + + method del_node (i) = + {< + (* check: e is effectively the index associated with e, + and check that already in *) + + (* todo: assert that have no pred and succ, otherwise + * will have some dangling pointers + *) + nods = nods#delkey i; + pred = pred#delkey i; + succ = succ#delkey i; + >} + + method replace_node (i, (e: 'a)) = + assert (nods#haskey i); + {< + nods = nods#replkey (i, e); + >} + + method add_arc ((a,b),(v: 'b)) = + {< + succ = succ#replkey (a, (succ#find a)#add (b, v)); + pred = pred#replkey (b, (pred#find b)#add (a, v)); + >} + method del_arc ((a,b),v) = + {< + succ = succ#replkey (a, (succ#find a)#del (b,v)); + pred = pred#replkey (b, (pred#find b)#del (a,v)); + >} + + method successors e = succ#find e + method predecessors e = pred#find e + + method nodes = nods + method allsuccessors = succ + +(* + method ancestors xs = + let rec aux xs acc = + match xs#view with (* could be done with an iter *) + | Empty -> acc + | Cons(x, xs) -> (acc#add x) + +> (fun newacc -> aux (o#predecessors x) newacc) + +> (fun newacc -> aux xs newacc) + in aux xs (f2()) (* (new osetb []) *) + + method children xs = + let rec aux xs acc = + match xs#view with (* could be done with an iter *) + | Empty -> acc + | Cons(x, xs) -> (acc#add x) + +> (fun newacc -> aux (o#successors x) newacc) + +> (fun newacc -> aux xs newacc) + in aux xs (f2()) (* (new osetb []) *) + + method brothers x = + let parents = o#predecessors x in + (parents#fold (fun acc e -> acc $++$ o#successors e) (f2()))#del x + +*) + + end + + + + +class ['a,'b] ograph_mutable = + let build_assoc () = new oassocb [] in + let build_set () = new osetb Setb.empty in + + object(o) + + val mutable free_index = 0 + + val mutable succ = build_assoc() + val mutable pred = build_assoc() + val mutable nods = build_assoc() + + method add_node (e: 'a) = + let i = free_index in + nods <- nods#add (i, e); + pred <- pred#add (i, build_set() ); + succ <- succ#add (i, build_set() ); + free_index <- i + 1; + i + + method add_nodei i (e: 'a) = + nods <- nods#add (i, e); + pred <- pred#add (i, build_set() ); + succ <- succ#add (i, build_set() ); + free_index <- (max free_index i) + 1; + + + method del_node (i) = + (* check: e is effectively the index associated with e, + and check that already in *) + + (* todo: assert that have no pred and succ, otherwise + * will have some dangling pointers + *) + nods <- nods#delkey i; + pred <- pred#delkey i; + succ <- succ#delkey i; + + method replace_node (i, (e: 'a)) = + assert (nods#haskey i); + nods <- nods#replkey (i, e); + + method add_arc ((a,b),(v: 'b)) = + succ <- succ#replkey (a, (succ#find a)#add (b, v)); + pred <- pred#replkey (b, (pred#find b)#add (a, v)); + method del_arc ((a,b),v) = + succ <- succ#replkey (a, (succ#find a)#del (b,v)); + pred <- pred#replkey (b, (pred#find b)#del (a,v)); + + method successors e = succ#find e + method predecessors e = pred#find e + + method nodes = nods + method allsuccessors = succ + + end + + +(* depth first search *) +let dfs_iter xi f g = + let already = Hashtbl.create 101 in + let rec aux_dfs xs = + xs +> List.iter (fun xi -> + if Hashtbl.mem already xi then () + else begin + Hashtbl.add already xi true; + f xi; + let succ = g#successors xi in + aux_dfs (succ#tolist +> List.map fst); + end + ) in + aux_dfs [xi] + + +let dfs_iter_with_path xi f g = + let already = Hashtbl.create 101 in + let rec aux_dfs path xi = + if Hashtbl.mem already xi then () + else begin + Hashtbl.add already xi true; + f xi path; + let succ = g#successors xi in + let succ' = succ#tolist +> List.map fst in + succ' +> List.iter (fun yi -> + aux_dfs (xi::path) yi + ); + end + in + aux_dfs [] xi + + + + +let generate_ograph_xxx g filename = + with_open_outfile filename (fun (pr,_) -> + pr "digraph misc {\n" ; + pr "size = \"10,10\";\n" ; + + let nodes = g#nodes in + nodes#iter (fun (k,(node, s)) -> + (* so can see if nodes without arcs were created *) + pr (sprintf "%d [label=\"%s [%d]\"];" k s k); + ); + + nodes#iter (fun (k,node) -> + let succ = g#successors k in + succ#iter (fun (j,edge) -> + pr (sprintf "%d -> %d;\n" k j); + ); + ); + pr "}\n" ; + ); + let _status = + Unix.system ("dot " ^ filename ^ " -Tps -o " ^ filename ^ ".ps;") in + () + +let launch_gv filename = + let _status = Unix.system ("gv " ^ filename ^ ".ps &") + in + (* zarb: I need this when I launch the program via eshell, otherwise gv + do not get the chance to be launched *) + Unix.sleep 1; + () + +let print_ograph_extended g filename launchgv = + generate_ograph_xxx g filename; + if launchgv then launch_gv filename + +let print_ograph_mutable g filename launchgv = + generate_ograph_xxx g filename; + if launchgv then launch_gv filename diff --git a/commons/ograph_extended.mli b/commons/ograph_extended.mli new file mode 100644 index 0000000..5b9908a --- /dev/null +++ b/commons/ograph_extended.mli @@ -0,0 +1,73 @@ +open Common + +type nodei = int + +(* graph structure: + * - node: index -> nodevalue + * - arc: (index * index) * edgevalue + * + * How ? matrix ? but no growing array :( + * + * When need index ? Must have an index when can't just use the nodevalue + * as a key, cos sometimes may have 2 times the same key, but it must + * be 2 different nodes. For instance in a C program 'f(); f();' we want 2 + * nodes, one per 'f();' hence the index. If each node is different, then + * no problem, can omit index. + *) + +class ['node, 'edge] ograph_extended : +object ('o) + method add_node : 'node -> 'o * nodei + method add_nodei : nodei -> 'node -> 'o * nodei + method replace_node : nodei * 'node -> 'o + method del_node : nodei -> 'o + + method add_arc : (nodei * nodei) * 'edge -> 'o + method del_arc : (nodei * nodei) * 'edge -> 'o + + method nodes : (nodei, 'node) Oassoc.oassoc + + method successors : nodei -> (nodei * 'edge) Oset.oset + method predecessors : nodei -> (nodei * 'edge) Oset.oset + method allsuccessors : (nodei, (nodei * 'edge) Oset.oset) Oassoc.oassoc +end + + +class ['node, 'edge] ograph_mutable : +object ('o) + method add_node : 'node -> nodei + method add_nodei : nodei -> 'node -> unit + method replace_node : nodei * 'node -> unit + method del_node : nodei -> unit + + method add_arc : (nodei * nodei) * 'edge -> unit + method del_arc : (nodei * nodei) * 'edge -> unit + + method nodes : (nodei, 'node) Oassoc.oassoc + + method successors : nodei -> (nodei * 'edge) Oset.oset + method predecessors : nodei -> (nodei * 'edge) Oset.oset + method allsuccessors : (nodei, (nodei * 'edge) Oset.oset) Oassoc.oassoc +end + + +val dfs_iter : + nodei -> (nodei -> unit) -> ('node, 'edge) ograph_mutable -> unit + +val dfs_iter_with_path : + nodei -> (nodei -> nodei list -> unit) -> ('node, 'edge) ograph_mutable -> + unit + + +val print_ograph_extended : + ('node * string, 'edge) ograph_extended -> + filename (* output file *) -> + bool (* launch gv ? *) -> + unit + +val print_ograph_mutable : + ('node * string, 'edge) ograph_mutable -> + filename (* output file *) -> + bool (* launch gv ? *) -> + unit + diff --git a/commons/osequence.ml b/commons/osequence.ml new file mode 100644 index 0000000..c58ab31 --- /dev/null +++ b/commons/osequence.ml @@ -0,0 +1,13 @@ +open Oassoc + +class virtual ['a] osequence = +object(o: 'o) + (* inherit ['a] ocollection *) + inherit [int, 'a] oassoc + + method virtual nth: int -> 'a + method virtual first: 'a + method virtual last: 'a + (* head tail push pop top cons snoc *) +end + diff --git a/commons/osequence.mli b/commons/osequence.mli new file mode 100644 index 0000000..6e0092e --- /dev/null +++ b/commons/osequence.mli @@ -0,0 +1,8 @@ +class virtual ['a] osequence : +object ('o) + inherit [int, 'a] Oassoc.oassoc + + method virtual nth : int -> 'a + method virtual first : 'a + method virtual last : 'a +end diff --git a/commons/oset.ml b/commons/oset.ml new file mode 100644 index 0000000..064d8c4 --- /dev/null +++ b/commons/oset.ml @@ -0,0 +1,50 @@ +open Common + +open Ocollection + +class virtual ['a] oset = +object(o: 'o) + inherit ['a] ocollection + + (* no need virtual, but better to redefine (efficiency) *) + method virtual union: 'o -> 'o + method virtual inter: 'o -> 'o + method virtual minus: 'o -> 'o + + (* allow binary methods tricks, generate exception when not good type *) + method tosetb: 'a Setb.t = raise Impossible + method tosetpt: SetPt.t = raise Impossible + method toseti: Seti.seti = raise Impossible + method virtual toset: 'b. 'b (* generic (not safe) tricks *) + + (* is_intersect, equal, subset *) + method is_subset_of: 'o -> bool = fun o2 -> + ((o2#minus o)#cardinal >= 0) && ((o#minus o2)#cardinal = 0) + + method is_equal: 'o -> bool = fun o2 -> + ((o2#minus o)#cardinal = 0) && ((o#minus o2)#cardinal = 0) + + + method is_singleton: bool = (* can be short circuited *) + o#length = 1 + method cardinal: int = (* just to keep naming conventions *) + o#length + (* dont work: + method big_union: 'b. ('a -> 'b oset) -> 'b oset = fun f -> todo() + *) + +end + +let ($??$) e xs = xs#mem e +let ($++$) xs ys = xs#union ys +let ($**$) xs ys = xs#inter ys +let ($--$) xs ys = xs#minus ys +let ($<<=$) xs ys = xs#is_subset_of ys +let ($==$) xs ys = xs#is_equal ys + +(* todo: pas beau le seed. I dont put the type otherwise have to + * put explicit :> + *) +let (mapo: ('a -> 'b) -> 'b oset -> 'a oset -> 'b oset) = fun f seed xs -> + xs#fold (fun acc x -> acc#add (f x)) seed + diff --git a/commons/oset.mli b/commons/oset.mli new file mode 100644 index 0000000..72b8e46 --- /dev/null +++ b/commons/oset.mli @@ -0,0 +1,28 @@ +class virtual ['a] oset : +object ('o) + inherit ['a] Ocollection.ocollection + + method cardinal : int + + method virtual inter : 'o -> 'o + method virtual minus : 'o -> 'o + method virtual union : 'o -> 'o + + method is_singleton : bool + method is_subset_of : 'o -> bool + method is_equal : 'o -> bool + + method virtual toset : 'd + method tosetb : 'a Setb.t + method toseti : Seti.seti + method tosetpt : SetPt.t +end + +val ( $??$ ) : 'a -> < mem : 'a -> bool; .. > -> bool +val ( $++$ ) : < union : 'a -> 'o; .. > -> 'a -> 'o +val ( $**$ ) : < inter : 'a -> 'o; .. > -> 'a -> 'o +val ( $--$ ) : < minus : 'a -> 'o; .. > -> 'a -> 'o +val ( $<<=$ ) : < is_subset_of : 'a -> bool; .. > -> 'a -> bool +val ( $==$ ) : < is_equal : 'a -> bool; .. > -> 'a -> bool + +val mapo : ('a -> 'o) -> 'o oset -> 'a oset -> 'o oset diff --git a/commons/osetb.ml b/commons/osetb.ml new file mode 100644 index 0000000..3cf83a0 --- /dev/null +++ b/commons/osetb.ml @@ -0,0 +1,36 @@ +open Ocollection +open Oset + +let empty = Setb.empty + +class ['a] osetb xs = + object(o) + inherit ['a] oset + + val data = xs (* Setb.empty *) + method tosetb = data + + (* if put [] then no segfault, if [11] then segfault *) + method toset = Obj.magic data + + method empty = {< data = Setb.empty >} + method add e = {< data = Setb.add e data >} + method iter f = Setb.iter f data + method view = + if Setb.is_empty data + then Empty + else let el = Setb.choose data in Cons (el, o#del el) + + method del e = {< data = Setb.remove e data >} + method mem e = Setb.mem e data + method null = Setb.is_empty data + + method tolist = Setb.elements data + method length = Setb.cardinal data + + method union s = {< data = Setb.union data s#tosetb >} + method inter s = {< data = Setb.inter data s#tosetb >} + method minus s = {< data = Setb.diff data s#tosetb >} + (* todo: include, ... *) + + end diff --git a/commons/oseth.ml b/commons/oseth.ml new file mode 100644 index 0000000..2e74439 --- /dev/null +++ b/commons/oseth.ml @@ -0,0 +1,62 @@ +open Common + +open Oset + +(* !!take care!!: this class does side effect, not a pure oassoc *) +class ['a] oseth xs = +object(o) + inherit ['a] oset + + val data = Hashtbl.create 100 + + (* if put [] then no segfault, if [11] then segfault *) + method toset = Obj.magic data + + method empty = {< data = Hashtbl.create 100 >} + method add k = + Hashtbl.add data k true; + o + + method iter f = Hashtbl.iter (fun k v -> f k) data + method view = raise Todo + + method del k = + Hashtbl.remove data k; + o + method mem k = + try (ignore(Hashtbl.find data k); true) + with Not_found -> false + + method null = + try (Hashtbl.iter (fun k v -> raise ReturnExn) data; false) + with ReturnExn -> true + +(* TODO method length *) + + method union s = + let v = Hashtbl.create 100 in + o#iter (fun k -> Hashtbl.add v k true); + s#iter (fun k -> Hashtbl.add v k true); + {< data = v >} + method inter s = + let v = Hashtbl.create 100 in + o#iter (fun k -> if s#mem k then Hashtbl.add v k true); + {< data = v >} + method minus s = + let v = Hashtbl.create 100 in + o#iter (fun k -> if not(s#mem k) then Hashtbl.add v k true); + {< data = v >} + + (* override default *) + method getone = + let x = ref None in + try ( + Hashtbl.iter (fun k _ -> x := Some k; raise ReturnExn) data; + raise Not_found + ) + with ReturnExn -> some !x + + +end + + diff --git a/commons/oseti.ml b/commons/oseti.ml new file mode 100644 index 0000000..a0c8512 --- /dev/null +++ b/commons/oseti.ml @@ -0,0 +1,35 @@ +open Ocollection +open Oset + +class ['a] oseti xs = + object(o) + inherit [int] oset + + val data = xs (* Seti.empty *) + method toseti = data + method toset = Obj.magic data + + method empty = {< data = Seti.empty >} + method add e = {< data = Seti.add e data >} + method iter f = Seti.iter f data + method view = + if Seti.is_empty data + then Empty + else let el = Seti.choose data in Cons (el, o#del el) + + method del e = {< data = Seti.remove e data >} + method mem e = Seti.mem e data + method null = Seti.is_empty data + + method tolist = Seti.elements data + method length = Seti.cardinal data + + method union s = {< data = Seti.union data s#toseti >} + method inter s = {< data = Seti.inter data s#toseti >} + method minus s = {< data = Seti.diff data s#toseti >} + + method invariant () = Seti.invariant data + method to_string () = Seti.string_of_seti data + + method misc_op_hook () = {< data = Seti.patch3 data >} + end diff --git a/commons/osetpt.ml b/commons/osetpt.ml new file mode 100644 index 0000000..5ef3a6d --- /dev/null +++ b/commons/osetpt.ml @@ -0,0 +1,33 @@ +open Ocollection +open Oset + + +class ['a] osetpt xs = + object(o) + inherit [int] oset + + val data = SetPt.empty + method tosetpt = data + (* if put [] then no segfault, if [11] then segfault *) + method toset = Obj.magic data + + method empty = {< data = SetPt.empty >} + method add e = {< data = SetPt.add e data >} + method iter f = SetPt.iter f data + method view = + if SetPt.is_empty data + then Empty + else let el = SetPt.choose data in Cons (el, o#del el) + + method del e = {< data = SetPt.remove e data >} + method mem e = SetPt.mem e data + method null = SetPt.is_empty data + + method tolist = SetPt.elements data + method length = SetPt.cardinal data + + method union s = {< data = SetPt.union data s#tosetpt >} + method inter s = {< data = SetPt.inter data s#tosetpt >} + method minus s = {< data = SetPt.diff data s#tosetpt >} + + end diff --git a/commons/seti.ml b/commons/seti.ml new file mode 100644 index 0000000..f9ba591 --- /dev/null +++ b/commons/seti.ml @@ -0,0 +1,350 @@ +open Common + +(*****************************************************************************) +(* coded for LFS *) + +(* todo: could take an incr/decr func in param, to make it generic + * opti: remember the min/max (optimisation to have intersect biggest x -> x) + * opti: avoid all those rev, and avoid the intervise + * (but yes the algo are then more complex :) + * opti: balanced set intervalle +*) + +(*****************************************************************************) +type seti = elt list (* last elements is in first pos, ordered reverse *) + and elt = Exact of int | Interv of int * int + +(* invariant= ordered list, no incoherent interv (one elem or zero elem), + * merged (intervalle are separated) *) +let invariant xs = + let rec aux min xs = + xs +> List.fold_left (fun min e -> + match e with + | Exact i -> + if i <= min then pr2 (sprintf "i = %d, min = %d" i min); + (* todo: should be even stronger, shoud be i > min+1 *) + assert (i > min); + i + | Interv (i,j) -> + assert (i > min); + assert (j > i); + j + ) min + in + ignore(aux min_int (List.rev xs)); + () + +let string_of_seti xs = + "[" ^ + join "," (xs +> List.rev +> map (function + | (Exact i) -> string_of_int i + | (Interv (i,j)) -> Printf.sprintf "%d - %d" i j)) ^ + "]" + +(*****************************************************************************) +let empty = [] + +let pack newi j = function + | [] -> [Interv (newi,j)] + | (Exact z)::xs -> (Interv (newi, j))::(if newi = z then xs else (Exact z)::xs) + | (Interv (i', j'))::xs -> + if newi = j' + then (Interv (i', j))::xs (* merge *) + else (Interv (newi, j))::(Interv (i', j'))::xs + + +(* the only possible merges are when x = i-1, otherwise, the job is done before *) +let rec (add2: int -> seti -> seti) = fun x -> function + | [] -> [Exact x] + | (Exact i)::xs when x > i+1 -> (Exact x)::(Exact i)::xs + | (Interv (i,j)::xs) when x > j+1 -> (Exact x)::(Interv (i,j))::xs + | (Interv (i,j)::xs) when x = j+1 -> (Interv (i,x))::xs + | (Exact i)::xs when x = i+1 -> (Interv (i,x))::xs + + | (Exact i)::xs when i = x -> (Exact i)::xs + | (Interv (i,j)::xs) when x <= j && x >= i -> (Interv (i,j))::xs + | other -> +(* let _ = log "Cache miss" in *) + let _ = count2 () in + (match other with + | (Exact i)::xs when x = i-1 -> pack x i xs + | (Exact i)::xs when x < i-1 -> (Exact i)::add x xs + + | (Interv (i,j)::xs) when x = i-1 -> pack x j xs + | (Interv (i,j)::xs) when x < i-1 -> (Interv (i,j))::add x xs + | _ -> raise Impossible + ) +and add x y = let _ = count5 () in add2 x y + + +let rec tolist2 = function + | [] -> [] + | (Exact i)::xs -> i::tolist2 xs + | (Interv (i,j))::xs -> enum i j @ tolist2 xs +let rec tolist xs = List.rev (tolist2 xs) + +let rec fromlist = function xs -> List.fold_left (fun a e -> add e a) empty xs + +let intervise = function + | Exact x -> Interv (x,x) + | y -> y +let exactize = function + | Interv (i,j) when i = j -> Exact i + | y -> y +let exactize2 x y = if x = y then Exact x else Interv (x,y) + + +let rec (remove: int -> seti -> seti) = fun x xs -> + match xs with + | [] -> [] (* pb, not in *) + | (Exact z)::zs -> + (match x <=> z with + | Equal -> zs + | Sup -> xs (* pb, not in *) + | Inf -> (Exact z)::remove x zs + ) + | (Interv (i,j)::zs) -> + if x > j then xs (* pb not in *) + else + if x >= i && x <= j then + ( + let _ = assert (j > i) in (* otherwise can lead to construct seti such as [7,6] when removing 6 from [6,6] *) + match () with + | _ when x = i -> [exactize2 (i+1) j] + | _ when x = j -> [exactize2 i (j-1)] + | _ -> [exactize2 (x+1) j; exactize2 i (x-1)] + ) @ zs + else (Interv (i,j))::remove x zs + +(* let _ = Example (remove 635 [Interv (3, 635)] = [Interv (3, 634)]) *) +(* let _ = Example (remove 2 [Interv (6, 7); Interv(1,4)] = [Interv (6,7); Interv (3,4); Exact 1]) *) +(* let _ = Example (remove 6 [Interv (6, 7); Interv(1,4)] = [Exact 7; Interv (1,4)]) *) +(* let _ = Example (remove 1 [Interv (6, 7); Interv(1,2)] = [Interv (6,7); Exact 2]) *) +(* let _ = Example (remove 3 [Interv (1, 7)] = [Interv (4,7); Interv (1,2)]) *) +let _ = assert_equal (remove 3 [Interv (1, 7)]) [Interv (4,7); Interv (1,2)] +let _ = assert_equal (remove 4 [Interv (3, 4)]) [Exact (3);] +(* let _ = example (try (ignore(remove 6 [Interv (6, 6)] = []); false) with _ -> true) *) + + +let rec mem e = function + | [] -> false + | (Exact x)::xs -> + (match e <=> x with + | Equal -> true + | Sup -> false + | Inf -> mem e xs + ) + | (Interv (i,j)::xs) -> + if e > j then false + else + if e >= i && e <= j then true + else mem e xs + +let iter f xs = xs +> List.iter + (function + | Exact i -> f i + | Interv (i, j) -> for k = i to j do f k done + ) + +let is_empty xs = xs = [] +let choose = function + | [] -> failwith "not supposed to be called with empty set" + | (Exact i)::xs -> i + | (Interv (i,j))::xs -> i + +let elements xs = tolist xs +let rec cardinal = function + | [] -> 0 + | (Exact _)::xs -> 1+cardinal xs + | (Interv (i,j)::xs) -> (j-i) +1 + cardinal xs + +(*****************************************************************************) +(* TODO: could return corresponding osetb ? *) +let rec inter xs ys = + let rec aux = fun xs ys -> + match (xs, ys) with + | (_, []) -> [] + | ([],_) -> [] + | (x::xs, y::ys) -> + (match (x, y) with + | (Interv (i1, j1), Interv (i2, j2)) -> + (match i1 <=> i2 with + | Equal -> + (match j1 <=> j2 with + | Equal -> (Interv (i1,j1))::aux xs ys + (* [ ] *) + (* [ ] *) + | Inf -> (Interv (i1, j1))::aux xs ((Interv (j1+1, j2))::ys) + (* [ ] [ TODO? could have [ so cant englobe right now, but would be better *) + (* [ ] *) + | Sup -> (Interv (i1, j2))::aux ((Interv (j2+1, j1))::xs) ys + (* [ ] *) + (* [ ] [ same *) + ) + | Inf -> + if j1 < i2 then aux xs (y::ys) (* need order ? *) + (* [ ] *) + (* [ ] *) + else + (match j1 <=> j2 with + | Equal -> (Interv (i2, j1))::aux xs ys + (* [ ] *) + (* [ ] *) + | Inf -> (Interv (i2, j1))::aux xs ((Interv (j1+1, j2))::ys) + (* [ ] [ same *) + (* [ ] *) + | Sup -> (Interv (i2, j2))::aux ((Interv (j2+1, j1))::xs) ys + (* [ ] *) + (* [ ] [ same *) + ) + | Sup -> aux (y::ys) (x::xs) (* can cos commutative *) + ) + | _ -> raise Impossible (* intervise *) + ) + in + (* TODO avoid the rev rev, but aux good ? need order ? *) + List.rev_map exactize (aux (List.rev_map intervise xs) (List.rev_map intervise ys)) + +let union xs ys = + let rec aux = fun xs ys -> + match (xs, ys) with + | (vs, []) -> vs + | ([],vs) -> vs + | (x::xs, y::ys) -> + (match (x, y) with + | (Interv (i1, j1), Interv (i2, j2)) -> + (match i1 <=> i2 with + | Equal -> + (match j1 <=> j2 with + | Equal -> (Interv (i1,j1))::aux xs ys + (* [ ] *) + (* [ ] *) + | Inf -> (Interv (i1, j1))::aux xs ((Interv (j1+1, j2))::ys) + (* [ ] [ TODO? could have [ so cant englobe right now, but would be better *) + (* [ ] *) + | Sup -> (Interv (i1, j2))::aux ((Interv (j2+1, j1))::xs) ys + (* [ ] *) + (* [ ] [ same *) + ) + | Inf -> + if j1 < i2 then Interv (i1, j1):: aux xs (y::ys) + (* [ ] *) + (* [ ] *) + else + (match j1 <=> j2 with + | Equal -> (Interv (i1, j1))::aux xs ys + (* [ ] *) + (* [ ] *) + | Inf -> (Interv (i1, j1))::aux xs ((Interv (j1+1, j2))::ys) + (* [ ] [ same *) + (* [ ] *) + | Sup -> (Interv (i1, j2))::aux ((Interv (j2+1, j1))::xs) ys + (* [ ] *) + (* [ ] [ same *) + ) + | Sup -> aux (y::ys) (x::xs) (* can cos commutative *) + ) + | _ -> raise Impossible (* intervise *) + ) + in +(* union_set (tolist xs) (tolist ys) +> fromlist *) + List.rev_map exactize (aux (List.rev_map intervise xs) (List.rev_map intervise ys)) + +(* bug/feature: discovered by vlad rusu, my invariant for intervalle is + * not very strong, should return (Interv (1,4)) *) +(* let _ = Example (union [Interv (1, 4)] [Interv (1, 3)] = ([Exact 4; Interv (1,3)])) *) + +let diff xs ys = + let rec aux = fun xs ys -> + match (xs, ys) with + | (vs, []) -> vs + | ([],vs) -> [] + | (x::xs, y::ys) -> + (match (x, y) with + | (Interv (i1, j1), Interv (i2, j2)) -> + (match i1 <=> i2 with + | Equal -> + (match j1 <=> j2 with + | Equal -> aux xs ys + (* [ ] *) + (* [ ] *) + | Inf -> aux xs ((Interv (j1+1, j2))::ys) + (* [ ] *) + (* [ ] *) + | Sup -> aux ((Interv (j2+1, j1))::xs) ys + (* [ ] *) + (* [ ] *) + ) + | Inf -> + if j1 < i2 then Interv (i1, j1):: aux xs (y::ys) + (* [ ] *) + (* [ ] *) + else + (match j1 <=> j2 with + | Equal -> (Interv (i1, i2-1))::aux xs ys (* -1 cos exlude [ *) + (* [ ] *) + (* [ ] *) + | Inf -> (Interv (i1, i2-1))::aux xs ((Interv (j1+1, j2))::ys) + (* [ ] *) + (* [ ] *) + | Sup -> (Interv (i1, i2-1))::aux ((Interv (j2+1, j1))::xs) ys + (* [ ] *) + (* [ ] *) + ) + | Sup -> + if j2 < i1 then aux (x::xs) ys + (* [ ] *) + (* [ ] *) + else + (match j1 <=> j2 with + | Equal -> aux xs ys + (* [ ] *) + (* [ ] *) + | Inf -> aux xs ((Interv (j1+1, j2))::ys) + (* [ ] *) + (* [ ] *) + | Sup -> aux ((Interv (j2+1, j1))::xs) ys + (* [ ] *) + (* [ ] *) + ) + ) + | _ -> raise Impossible (* intervise *) + ) + in +(* minus_set (tolist xs) (tolist ys) +> fromlist *) + List.rev_map exactize (aux (List.rev_map intervise xs) (List.rev_map intervise ys)) + + +(* let _ = Example (diff [Interv (3,7)] [Interv (4,5)] = [Interv (6, 7); Exact 3]) *) + +(*****************************************************************************) +let rec debug = function + | [] -> "" + | (Exact i)::xs -> (Printf.sprintf "Exact:%d;" i) ^ (debug xs) + | (Interv (i,j)::xs) -> (Printf.sprintf "Interv:(%d,%d);" i j) ^ debug xs + +(*****************************************************************************) +(* if operation return wrong result, then may later have to patch them *) +let patch1 xs = List.map exactize xs +let patch2 xs = xs +> List.map (fun e -> + match e with + | Interv (i,j) when i > j && i = j+1 -> + let _ = pr2 (sprintf "i = %d, j = %d" i j) in + Exact i + | e -> e +) +let patch3 xs = + let rec aux min xs = + xs +> List.fold_left (fun (min,acc) e -> + match e with + | Exact i -> + if i = min + then (min, acc) + else (i, (Exact i)::acc) + | Interv (i,j) -> + (j, (Interv (i,j)::acc)) + ) (min, []) + in + aux min_int (List.rev xs) +> snd + + diff --git a/configure b/configure new file mode 100755 index 0000000..9a6741c --- /dev/null +++ b/configure @@ -0,0 +1,227 @@ +#!/usr/bin/perl +###################################################################### +# Prelude +###################################################################### + +# Yes I know about autoconf ... and autoconf sux. + +# assume standard: diff +# assume standard: perl + +#TODO python 2.5 and perhaps a --disable-python + +#old: --with-menhir=/path/to/menhirLib or `ocamlfind query menhirLib` + +my $project = + "coccinelle"; +my $projectcmdline = + "spatch -cocci_file demos/simple.cocci demos/simple.c"; + + +###################################################################### +# Options +###################################################################### + +my $prefix="/usr/local"; +my $python=1; + +local $_ = join ' ', @ARGV; + +# Parse options +/-h/ || /--help/ and die "usage: $0 [--prefix=path] [--without-python]\n"; +/--prefix=([^ ]*)/ and $prefix = $1; +/--without-python/ and $python = 0; + +#if($ARGV[0] =~ "--prefix=(.*)") { +# $prefix = $1; +#} +#if($ARGV[1] =~ "--without-python") { +# $python = 0; +#} + +my $src="$prefix/share/$project"; + +###################################################################### +# Side effects +###################################################################### + + +###################################################################### +# Helpers +###################################################################### +#BEGIN { die "need Perl 5 or greater" if $] < 5 ; } + +#use Common; +sub pr2 { print STDERR "@_\n" } +sub cat { + my ($what) = @_; + my @list; + open(TMP, $what); + while() { push @list, "$_"; } + \@list; +} +sub notb { !$_[0] } +sub mapf { my ($f, $xs) = @_; [ map { &$f($_) } @{$xs} ] } +sub plural { my ($e) = @_; if ($e > 1) { "s" } else { "" } } + +sub check_config { my ($command, $expect, $msggood, $msgbad) = @_; + my $error = 0; + + my $full = cat($command); + my $res = join(" ", @{$full}); +# pr2 $res; + if(notb($res =~ $expect)) { $error++; pr2 "!!!! $msgbad !!!!"; } + else { pr2 $msggood } + return $error; +} + +###################################################################### +# Let's go +###################################################################### +pr2 "Checking your configuration.\n"; + +my $error = 0; + + +#--------------------------------------------------------------------- +# Compilers and runtimes +#--------------------------------------------------------------------- +$error += + check_config("echo \"1;;\\n\" | ocaml |", +# "Objective(.*) 3.0[9]", + "Objective(.*) 3.", + "OCaml (the wonderful language) is present.", + "The program ocaml is missing or is not a good version. We need at least 3.09", + ); + +#we have cached the result of menhir in the tgz we build. + +#$error += +# check_config("menhir --version |", +# "menhir, version 20071212", +## "menhir, version 2006.*", +# "Menhir (the parser generator) is present.", +# "The program menhir is missing or is not a good version.", +# ); + + +#--------------------------------------------------------------- +# Developers tools +#--------------------------------------------------------------- + +pr2 ""; + +$error += check_config( + "make -v 2>&1 |grep Make|", + "GNU Make 3\.[0-9]+", #version 3.81 + "make (gnu version) is present.", + "The program gnu make is missing or is not a good version. +We need 3.XX", +); + + +#--------------------------------------------------------------------- +# More developers tools +#--------------------------------------------------------------------- + +#--------------------------------------------------------------------- +# Librairies +#--------------------------------------------------------------------- + +###################################################################### +# Generate config files (platform/portability issues) +###################################################################### + + +###################################################################### +# Generate globals files (features issues) +###################################################################### + +###################################################################### +# Diagnostic +###################################################################### + + +if($error) { + pr2 " +---------------------------------------------------------------------- +!!!! There seems to have problem, we have found $error missing package" . +plural($error) . ". +" . (($error > 1) ? "Some of those packages" : "This package") . + " may be installed by picking " . ($error > 1 ? "them" : "it") . + " in $project-dependencies.tgz available +on the $project website. !!!! +---------------------------------------------------------------------- +"; +} else { + + pr2 " +---------------------------------------------------------------------- + +All seems fine for $project. + +To compile $project type: + make depend; make + +To install type: + make install + +Then, to test $project simply type: + $projectcmdline + +"; + + if($python) { + pr2 +"To use the python SmPL feature you may have to set some environment variables. +For bash do: +export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:$prefix/lib +export PYTHONPATH=\$PYTHONPATH:$src/python +" + } + pr2 " +---------------------------------------------------------------------- +"; +} + + + +###################################################################### +# Generating the configuration +###################################################################### + +pr2 "$project target prefix: $prefix (you can use --prefix to override it)"; +pr2 "Generating Makefile.config"; +open(CONFIG, ">Makefile.config"); +print CONFIG "# autogenerated by configure + +# Where to install the binary +BINDIR=$prefix/bin + +# Where to install the man pages +MANDIR=$prefix/man + +# Where to install the lib +LIBDIR=$prefix/lib + +# Where to install the configuration files +SHAREDIR=$src + +# Features +FEATURE_PYTHON=$python +"; + +pr2 "Modifying globals/config.ml"; +pr2 "Generating appropriate links in python/ (python=$python)"; +my $pythonprefix = $python ? "yes_" : "no_"; +`cd python; rm -f pycocci.ml pycocci_aux.ml;`; +`cd python; ln -s ${pythonprefix}pycocci.ml pycocci.ml; `; +`cd python; ln -s ${pythonprefix}pycocci_aux.ml pycocci_aux.ml;`; +`cd python; make depend`; + +my $command = "perl -p -i -e 's#Not_found.\*#Not_found->\\\"$src\\\"#' globals/config.ml"; +`$command`; + + + + diff --git a/copyright.txt b/copyright.txt new file mode 100644 index 0000000..9e222f9 --- /dev/null +++ b/copyright.txt @@ -0,0 +1,21 @@ +Coccinelle - Julia Lawall, Yoann Padioleau, Rene Rydhof Hansen, Henrik Stuart + +Copyright (C) 2005-2008 University of Copenhagen DIKU, Ecole des Mines de Nantes + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License (GPL) + version 2 as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + file license.txt for more details. + + +The contents of some files in this directory was derived from external +sources with compatible licenses. The original copyright and license +notice was preserved in the affected files. + +This software can be distributed under another license (dual license) making +it possible to use Coccinelle in a commercial software. +Contact one of the author for more information. diff --git a/credits.txt b/credits.txt new file mode 100644 index 0000000..c2e01b7 --- /dev/null +++ b/credits.txt @@ -0,0 +1,11 @@ +Thanks to + - Didier Le Botlan for the name of the tool: spatch. + - A guy from Cornell for suggesting the term "semantic patch". + +Thanks to + - Francois Pottier and Yann Regis-Gianas for menhir + - arty@users.sourceforge.net for pycaml + - Richard Jones for his dumper module, + +Thanks of course also to Stallman, Linus, Leroy, Knuth and their +acolytes for respectively Emacs, Linux, OCaml, and (La)TeX. diff --git a/ctl/.depend b/ctl/.depend new file mode 100644 index 0000000..df69418 --- /dev/null +++ b/ctl/.depend @@ -0,0 +1,19 @@ +ctl_engine.cmi: ../commons/ograph_extended.cmi ast_ctl.cmo +pretty_print_ctl.cmi: ast_ctl.cmo +wrapper_ctl.cmi: ctl_engine.cmi ast_ctl.cmo +ctl_engine.cmo: pretty_print_ctl.cmi ../commons/ograph_extended.cmi \ + flag_ctl.cmo ../commons/common.cmi ast_ctl.cmo ctl_engine.cmi +ctl_engine.cmx: pretty_print_ctl.cmx ../commons/ograph_extended.cmx \ + flag_ctl.cmx ../commons/common.cmx ast_ctl.cmx ctl_engine.cmi +pretty_print_ctl.cmo: flag_ctl.cmo ../commons/common.cmi ast_ctl.cmo \ + pretty_print_ctl.cmi +pretty_print_ctl.cmx: flag_ctl.cmx ../commons/common.cmx ast_ctl.cmx \ + pretty_print_ctl.cmi +test_ctl.cmo: wrapper_ctl.cmi ../commons/ograph_extended.cmi ctl_engine.cmi \ + ast_ctl.cmo +test_ctl.cmx: wrapper_ctl.cmx ../commons/ograph_extended.cmx ctl_engine.cmx \ + ast_ctl.cmx +wrapper_ctl.cmo: ../globals/flag.cmo ctl_engine.cmi ../commons/common.cmi \ + ast_ctl.cmo wrapper_ctl.cmi +wrapper_ctl.cmx: ../globals/flag.cmx ctl_engine.cmx ../commons/common.cmx \ + ast_ctl.cmx wrapper_ctl.cmi diff --git a/ctl/Makefile b/ctl/Makefile new file mode 100644 index 0000000..e195a95 --- /dev/null +++ b/ctl/Makefile @@ -0,0 +1,95 @@ +# Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +# Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +# This file is part of Coccinelle. +# +# Coccinelle is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, according to version 2 of the License. +# +# Coccinelle is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Coccinelle. If not, see . +# +# The authors reserve the right to distribute this or future versions of +# Coccinelle under other licenses. + + +#note: if you add a file (a .mli or .ml), dont forget to do a make depend + +TARGET=ctl + +SRC=flag_ctl.ml ast_ctl.ml pretty_print_ctl.ml ctl_engine.ml wrapper_ctl.ml + +SYSLIBS=str.cma unix.cma +LIBS=../commons/commons.cma ../globals/globals.cma + +INCLUDES=-I ../commons -I ../commons/ocamlextra -I ../globals + + +#The Caml compilers. +#for warning: -w A +#for profiling: -p -inline 0 with OCAMLOPT +OCAMLCFLAGS ?= -g -dtypes +OCAMLC =ocamlc$(OPTBIN) $(OCAMLCFLAGS) $(INCLUDES) +OCAMLOPT = ocamlopt$(OPTBIN) $(OPTFLAGS) $(INCLUDES) +OCAMLDEP = ocamldep$(OPTBIN) $(INCLUDES) +OCAMLMKTOP=ocamlmktop -g -custom $(INCLUDES) + + + +LIB=$(TARGET).cma +OPTLIB=$(LIB:.cma=.cmxa) + +OBJS = $(SRC:.ml=.cmo) +OPTOBJS = $(SRC:.ml=.cmx) + +all: $(LIB) +all.opt: $(OPTLIB) + +$(TARGET).top: $(LIB) test_ctl.cmo + $(OCAMLMKTOP) -o $(TARGET).top $(SYSLIBS) $(LIBS) $(OBJS) test_ctl.cmo + +$(LIB): $(OBJS) + $(OCAMLC) -a -o $(LIB) $(OBJS) + +$(OPTLIB): $(OPTOBJS) + $(OCAMLOPT) -a -o $(OPTLIB) $(OPTOBJS) + +clean:: + rm -f $(LIB) $(OPTLIB) $(LIB:.cma=.a) $(TARGET).top + + +.SUFFIXES: +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) -c $< + +.mli.cmi: + $(OCAMLC) -c $< + +.ml.cmx: + $(OCAMLOPT) -c $< + + + + +# clean rule for others files +clean:: + rm -f *.cm[iox] *.o *.annot + rm -f *~ .*~ #*# + +depend: + $(OCAMLDEP) *.mli *.ml > .depend + +distclean:: + rm -f .depend + +.depend: + $(OCAMLDEP) *.mli *.ml > .depend + +-include .depend diff --git a/ctl/ast_ctl.ml b/ctl/ast_ctl.ml new file mode 100644 index 0000000..ac26eec --- /dev/null +++ b/ctl/ast_ctl.ml @@ -0,0 +1,98 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + + +(* ---------------------------------------------------------------------- *) +(* Types *) +(* ---------------------------------------------------------------------- *) + +type strict = STRICT | NONSTRICT + +type keep_binding = bool (* true = put in witness tree *) + +(* CTL parameterised on basic predicates and metavar's*) +type ('pred,'mvar,'anno) generic_ctl = + | False + | True + | Pred of 'pred + | Not of (('pred,'mvar,'anno) generic_ctl) + | Exists of keep_binding * 'mvar * (('pred,'mvar,'anno) generic_ctl) + | And of strict * (('pred,'mvar,'anno) generic_ctl) * + (('pred,'mvar,'anno) generic_ctl) + | AndAny of direction * strict * (('pred,'mvar,'anno) generic_ctl) * + (('pred,'mvar,'anno) generic_ctl) + | HackForStmt of direction * strict * (('pred,'mvar,'anno) generic_ctl) * + (('pred,'mvar,'anno) generic_ctl) + | Or of (('pred,'mvar,'anno) generic_ctl) * + (('pred,'mvar,'anno) generic_ctl) + | Implies of (('pred,'mvar,'anno) generic_ctl) * + (('pred,'mvar,'anno) generic_ctl) + | AF of direction * strict * (('pred,'mvar,'anno) generic_ctl) + | AX of direction * strict * (('pred,'mvar,'anno) generic_ctl) + | AG of direction * strict * (('pred,'mvar,'anno) generic_ctl) + | AW of direction * strict * + (* versions with exists v *) + (('pred,'mvar,'anno) generic_ctl) * (('pred,'mvar,'anno) generic_ctl) + | AU of direction * strict * + (* versions with exists v *) + (('pred,'mvar,'anno) generic_ctl) * (('pred,'mvar,'anno) generic_ctl) + | EF of direction * (('pred,'mvar,'anno) generic_ctl) + | EX of direction * (('pred,'mvar,'anno) generic_ctl) + | EG of direction * (('pred,'mvar,'anno) generic_ctl) + | EU of direction * (('pred,'mvar,'anno) generic_ctl) * + (('pred,'mvar,'anno) generic_ctl) + | Let of string * + (('pred,'mvar,'anno) generic_ctl) * + (('pred,'mvar,'anno) generic_ctl) + | LetR of direction * string * (* evals phi1 wrt reachable states *) + (('pred,'mvar,'anno) generic_ctl) * + (('pred,'mvar,'anno) generic_ctl) + | Ref of string + | SeqOr of (('pred,'mvar,'anno) generic_ctl) * + (('pred,'mvar,'anno) generic_ctl) + | Uncheck of (('pred,'mvar,'anno) generic_ctl) + | InnerAnd of (('pred,'mvar,'anno) generic_ctl) + | XX of (('pred,'mvar,'anno) generic_ctl) (* fake, used in asttoctl *) + +and direction = FORWARD (* the normal way *) | BACKWARD (* toward the start *) + +let unwrap (ctl,_) = ctl +let rewrap (_,model) ctl = (ctl,model) +let get_line (_,l) = l + + +(* NOTE: No explicit representation of the bottom subst., i.e., FALSE *) +type ('mvar,'value) generic_subst = + | Subst of 'mvar * 'value + | NegSubst of 'mvar * 'value +type ('mvar,'value) generic_substitution = ('mvar,'value) generic_subst list + +type ('state,'subst,'anno) generic_witnesstree = + Wit of + 'state * 'subst * 'anno * ('state,'subst,'anno) generic_witnesstree list + | NegWit of ('state,'subst,'anno) generic_witnesstree + +(* ---------------------------------------------------------------------- *) + +type 'a modif = Modif of 'a | UnModif of 'a | Control + +(* ---------------------------------------------------------------------- *) diff --git a/ctl/ctl_engine.ml b/ctl/ctl_engine.ml new file mode 100644 index 0000000..cee310c --- /dev/null +++ b/ctl/ctl_engine.ml @@ -0,0 +1,2418 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(*external c_counter : unit -> int = "c_counter"*) +let timeout = 800 +(* Optimize triples_conj by first extracting the intersection of the two sets, +which can certainly be in the intersection *) +let pTRIPLES_CONJ_OPT = ref true +(* For complement, make NegState for the negation of a single state *) +let pTRIPLES_COMPLEMENT_OPT = ref true +(* For complement, do something special for the case where the environment +and witnesses are empty *) +let pTRIPLES_COMPLEMENT_SIMPLE_OPT = ref true +(* "Double negate" the arguments of the path operators *) +let pDOUBLE_NEGATE_OPT = ref true +(* Only do pre_forall/pre_exists on new elements in fixpoint iteration *) +let pNEW_INFO_OPT = ref true +(* Filter the result of the label function to drop entries that aren't +compatible with any of the available environments *) +let pREQUIRED_ENV_OPT = ref true +(* Memoize the raw result of the label function *) +let pSATLABEL_MEMO_OPT = ref true +(* Filter results according to the required states *) +let pREQUIRED_STATES_OPT = ref true +(* Drop negative witnesses at Uncheck *) +let pUNCHECK_OPT = ref true +let pANY_NEG_OPT = ref true +let pLazyOpt = ref true + +(* +let pTRIPLES_CONJ_OPT = ref false +let pTRIPLES_COMPLEMENT_OPT = ref false +let pTRIPLES_COMPLEMENT_SIMPLE_OPT = ref false +let pDOUBLE_NEGATE_OPT = ref false +let pNEW_INFO_OPT = ref false +let pREQUIRED_ENV_OPT = ref false +let pSATLABEL_MEMO_OPT = ref false +let pREQUIRED_STATES_OPT = ref false +let pUNCHECK_OPT = ref false +let pANY_NEG_OPT = ref false +let pLazyOpt = ref false +*) + + +let step_count = ref 0 +exception Steps +let inc_step _ = + if not (!step_count = 0) + then + begin + step_count := !step_count - 1; + if !step_count = 0 then raise Steps + end + +let inc cell = cell := !cell + 1 + +let satEU_calls = ref 0 +let satAW_calls = ref 0 +let satAU_calls = ref 0 +let satEF_calls = ref 0 +let satAF_calls = ref 0 +let satEG_calls = ref 0 +let satAG_calls = ref 0 + +let triples = ref 0 + +let ctr = ref 0 +let new_let _ = + let c = !ctr in + ctr := c + 1; + Printf.sprintf "_fresh_r_%d" c + +(* ********************************************************************** + * + * Implementation of a Witness Tree model checking engine for CTL-FVex + * + * + * **********************************************************************) + +(* ********************************************************************** *) +(* Module: SUBST (substitutions: meta. vars and values) *) +(* ********************************************************************** *) + +module type SUBST = + sig + type value + type mvar + val eq_mvar: mvar -> mvar -> bool + val eq_val: value -> value -> bool + val merge_val: value -> value -> value + val print_mvar : mvar -> unit + val print_value : value -> unit + end +;; + +(* ********************************************************************** *) +(* Module: GRAPH (control flow graphs / model) *) +(* ********************************************************************** *) + +module type GRAPH = + sig + type node + type cfg + val predecessors: cfg -> node -> node list + val successors: cfg -> node -> node list + val extract_is_loop : cfg -> node -> bool + val print_node : node -> unit + val size : cfg -> int + end +;; + +module OGRAPHEXT_GRAPH = + struct + type node = int;; + type cfg = (string,unit) Ograph_extended.ograph_mutable;; + let predecessors cfg n = List.map fst ((cfg#predecessors n)#tolist);; + let print_node i = Format.print_string (Common.i_to_s i) + end +;; + +(* ********************************************************************** *) +(* Module: PREDICATE (predicates for CTL formulae) *) +(* ********************************************************************** *) + +module type PREDICATE = +sig + type t + val print_predicate : t -> unit +end + + +(* ********************************************************************** *) + +(* ---------------------------------------------------------------------- *) +(* Misc. useful generic functions *) +(* ---------------------------------------------------------------------- *) + +let head = List.hd + +let tail l = + match l with + [] -> [] + | (x::xs) -> xs +;; + +let foldl = List.fold_left;; + +let foldl1 f xs = foldl f (head xs) (tail xs) + +type 'a esc = ESC of 'a | CONT of 'a + +let foldr = List.fold_right;; + +let concat = List.concat;; + +let map = List.map;; + +let filter = List.filter;; + +let partition = List.partition;; + +let concatmap f l = List.concat (List.map f l);; + +let maybe f g opt = + match opt with + | None -> g + | Some x -> f x +;; + +let some_map f opts = map (maybe (fun x -> Some (f x)) None) opts + +let some_tolist_alt opts = concatmap (maybe (fun x -> [x]) []) opts + +let rec some_tolist opts = + match opts with + | [] -> [] + | (Some x)::rest -> x::(some_tolist rest) + | _::rest -> some_tolist rest +;; + +let rec groupBy eq l = + match l with + [] -> [] + | (x::xs) -> + let (xs1,xs2) = partition (fun x' -> eq x x') xs in + (x::xs1)::(groupBy eq xs2) +;; + +let group l = groupBy (=) l;; + +let rec memBy eq x l = + match l with + [] -> false + | (y::ys) -> if (eq x y) then true else (memBy eq x ys) +;; + +let rec nubBy eq ls = + match ls with + [] -> [] + | (x::xs) when (memBy eq x xs) -> nubBy eq xs + | (x::xs) -> x::(nubBy eq xs) +;; + +let rec nub ls = + match ls with + [] -> [] + | (x::xs) when (List.mem x xs) -> nub xs + | (x::xs) -> x::(nub xs) +;; + +let state_compare (s1,_,_) (s2,_,_) = compare s1 s2 + +let setifyBy eq xs = nubBy eq xs;; + +let setify xs = nub xs;; + +let inner_setify xs = List.sort compare (nub xs);; + +let unionBy compare eq xs = function + [] -> xs + | ys -> + let rec loop = function + [] -> ys + | x::xs -> if memBy eq x ys then loop xs else x::(loop xs) in + List.sort compare (loop xs) +;; + +let union xs ys = unionBy state_compare (=) xs ys;; + +let setdiff xs ys = filter (fun x -> not (List.mem x ys)) xs;; + +let subseteqBy eq xs ys = List.for_all (fun x -> memBy eq x ys) xs;; + +let subseteq xs ys = List.for_all (fun x -> List.mem x ys) xs;; +let supseteq xs ys = subseteq ys xs + +let setequalBy eq xs ys = (subseteqBy eq xs ys) & (subseteqBy eq ys xs);; + +let setequal xs ys = (subseteq xs ys) & (subseteq ys xs);; + +(* Fix point calculation *) +let rec fix eq f x = + let x' = f x in if (eq x' x) then x' else fix eq f x' +;; + +(* Fix point calculation on set-valued functions *) +let setfix f x = (fix subseteq f x) (*if new is a subset of old, stop*) +let setgfix f x = (fix supseteq f x) (*if new is a supset of old, stop*) + +let get_states l = nub (List.map (function (s,_,_) -> s) l) + +(* ********************************************************************** *) +(* Module: CTL_ENGINE *) +(* ********************************************************************** *) + +module CTL_ENGINE = + functor (SUB : SUBST) -> + functor (G : GRAPH) -> + functor (P : PREDICATE) -> +struct + +module A = Ast_ctl + +type substitution = (SUB.mvar, SUB.value) Ast_ctl.generic_substitution + +type ('pred,'anno) witness = + (G.node, substitution, + ('pred, SUB.mvar, 'anno) Ast_ctl.generic_ctl list) + Ast_ctl.generic_witnesstree + +type ('pred,'anno) triples = + (G.node * substitution * ('pred,'anno) witness list) list + +(* ---------------------------------------------------------------------- *) +(* Pretty printing functions *) +(* ---------------------------------------------------------------------- *) + +let (print_generic_substitution : substitution -> unit) = fun substxs -> + let print_generic_subst = function + A.Subst (mvar, v) -> + SUB.print_mvar mvar; Format.print_string " --> "; SUB.print_value v + | A.NegSubst (mvar, v) -> + SUB.print_mvar mvar; Format.print_string " -/-> "; SUB.print_value v in + Format.print_string "["; + Common.print_between (fun () -> Format.print_string ";" ) + print_generic_subst substxs; + Format.print_string "]" + +let rec (print_generic_witness: ('pred, 'anno) witness -> unit) = + function + | A.Wit (state, subst, anno, childrens) -> + Format.print_string "wit "; + G.print_node state; + print_generic_substitution subst; + (match childrens with + [] -> Format.print_string "{}" + | _ -> + Format.force_newline(); Format.print_string " "; Format.open_box 0; + print_generic_witnesstree childrens; Format.close_box()) + | A.NegWit(wit) -> + Format.print_string "!"; + print_generic_witness wit + +and (print_generic_witnesstree: ('pred,'anno) witness list -> unit) = + fun witnesstree -> + Format.open_box 1; + Format.print_string "{"; + Common.print_between + (fun () -> Format.print_string ";"; Format.force_newline() ) + print_generic_witness witnesstree; + Format.print_string "}"; + Format.close_box() + +and print_generic_triple (node,subst,tree) = + G.print_node node; + print_generic_substitution subst; + print_generic_witnesstree tree + +and (print_generic_algo : ('pred,'anno) triples -> unit) = fun xs -> + Format.print_string "<"; + Common.print_between + (fun () -> Format.print_string ";"; Format.force_newline()) + print_generic_triple xs; + Format.print_string ">" +;; + +let print_state (str : string) (l : ('pred,'anno) triples) = + Printf.printf "%s\n" str; + List.iter (function x -> + print_generic_triple x; Format.print_newline(); flush stdout) + (List.sort compare l); + Printf.printf "\n" + +let print_required_states = function + None -> Printf.printf "no required states\n" + | Some states -> + Printf.printf "required states: "; + List.iter + (function x -> + G.print_node x; Format.print_string " "; Format.print_flush()) + states; + Printf.printf "\n" + +let mkstates states = function + None -> states + | Some states -> states + +(* ---------------------------------------------------------------------- *) +(* *) +(* ---------------------------------------------------------------------- *) + + +(* ************************* *) +(* Substitutions *) +(* ************************* *) + +let dom_sub sub = + match sub with + | A.Subst(x,_) -> x + | A.NegSubst(x,_) -> x +;; + +let ran_sub sub = + match sub with + | A.Subst(_,x) -> x + | A.NegSubst(_,x) -> x +;; + +let eq_subBy eqx eqv sub sub' = + match (sub,sub') with + | (A.Subst(x,v),A.Subst(x',v')) -> (eqx x x') && (eqv v v') + | (A.NegSubst(x,v),A.NegSubst(x',v')) -> (eqx x x') && (eqv v v') + | _ -> false +;; + +(* NOTE: functor *) +let eq_sub sub sub' = eq_subBy SUB.eq_mvar SUB.eq_val sub sub' + +let eq_subst th th' = setequalBy eq_sub th th';; + +let merge_subBy eqx (===) (>+<) sub sub' = + (* variable part is guaranteed to be the same *) + match (sub,sub') with + (A.Subst (x,v),A.Subst (x',v')) -> + if (v === v') + then Some [A.Subst(x, v >+< v')] + else None + | (A.NegSubst(x,v),A.Subst(x',v')) -> + if (not (v === v')) + then Some [A.Subst(x',v')] + else None + | (A.Subst(x,v),A.NegSubst(x',v')) -> + if (not (v === v')) + then Some [A.Subst(x,v)] + else None + | (A.NegSubst(x,v),A.NegSubst(x',v')) -> + if (v === v') + then + let merged = v >+< v' in + if merged = v && merged = v' + then Some [A.NegSubst(x,v >+< v')] + else + (* positions are compatible, but not identical. keep apart. *) + Some [A.NegSubst(x,v);A.NegSubst(x',v')] + else Some [A.NegSubst(x,v);A.NegSubst(x',v')] +;; + +(* NOTE: functor *) +let merge_sub sub sub' = + merge_subBy SUB.eq_mvar SUB.eq_val SUB.merge_val sub sub' + +let clean_substBy eq cmp theta = List.sort cmp (nubBy eq theta);; + +(* NOTE: we sort by using the generic "compare" on (meta-)variable + * names; we could also require a definition of compare for meta-variables + * or substitutions but that seems like overkill for sorting + *) +let clean_subst theta = + let res = + clean_substBy eq_sub + (fun s s' -> + let res = compare (dom_sub s) (dom_sub s') in + if res = 0 + then + match (s,s') with + (A.Subst(_,_),A.NegSubst(_,_)) -> -1 + | (A.NegSubst(_,_),A.Subst(_,_)) -> 1 + | _ -> compare (ran_sub s) (ran_sub s') + else res) + theta in + let rec loop = function + [] -> [] + | (A.Subst(x,v)::A.NegSubst(y,v')::rest) when SUB.eq_mvar x y -> + loop (A.Subst(x,v)::rest) + | x::xs -> x::(loop xs) in + loop res + +let top_subst = [];; (* Always TRUE subst. *) + +(* Split a theta in two parts: one with (only) "x" and one without *) +(* NOTE: functor *) +let split_subst theta x = + partition (fun sub -> SUB.eq_mvar (dom_sub sub) x) theta;; + +exception SUBST_MISMATCH +let conj_subst theta theta' = + match (theta,theta') with + | ([],_) -> Some theta' + | (_,[]) -> Some theta + | _ -> + let rec classify = function + [] -> [] + | [x] -> [(dom_sub x,[x])] + | x::xs -> + (match classify xs with + ((nm,y)::ys) as res -> + if dom_sub x = nm + then (nm,x::y)::ys + else (dom_sub x,[x])::res + | _ -> failwith "not possible") in + let merge_all theta theta' = + foldl + (function rest -> + function sub -> + foldl + (function rest -> + function sub' -> + match (merge_sub sub sub') with + Some subs -> subs @ rest + | _ -> raise SUBST_MISMATCH) + rest theta') + [] theta in + let rec loop = function + ([],ctheta') -> + List.concat (List.map (function (_,ths) -> ths) ctheta') + | (ctheta,[]) -> + List.concat (List.map (function (_,ths) -> ths) ctheta) + | ((x,ths)::xs,(y,ths')::ys) -> + (match compare x y with + 0 -> (merge_all ths ths') @ loop (xs,ys) + | -1 -> ths @ loop (xs,((y,ths')::ys)) + | 1 -> ths' @ loop (((x,ths)::xs),ys) + | _ -> failwith "not possible") in + try Some (clean_subst(loop (classify theta, classify theta'))) + with SUBST_MISMATCH -> None +;; + +(* theta' must be a subset of theta *) +let conj_subst_none theta theta' = + match (theta,theta') with + | (_,[]) -> Some theta + | ([],_) -> None + | _ -> + let rec classify = function + [] -> [] + | [x] -> [(dom_sub x,[x])] + | x::xs -> + (match classify xs with + ((nm,y)::ys) as res -> + if dom_sub x = nm + then (nm,x::y)::ys + else (dom_sub x,[x])::res + | _ -> failwith "not possible") in + let merge_all theta theta' = + foldl + (function rest -> + function sub -> + foldl + (function rest -> + function sub' -> + match (merge_sub sub sub') with + Some subs -> subs @ rest + | _ -> raise SUBST_MISMATCH) + rest theta') + [] theta in + let rec loop = function + (ctheta,[]) -> + List.concat (List.map (function (_,ths) -> ths) ctheta) + | ([],ctheta') -> raise SUBST_MISMATCH + | ((x,ths)::xs,(y,ths')::ys) -> + (match compare x y with + 0 -> (merge_all ths ths') @ loop (xs,ys) + | -1 -> ths @ loop (xs,((y,ths')::ys)) + | 1 -> raise SUBST_MISMATCH + | _ -> failwith "not possible") in + try Some (clean_subst(loop (classify theta, classify theta'))) + with SUBST_MISMATCH -> None +;; + +let negate_sub sub = + match sub with + | A.Subst(x,v) -> A.NegSubst (x,v) + | A.NegSubst(x,v) -> A.Subst(x,v) +;; + +(* Turn a (big) theta into a list of (small) thetas *) +let negate_subst theta = (map (fun sub -> [negate_sub sub]) theta);; + + +(* ************************* *) +(* Witnesses *) +(* ************************* *) + +(* Always TRUE witness *) +let top_wit = ([] : (('pred, 'anno) witness list));; + +let eq_wit wit wit' = wit = wit';; + +let union_wit wit wit' = (*List.sort compare (wit' @ wit) for popl*) + let res = unionBy compare (=) wit wit' in + let anynegwit = (* if any is neg, then all are *) + List.exists (function A.NegWit _ -> true | A.Wit _ -> false) in + if anynegwit res + then List.filter (function A.NegWit _ -> true | A.Wit _ -> false) res + else res + +let negate_wit wit = A.NegWit wit (* + match wit with + | A.Wit(s,th,anno,ws) -> A.NegWitWit(s,th,anno,ws) + | A.NegWitWit(s,th,anno,ws) -> A.Wit(s,th,anno,ws)*) +;; + +let negate_wits wits = + List.sort compare (map (fun wit -> [negate_wit wit]) wits);; + +let unwitify trips = + let anynegwit = (* if any is neg, then all are *) + List.exists (function A.NegWit _ -> true | A.Wit _ -> false) in + setify + (List.fold_left + (function prev -> + function (s,th,wit) -> + if anynegwit wit then prev else (s,th,top_wit)::prev) + [] trips) + +(* ************************* *) +(* Triples *) +(* ************************* *) + +(* Triples are equal when the constituents are equal *) +let eq_trip (s,th,wit) (s',th',wit') = + (s = s') && (eq_wit wit wit') && (eq_subst th th');; + +let triples_top states = map (fun s -> (s,top_subst,top_wit)) states;; + +let normalize trips = + List.map + (function (st,th,wit) -> (st,List.sort compare th,List.sort compare wit)) + trips + + +(* conj opt doesn't work ((1,[],{{x=3}}) v (1,[],{{x=4}})) & (1,[],{{x=4}}) = +(1,[],{{x=3},{x=4}}), not (1,[],{{x=4}}) *) +let triples_conj trips trips' = + let (trips,shared,trips') = + if false && !pTRIPLES_CONJ_OPT (* see comment above *) + then + let (shared,trips) = + List.partition (function t -> List.mem t trips') trips in + let trips' = + List.filter (function t -> not(List.mem t shared)) trips' in + (trips,shared,trips') + else (trips,[],trips') in + foldl (* returns a set - setify inlined *) + (function rest -> + function (s1,th1,wit1) -> + foldl + (function rest -> + function (s2,th2,wit2) -> + if (s1 = s2) then + (match (conj_subst th1 th2) with + Some th -> + let t = (s1,th,union_wit wit1 wit2) in + if List.mem t rest then rest else t::rest + | _ -> rest) + else rest) + rest trips') + shared trips +;; + +(* ignore the state in the right argument. always pretend it is the same as +the left one *) +(* env on right has to be a subset of env on left *) +let triples_conj_none trips trips' = + let (trips,shared,trips') = + if false && !pTRIPLES_CONJ_OPT (* see comment above *) + then + let (shared,trips) = + List.partition (function t -> List.mem t trips') trips in + let trips' = + List.filter (function t -> not(List.mem t shared)) trips' in + (trips,shared,trips') + else (trips,[],trips') in + foldl (* returns a set - setify inlined *) + (function rest -> + function (s1,th1,wit1) -> + foldl + (function rest -> + function (s2,th2,wit2) -> + match (conj_subst_none th1 th2) with + Some th -> + let t = (s1,th,union_wit wit1 wit2) in + if List.mem t rest then rest else t::rest + | _ -> rest) + rest trips') + shared trips +;; + +exception AW + +let triples_conj_AW trips trips' = + let (trips,shared,trips') = + if false && !pTRIPLES_CONJ_OPT + then + let (shared,trips) = + List.partition (function t -> List.mem t trips') trips in + let trips' = + List.filter (function t -> not(List.mem t shared)) trips' in + (trips,shared,trips') + else (trips,[],trips') in + foldl (* returns a set - setify inlined *) + (function rest -> + function (s1,th1,wit1) -> + foldl + (function rest -> + function (s2,th2,wit2) -> + if (s1 = s2) then + (match (conj_subst th1 th2) with + Some th -> + let t = (s1,th,union_wit wit1 wit2) in + if List.mem t rest then rest else t::rest + | _ -> raise AW) + else rest) + rest trips') + shared trips +;; + +(* *************************** *) +(* NEGATION (NegState style) *) +(* *************************** *) + +(* Constructive negation at the state level *) +type ('a) state = + PosState of 'a + | NegState of 'a list +;; + +let compatible_states = function + (PosState s1, PosState s2) -> + if s1 = s2 then Some (PosState s1) else None + | (PosState s1, NegState s2) -> + if List.mem s1 s2 then None else Some (PosState s1) + | (NegState s1, PosState s2) -> + if List.mem s2 s1 then None else Some (PosState s2) + | (NegState s1, NegState s2) -> Some (NegState (s1 @ s2)) +;; + +(* Conjunction on triples with "special states" *) +let triples_state_conj trips trips' = + let (trips,shared,trips') = + if !pTRIPLES_CONJ_OPT + then + let (shared,trips) = + List.partition (function t -> List.mem t trips') trips in + let trips' = + List.filter (function t -> not(List.mem t shared)) trips' in + (trips,shared,trips') + else (trips,[],trips') in + foldl + (function rest -> + function (s1,th1,wit1) -> + foldl + (function rest -> + function (s2,th2,wit2) -> + match compatible_states(s1,s2) with + Some s -> + (match (conj_subst th1 th2) with + Some th -> + let t = (s,th,union_wit wit1 wit2) in + if List.mem t rest then rest else t::rest + | _ -> rest) + | _ -> rest) + rest trips') + shared trips +;; + +let triple_negate (s,th,wits) = + let negstates = (NegState [s],top_subst,top_wit) in + let negths = map (fun th -> (PosState s,th,top_wit)) (negate_subst th) in + let negwits = map (fun nwit -> (PosState s,th,nwit)) (negate_wits wits) in + negstates :: (negths @ negwits) (* all different *) + +(* FIX ME: it is not necessary to do full conjunction *) +let triples_complement states (trips : ('pred, 'anno) triples) = + if !pTRIPLES_COMPLEMENT_OPT + then + (let cleanup (s,th,wit) = + match s with + PosState s' -> [(s',th,wit)] + | NegState ss -> + assert (th=top_subst); + assert (wit=top_wit); + map (fun st -> (st,top_subst,top_wit)) (setdiff states ss) in + let (simple,complex) = + if !pTRIPLES_COMPLEMENT_SIMPLE_OPT + then + let (simple,complex) = + List.partition (function (s,[],[]) -> true | _ -> false) trips in + let simple = + [(NegState(List.map (function (s,_,_) -> s) simple), + top_subst,top_wit)] in + (simple,complex) + else ([(NegState [],top_subst,top_wit)],trips) in + let rec compl trips = + match trips with + [] -> simple + | (t::ts) -> triples_state_conj (triple_negate t) (compl ts) in + let compld = (compl complex) in + let compld = concatmap cleanup compld in + compld) + else + let negstates (st,th,wits) = + map (function st -> (st,top_subst,top_wit)) (setdiff states [st]) in + let negths (st,th,wits) = + map (function th -> (st,th,top_wit)) (negate_subst th) in + let negwits (st,th,wits) = + map (function nwit -> (st,th,nwit)) (negate_wits wits) in + match trips with + [] -> map (function st -> (st,top_subst,top_wit)) states + | x::xs -> + setify + (foldl + (function prev -> + function cur -> + triples_conj (negstates cur @ negths cur @ negwits cur) prev) + (negstates x @ negths x @ negwits x) xs) +;; + +let triple_negate (s,th,wits) = + let negths = map (fun th -> (s,th,top_wit)) (negate_subst th) in + let negwits = map (fun nwit -> (s,th,nwit)) (negate_wits wits) in + ([s], negths @ negwits) (* all different *) + +let print_compl_state str (n,p) = + Printf.printf "%s neg: " str; + List.iter + (function x -> G.print_node x; Format.print_flush(); Printf.printf " ") + n; + Printf.printf "\n"; + print_state "pos" p + +let triples_complement states (trips : ('pred, 'anno) triples) = + if trips = [] + then map (function st -> (st,top_subst,top_wit)) states + else + let cleanup (neg,pos) = + let keep_pos = + List.filter (function (s,_,_) -> List.mem s neg) pos in + (map (fun st -> (st,top_subst,top_wit)) (setdiff states neg)) @ + keep_pos in + let trips = List.sort state_compare trips in + let all_negated = List.map triple_negate trips in + let merge_one (neg1,pos1) (neg2,pos2) = + let (pos1conj,pos1keep) = + List.partition (function (s,_,_) -> List.mem s neg2) pos1 in + let (pos2conj,pos2keep) = + List.partition (function (s,_,_) -> List.mem s neg1) pos2 in + (Common.union_set neg1 neg2, + (triples_conj pos1conj pos2conj) @ pos1keep @ pos2keep) in + let rec inner_loop = function + x1::x2::rest -> (merge_one x1 x2) :: (inner_loop rest) + | l -> l in + let rec outer_loop = function + [x] -> x + | l -> outer_loop (inner_loop l) in + cleanup (outer_loop all_negated) + +(* ********************************** *) +(* END OF NEGATION (NegState style) *) +(* ********************************** *) + +(* now this is always true, so we could get rid of it *) +let something_dropped = ref true + +let triples_union trips trips' = + (*unionBy compare eq_trip trips trips';;*) + (* returns -1 is t1 > t2, 1 if t2 >= t1, and 0 otherwise *) +(* +The following does not work. Suppose we have ([x->3],{A}) and ([],{A,B}). +Then, the following says that since the first is a more restrictive +environment and has fewer witnesses, then it should be dropped. But having +fewer witnesses is not necessarily less informative than having more, +because fewer witnesses can mean the absence of the witness-causing thing. +So the fewer witnesses have to be kept around. +subseteq changed to = to make it hopefully work +*) + if !pNEW_INFO_OPT + then + begin + something_dropped := false; + if trips = trips' + then (something_dropped := true; trips) + else + let subsumes (s1,th1,wit1) (s2,th2,wit2) = + if s1 = s2 + then + (match conj_subst th1 th2 with + Some conj -> + if conj = th1 + then if (*subseteq*) wit1 = wit2 then 1 else 0 + else + if conj = th2 + then if (*subseteq*) wit2 = wit1 then (-1) else 0 + else 0 + | None -> 0) + else 0 in + let rec first_loop second = function + [] -> second + | x::xs -> first_loop (second_loop x second) xs + and second_loop x = function + [] -> [x] + | (y::ys) as all -> + match subsumes x y with + 1 -> something_dropped := true; all + | (-1) -> second_loop x ys + | _ -> y::(second_loop x ys) in + first_loop trips trips' + end + else unionBy compare eq_trip trips trips' + + +let triples_witness x unchecked not_keep trips = + let anyneg = (* if any is neg, then all are *) + List.exists (function A.NegSubst _ -> true | A.Subst _ -> false) in + let anynegwit = (* if any is neg, then all are *) + List.exists (function A.NegWit _ -> true | A.Wit _ -> false) in + let allnegwit = (* if any is neg, then all are *) + List.for_all (function A.NegWit _ -> true | A.Wit _ -> false) in + let negtopos = + List.map (function A.NegWit w -> w | A.Wit _ -> failwith "bad wit")in + let res = + List.fold_left + (function prev -> + function (s,th,wit) as t -> + let (th_x,newth) = split_subst th x in + match th_x with + [] -> + (* one consider whether if not not_keep is true, then we should + fail. but it could be that the variable is a used_after and + then it is the later rule that should fail and not this one *) + if not not_keep && !Flag_ctl.verbose_ctl_engine + then + (SUB.print_mvar x; Format.print_flush(); + print_state ": empty witness from" [t]); + t::prev + | l when anyneg l && !pANY_NEG_OPT -> prev + (* see tests/nestseq for how neg bindings can come up even + without eg partial matches + (* negated substitution only allowed with negwits. + just dropped *) + if anynegwit wit && allnegwit wit (* nonempty negwit list *) + then prev + else + (print_generic_substitution l; Format.print_newline(); + failwith"unexpected negative binding with positive witnesses")*) + | _ -> + let new_triple = + if unchecked or not_keep + then (s,newth,wit) + else + if anynegwit wit && allnegwit wit + then (s,newth,[A.NegWit(A.Wit(s,th_x,[],negtopos wit))]) + else (s,newth,[A.Wit(s,th_x,[],wit)]) in + new_triple::prev) + [] trips in + if unchecked || !Flag_ctl.partial_match (* the only way to have a NegWit *) + then setify res + else List.rev res +;; + + +(* ---------------------------------------------------------------------- *) +(* SAT - Model Checking Algorithm for CTL-FVex *) +(* *) +(* TODO: Implement _all_ operators (directly) *) +(* ---------------------------------------------------------------------- *) + + +(* ************************************* *) +(* The SAT algorithm and special helpers *) +(* ************************************* *) + +let rec pre_exist dir (grp,_,_) y reqst = + let check s = + match reqst with None -> true | Some reqst -> List.mem s reqst in + let exp (s,th,wit) = + concatmap + (fun s' -> if check s' then [(s',th,wit)] else []) + (match dir with + A.FORWARD -> G.predecessors grp s + | A.BACKWARD -> G.successors grp s) in + setify (concatmap exp y) +;; + +exception Empty + +let pre_forall dir (grp,_,states) y all reqst = + let check s = + match reqst with + None -> true | Some reqst -> List.mem s reqst in + let pred = + match dir with + A.FORWARD -> G.predecessors | A.BACKWARD -> G.successors in + let succ = + match dir with + A.FORWARD -> G.successors | A.BACKWARD -> G.predecessors in + let neighbors = + List.map + (function p -> (p,succ grp p)) + (setify + (concatmap + (function (s,_,_) -> List.filter check (pred grp s)) y)) in + (* would a hash table be more efficient? *) + let all = List.sort state_compare all in + let rec up_nodes child s = function + [] -> [] + | (s1,th,wit)::xs -> + (match compare s1 child with + -1 -> up_nodes child s xs + | 0 -> (s,th,wit)::(up_nodes child s xs) + | _ -> []) in + let neighbor_triples = + List.fold_left + (function rest -> + function (s,children) -> + try + (List.map + (function child -> + match up_nodes child s all with [] -> raise Empty | l -> l) + children) :: rest + with Empty -> rest) + [] neighbors in + match neighbor_triples with + [] -> [] + | _ -> + (*normalize*) + (foldl1 (@) (List.map (foldl1 triples_conj) neighbor_triples)) + +let pre_forall_AW dir (grp,_,states) y all reqst = + let check s = + match reqst with + None -> true | Some reqst -> List.mem s reqst in + let pred = + match dir with + A.FORWARD -> G.predecessors | A.BACKWARD -> G.successors in + let succ = + match dir with + A.FORWARD -> G.successors | A.BACKWARD -> G.predecessors in + let neighbors = + List.map + (function p -> (p,succ grp p)) + (setify + (concatmap + (function (s,_,_) -> List.filter check (pred grp s)) y)) in + (* would a hash table be more efficient? *) + let all = List.sort state_compare all in + let rec up_nodes child s = function + [] -> [] + | (s1,th,wit)::xs -> + (match compare s1 child with + -1 -> up_nodes child s xs + | 0 -> (s,th,wit)::(up_nodes child s xs) + | _ -> []) in + let neighbor_triples = + List.fold_left + (function rest -> + function (s,children) -> + (List.map + (function child -> + match up_nodes child s all with [] -> raise AW | l -> l) + children) :: rest) + [] neighbors in + match neighbor_triples with + [] -> [] + | _ -> foldl1 (@) (List.map (foldl1 triples_conj_AW) neighbor_triples) + +(* drop_negwits will call setify *) +let satEX dir m s reqst = pre_exist dir m s reqst;; + +let satAX dir m s reqst = pre_forall dir m s s reqst +;; + +(* E[phi1 U phi2] == phi2 \/ (phi1 /\ EXE[phi1 U phi2]) *) +let satEU dir ((_,_,states) as m) s1 s2 reqst = + inc satEU_calls; + if s1 = [] + then s2 + else + (*let ctr = ref 0 in*) + if !pNEW_INFO_OPT + then + let rec f y new_info = + inc_step(); + match new_info with + [] -> y + | new_info -> + ctr := !ctr + 1; + let first = triples_conj s1 (pre_exist dir m new_info reqst) in + let res = triples_union first y in + let new_info = setdiff res y in + (*Printf.printf "iter %d res %d new_info %d\n" + !ctr (List.length res) (List.length new_info); + flush stdout;*) + f res new_info in + f s2 s2 + else + let f y = + inc_step(); + let pre = pre_exist dir m y reqst in + triples_union s2 (triples_conj s1 pre) in + setfix f s2 +;; + +(* EF phi == E[true U phi] *) +let satEF dir m s2 reqst = + inc satEF_calls; + (*let ctr = ref 0 in*) + if !pNEW_INFO_OPT + then + let rec f y new_info = + inc_step(); + match new_info with + [] -> y + | new_info -> + (*ctr := !ctr + 1; + print_state (Printf.sprintf "iteration %d\n" !ctr) y;*) + let first = pre_exist dir m new_info reqst in + let res = triples_union first y in + let new_info = setdiff res y in + (*Printf.printf "EF %s iter %d res %d new_info %d\n" + (if dir = A.BACKWARD then "reachable" else "real ef") + !ctr (List.length res) (List.length new_info); + print_state "new info" new_info; + flush stdout;*) + f res new_info in + f s2 s2 + else + let f y = + inc_step(); + let pre = pre_exist dir m y reqst in + triples_union s2 pre in + setfix f s2 + + +type ('pred,'anno) auok = + AUok of ('pred,'anno) triples | AUfailed of ('pred,'anno) triples + +(* A[phi1 U phi2] == phi2 \/ (phi1 /\ AXA[phi1 U phi2]) *) +let satAU dir ((cfg,_,states) as m) s1 s2 reqst = + inc satAU_calls; + if s1 = [] + then AUok s2 + else + (*let ctr = ref 0 in*) + let pre_forall = + if !Flag_ctl.loop_in_src_code + then pre_forall_AW + else pre_forall in + if !pNEW_INFO_OPT + then + let rec f y newinfo = + inc_step(); + match newinfo with + [] -> AUok y + | new_info -> + (*ctr := !ctr + 1; + print_state (Printf.sprintf "iteration %d\n" !ctr) y; + flush stdout;*) + let pre = + try Some (pre_forall dir m new_info y reqst) + with AW -> None in + match pre with + None -> AUfailed y + | Some pre -> + match triples_conj s1 pre with + [] -> AUok y + | first -> + (*print_state "s1" s1; + print_state "pre" pre; + print_state "first" first;*) + let res = triples_union first y in + let new_info = + if not !something_dropped + then first + else setdiff res y in + (*Printf.printf + "iter %d res %d new_info %d\n" + !ctr (List.length res) (List.length new_info); + flush stdout;*) + f res new_info in + f s2 s2 + else + if !Flag_ctl.loop_in_src_code + then AUfailed s2 + else + (*let setfix = + fix (function s1 -> function s2 -> + let s1 = List.map (function (s,th,w) -> (s,th,nub w)) s1 in + let s2 = List.map (function (s,th,w) -> (s,th,nub w)) s2 in + subseteq s1 s2) in for popl *) + let f y = + inc_step(); + let pre = pre_forall dir m y y reqst in + triples_union s2 (triples_conj s1 pre) in + AUok (setfix f s2) +;; + + +(* reqst could be the states of s1 *) + (* + let lstates = mkstates states reqst in + let initial_removed = + triples_complement lstates (triples_union s1 s2) in + let initial_base = triples_conj s1 (triples_complement lstates s2) in + let rec loop base removed = + let new_removed = + triples_conj base (pre_exist dir m removed reqst) in + let new_base = + triples_conj base (triples_complement lstates new_removed) in + if supseteq new_base base + then triples_union base s2 + else loop new_base new_removed in + loop initial_base initial_removed *) + +let satAW dir ((grp,_,states) as m) s1 s2 reqst = + inc satAW_calls; + if s1 = [] + then s2 + else + (* + This works extremely badly when the region is small and the end of the + region is very ambiguous, eg free(x) ... x + see free.c + if !pNEW_INFO_OPT + then + let get_states l = setify(List.map (function (s,_,_) -> s) l) in + let ostates = Common.union_set (get_states s1) (get_states s2) in + let succ = + (match dir with + A.FORWARD -> G.successors grp + | A.BACKWARD -> G.predecessors grp) in + let states = + List.fold_left Common.union_set ostates (List.map succ ostates) in + let negphi = triples_complement states s1 in + let negpsi = triples_complement states s2 in + triples_complement ostates + (satEU dir m negpsi (triples_conj negphi negpsi) (Some ostates)) + else + *) + (*let ctr = ref 0 in*) + let f y = + inc_step(); + (*ctr := !ctr + 1; + Printf.printf "iter %d y %d\n" !ctr (List.length y); + print_state "y" y; + flush stdout;*) + let pre = pre_forall dir m y y reqst in + let conj = triples_conj s1 pre in (* or triples_conj_AW *) + triples_union s2 conj in + setgfix f (triples_union s1 s2) +;; + +let satAF dir m s reqst = + inc satAF_calls; + if !pNEW_INFO_OPT + then + let rec f y newinfo = + inc_step(); + match newinfo with + [] -> y + | new_info -> + let first = pre_forall dir m new_info y reqst in + let res = triples_union first y in + let new_info = setdiff res y in + f res new_info in + f s s + else + let f y = + inc_step(); + let pre = pre_forall dir m y y reqst in + triples_union s pre in + setfix f s + +let satAG dir ((_,_,states) as m) s reqst = + inc satAG_calls; + let f y = + inc_step(); + let pre = pre_forall dir m y y reqst in + triples_conj y pre in + setgfix f s + +let satEG dir ((_,_,states) as m) s reqst = + inc satEG_calls; + let f y = + inc_step(); + let pre = pre_exist dir m y reqst in + triples_conj y pre in + setgfix f s + +(* **************************************************************** *) +(* Inner And - a way of dealing with multiple matches within a node *) +(* **************************************************************** *) +(* applied to the result of matching a node. collect witnesses when the +states and environments are the same *) + +let inner_and trips = + let rec loop = function + [] -> ([],[]) + | (s,th,w)::trips -> + let (cur,acc) = loop trips in + (match cur with + (s',_,_)::_ when s = s' -> + let rec loop' = function + [] -> [(s,th,w)] + | ((_,th',w') as t')::ts' -> + (match conj_subst th th' with + Some th'' -> (s,th'',union_wit w w')::ts' + | None -> t'::(loop' ts')) in + (loop' cur,acc) + | _ -> ([(s,th,w)],cur@acc)) in + let (cur,acc) = + loop (List.sort state_compare trips) (* is this sort needed? *) in + cur@acc + +(* *************** *) +(* Partial matches *) +(* *************** *) + +let filter_conj states unwanted partial_matches = + let x = + triples_conj (triples_complement states (unwitify unwanted)) + partial_matches in + triples_conj (unwitify x) (triples_complement states x) + +let strict_triples_conj strict states trips trips' = + let res = triples_conj trips trips' in + if !Flag_ctl.partial_match && strict = A.STRICT + then + let fail_left = filter_conj states trips trips' in + let fail_right = filter_conj states trips' trips in + let ors = triples_union fail_left fail_right in + triples_union res ors + else res + +let strict_triples_conj_none strict states trips trips' = + let res = triples_conj_none trips trips' in + if !Flag_ctl.partial_match && strict = A.STRICT + then + let fail_left = filter_conj states trips trips' in + let fail_right = filter_conj states trips' trips in + let ors = triples_union fail_left fail_right in + triples_union res ors + else res + +let left_strict_triples_conj strict states trips trips' = + let res = triples_conj trips trips' in + if !Flag_ctl.partial_match && strict = A.STRICT + then + let fail_left = filter_conj states trips trips' in + triples_union res fail_left + else res + +let strict_A1 strict op failop dir ((_,_,states) as m) trips required_states = + let res = op dir m trips required_states in + if !Flag_ctl.partial_match && strict = A.STRICT + then + let states = mkstates states required_states in + let fail = filter_conj states res (failop dir m trips required_states) in + triples_union res fail + else res + +let strict_A2 strict op failop dir ((_,_,states) as m) trips trips' + required_states = + let res = op dir m trips trips' required_states in + if !Flag_ctl.partial_match && strict = A.STRICT + then + let states = mkstates states required_states in + let fail = filter_conj states res (failop dir m trips' required_states) in + triples_union res fail + else res + +let strict_A2au strict op failop dir ((_,_,states) as m) trips trips' + required_states = + match op dir m trips trips' required_states with + AUok res -> + if !Flag_ctl.partial_match && strict = A.STRICT + then + let states = mkstates states required_states in + let fail = + filter_conj states res (failop dir m trips' required_states) in + AUok (triples_union res fail) + else AUok res + | AUfailed res -> AUfailed res + +(* ********************* *) +(* Environment functions *) +(* ********************* *) + +let drop_wits required_states s phi = + match required_states with + None -> s + | Some states -> List.filter (function (s,_,_) -> List.mem s states) s + + +let print_required required = + List.iter + (function l -> + Format.print_string "{"; + List.iter + (function reqd -> + print_generic_substitution reqd; Format.print_newline()) + l; + Format.print_string "}"; + Format.print_newline()) + required + +exception Too_long + +let extend_required trips required = + if !Flag_ctl.partial_match + then required + else + if !pREQUIRED_ENV_OPT + then + (* make it a set *) + let envs = + List.fold_left + (function rest -> + function (_,t,_) -> if List.mem t rest then rest else t::rest) + [] trips in + let envs = if List.mem [] envs then [] else envs in + match (envs,required) with + ([],_) -> required + | (envs,hd::tl) -> + (try + let hdln = List.length hd + 5 (* let it grow a little bit *) in + let (_,merged) = + let add x (ln,y) = + if List.mem x y + then (ln,y) + else if ln + 1 > hdln then raise Too_long else (ln+1,x::y) in + foldl + (function rest -> + function t -> + foldl + (function rest -> + function r -> + match conj_subst t r with + None -> rest | Some th -> add th rest) + rest hd) + (0,[]) envs in + merged :: tl + with Too_long -> envs :: required) + | (envs,_) -> envs :: required + else required + +let drop_required v required = + if !pREQUIRED_ENV_OPT + then + let res = + inner_setify + (List.map + (function l -> + inner_setify + (List.map (List.filter (function sub -> not(dom_sub sub = v))) l)) + required) in + (* check whether an entry has become useless *) + List.filter (function l -> not (List.exists (function x -> x = []) l)) res + else required + +(* no idea how to write this function ... *) +let memo_label = + (Hashtbl.create(50) : (P.t, (G.node * substitution) list) Hashtbl.t) + +let satLabel label required p = + let triples = + if !pSATLABEL_MEMO_OPT + then + try + let states_subs = Hashtbl.find memo_label p in + List.map (function (st,th) -> (st,th,[])) states_subs + with + Not_found -> + let triples = setify(label p) in + Hashtbl.add memo_label p + (List.map (function (st,th,_) -> (st,th)) triples); + triples + else setify(label p) in + normalize + (if !pREQUIRED_ENV_OPT + then + foldl + (function rest -> + function ((s,th,_) as t) -> + if List.for_all + (List.exists (function th' -> not(conj_subst th th' = None))) + required + then t::rest + else rest) + [] triples + else triples) + +let get_required_states l = + if !pREQUIRED_STATES_OPT && not !Flag_ctl.partial_match + then + Some(inner_setify (List.map (function (s,_,_) -> s) l)) + else None + +let get_children_required_states dir (grp,_,_) required_states = + if !pREQUIRED_STATES_OPT && not !Flag_ctl.partial_match + then + match required_states with + None -> None + | Some states -> + let fn = + match dir with + A.FORWARD -> G.successors + | A.BACKWARD -> G.predecessors in + Some (inner_setify (List.concat (List.map (fn grp) states))) + else None + +let reachable_table = + (Hashtbl.create(50) : (G.node * A.direction, G.node list) Hashtbl.t) + +(* like satEF, but specialized for get_reachable *) +let reachsatEF dir (grp,_,_) s2 = + let dirop = + match dir with A.FORWARD -> G.successors | A.BACKWARD -> G.predecessors in + let union = unionBy compare (=) in + let rec f y = function + [] -> y + | new_info -> + let (pre_collected,new_info) = + List.partition (function Common.Left x -> true | _ -> false) + (List.map + (function x -> + try Common.Left (Hashtbl.find reachable_table (x,dir)) + with Not_found -> Common.Right x) + new_info) in + let y = + List.fold_left + (function rest -> + function Common.Left x -> union x rest + | _ -> failwith "not possible") + y pre_collected in + let new_info = + List.map + (function Common.Right x -> x | _ -> failwith "not possible") + new_info in + let first = inner_setify (concatmap (dirop grp) new_info) in + let new_info = setdiff first y in + let res = new_info @ y in + f res new_info in + List.rev(f s2 s2) (* put root first *) + +let get_reachable dir m required_states = + match required_states with + None -> None + | Some states -> + Some + (List.fold_left + (function rest -> + function cur -> + if List.mem cur rest + then rest + else + Common.union_set + (try Hashtbl.find reachable_table (cur,dir) + with + Not_found -> + let states = reachsatEF dir m [cur] in + Hashtbl.add reachable_table (cur,dir) states; + states) + rest) + [] states) + +let ctr = ref 0 +let new_var _ = + let c = !ctr in + ctr := !ctr + 1; + Printf.sprintf "_c%d" c + +(* **************************** *) +(* End of environment functions *) +(* **************************** *) + +type ('code,'value) cell = Frozen of 'code | Thawed of 'value + +let rec satloop unchecked required required_states + ((grp,label,states) as m) phi env = + let rec loop unchecked required required_states phi = + (*Common.profile_code "satloop" (fun _ -> *) + let res = + match phi with + A.False -> [] + | A.True -> triples_top states + | A.Pred(p) -> satLabel label required p + | A.Uncheck(phi1) -> + let unchecked = if !pUNCHECK_OPT then true else false in + loop unchecked required required_states phi1 + | A.Not(phi) -> + let phires = loop unchecked required required_states phi in + (*let phires = + List.map (function (s,th,w) -> (s,th,[])) phires in*) + triples_complement (mkstates states required_states) + phires + | A.Or(phi1,phi2) -> + triples_union + (loop unchecked required required_states phi1) + (loop unchecked required required_states phi2) + | A.SeqOr(phi1,phi2) -> + let res1 = loop unchecked required required_states phi1 in + let res2 = loop unchecked required required_states phi2 in + let res1neg = unwitify res1 in + triples_union res1 + (triples_conj + (triples_complement (mkstates states required_states) res1neg) + res2) + | A.And(strict,phi1,phi2) -> + (* phi1 is considered to be more likely to be [], because of the + definition of asttoctl. Could use heuristics such as the size of + the term *) + let pm = !Flag_ctl.partial_match in + (match (pm,loop unchecked required required_states phi1) with + (false,[]) when !pLazyOpt -> [] + | (_,phi1res) -> + let new_required = extend_required phi1res required in + let new_required_states = get_required_states phi1res in + (match (pm,loop unchecked new_required new_required_states phi2) + with + (false,[]) when !pLazyOpt -> [] + | (_,phi2res) -> + strict_triples_conj strict + (mkstates states required_states) + phi1res phi2res)) + | A.AndAny(dir,strict,phi1,phi2) -> + (* phi2 can appear anywhere that is reachable *) + let pm = !Flag_ctl.partial_match in + (match (pm,loop unchecked required required_states phi1) with + (false,[]) -> [] + | (_,phi1res) -> + let new_required = extend_required phi1res required in + let new_required_states = get_required_states phi1res in + let new_required_states = + get_reachable dir m new_required_states in + (match (pm,loop unchecked new_required new_required_states phi2) + with + (false,[]) -> phi1res + | (_,phi2res) -> + (match phi1res with + [] -> (* !Flag_ctl.partial_match must be true *) + if phi2res = [] + then [] + else + let s = mkstates states required_states in + List.fold_left + (function a -> function b -> + strict_triples_conj strict s a [b]) + [List.hd phi2res] (List.tl phi2res) + | [(state,_,_)] -> + let phi2res = + List.map (function (s,e,w) -> [(state,e,w)]) phi2res in + let s = mkstates states required_states in + List.fold_left + (function a -> function b -> + strict_triples_conj strict s a b) + phi1res phi2res + | _ -> + failwith + "only one result allowed for the left arg of AndAny"))) + | A.HackForStmt(dir,strict,phi1,phi2) -> + (* phi2 can appear anywhere that is reachable *) + let pm = !Flag_ctl.partial_match in + (match (pm,loop unchecked required required_states phi1) with + (false,[]) -> [] + | (_,phi1res) -> + let new_required = extend_required phi1res required in + let new_required_states = get_required_states phi1res in + let new_required_states = + get_reachable dir m new_required_states in + (match (pm,loop unchecked new_required new_required_states phi2) + with + (false,[]) -> phi1res + | (_,phi2res) -> + (* if there is more than one state, something about the + environment has to ensure that the right triples of + phi2 get associated with the triples of phi1. + the asttoctl2 has to ensure that that is the case. + these should thus be structural properties. + env of phi2 has to be a proper subset of env of phi1 + to ensure all end up being consistent. no new triples + should be generated. strict_triples_conj_none takes + care of this. + *) + let s = mkstates states required_states in + List.fold_left + (function acc -> + function (st,th,_) as phi2_elem -> + let inverse = + triples_complement [st] [(st,th,[])] in + strict_triples_conj_none strict s acc + (phi2_elem::inverse)) + phi1res phi2res)) + | A.InnerAnd(phi) -> + inner_and(loop unchecked required required_states phi) + | A.EX(dir,phi) -> + let new_required_states = + get_children_required_states dir m required_states in + satEX dir m (loop unchecked required new_required_states phi) + required_states + | A.AX(dir,strict,phi) -> + let new_required_states = + get_children_required_states dir m required_states in + let res = loop unchecked required new_required_states phi in + strict_A1 strict satAX satEX dir m res required_states + | A.EF(dir,phi) -> + let new_required_states = get_reachable dir m required_states in + satEF dir m (loop unchecked required new_required_states phi) + new_required_states + | A.AF(dir,strict,phi) -> + if !Flag_ctl.loop_in_src_code + then + loop unchecked required required_states + (A.AU(dir,strict,A.True,phi)) + else + let new_required_states = get_reachable dir m required_states in + let res = loop unchecked required new_required_states phi in + strict_A1 strict satAF satEF dir m res new_required_states + | A.EG(dir,phi) -> + let new_required_states = get_reachable dir m required_states in + satEG dir m (loop unchecked required new_required_states phi) + new_required_states + | A.AG(dir,strict,phi) -> + let new_required_states = get_reachable dir m required_states in + let res = loop unchecked required new_required_states phi in + strict_A1 strict satAG satEF dir m res new_required_states + | A.EU(dir,phi1,phi2) -> + let new_required_states = get_reachable dir m required_states in + (match loop unchecked required new_required_states phi2 with + [] when !pLazyOpt -> [] + | s2 -> + let new_required = extend_required s2 required in + let s1 = loop unchecked new_required new_required_states phi1 in + satEU dir m s1 s2 new_required_states) + | A.AW(dir,strict,phi1,phi2) -> + let new_required_states = get_reachable dir m required_states in + (match loop unchecked required new_required_states phi2 with + [] when !pLazyOpt -> [] + | s2 -> + let new_required = extend_required s2 required in + let s1 = loop unchecked new_required new_required_states phi1 in + strict_A2 strict satAW satEF dir m s1 s2 new_required_states) + | A.AU(dir,strict,phi1,phi2) -> + (*Printf.printf "using AU\n"; flush stdout;*) + let new_required_states = get_reachable dir m required_states in + (match loop unchecked required new_required_states phi2 with + [] when !pLazyOpt -> [] + | s2 -> + let new_required = extend_required s2 required in + let s1 = loop unchecked new_required new_required_states phi1 in + let res = + strict_A2au strict satAU satEF dir m s1 s2 new_required_states in + match res with + AUok res -> res + | AUfailed tmp_res -> + (* found a loop, have to try AW *) + (* the formula is + A[E[phi1 U phi2] & phi1 W phi2] + the and is nonstrict *) + (* tmp_res is bigger than s2, so perhaps closer to s1 *) + (*Printf.printf "using AW\n"; flush stdout;*) + let s1 = + triples_conj (satEU dir m s1 tmp_res new_required_states) + s1 in + strict_A2 strict satAW satEF dir m s1 s2 new_required_states) + | A.Implies(phi1,phi2) -> + loop unchecked required required_states (A.Or(A.Not phi1,phi2)) + | A.Exists (keep,v,phi) -> + let new_required = drop_required v required in + triples_witness v unchecked (not keep) + (loop unchecked new_required required_states phi) + | A.Let(v,phi1,phi2) -> + (* should only be used when the properties unchecked, required, + and required_states are known to be the same or at least + compatible between all the uses. this is not checked. *) + let res = loop unchecked required required_states phi1 in + satloop unchecked required required_states m phi2 ((v,res) :: env) + | A.LetR(dir,v,phi1,phi2) -> + (* should only be used when the properties unchecked, required, + and required_states are known to be the same or at least + compatible between all the uses. this is not checked. *) + let new_required_states = get_reachable dir m required_states in + let res = loop unchecked required new_required_states phi1 in + satloop unchecked required required_states m phi2 ((v,res) :: env) + | A.Ref(v) -> + let res = List.assoc v env in + if unchecked + then List.map (function (s,th,_) -> (s,th,[])) res + else res + | A.XX(phi) -> failwith "should have been removed" in + if !Flag_ctl.bench > 0 then triples := !triples + (List.length res); + drop_wits required_states res phi (* ) *) in + + loop unchecked required required_states phi +;; + + +(* SAT with tracking *) +let rec sat_verbose_loop unchecked required required_states annot maxlvl lvl + ((_,label,states) as m) phi env = + let anno res children = (annot lvl phi res children,res) in + let satv unchecked required required_states phi0 env = + sat_verbose_loop unchecked required required_states annot maxlvl (lvl+1) + m phi0 env in + if (lvl > maxlvl) && (maxlvl > -1) then + anno (satloop unchecked required required_states m phi env) [] + else + let (child,res) = + match phi with + A.False -> anno [] [] + | A.True -> anno (triples_top states) [] + | A.Pred(p) -> + Printf.printf "label\n"; flush stdout; + anno (satLabel label required p) [] + | A.Uncheck(phi1) -> + let unchecked = if !pUNCHECK_OPT then true else false in + let (child1,res1) = satv unchecked required required_states phi1 env in + Printf.printf "uncheck\n"; flush stdout; + anno res1 [child1] + | A.Not(phi1) -> + let (child,res) = + satv unchecked required required_states phi1 env in + Printf.printf "not\n"; flush stdout; + anno (triples_complement (mkstates states required_states) res) [child] + | A.Or(phi1,phi2) -> + let (child1,res1) = + satv unchecked required required_states phi1 env in + let (child2,res2) = + satv unchecked required required_states phi2 env in + Printf.printf "or\n"; flush stdout; + anno (triples_union res1 res2) [child1; child2] + | A.SeqOr(phi1,phi2) -> + let (child1,res1) = + satv unchecked required required_states phi1 env in + let (child2,res2) = + satv unchecked required required_states phi2 env in + let res1neg = + List.map (function (s,th,_) -> (s,th,[])) res1 in + Printf.printf "seqor\n"; flush stdout; + anno (triples_union res1 + (triples_conj + (triples_complement (mkstates states required_states) + res1neg) + res2)) + [child1; child2] + | A.And(strict,phi1,phi2) -> + let pm = !Flag_ctl.partial_match in + (match (pm,satv unchecked required required_states phi1 env) with + (false,(child1,[])) -> + Printf.printf "and\n"; flush stdout; anno [] [child1] + | (_,(child1,res1)) -> + let new_required = extend_required res1 required in + let new_required_states = get_required_states res1 in + (match (pm,satv unchecked new_required new_required_states phi2 + env) with + (false,(child2,[])) -> + Printf.printf "and\n"; flush stdout; anno [] [child1;child2] + | (_,(child2,res2)) -> + Printf.printf "and\n"; flush stdout; + let res = + strict_triples_conj strict + (mkstates states required_states) + res1 res2 in + anno res [child1; child2])) + | A.AndAny(dir,strict,phi1,phi2) -> + let pm = !Flag_ctl.partial_match in + (match (pm,satv unchecked required required_states phi1 env) with + (false,(child1,[])) -> + Printf.printf "and\n"; flush stdout; anno [] [child1] + | (_,(child1,res1)) -> + let new_required = extend_required res1 required in + let new_required_states = get_required_states res1 in + let new_required_states = + get_reachable dir m new_required_states in + (match (pm,satv unchecked new_required new_required_states phi2 + env) with + (false,(child2,[])) -> + Printf.printf "andany\n"; flush stdout; + anno res1 [child1;child2] + | (_,(child2,res2)) -> + (match res1 with + [] -> (* !Flag_ctl.partial_match must be true *) + if res2 = [] + then anno [] [child1; child2] + else + let res = + let s = mkstates states required_states in + List.fold_left + (function a -> function b -> + strict_triples_conj strict s a [b]) + [List.hd res2] (List.tl res2) in + anno res [child1; child2] + | [(state,_,_)] -> + let res2 = + List.map (function (s,e,w) -> [(state,e,w)]) res2 in + Printf.printf "andany\n"; flush stdout; + let res = + let s = mkstates states required_states in + List.fold_left + (function a -> function b -> + strict_triples_conj strict s a b) + res1 res2 in + anno res [child1; child2] + | _ -> + failwith + "only one result allowed for the left arg of AndAny"))) + | A.HackForStmt(dir,strict,phi1,phi2) -> + let pm = !Flag_ctl.partial_match in + (match (pm,satv unchecked required required_states phi1 env) with + (false,(child1,[])) -> + Printf.printf "and\n"; flush stdout; anno [] [child1] + | (_,(child1,res1)) -> + let new_required = extend_required res1 required in + let new_required_states = get_required_states res1 in + let new_required_states = + get_reachable dir m new_required_states in + (match (pm,satv unchecked new_required new_required_states phi2 + env) with + (false,(child2,[])) -> + Printf.printf "andany\n"; flush stdout; + anno res1 [child1;child2] + | (_,(child2,res2)) -> + let res = + let s = mkstates states required_states in + List.fold_left + (function acc -> + function (st,th,_) as phi2_elem -> + let inverse = + triples_complement [st] [(st,th,[])] in + strict_triples_conj_none strict s acc + (phi2_elem::inverse)) + res1 res2 in + anno res [child1; child2])) + | A.InnerAnd(phi1) -> + let (child1,res1) = satv unchecked required required_states phi1 env in + Printf.printf "uncheck\n"; flush stdout; + anno (inner_and res1) [child1] + | A.EX(dir,phi1) -> + let new_required_states = + get_children_required_states dir m required_states in + let (child,res) = + satv unchecked required new_required_states phi1 env in + Printf.printf "EX\n"; flush stdout; + anno (satEX dir m res required_states) [child] + | A.AX(dir,strict,phi1) -> + let new_required_states = + get_children_required_states dir m required_states in + let (child,res) = + satv unchecked required new_required_states phi1 env in + Printf.printf "AX\n"; flush stdout; + let res = strict_A1 strict satAX satEX dir m res required_states in + anno res [child] + | A.EF(dir,phi1) -> + let new_required_states = get_reachable dir m required_states in + let (child,res) = + satv unchecked required new_required_states phi1 env in + Printf.printf "EF\n"; flush stdout; + anno (satEF dir m res new_required_states) [child] + | A.AF(dir,strict,phi1) -> + if !Flag_ctl.loop_in_src_code + then + satv unchecked required required_states + (A.AU(dir,strict,A.True,phi1)) + env + else + (let new_required_states = get_reachable dir m required_states in + let (child,res) = + satv unchecked required new_required_states phi1 env in + Printf.printf "AF\n"; flush stdout; + let res = + strict_A1 strict satAF satEF dir m res new_required_states in + anno res [child]) + | A.EG(dir,phi1) -> + let new_required_states = get_reachable dir m required_states in + let (child,res) = + satv unchecked required new_required_states phi1 env in + Printf.printf "EG\n"; flush stdout; + anno (satEG dir m res new_required_states) [child] + | A.AG(dir,strict,phi1) -> + let new_required_states = get_reachable dir m required_states in + let (child,res) = + satv unchecked required new_required_states phi1 env in + Printf.printf "AG\n"; flush stdout; + let res = strict_A1 strict satAG satEF dir m res new_required_states in + anno res [child] + + | A.EU(dir,phi1,phi2) -> + let new_required_states = get_reachable dir m required_states in + (match satv unchecked required new_required_states phi2 env with + (child2,[]) -> + Printf.printf "EU\n"; flush stdout; + anno [] [child2] + | (child2,res2) -> + let new_required = extend_required res2 required in + let (child1,res1) = + satv unchecked new_required new_required_states phi1 env in + Printf.printf "EU\n"; flush stdout; + anno (satEU dir m res1 res2 new_required_states) [child1; child2]) + | A.AW(dir,strict,phi1,phi2) -> + failwith "should not be used" (* + let new_required_states = get_reachable dir m required_states in + (match satv unchecked required new_required_states phi2 env with + (child2,[]) -> + Printf.printf "AW %b\n" unchecked; flush stdout; anno [] [child2] + | (child2,res2) -> + let new_required = extend_required res2 required in + let (child1,res1) = + satv unchecked new_required new_required_states phi1 env in + Printf.printf "AW %b\n" unchecked; flush stdout; + let res = + strict_A2 strict satAW satEF dir m res1 res2 + new_required_states in + anno res [child1; child2]) *) + | A.AU(dir,strict,phi1,phi2) -> + let new_required_states = get_reachable dir m required_states in + (match satv unchecked required new_required_states phi2 env with + (child2,[]) -> + Printf.printf "AU\n"; flush stdout; anno [] [child2] + | (child2,s2) -> + let new_required = extend_required s2 required in + let (child1,s1) = + satv unchecked new_required new_required_states phi1 env in + Printf.printf "AU\n"; flush stdout; + let res = + strict_A2au strict satAU satEF dir m s1 s2 new_required_states in + (match res with + AUok res -> + anno res [child1; child2] + | AUfailed tmp_res -> + (* found a loop, have to try AW *) + (* the formula is + A[E[phi1 U phi2] & phi1 W phi2] + the and is nonstrict *) + (* tmp_res is bigger than s2, so perhaps closer to s1 *) + Printf.printf "AW\n"; flush stdout; + let s1 = + triples_conj (satEU dir m s1 tmp_res new_required_states) s1 in + let res = + strict_A2 strict satAW satEF dir m s1 s2 new_required_states in + anno res [child1; child2])) + | A.Implies(phi1,phi2) -> + satv unchecked required required_states + (A.Or(A.Not phi1,phi2)) + env + | A.Exists (keep,v,phi1) -> + let new_required = drop_required v required in + let (child,res) = + satv unchecked new_required required_states phi1 env in + Printf.printf "exists\n"; flush stdout; + anno (triples_witness v unchecked (not keep) res) [child] + | A.Let(v,phi1,phi2) -> + let (child1,res1) = + satv unchecked required required_states phi1 env in + let (child2,res2) = + satv unchecked required required_states phi2 ((v,res1) :: env) in + anno res2 [child1;child2] + | A.LetR(dir,v,phi1,phi2) -> + let new_required_states = get_reachable dir m required_states in + let (child1,res1) = + satv unchecked required new_required_states phi1 env in + let (child2,res2) = + satv unchecked required required_states phi2 ((v,res1) :: env) in + anno res2 [child1;child2] + | A.Ref(v) -> + Printf.printf "Ref\n"; flush stdout; + let res = List.assoc v env in + let res = + if unchecked + then List.map (function (s,th,_) -> (s,th,[])) res + else res in + anno res [] + | A.XX(phi) -> failwith "should have been removed" in + let res1 = drop_wits required_states res phi in + if not(res1 = res) + then + begin + print_required_states required_states; + print_state "after drop_wits" res1 end; + (child,res1) + +;; + +let sat_verbose annotate maxlvl lvl m phi = + sat_verbose_loop false [] None annotate maxlvl lvl m phi [] + +(* Type for annotations collected in a tree *) +type ('a) witAnnoTree = WitAnno of ('a * ('a witAnnoTree) list);; + +let sat_annotree annotate m phi = + let tree_anno l phi res chld = WitAnno(annotate l phi res,chld) in + sat_verbose_loop false [] None tree_anno (-1) 0 m phi [] +;; + +(* +let sat m phi = satloop m phi [] +;; +*) + +let simpleanno l phi res = + let pp s = + Format.print_string ("\n" ^ s ^ "\n------------------------------\n"); + print_generic_algo (List.sort compare res); + Format.print_string "\n------------------------------\n\n" in + let pp_dir = function + A.FORWARD -> () + | A.BACKWARD -> pp "^" in + match phi with + | A.False -> pp "False" + | A.True -> pp "True" + | A.Pred(p) -> pp ("Pred" ^ (Common.dump p)) + | A.Not(phi) -> pp "Not" + | A.Exists(_,v,phi) -> pp ("Exists " ^ (Common.dump(v))) + | A.And(_,phi1,phi2) -> pp "And" + | A.AndAny(dir,_,phi1,phi2) -> pp "AndAny" + | A.HackForStmt(dir,_,phi1,phi2) -> pp "HackForStmt" + | A.Or(phi1,phi2) -> pp "Or" + | A.SeqOr(phi1,phi2) -> pp "SeqOr" + | A.Implies(phi1,phi2) -> pp "Implies" + | A.AF(dir,_,phi1) -> pp "AF"; pp_dir dir + | A.AX(dir,_,phi1) -> pp "AX"; pp_dir dir + | A.AG(dir,_,phi1) -> pp "AG"; pp_dir dir + | A.AW(dir,_,phi1,phi2)-> pp "AW"; pp_dir dir + | A.AU(dir,_,phi1,phi2)-> pp "AU"; pp_dir dir + | A.EF(dir,phi1) -> pp "EF"; pp_dir dir + | A.EX(dir,phi1) -> pp "EX"; pp_dir dir + | A.EG(dir,phi1) -> pp "EG"; pp_dir dir + | A.EU(dir,phi1,phi2) -> pp "EU"; pp_dir dir + | A.Let (x,phi1,phi2) -> pp ("Let"^" "^x) + | A.LetR (dir,x,phi1,phi2) -> pp ("LetR"^" "^x); pp_dir dir + | A.Ref(s) -> pp ("Ref("^s^")") + | A.Uncheck(s) -> pp "Uncheck" + | A.InnerAnd(s) -> pp "InnerAnd" + | A.XX(phi1) -> pp "XX" +;; + + +(* pad: Rene, you can now use the module pretty_print_ctl.ml to + print a ctl formula more accurately if you want. + Use the print_xxx provided in the different module to call + Pretty_print_ctl.pp_ctl. + *) + +let simpleanno2 l phi res = + begin + Pretty_print_ctl.pp_ctl (P.print_predicate, SUB.print_mvar) false phi; + Format.print_newline (); + Format.print_string "----------------------------------------------------"; + Format.print_newline (); + print_generic_algo (List.sort compare res); + Format.print_newline (); + Format.print_string "----------------------------------------------------"; + Format.print_newline (); + Format.print_newline (); + end + + +(* ---------------------------------------------------------------------- *) +(* Benchmarking *) +(* ---------------------------------------------------------------------- *) + +type optentry = bool ref * string +type options = {label : optentry; unch : optentry; + conj : optentry; compl1 : optentry; compl2 : optentry; + newinfo : optentry; + reqenv : optentry; reqstates : optentry} + +let options = + {label = (pSATLABEL_MEMO_OPT,"satlabel_memo_opt"); + unch = (pUNCHECK_OPT,"uncheck_opt"); + conj = (pTRIPLES_CONJ_OPT,"triples_conj_opt"); + compl1 = (pTRIPLES_COMPLEMENT_OPT,"triples_complement_opt"); + compl2 = (pTRIPLES_COMPLEMENT_SIMPLE_OPT,"triples_complement_simple_opt"); + newinfo = (pNEW_INFO_OPT,"new_info_opt"); + reqenv = (pREQUIRED_ENV_OPT,"required_env_opt"); + reqstates = (pREQUIRED_STATES_OPT,"required_states_opt")} + +let baseline = + [("none ",[]); + ("label ",[options.label]); + ("unch ",[options.unch]); + ("unch and label ",[options.label;options.unch])] + +let conjneg = + [("conj ", [options.conj]); + ("compl1 ", [options.compl1]); + ("compl12 ", [options.compl1;options.compl2]); + ("conj/compl12 ", [options.conj;options.compl1;options.compl2]); + ("conj unch satl ", [options.conj;options.unch;options.label]); +(* + ("compl1 unch satl ", [options.compl1;options.unch;options.label]); + ("compl12 unch satl ", + [options.compl1;options.compl2;options.unch;options.label]); *) + ("conj/compl12 unch satl ", + [options.conj;options.compl1;options.compl2;options.unch;options.label])] + +let path = + [("newinfo ", [options.newinfo]); + ("newinfo unch satl ", [options.newinfo;options.unch;options.label])] + +let required = + [("reqenv ", [options.reqenv]); + ("reqstates ", [options.reqstates]); + ("reqenv/states ", [options.reqenv;options.reqstates]); +(* ("reqenv unch satl ", [options.reqenv;options.unch;options.label]); + ("reqstates unch satl ", + [options.reqstates;options.unch;options.label]);*) + ("reqenv/states unch satl ", + [options.reqenv;options.reqstates;options.unch;options.label])] + +let all_options = + [options.label;options.unch;options.conj;options.compl1;options.compl2; + options.newinfo;options.reqenv;options.reqstates] + +let all = + [("all ",all_options)] + +let all_options_but_path = + [options.label;options.unch;options.conj;options.compl1;options.compl2; + options.reqenv;options.reqstates] + +let all_but_path = ("all but path ",all_options_but_path) + +let counters = + [(satAW_calls, "satAW", ref 0); + (satAU_calls, "satAU", ref 0); + (satEF_calls, "satEF", ref 0); + (satAF_calls, "satAF", ref 0); + (satEG_calls, "satEG", ref 0); + (satAG_calls, "satAG", ref 0); + (satEU_calls, "satEU", ref 0)] + +let perms = + map + (function (opt,x) -> + (opt,x,ref 0.0,ref 0, + List.map (function _ -> (ref 0, ref 0, ref 0)) counters)) + [List.hd all;all_but_path] + (*(all@baseline@conjneg@path@required)*) + +exception Out + +let rec iter fn = function + 1 -> fn() + | n -> let _ = fn() in + (Hashtbl.clear reachable_table; + Hashtbl.clear memo_label; + triples := 0; + iter fn (n-1)) + +let copy_to_stderr fl = + let i = open_in fl in + let rec loop _ = + Printf.fprintf stderr "%s\n" (input_line i); + loop() in + try loop() with _ -> (); + close_in i + +let bench_sat (_,_,states) fn = + List.iter (function (opt,_) -> opt := false) all_options; + let answers = + concatmap + (function (name,options,time,trips,counter_info) -> + let iterct = !Flag_ctl.bench in + if !time > float_of_int timeout then time := -100.0; + if not (!time = -100.0) + then + begin + Hashtbl.clear reachable_table; + Hashtbl.clear memo_label; + List.iter (function (opt,_) -> opt := true) options; + List.iter (function (calls,_,save_calls) -> save_calls := !calls) + counters; + triples := 0; + let res = + let bef = Sys.time() in + try + Common.timeout_function timeout + (fun () -> + let bef = Sys.time() in + let res = iter fn iterct in + let aft = Sys.time() in + time := !time +. (aft -. bef); + trips := !trips + !triples; + List.iter2 + (function (calls,_,save_calls) -> + function (current_calls,current_cfg,current_max_cfg) -> + current_calls := + !current_calls + (!calls - !save_calls); + if (!calls - !save_calls) > 0 + then + (let st = List.length states in + current_cfg := !current_cfg + st; + if st > !current_max_cfg + then current_max_cfg := st)) + counters counter_info; + [res]) + with + Common.Timeout -> + begin + let aft = Sys.time() in + time := -100.0; + Printf.fprintf stderr "Timeout at %f on: %s\n" + (aft -. bef) name; + [] + end in + List.iter (function (opt,_) -> opt := false) options; + res + end + else []) + perms in + Printf.fprintf stderr "\n"; + match answers with + [] -> [] + | res::rest -> + (if not(List.for_all (function x -> x = res) rest) + then + (List.iter (print_state "a state") answers; + Printf.printf "something doesn't work\n"); + res) + +let print_bench _ = + let iterct = !Flag_ctl.bench in + if iterct > 0 + then + (List.iter + (function (name,options,time,trips,counter_info) -> + Printf.fprintf stderr "%s Numbers: %f %d " + name (!time /. (float_of_int iterct)) !trips; + List.iter + (function (calls,cfg,max_cfg) -> + Printf.fprintf stderr "%d %d %d " (!calls / iterct) !cfg !max_cfg) + counter_info; + Printf.fprintf stderr "\n") + perms) + +(* ---------------------------------------------------------------------- *) +(* preprocessing: ignore irrelevant functions *) + +let preprocess (cfg,_,_) label = function + [] -> true (* no information, try everything *) + | l -> + let sz = G.size cfg in + let verbose_output pred = function + [] -> + Printf.printf "did not find:\n"; + P.print_predicate pred; Format.print_newline() + | _ -> + Printf.printf "found:\n"; + P.print_predicate pred; Format.print_newline(); + Printf.printf "but it was not enough\n" in + let get_any verbose x = + let res = + try Hashtbl.find memo_label x + with + Not_found -> + (let triples = label x in + let filtered = + List.map (function (st,th,_) -> (st,th)) triples in + Hashtbl.add memo_label x filtered; + filtered) in + if verbose then verbose_output x res; + not([] = res) in + let get_all l = + (* don't bother testing when there are more patterns than nodes *) + if List.length l > sz-2 + then false + else List.for_all (get_any false) l in + if List.exists get_all l + then true + else + (if !Flag_ctl.verbose_match + then + List.iter (List.iter (function x -> let _ = get_any true x in ())) + l; + false) + +let filter_partial_matches trips = + if !Flag_ctl.partial_match + then + let anynegwit = (* if any is neg, then all are *) + List.exists (function A.NegWit _ -> true | A.Wit _ -> false) in + let (bad,good) = + List.partition (function (s,th,wit) -> anynegwit wit) trips in + (match bad with + [] -> () + | _ -> print_state "partial matches" bad; Format.print_newline()); + good + else trips + +(* ---------------------------------------------------------------------- *) +(* Main entry point for engine *) +let sat m phi reqopt = + try + (match !Flag_ctl.steps with + None -> step_count := 0 + | Some x -> step_count := x); + Hashtbl.clear reachable_table; + Hashtbl.clear memo_label; + let (x,label,states) = m in + if (!Flag_ctl.bench > 0) or (preprocess m label reqopt) + then + ((* to drop when Yoann initialized this flag *) + if List.exists (G.extract_is_loop x) states + then Flag_ctl.loop_in_src_code := true; + let m = (x,label,List.sort compare states) in + let res = + if(!Flag_ctl.verbose_ctl_engine) + then + let fn _ = snd (sat_annotree simpleanno2 m phi) in + if !Flag_ctl.bench > 0 + then bench_sat m fn + else fn() + else + let fn _ = satloop false [] None m phi [] in + if !Flag_ctl.bench > 0 + then bench_sat m fn + else Common.profile_code "ctl" (fun _ -> fn()) in + let res = filter_partial_matches res in + (* + Printf.printf "steps: start %d, stop %d\n" + (match !Flag_ctl.steps with Some x -> x | _ -> 0) + !step_count; + Printf.printf "triples: %d\n" !triples; + print_state "final result" res; + *) + res) + else + (if !Flag_ctl.verbose_ctl_engine + then Common.pr2 "missing something required"; + []) + with Steps -> [] +;; + +(* ********************************************************************** *) +(* End of Module: CTL_ENGINE *) +(* ********************************************************************** *) +end +;; + diff --git a/ctl/ctl_engine.mli b/ctl/ctl_engine.mli new file mode 100644 index 0000000..05e2f5e --- /dev/null +++ b/ctl/ctl_engine.mli @@ -0,0 +1,64 @@ +open Ast_ctl + +module type SUBST = + sig + type value + type mvar + val eq_mvar : mvar -> mvar -> bool + val eq_val : value -> value -> bool + val merge_val : value -> value -> value + val print_mvar : mvar -> unit + val print_value : value -> unit + end + +module type GRAPH = + sig + type node + type cfg + val predecessors: cfg -> node -> node list + val successors: cfg -> node -> node list + val extract_is_loop : cfg -> node -> bool + val print_node : node -> unit + val size : cfg -> int + end + +module OGRAPHEXT_GRAPH : + sig + type node = int + type cfg = (string, unit) Ograph_extended.ograph_mutable + val predecessors : + < predecessors : 'a -> < tolist : ('b * 'c) list; .. >; .. > -> + 'a -> 'b list + val print_node : node -> unit + end + +module type PREDICATE = +sig + type t + val print_predicate : t -> unit +end + +module CTL_ENGINE : + functor (SUB : SUBST) -> + functor (G : GRAPH) -> + functor (P : PREDICATE) -> + sig + + type substitution = (SUB.mvar, SUB.value) Ast_ctl.generic_subst list + + type ('pred,'anno) witness = + (G.node, substitution, + ('pred, SUB.mvar, 'anno) Ast_ctl.generic_ctl list) + Ast_ctl.generic_witnesstree + + type ('pred,'anno) triples = + (G.node * substitution * ('pred,'anno) witness list) list + + val sat : + G.cfg * (P.t -> (P.t,'anno) triples) * G.node list -> + (P.t, SUB.mvar, 'c) Ast_ctl.generic_ctl -> + (P.t list list (* optional and required things *)) -> + (P.t,'anno) triples + + val print_bench : unit -> unit + end diff --git a/ctl/double_negate_ml b/ctl/double_negate_ml new file mode 100644 index 0000000..446acc3 --- /dev/null +++ b/ctl/double_negate_ml @@ -0,0 +1,75 @@ +(* optimizes triples that have complementary environments and the same +witnesses *) + +let double_negate trips = + let y = + List.sort + (function (s,_,wit) -> function (s',_,wit') -> compare (s,wit) (s',wit')) + trips in + let rec classify = function + [] -> [] + | ((s,th,wit) as x)::rest -> + (match classify rest with + [] -> [[x]] + | (((s',th',wit')::_) as x1)::rest -> + if (s,wit) = (s',wit') + then (x::x1)::rest + else [x]::(x1::rest) + | _ -> failwith "not possible") in + let y = + List.map + (function + (((s,_,wit)::_) as all) -> + ((s,wit),List.map (function (_,th,_) -> th) all) + | _ -> failwith "not possible") + (classify y) in + let cnf rest_th th = + List.fold_left + (function rest -> + function sub1 -> + List.fold_left + (function rest -> + function subs -> + if memBy eq_sub (negate_sub sub1) subs + then rest + else if memBy eq_sub sub1 subs + then subs::rest + else (sub1::subs)::rest) + rest rest_th) + [] th in + let dnf rest_th th = + List.fold_left + (function rest -> + function sub1 -> + List.fold_left + (function rest -> + function subs -> + match conj_subst [sub1] subs with + None -> rest + | Some th -> th::rest) + rest rest_th) + [] th in + let res = + List.sort compare + (List.fold_left + (function rest -> + function + ((s,wit),[th]) -> (s,th,wit)::rest + | ((s,wit),ths) -> + match ths with + [] -> failwith "not possible" + | (th::ths) -> + let (cnf : substitution list) = + List.fold_left cnf + (List.map (function x -> [x]) th) ths in + match cnf with + [] -> (s,[],wit)::rest + | th::ths -> + let res = + setify + (List.fold_left dnf + (List.map (function x -> [x]) th) + ths) in + (List.map (function th -> (s,th,wit)) res) @ rest) + [] y) in + res diff --git a/ctl/flag_ctl.ml b/ctl/flag_ctl.ml new file mode 100644 index 0000000..97a487d --- /dev/null +++ b/ctl/flag_ctl.ml @@ -0,0 +1,38 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* option -verbose_ctl_engine *) +let verbose_ctl_engine = ref false + +(* cheap partial matches using assttomember *) +let verbose_match = ref false + +let partial_match = ref false + +let poswits_only = ref false + +let loop_in_src_code = ref false + +let bench = ref 0 + +let steps = ref (None : int option) + diff --git a/ctl/pretty_print_ctl.ml b/ctl/pretty_print_ctl.ml new file mode 100644 index 0000000..7da4cad --- /dev/null +++ b/ctl/pretty_print_ctl.ml @@ -0,0 +1,183 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Common +open Format + +open Ast_ctl + +(* todo?: a txt_to_latex, that use Format to compute the good space but + * then generate latex to better output. + *) + +let char_and = "&" +let char_and_any = "&+" +let char_hack = "&h+" +let char_or = "v" +let char_seqor = "|" +let char_not = "!" +let char_back = "^" + +(* +let char_and = "/\\" +let char_or = "\\/" +let char_not = "-|" +*) + +(* need introduce the Val constructor, or use -rectype. *) +type ('a,'b,'c) environment = (string, ('a,'b,'c) binding_val) Common.assoc +and ('a, 'b, 'c) binding_val = + Val of ('a,'b,'c) generic_ctl * ('a,'b,'c) environment + +let rec (pp_ctl: + ('pred -> unit) * ('mvar -> unit) -> bool -> + ('pred, 'mvar, 'info) generic_ctl -> + unit) = + fun (pp_pred, pp_mvar) inline_let_def ctl -> + + let rec pp_aux env = function + False -> pp "False" + | True -> pp "True" + | Pred(p) -> pp_pred p + | Not(phi) -> + pp char_not; Common.pp_do_in_box (fun () -> pp_aux env phi) + | Exists(keep,v,phi) -> + pp "("; + if keep then pp ("Ex ") else pp ("Ex_ "); + pp_mvar v; + pp " . "; + print_cut(); + Common.pp_do_in_box (fun () -> pp_aux env phi); + pp ")"; + | AndAny(dir,s,phi1,phi2) -> + pp_2args env (char_and_any^(pp_dirc dir)^(pp_sc s)) phi1 phi2; + | HackForStmt(dir,s,phi1,phi2) -> + pp_2args env (char_hack^(pp_dirc dir)^(pp_sc s)) phi1 phi2; + | And(s,phi1,phi2) -> pp_2args env (char_and^(pp_sc s)) phi1 phi2; + | Or(phi1,phi2) -> pp_2args env char_or phi1 phi2; + | SeqOr(phi1,phi2) -> pp_2args env char_seqor phi1 phi2; + | Implies(phi1,phi2) -> pp_2args env "=>" phi1 phi2; + | AF(dir,s,phi1) -> pp "AF"; pp_dir dir; pp_s s; pp_arg_paren env phi1; + | AX(dir,s,phi1) -> pp "AX"; pp_dir dir; pp_s s; pp_arg_paren env phi1; + | AG(dir,s,phi1) -> pp "AG"; pp_dir dir; pp_s s; pp_arg_paren env phi1; + | EF(dir,phi1) -> pp "EF"; pp_dir dir; pp_arg_paren env phi1; + | EX(dir,phi1) -> pp "EX"; pp_dir dir; pp_arg_paren env phi1; + | EG(dir,phi1) -> pp "EG"; pp_dir dir; pp_arg_paren env phi1; + | AW(dir,s,phi1,phi2) -> + pp "A"; pp_dir dir; pp_s s; pp "["; + pp_2args_bis env "W" phi1 phi2; + pp "]" + | AU(dir,s,phi1,phi2) -> + pp "A"; pp_dir dir; pp_s s; pp "["; + pp_2args_bis env "U" phi1 phi2; + pp "]" + | EU(dir,phi1,phi2) -> + pp "E"; pp_dir dir; pp "["; + pp_2args_bis env "U" phi1 phi2; + pp "]" + | Let (x,phi1,phi2) -> + let env' = (x, (Val (phi1,env)))::env in + + if not inline_let_def + then + begin + pp ("Let"^" "^x); + pp " = "; + print_cut(); + Common.pp_do_in_box (fun () -> pp_aux env phi1); + print_space (); + pp "in"; + print_space (); + end; + pp_do_in_zero_box (fun () -> pp_aux env' phi2); + | LetR (dir,x,phi1,phi2) -> + let env' = (x, (Val (phi1,env)))::env in + + if not inline_let_def + then + begin + pp ("LetR"^" "^x); pp_dir dir; + pp " = "; + print_cut(); + Common.pp_do_in_box (fun () -> pp_aux env phi1); + print_space (); + pp "in"; + print_space (); + end; + pp_do_in_zero_box (fun () -> pp_aux env' phi2); + | Ref(s) -> + if inline_let_def + then + let Val (phi1,env') = List.assoc s env in + pp_aux env' phi1 + else + (* pp "Ref("; *) + pp s + (* pp ")" *) + | Uncheck(phi1) -> + pp "Uncheck"; pp_arg_paren env phi1 + | InnerAnd(phi1) -> + pp "InnerAnd"; pp_arg_paren env phi1 + | XX _ -> failwith "should be removed" + + and pp_dir = function + FORWARD -> () + | BACKWARD -> pp char_back + + and pp_dirc = function + FORWARD -> "" + | BACKWARD -> char_back + + and pp_s = function + STRICT -> if !Flag_ctl.partial_match then pp "," else () + | NONSTRICT -> () + + and pp_sc = function + STRICT -> "," + | NONSTRICT -> "" + + and pp_2args env sym phi1 phi2 = + begin + pp "("; + Common.pp_do_in_box (fun () -> pp_aux env phi1); + print_space(); + pp sym; + print_space (); + Common.pp_do_in_box (fun () -> pp_aux env phi2); + pp ")"; + end + and pp_2args_bis env sym phi1 phi2 = + begin + Common.pp_do_in_box (fun () -> pp_aux env phi1); + print_space(); + pp sym; + print_space(); + Common.pp_do_in_box (fun () -> pp_aux env phi2); + end + + and pp_arg_paren env phi = Common.pp_do_in_box (fun () -> + pp "("; + pp_aux env phi; + pp ")"; + ) + in + Common.pp_do_in_box (fun () -> pp_aux [] ctl;) diff --git a/ctl/pretty_print_ctl.mli b/ctl/pretty_print_ctl.mli new file mode 100644 index 0000000..a7c57fc --- /dev/null +++ b/ctl/pretty_print_ctl.mli @@ -0,0 +1,4 @@ + +val pp_ctl: + ('pred -> unit) * ('mvar -> unit) -> bool (* inline_let_def *) -> + ('pred, 'mvar, 'info) Ast_ctl.generic_ctl -> unit diff --git a/ctl/test_ctl.ml b/ctl/test_ctl.ml new file mode 100644 index 0000000..1ead1af --- /dev/null +++ b/ctl/test_ctl.ml @@ -0,0 +1,302 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + + +(* ********************************************************************** *) +(* Module: EXAMPLE_ENGINE (instance of CTL_ENGINE) *) +(* ********************************************************************** *) + +(* Simple env.: meta.vars and values are strings *) +module SIMPLE_ENV = + struct + type value = string;; + type mvar = string;; + let eq_mvar x x' = x = x';; + let eq_val v v' = v = v';; + let merge_val v v' = v;; + end +;; + +(* Simple predicates *) +module WRAPPER_PRED = + struct + type predicate = string + end + +module EXAMPLE_ENGINE = + Wrapper_ctl.CTL_ENGINE_BIS (SIMPLE_ENV) (Ctl_engine.OGRAPHEXT_GRAPH) (WRAPPER_PRED) + +let top_wit = [] + +(* ******************************************************************** *) +(* *) +(* EXAMPLES *) +(* *) +(* ******************************************************************** *) + +(* For convenience in the examples *) +(* FIX ME: remove *) +open Ctl_engine.OGRAPHEXT_GRAPH;; +open EXAMPLE_ENGINE;; +open Ast_ctl;; + +(* ---------------------------------------------------------------------- *) +(* Helpers *) +(* ---------------------------------------------------------------------- *) + +(* FIX ME: move to ENGINE module *) +let (-->) x v = Subst (x,v);; + +(* FIX ME: move to ENGINE module *) +let (-/->) x v = NegSubst(x,v);; + +let mkgraph nodes edges = + let g = ref (new Ograph_extended.ograph_extended) in + let addn (n,x) = + (* let (g',i) = (!g)#add_node x in *) + (* now I need to force the nodei of a node, because of the state(vx) predicates + hence add_node -> add_nodei + *) + let (g', i) = !g#add_nodei n x in + assert (i = n); + g := g'; (n,i) in + let adde anodes (n1,n2,x) = + let g' = (!g)#add_arc ((List.assoc n1 anodes,List.assoc n2 anodes),x) in + g := g'; () in + let add_nodes = List.map addn nodes in + let _add_edges = List.map (adde add_nodes) edges in + !g +;; + + +(* CTL parameterised on basic predicates and metavar's*) +type ('pred,'mvar) old_gen_ctl = + | False_ + | True_ + | Pred_ of 'pred + | Not_ of ('pred,'mvar) old_gen_ctl + | Exists_ of 'mvar * ('pred,'mvar) old_gen_ctl (* !!! *) + | And_ of ('pred,'mvar) old_gen_ctl * ('pred,'mvar) old_gen_ctl + | Or_ of ('pred,'mvar) old_gen_ctl * ('pred,'mvar) old_gen_ctl + | Implies_ of ('pred,'mvar) old_gen_ctl * ('pred,'mvar) old_gen_ctl + | AF_ of ('pred,'mvar) old_gen_ctl + | AX_ of ('pred,'mvar) old_gen_ctl + | AG_ of ('pred,'mvar) old_gen_ctl + | AU_ of ('pred,'mvar) old_gen_ctl * ('pred,'mvar) old_gen_ctl + | EF_ of ('pred,'mvar) old_gen_ctl + | EX_ of ('pred,'mvar) old_gen_ctl + | EG_ of ('pred,'mvar) old_gen_ctl + | EU_ of ('pred,'mvar) old_gen_ctl * ('pred,'mvar) old_gen_ctl + | Let_ of string * ('pred,'mvar) old_gen_ctl * ('pred,'mvar) old_gen_ctl + | Ref_ of string + +let rec mkanno phi0 = + let anno phi = (phi,None) in + match phi0 with + | False_ -> anno False + | True_ -> anno True + | Pred_(p) -> anno (Pred(p)) + | Not_(phi) -> anno (Not(mkanno phi)) + | Exists_(v,phi) -> anno (Exists(v,mkanno phi)) + | And_(phi1,phi2) -> anno (And(mkanno phi1,mkanno phi2)) + | Or_(phi1,phi2) -> anno (Or(mkanno phi1,mkanno phi2)) + | Implies_(phi1,phi2) -> anno (Implies(mkanno phi1,mkanno phi2)) + | AF_(phi1) -> anno (AF(mkanno phi1)) + | AX_(phi1) -> anno (AX(mkanno phi1)) + | AG_(phi1) -> anno (AG(mkanno phi1)) + | AU_(phi1,phi2) -> anno (AU(mkanno phi1,mkanno phi2)) + | EF_(phi1) -> anno (EF(mkanno phi1)) + | EX_(phi1) -> anno (EX(mkanno phi1)) + | EG_(phi1) -> anno (EG(mkanno phi1)) + | EU_(phi1,phi2) -> anno (EU(mkanno phi1,mkanno phi2)) + | Let_ (x,phi1,phi2) -> anno (Let(x,mkanno phi1,mkanno phi2)) + | Ref_(s) -> anno (Ref(s)) + + +(* ******************************************************************** *) +(* Example 1 *) +(* CTL: f(x) /\ AF(Ey.g(y)) *) +(* ******************************************************************** *) + +let ex1lab s = + match s with + | "f(x)" -> [(0,["x" --> "1"]); (1,["x" --> "2"])] + | "g(y)" -> [(3,["y" --> "1"]); (4,["y" --> "2"])] + | "f(1)" -> [(0,[])] + | "f(2)" -> [(1,[])] + | "g(1)" -> [(3,[])] + | "g(2)" -> [(4,[])] + | _ -> [] +;; + +let ex1graph = + let nodes = + [(0,"f(1)");(1,"f(2)");(2,"< >");(3,"g(1)");(4,"g(2)");(5,"")] in + let edges = [(0,2); (1,2); (2,3); (2,4); (3,5); (4,5); (5,5)] in + mkgraph nodes (List.map (fun (x,y) -> (x,y,())) edges) +;; + +let ex1states = List.map fst (ex1graph#nodes)#tolist;; + +let ex1model = (ex1graph,ex1lab,ex1states);; +let ex1model_wrapped = (ex1graph,wrap_label ex1lab,ex1states);; + +let ex1s0 = Exists_("v0",Pred_ ("f(x)",UnModif "v0"));; +let ex1s1 = Exists_("v1",Pred_ ("g(y)",Modif "v1"));; +let ex1s2 = Exists_("y",ex1s1);; +let ex1s3 = AF_(ex1s2);; +let ex1s4 = And_(ex1s0,ex1s3);; + +let ex1s3a = AX_(ex1s2);; +let ex1s4a = AX_(AX_(ex1s2));; +let ex1s5a = And_(ex1s0,ex1s4a);; + +let ex1s0b = Pred_ ("g(y)", Modif "v0");; +let ex1s1b = Exists_ ("v0",ex1s0b);; +let ex1s2b = Exists_ ("y",ex1s1b);; +let ex1s3b = AF_(ex1s2b);; +let ex1s4b = AX_(ex1s3b);; +let ex1s5b = Pred_ ("f(x)", UnModif "v3");; +let ex1s6b = Exists_ ("v3", ex1s5b);; +let ex1s7b = Exists_ ("x", ex1s6b);; +let ex1s8b = And_(ex1s7b,ex1s4b);; + +let ex1s7c = And_(ex1s6b,ex1s4b);; +let ex1s8c = Exists_("x",ex1s7c);; + +let ex1phi1 = ex1s4;; +let ex1phi2 = ex1s5a;; +let ex1phi3 = + And_ + (Exists_ ("x", + (Exists_ ("v3", + Pred_ ("f(x)", UnModif "v3")))), + AX_ + (AF_ + (Exists_ ("y", (* change this to Y and have strange behaviour *) + (Exists_ ("v0", + Pred_ ("g(y)", Modif "v0") + ))))));; + +let ex1phi4 = + Exists_ ("x", + And_ ( + (Exists_ ("v3", + Pred_ ("f(x)", UnModif "v3"))), + AX_ + (AF_ + (Exists_ ("y", (* change this to Y and have strange behaviour *) + (Exists_ ("v0", + Pred_ ("g(y)", Modif "v0") + )))))));; + + +let ex1phi5 = AU_(True_,Exists_("y", Exists_("v0",Pred_("g(y)",Modif "v0"))));; + +let ex1phi6 = + AU_( + Not_(Exists_("x",Exists_("v1",Pred_("f(x)",UnModif "v1")))), + Exists_("y", Exists_("v0",Pred_("g(y)",Modif "v0"))) + );; + +(* use with ex1nc *) +let ex1phi7 = + AU_( + Not_(Or_(Pred_("f(1)",Control),Pred_("f(2)",Control))), + Exists_("y", Exists_("v0",Pred_("g(y)",Modif "v0"))) + );; + +let ex1 phi = satbis ex1model (mkanno phi);; +let ex1nc phi = satbis_noclean ex1model (mkanno phi);; + + +(* ******************************************************************** *) +(* Example 2 *) +(* ******************************************************************** *) + +let ex2lab s = + match s with + | "p" -> [0,[]] + | "{" -> [(1,[]); (2,[])] + | "}" -> [(3,[]); (4,[])] + | "paren(v)" -> [(1,["v" --> "1"]); (2,["v" --> "2"]); + (3,["v" --> "2"]); (4,["v" --> "1"])] + | _ -> [] +;; + +let ex2graph = + let nodes = + [(0,"p");(1,"{");(2,"{");(3,"}");(4,"}");(5,"")] in + let edges = [(0,1); (1,2); (2,3); (3,4); (4,5); (5,5)] in + mkgraph nodes (List.map (fun (x,y) -> (x,y,())) edges) +;; + +let ex2states = List.map fst (ex2graph#nodes)#tolist;; + +let ex2model = (ex2graph,ex2lab,ex2states);; +let ex2model_wrapped = (ex2graph,wrap_label ex2lab,ex2states);; + +let ex2s0 = Pred_("p",Control);; +let ex2s1 = Pred_("{",Control);; +let ex2s2 = Pred_("paren(v)",Control);; +let ex2s3 = And_(ex2s1,ex2s2);; +let ex2s4 = Pred_("}",Control);; +let ex2s5 = Pred_("paren(v)",Control);; +let ex2s6 = And_(ex2s4,ex2s5);; +let ex2s7 = AF_(ex2s6);; +let ex2s8 = And_(ex2s3,ex2s7);; +let ex2s9 = Exists_("v",ex2s8);; +let ex2s10 = AX_(ex2s9);; +let ex2s11 = And_(ex2s0,ex2s10);; + +let ex2phi1 = ex2s11;; + +let ex2 phi = satbis_noclean ex2model (mkanno phi) + +(* + +--- s11:& ---+ + | | + s0:p s10:AX + | + s9:exists v + | + +---------- s8:& --------+ + | | + +-- s3:& --+ s7:AF + | | | + s1:"{" s2:paren(v) +-- s6:& -+ + | | + s4:"}" s5:paren(v) + + s0 : p : (0,_,_) + s1 : "{" : (1,_,_); (2,_,_) + s2 : paren(v) : (1,v=1,_); (2,v=2,_); (3,v=2,_); (4,v=1,_) + s3 : "{" & paren(v) : (1,v=1,_); (2,v=2,_) + s4 : "}" : (3,_,_); (4,_,_) + s5 : paren(v) : (1,v=1,_); (2,v=2,_); (3,v=2,_); (4,v=1,_) + s6 : "}" & paren(v) : (3,v=2,_); (4,v=1,_) + s7 : AF(...) : (0;1;2;3,v=2,_); (0;1;2;3;4,v=1,_) + s8 : (...&...) & AF(...) : (1,v=1,_); (2,v=2,_) + s9 : exists ... : (1,_,(1,v=1)); (2,_,(2,v=2)) + s10 : AX(...) : (0,_,(1,v=1)); (1,_,(2,v=2)) + s11 : p & AX(...) : (0,_,(1,v=1)) +*) diff --git a/ctl/wrapper_ctl.ml b/ctl/wrapper_ctl.ml new file mode 100644 index 0000000..35cf043 --- /dev/null +++ b/ctl/wrapper_ctl.ml @@ -0,0 +1,258 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* ********************************************************************** + * + * Wrapping for FUNCTORS and MODULES + * + * + * $Id: wrapper_ctl.ml,v 1.67 2007/11/20 12:57:25 julia Exp $ + * + * **********************************************************************) + +type info = int + +type ('pred, 'mvar) wrapped_ctl = + ('pred * 'mvar Ast_ctl.modif, 'mvar, info) Ast_ctl.generic_ctl + +type ('value, 'pred) wrapped_binding = + | ClassicVal of 'value + | PredVal of 'pred Ast_ctl.modif + +type ('pred,'state,'mvar,'value) labelfunc = + 'pred -> + ('state * ('pred * ('mvar, 'value) Ast_ctl.generic_substitution)) list + +(* pad: what is 'wit ? *) +type ('pred,'state,'mvar,'value,'wit) wrapped_labelfunc = + ('pred * 'mvar Ast_ctl.modif) -> + ('state * + ('mvar,('value,'pred) wrapped_binding) Ast_ctl.generic_substitution * + 'wit + ) list + +(* ********************************************************************** *) +(* Module type: CTL_ENGINE_BIS (wrapper for CTL_ENGINE) *) +(* ********************************************************************** *) + +(* This module must convert the labelling function passed as parameter, by + using convert_label. Then create a SUBST2 module handling the + wrapped_binding. Then it can instantiates the generic CTL_ENGINE + module. Call sat. And then process the witness tree to remove all that + is not revelevant for the transformation phase. +*) + +module CTL_ENGINE_BIS = + functor (SUB : Ctl_engine.SUBST) -> + functor (G : Ctl_engine.GRAPH) -> + functor(P : Ctl_engine.PREDICATE) -> +struct + + exception TODO_CTL of string (* implementation still not quite done so... *) + exception NEVER_CTL of string (* Some things should never happen *) + + module A = Ast_ctl + + type predicate = P.t + module WRAPPER_ENV = + struct + type mvar = SUB.mvar + type value = (SUB.value,predicate) wrapped_binding + let eq_mvar = SUB.eq_mvar + let eq_val wv1 wv2 = + match (wv1,wv2) with + | (ClassicVal(v1),ClassicVal(v2)) -> SUB.eq_val v1 v2 + | (PredVal(v1),PredVal(v2)) -> v1 = v2 (* FIX ME: ok? *) + | _ -> false + let merge_val wv1 wv2 = + match (wv1,wv2) with + | (ClassicVal(v1),ClassicVal(v2)) -> ClassicVal(SUB.merge_val v1 v2) + | _ -> wv1 (* FIX ME: ok? *) + + + let print_mvar x = SUB.print_mvar x + let print_value x = + match x with + ClassicVal v -> SUB.print_value v + | PredVal(A.Modif v) -> P.print_predicate v + | PredVal(A.UnModif v) -> P.print_predicate v + | PredVal(A.Control) -> Format.print_string "no value" + end + + module WRAPPER_PRED = + struct + type t = P.t * SUB.mvar Ast_ctl.modif + let print_predicate (pred, modif) = + begin + P.print_predicate pred; + (match modif with + Ast_ctl.Modif x | Ast_ctl.UnModif x -> + Format.print_string " with " + | Ast_ctl.Control -> ()) + end + end + + (* Instantiate a wrapped version of CTL_ENGINE *) + module WRAPPER_ENGINE = + Ctl_engine.CTL_ENGINE (WRAPPER_ENV) (G) (WRAPPER_PRED) + + (* Wrap a label function *) + let (wrap_label: ('pred,'state,'mvar,'value) labelfunc -> + ('pred,'state,'mvar,'value,'wit) wrapped_labelfunc) = + fun oldlabelfunc -> + fun (p, predvar) -> + + let penv p' = + match predvar with + | A.Modif(x) -> [A.Subst(x,PredVal(A.Modif(p')))] + | A.UnModif(x) -> [A.Subst(x,PredVal(A.UnModif(p')))] + | A.Control -> [] in + + let conv_sub sub = + match sub with + | A.Subst(x,v) -> A.Subst(x,ClassicVal(v)) + | A.NegSubst(x,v) -> A.NegSubst(x,ClassicVal(v)) in + + let conv_trip (s,(p',env)) = + (s,penv p' @ (List.map conv_sub env),[](*pad: ?*)) + in + List.map conv_trip (oldlabelfunc p) + + (* ---------------------------------------------------------------- *) + + (* FIX ME: what about negative witnesses and negative substitutions *) + let unwrap_wits modifonly wits = + let mkth th = + Common.map_filter + (function A.Subst(x,ClassicVal(v)) -> Some (x,v) | _ -> None) + th in + let rec loop neg acc = function + A.Wit(st,[A.Subst(x,PredVal(A.Modif(v)))],anno,wit) -> + (match wit with + [] -> [(st,acc,v)] + | _ -> raise (NEVER_CTL "predvar tree should have no children")) + | A.Wit(st,[A.Subst(x,PredVal(A.UnModif(v)))],anno,wit) + when not modifonly or !Flag.track_iso_usage -> + (match wit with + [] -> [(st,acc,v)] + | _ -> raise (NEVER_CTL "predvar tree should have no children")) + | A.Wit(st,th,anno,wit) -> + List.concat (List.map (loop neg ((mkth th) @ acc)) wit) + | A.NegWit(_) -> [] (* why not failure? *) in + List.concat (List.map (function wit -> loop false [] wit) wits) + ;; + +(* + (* a match can return many trees, but within each tree, there has to be + at most one value for each variable that is in the used_after list *) + let collect_used_after used_after envs = + let print_var var = SUB.print_mvar var; Format.print_flush() in + List.concat + (List.map + (function used_after_var -> + let vl = + List.fold_left + (function rest -> + function env -> + try + let vl = List.assoc used_after_var env in + match rest with + None -> Some vl + | Some old_vl when SUB.eq_val vl old_vl -> rest + | Some old_vl -> print_var used_after_var; + Format.print_newline(); + SUB.print_value old_vl; + Format.print_newline(); + SUB.print_value vl; + Format.print_newline(); + failwith "incompatible values" + with Not_found -> rest) + None envs in + match vl with + None -> [] + | Some vl -> [(used_after_var, vl)]) + used_after) +*) + + (* a match can return many trees, but within each tree, there has to be + at most one value for each variable that is in the used_after list *) + (* actually, this should always be the case, because these variables + should be quantified at the top level. so the more complicated + definition above should not be needed. *) + let collect_used_after used_after envs = + List.concat + (List.map + (function used_after_var -> + let vl = + List.fold_left + (function rest -> + function env -> + try + let vl = List.assoc used_after_var env in + if List.exists (function x -> SUB.eq_val x vl) rest + then rest + else vl::rest + with Not_found -> rest) + [] envs in + List.map (function x -> (used_after_var, x)) vl) + used_after) + + (* ----------------------------------------------------- *) + + (* The wrapper for sat from the CTL_ENGINE *) + let satbis_noclean (grp,lab,states) (phi,reqopt) : + ('pred,'anno) WRAPPER_ENGINE.triples = + WRAPPER_ENGINE.sat (grp,wrap_label lab,states) phi reqopt + + (* Returns the "cleaned up" result from satbis_noclean *) + let (satbis : + G.cfg * + (predicate,G.node,SUB.mvar,SUB.value) labelfunc * + G.node list -> + ((predicate,SUB.mvar) wrapped_ctl * + (WRAPPER_PRED.t list list)) -> + (WRAPPER_ENV.mvar list * (SUB.mvar * SUB.value) list) -> + ((WRAPPER_PRED.t, 'a) WRAPPER_ENGINE.triples * + ((G.node * (SUB.mvar * SUB.value) list * predicate) + list list * + bool * + (WRAPPER_ENV.mvar * SUB.value) list list))) = + fun m phi (used_after, binding) -> + let noclean = satbis_noclean m phi in + let witness_trees = List.map (fun (_,_,w) -> w) noclean in + let res = List.map (unwrap_wits true) witness_trees in + let new_bindings = + List.map + (function bindings_per_witness_tree -> + (List.map (function (_,env,_) -> env) bindings_per_witness_tree)) + (List.map (unwrap_wits false) witness_trees) in + (noclean, + (res,not(noclean = []), + (* throw in the old binding. By construction it doesn't conflict + with any of the new things, and it is useful if there are no new + things. *) + (List.map (collect_used_after used_after) new_bindings))) + +let print_bench _ = WRAPPER_ENGINE.print_bench() + +(* END OF MODULE: CTL_ENGINE_BIS *) +end diff --git a/ctl/wrapper_ctl.mli b/ctl/wrapper_ctl.mli new file mode 100644 index 0000000..62319da --- /dev/null +++ b/ctl/wrapper_ctl.mli @@ -0,0 +1,65 @@ +type info = int + +type ('pred, 'mvar) wrapped_ctl = + ('pred * 'mvar Ast_ctl.modif, 'mvar, info) Ast_ctl.generic_ctl + +type ('a, 'b) wrapped_binding = + ClassicVal of 'a + | PredVal of 'b Ast_ctl.modif + +type ('pred,'state,'mvar,'value) labelfunc = + 'pred -> + ('state * ('pred * ('mvar, 'value) Ast_ctl.generic_substitution)) list + +module CTL_ENGINE_BIS : + functor (SUB : Ctl_engine.SUBST) -> + functor (G : Ctl_engine.GRAPH) -> + functor(P : Ctl_engine.PREDICATE) -> + sig + + type predicate = P.t + module WRAPPER_ENV : + sig + type mvar = SUB.mvar + type value = (SUB.value, predicate) wrapped_binding + end + module WRAPPER_PRED : + sig + type t = P.t * SUB.mvar Ast_ctl.modif + end + module WRAPPER_ENGINE : + sig + type substitution = + (WRAPPER_ENV.mvar, WRAPPER_ENV.value) Ast_ctl.generic_subst list + type ('a, 'b) witness = + (G.node, substitution, + ('a, WRAPPER_ENV.mvar, 'b) Ast_ctl.generic_ctl list) + Ast_ctl.generic_witnesstree + type ('a, 'b) triples = + (G.node * substitution * ('a, 'b) witness list) list + end + + + val satbis_noclean : + G.cfg * + (predicate, G.node, WRAPPER_ENV.mvar, SUB.value) labelfunc * + G.node list -> + ((WRAPPER_PRED.t, WRAPPER_ENV.mvar, int) Ast_ctl.generic_ctl * + (WRAPPER_PRED.t list list)) -> + (WRAPPER_PRED.t, 'a) WRAPPER_ENGINE.triples + + val satbis : + G.cfg * + (predicate,G.node,SUB.mvar,SUB.value) labelfunc * + G.node list -> + ((predicate,SUB.mvar) wrapped_ctl * + (WRAPPER_PRED.t list list)) -> + (WRAPPER_ENV.mvar list * (SUB.mvar * SUB.value) list) -> + ((WRAPPER_PRED.t, 'a) WRAPPER_ENGINE.triples * + ((G.node * (SUB.mvar * SUB.value) list * predicate) + list list * + bool * + (WRAPPER_ENV.mvar * SUB.value) list list)) + + val print_bench : unit -> unit +end diff --git a/demos/check_region.c b/demos/check_region.c new file mode 100644 index 0000000..163df96 --- /dev/null +++ b/demos/check_region.c @@ -0,0 +1,21 @@ +int main(int i) { + + if(check_region(piix,8)){ + printk("error1"); + return -ENODEV; + } + if(force_addr) { + printk("warning1"); + } else if((temp & 1) == 0) { + if(force) { + printk("warning2"); + } else { + printk("error2"); + + return -ENODEV; + } + } + request_region(piix,8); + printk("done"); +} + diff --git a/demos/check_region.cocci b/demos/check_region.cocci new file mode 100644 index 0000000..5581f6e --- /dev/null +++ b/demos/check_region.cocci @@ -0,0 +1,14 @@ +@@ +expression e1, e2; +@@ + +- if(check_region(e1,e2)!=0) ++ if(!request_region(e1,e2)) + { ... return ...; } + <... ++ release_region(e1); + return ...; + ...> +- request_region(e1,e2); + + diff --git a/demos/ctr_unit_test.c b/demos/ctr_unit_test.c new file mode 100644 index 0000000..b55d0a2 --- /dev/null +++ b/demos/ctr_unit_test.c @@ -0,0 +1,28 @@ + +int classA(int i) { + if(classA()) { x=0; } + + UnitTestEntry("A1"); + if(MethodA1()) { } + if(MethodA2()) { } + UnitTestEntry("A3"); + if(MethodA3()) { } + if(MethodA4()) { } + +} + +int classB(int i) { + if(classB()) { x=0; } + + if(MethodB1()) { } + UnitTestEntry("B2"); + if(MethodB2()) { } + if(MethodB3()) { } + UnitTestEntry("B4"); + if(MethodB4()) { } + + +} + +int lastfunction(int i) { +} diff --git a/demos/ctr_unit_test.cocci b/demos/ctr_unit_test.cocci new file mode 100644 index 0000000..f6d9b95 --- /dev/null +++ b/demos/ctr_unit_test.cocci @@ -0,0 +1,79 @@ +@ rule1 @ +identifier C; +@@ + int C(int i) { + ... + if(C()) { ... } + ... ++ if(UnitTest()) { ++ int c; ++ C(); ++ } + } + + +@@ +identifier TestMethod; +expression name; +statement S1,S2; +identifier rule1.C; +// if put identifier name; then cocci does not help +// to say that there is a partial match :( +@@ + +// int C(int i) { +// ... +// UnitTestEntry(name); +// if(TestMethod()) { ... } +// ... +// if(UnitTest()) { +// int c; +// ... +//+ c = C(); +//+ Console.WriteLine("invoking test", name); +//+ c.TestMethod(); +// } +// } + + +// int C(int i) { +// <... UnitTestEntry(...); ...> +// UnitTestEntry(name); +// if(TestMethod()) { ... } +// <... UnitTestEntry(...); ...> +// } + +// or simply (does not work ) + +// int C(int i) { +// <... +// UnitTestEntry(name); +// if(TestMethod()) { ... } +// ...> +// } + +// or + + int C(int i) { +// <... UnitTestEntry(name); if(TestMethod()) { ... } ...> +// <... UnitTestEntry(...); if(...) { ... } ...> + <... S1 ...> + UnitTestEntry(name); if(TestMethod()) { ... } + <... S2 ...> +// <... UnitTestEntry(...); if(...) { ... } ...> +// <... UnitTestEntry(name); if(TestMethod()) { ... } ...> + } + +@@ +identifier rule1.C; +@@ + int C(int i) { + ... + if(UnitTest()) { + int c; + ... ++ c = C(); ++ Console.WriteLine("invoking test", name); ++ c.TestMethod(); + } + } diff --git a/demos/demo_rule9/README b/demos/demo_rule9/README new file mode 100644 index 0000000..a8190ea --- /dev/null +++ b/demos/demo_rule9/README @@ -0,0 +1,73 @@ +1. Motivate in some way the changes that need to be made. + +2. Show the semantic patch in rule9_1.cocci. This could also be developed + incrementally, with first the lines for get and put, then the line for + the error checking on hostptr, then the - and + line for moving the + declaration of hostptr to the parameter list. Finally, drop the hostno + parameter. Explain the metavariables. Note that a rule is + automatically generated to update the prototype of the proc_info + function, if one is available. + +3. Apply it to scsiglue.c and show what has changed. + +4. Some issues: + + * In nsp_cs.c (and a lot of other files), there is no call to the put + function. Indeed, the reason for the CE was that driver programmers + were forgetting to call the put function. We thus would like to make + it optional, the idea being that if we find it we should delete it, + but if we don't find it, the rest of the transformation should still + take place. + + * In g_NCR5380.c, there is no error checking on the result of calling + the get function. Thus, that has to be optional as well. The result + of making both of these changes is in rule9_2.cocci. + + * In sym53c8xx.c, there are no braces around the if branch in the error + handling code. Explain about the isomorphisms. + + * In nsp_cs.c, hostptr is compared to NULL. There is an isomorphism for + that as well. + + * The function is essentially identified by the types of its + parameters. Since there are quite a lot of them, with quite varied + typed, this is probably enough to uniquely identify the function + within each driver in practice. But for greater safety, we should + describe the function in terms of how it interacts with the SCSI + library, because it is the SCSI library that will be responsible for + supplying the extra argument. For this we add a new rule + (rule9_3.cocci). This rule identifies the function as the one that is + stored in the proc_info field of a structure of type SHT (also given + the typedef name of Scsi_Host_Template). Isomorphisms take case of + the case where this assignment has other forms, eg involving a pointer + to the structure or is part of a top-level structure initialization. + + Now we want to inherit the binding of proc_info_func from the first + rule to the second one. For this, we give the first one a name, and + use that name in declaring the proc_info_func metavariable in the + second rule. The second rule will be applied once for each successful + match of the first rule, but in practice, there is only one. + +5. The transformation that is implemented is not yet complete, as one can + see by comparing with the .res file. We also have to rename the hostno + variable everywhere that it occurs. Because it can in principle occur + anywhere, we make a separate rule to avoid cluttering up the previous + one. This rule inherits the name of the proc_info function from rule1 + and the names of the hostno and hostptr variables from rule2. The + transformation is to replace occurrences of hostno by a reference to the + host_no field of hostptr everywhere hostno occurs, as indicated by the + <... ...>. + +6. Finally, the proc_info function may be called from other places within + the current driver. These cases must be updated as well with the new + argument. For this, we have to find an appropriate value somewhere. + Because the get function has been deprecated, the driver will normally + get this information as a parameter, and that is the only case we + consider here. The name of the function enclosing the call is arbitrary + (as indicated by a metavariable) as is the position of the + Scsi_Host-typed parameter (as indicated by the dots in the parameter + list). As for the previous rule, we use <... ...> to update a call to + the proc_info function wherever it occurs. Note that although we have + used the same names as for the parameter list in rule2, buffer, start, + etc. are now arbitrary expressions. + diff --git a/demos/demo_rule9/g_NCR5380.c b/demos/demo_rule9/g_NCR5380.c new file mode 100644 index 0000000..f0ca28b --- /dev/null +++ b/demos/demo_rule9/g_NCR5380.c @@ -0,0 +1,942 @@ +/* + * Generic Generic NCR5380 driver + * + * Copyright 1993, Drew Eckhardt + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@colorado.edu + * +1 (303) 440-4894 + * + * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin + * K.Lentin@cs.monash.edu.au + * + * NCR53C400A extensions (c) 1996, Ingmar Baumgart + * ingmar@gonzo.schwaben.de + * + * DTC3181E extensions (c) 1997, Ronald van Cuijlenborg + * ronald.van.cuijlenborg@tip.nl or nutty@dds.nl + * + * Added ISAPNP support for DTC436 adapters, + * Thomas Sailer, sailer@ife.ee.ethz.ch + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * TODO : flesh out DMA support, find some one actually using this (I have + * a memory mapped Trantor board that works fine) + */ + +/* + * Options : + * + * PARITY - enable parity checking. Not supported. + * + * SCSI2 - enable support for SCSI-II tagged queueing. Untested. + * + * USLEEP - enable support for devices that don't disconnect. Untested. + * + * The card is detected and initialized in one of several ways : + * 1. With command line overrides - NCR5380=port,irq may be + * used on the LILO command line to override the defaults. + * + * 2. With the GENERIC_NCR5380_OVERRIDE compile time define. This is + * specified as an array of address, irq, dma, board tuples. Ie, for + * one board at 0x350, IRQ5, no dma, I could say + * -DGENERIC_NCR5380_OVERRIDE={{0xcc000, 5, DMA_NONE, BOARD_NCR5380}} + * + * -1 should be specified for no or DMA interrupt, -2 to autoprobe for an + * IRQ line if overridden on the command line. + * + * 3. When included as a module, with arguments passed on the command line: + * ncr_irq=xx the interrupt + * ncr_addr=xx the port or base address (for port or memory + * mapped, resp.) + * ncr_dma=xx the DMA + * ncr_5380=1 to set up for a NCR5380 board + * ncr_53c400=1 to set up for a NCR53C400 board + * e.g. + * modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_5380=1 + * for a port mapped NCR5380 board or + * modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1 + * for a memory mapped NCR53C400 board with interrupts disabled. + * + * 255 should be specified for no or DMA interrupt, 254 to autoprobe for an + * IRQ line if overridden on the command line. + * + */ + +/* + * $Log: g_NCR5380.c,v $ + * Revision 1.1 2007/11/01 09:43:07 julia + * *** empty log message *** + * + * Revision 1.1.1.1 2007/03/28 16:38:53 pad + * your commit message + * + * Revision 1.1 2006/09/20 01:30:53 pad + * new files + * + */ + +/* settings for DTC3181E card with only Mustek scanner attached */ +#define USLEEP +#define USLEEP_POLL 1 +#define USLEEP_SLEEP 20 +#define USLEEP_WAITLONG 500 + +#define AUTOPROBE_IRQ +#define AUTOSENSE + +#include + +#ifdef CONFIG_SCSI_GENERIC_NCR53C400 +#define NCR53C400_PSEUDO_DMA 1 +#define PSEUDO_DMA +#define NCR53C400 +#define NCR5380_STATS +#undef NCR5380_STAT_LIMIT +#endif + +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" +#include "g_NCR5380.h" +#include "NCR5380.h" +#include +#include +#include +#include +#include +#include + +#define NCR_NOT_SET 0 +static int ncr_irq = NCR_NOT_SET; +static int ncr_dma = NCR_NOT_SET; +static int ncr_addr = NCR_NOT_SET; +static int ncr_5380 = NCR_NOT_SET; +static int ncr_53c400 = NCR_NOT_SET; +static int ncr_53c400a = NCR_NOT_SET; +static int dtc_3181e = NCR_NOT_SET; + +static struct override { + NCR5380_implementation_fields; + int irq; + int dma; + int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ +} overrides +#ifdef GENERIC_NCR5380_OVERRIDE +[] __initdata = GENERIC_NCR5380_OVERRIDE; +#else +[1] __initdata = { { 0,},}; +#endif + + +#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) + +#ifndef MODULE + +/** + * internal_setup - handle lilo command string override + * @board: BOARD_* identifier for the board + * @str: unused + * @ints: numeric parameters + * + * Do LILO command line initialization of the overrides array. Display + * errors when needed + * + * Locks: none + */ + +static void __init internal_setup(int board, char *str, int *ints) +{ + static int commandline_current = 0; + switch (board) { + case BOARD_NCR5380: + if (ints[0] != 2 && ints[0] != 3) { + printk(KERN_ERR "generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n"); + return; + } + break; + case BOARD_NCR53C400: + if (ints[0] != 2) { + printk(KERN_ERR "generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + case BOARD_NCR53C400A: + if (ints[0] != 2) { + printk(KERN_ERR "generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + case BOARD_DTC3181E: + if (ints[0] != 2) { + printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + } + + if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type) ints[1]; + overrides[commandline_current].irq = ints[2]; + if (ints[0] == 3) + overrides[commandline_current].dma = ints[3]; + else + overrides[commandline_current].dma = DMA_NONE; + overrides[commandline_current].board = board; + ++commandline_current; + } +} + + +/** + * do_NCR53C80_setup - set up entry point + * @str: unused + * + * Setup function invoked at boot to parse the ncr5380= command + * line. + */ + +static int __init do_NCR5380_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR5380, str, ints); + return 1; +} + +/** + * do_NCR53C400_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code + * + * Setup function invoked at boot to parse the ncr53c400= command + * line. + */ + +static int __init do_NCR53C400_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR53C400, str, ints); + return 1; +} + +/** + * do_NCR53C400A_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code + * + * Setup function invoked at boot to parse the ncr53c400a= command + * line. + */ + +static int __init do_NCR53C400A_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR53C400A, str, ints); + return 1; +} + +/** + * do_DTC3181E_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code + * + * Setup function invoked at boot to parse the dtc3181e= command + * line. + */ + +static int __init do_DTC3181E_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_DTC3181E, str, ints); + return 1; +} + +#endif + +/** + * generic_NCR5380_detect - look for NCR5380 controllers + * @tpnt: the scsi template + * + * Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E + * and DTC436(ISAPnP) controllers. If overrides have been set we use + * them. + * + * The caller supplied NCR5380_init function is invoked from here, before + * the interrupt line is taken. + * + * Locks: none + */ + +int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt) +{ + static int current_override = 0; + int count, i; + unsigned int *ports; + static unsigned int __initdata ncr_53c400a_ports[] = { + 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 + }; + static unsigned int __initdata dtc_3181e_ports[] = { + 0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0 + }; + int flags = 0; + struct Scsi_Host *instance; + + if (ncr_irq != NCR_NOT_SET) + overrides[0].irq = ncr_irq; + if (ncr_dma != NCR_NOT_SET) + overrides[0].dma = ncr_dma; + if (ncr_addr != NCR_NOT_SET) + overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr; + if (ncr_5380 != NCR_NOT_SET) + overrides[0].board = BOARD_NCR5380; + else if (ncr_53c400 != NCR_NOT_SET) + overrides[0].board = BOARD_NCR53C400; + else if (ncr_53c400a != NCR_NOT_SET) + overrides[0].board = BOARD_NCR53C400A; + else if (dtc_3181e != NCR_NOT_SET) + overrides[0].board = BOARD_DTC3181E; + + if (!current_override && isapnp_present()) { + struct pnp_dev *dev = NULL; + count = 0; + while ((dev = pnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) { + if (count >= NO_OVERRIDES) + break; + if (pnp_device_attach(dev) < 0) { + printk(KERN_ERR "dtc436e probe: attach failed\n"); + continue; + } + if (pnp_activate_dev(dev) < 0) { + printk(KERN_ERR "dtc436e probe: activate failed\n"); + pnp_device_detach(dev); + continue; + } + if (!pnp_port_valid(dev, 0)) { + printk(KERN_ERR "dtc436e probe: no valid port\n"); + pnp_device_detach(dev); + continue; + } + if (pnp_irq_valid(dev, 0)) + overrides[count].irq = pnp_irq(dev, 0); + else + overrides[count].irq = SCSI_IRQ_NONE; + if (pnp_dma_valid(dev, 0)) + overrides[count].dma = pnp_dma(dev, 0); + else + overrides[count].dma = DMA_NONE; + overrides[count].NCR5380_map_name = (NCR5380_map_type) pnp_port_start(dev, 0); + overrides[count].board = BOARD_DTC3181E; + count++; + } + } + + tpnt->proc_name = "g_NCR5380"; + + for (count = 0; current_override < NO_OVERRIDES; ++current_override) { + if (!(overrides[current_override].NCR5380_map_name)) + continue; + + ports = 0; + switch (overrides[current_override].board) { + case BOARD_NCR5380: + flags = FLAG_NO_PSEUDO_DMA; + break; + case BOARD_NCR53C400: + flags = FLAG_NCR53C400; + break; + case BOARD_NCR53C400A: + flags = FLAG_NO_PSEUDO_DMA; + ports = ncr_53c400a_ports; + break; + case BOARD_DTC3181E: + flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E; + ports = dtc_3181e_ports; + break; + } + +#ifndef CONFIG_SCSI_G_NCR5380_MEM + if (ports) { + /* wakeup sequence for the NCR53C400A and DTC3181E */ + + /* Disable the adapter and look for a free io port */ + outb(0x59, 0x779); + outb(0xb9, 0x379); + outb(0xc5, 0x379); + outb(0xae, 0x379); + outb(0xa6, 0x379); + outb(0x00, 0x379); + + if (overrides[current_override].NCR5380_map_name != PORT_AUTO) + for (i = 0; ports[i]; i++) { + if (overrides[current_override].NCR5380_map_name == ports[i]) + break; + } else + for (i = 0; ports[i]; i++) { + if ((!check_region(ports[i], 16)) && (inb(ports[i]) == 0xff)) + break; + } + if (ports[i]) { + outb(0x59, 0x779); + outb(0xb9, 0x379); + outb(0xc5, 0x379); + outb(0xae, 0x379); + outb(0xa6, 0x379); + outb(0x80 | i, 0x379); /* set io port to be used */ + outb(0xc0, ports[i] + 9); + if (inb(ports[i] + 9) != 0x80) + continue; + else + overrides[current_override].NCR5380_map_name = ports[i]; + } else + continue; + } + + request_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"); +#else + if (check_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size)) + continue; + request_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"); +#endif + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) { +#ifndef CONFIG_SCSI_G_NCR5380_MEM + release_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size); +#else + release_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size); +#endif + continue; + } + + instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name; + + NCR5380_init(instance, flags); + + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, 0xffff); + + if (instance->irq != SCSI_IRQ_NONE) + if (request_irq(instance->irq, generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = SCSI_IRQ_NONE; + } + + if (instance->irq == SCSI_IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + } + + printk(KERN_INFO "scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int) instance->NCR5380_instance_name); + if (instance->irq == SCSI_IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); + + ++current_override; + ++count; + } + return count; +} + +/** + * generic_NCR5380_info - reporting string + * @host: NCR5380 to report on + * + * Report driver information for the NCR5380 + */ + +const char *generic_NCR5380_info(struct Scsi_Host *host) +{ + static const char string[] = "Generic NCR5380/53C400 Driver"; + return string; +} + +/** + * generic_NCR5380_release_resources - free resources + * @instance: host adapter to clean up + * + * Free the generic interface resources from this adapter. + * + * Locks: none + */ + +int generic_NCR5380_release_resources(struct Scsi_Host *instance) +{ + NCR5380_local_declare(); + NCR5380_setup(instance); + +#ifndef CONFIG_SCSI_G_NCR5380_MEM + release_region(instance->NCR5380_instance_name, NCR5380_region_size); +#else + release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); +#endif + + if (instance->irq != SCSI_IRQ_NONE) + free_irq(instance->irq, NULL); + + return 0; +} + +#ifdef BIOSPARAM +/** + * generic_NCR5380_biosparam + * @disk: disk to compute geometry for + * @dev: device identifier for this disk + * @ip: sizes to fill in + * + * Generates a BIOS / DOS compatible H-C-S mapping for the specified + * device / size. + * + * XXX Most SCSI boards use this mapping, I could be incorrect. Someone + * using hard disks on a trantor should verify that this mapping + * corresponds to that used by the BIOS / ASPI driver by running the linux + * fdisk program and matching the H_C_S coordinates to what DOS uses. + * + * Locks: none + */ + +int generic_NCR5380_biosparam(struct scsi_device *sdev, + struct block_device *bdev, sector_t capacity, int *ip) +{ + ip[0] = 64; + ip[1] = 32; + ip[2] = capacity >> 11; + return 0; +} +#endif + +#if NCR53C400_PSEUDO_DMA + +/** + * NCR5380_pread - pseudo DMA read + * @instance: adapter to read from + * @dst: buffer to read into + * @len: buffer length + * + * Perform a psuedo DMA mode read from an NCR53C400 or equivalent + * controller + */ + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) +{ + int blocks = len / 128; + int start = 0; + int bl; + + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR); + NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); + while (1) { + if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { + break; + } + if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { + printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); + return -1; + } + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY); + +#ifndef CONFIG_SCSI_G_NCR5380_MEM + { + int i; + for (i = 0; i < 128; i++) + dst[start + i] = NCR5380_read(C400_HOST_BUFFER); + } +#else + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128); +#endif + start += 128; + blocks--; + } + + if (blocks) { + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + { + // FIXME - no timeout + } + +#ifndef CONFIG_SCSI_G_NCR5380_MEM + { + int i; + for (i = 0; i < 128; i++) + dst[start + i] = NCR5380_read(C400_HOST_BUFFER); + } +#else + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128); +#endif + start += 128; + blocks--; + } + + if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) + printk("53C400r: no 53C80 gated irq after transfer"); + +#if 0 + /* + * DON'T DO THIS - THEY NEVER ARRIVE! + */ + printk("53C400r: Waiting for 53C80 registers\n"); + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG) + ; +#endif + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) + printk(KERN_ERR "53C400r: no end dma signal\n"); + + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + return 0; +} + +/** + * NCR5380_write - pseudo DMA write + * @instance: adapter to read from + * @dst: buffer to read into + * @len: buffer length + * + * Perform a psuedo DMA mode read from an NCR53C400 or equivalent + * controller + */ + +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) +{ + int blocks = len / 128; + int start = 0; + int bl; + int i; + + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); + NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); + while (1) { + if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { + printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); + return -1; + } + + if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { + break; + } + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + ; // FIXME - timeout +#ifndef CONFIG_SCSI_G_NCR5380_MEM + { + for (i = 0; i < 128; i++) + NCR5380_write(C400_HOST_BUFFER, src[start + i]); + } +#else + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128); +#endif + start += 128; + blocks--; + } + if (blocks) { + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + ; // FIXME - no timeout + +#ifndef CONFIG_SCSI_G_NCR5380_MEM + { + for (i = 0; i < 128; i++) + NCR5380_write(C400_HOST_BUFFER, src[start + i]); + } +#else + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128); +#endif + start += 128; + blocks--; + } + +#if 0 + printk("53C400w: waiting for registers to be available\n"); + THEY NEVER DO ! while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG); + printk("53C400w: Got em\n"); +#endif + + /* Let's wait for this instead - could be ugly */ + /* All documentation says to check for this. Maybe my hardware is too + * fast. Waiting for it seems to work fine! KLL + */ + while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) + ; // FIXME - no timeout + + /* + * I know. i is certainly != 0 here but the loop is new. See previous + * comment. + */ + if (i) { + if (!((i = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER)) + printk(KERN_ERR "53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n", i); + } else + printk(KERN_ERR "53C400w: no 53C80 gated irq after transfer (last block)\n"); + +#if 0 + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) { + printk(KERN_ERR "53C400w: no end dma signal\n"); + } +#endif + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) + ; // TIMEOUT + return 0; +} +#endif /* PSEUDO_DMA */ + +/* + * Include the NCR5380 core code that we build our driver around + */ + +#include "NCR5380.c" + +#define PRINTP(x) len += sprintf(buffer+len, x) +#define ANDP , + +static int sprint_opcode(char *buffer, int len, int opcode) +{ + int start = len; + PRINTP("0x%02x " ANDP opcode); + return len - start; +} + +static int sprint_command(char *buffer, int len, unsigned char *command) +{ + int i, s, start = len; + len += sprint_opcode(buffer, len, command[0]); + for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + PRINTP("%02x " ANDP command[i]); + PRINTP("\n"); + return len - start; +} + +/** + * sprintf_Scsi_Cmnd - print a scsi command + * @buffer: buffr to print into + * @len: buffer length + * @cmd: SCSI command block + * + * Print out the target and command data in hex + */ + +static int sprint_Scsi_Cmnd(char *buffer, int len, Scsi_Cmnd * cmd) +{ + int start = len; + PRINTP("host number %d destination target %d, lun %d\n" ANDP cmd->device->host->host_no ANDP cmd->device->id ANDP cmd->device->lun); + PRINTP(" command = "); + len += sprint_command(buffer, len, cmd->cmnd); + return len - start; +} + +/** + * generic_NCR5380_proc_info - /proc for NCR5380 driver + * @buffer: buffer to print into + * @start: start position + * @offset: offset into buffer + * @len: length + * @hostno: instance to affect + * @inout: read/write + * + * Provide the procfs information for the 5380 controller. We fill + * this with useful debugging information including the commands + * being executed, disconnected command queue and the statistical + * data + * + * Locks: global cli/lock for queue walk + */ + +int generic_NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +{ + int len = 0; + NCR5380_local_declare(); + unsigned long flags; + unsigned char status; + int i; + struct Scsi_Host *scsi_ptr; + Scsi_Cmnd *ptr; + struct NCR5380_hostdata *hostdata; +#ifdef NCR5380_STATS + Scsi_Device *dev; + extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; +#endif + + /* For now this is constant so we may walk it */ + scsi_ptr = scsi_host_hn_get(hostno); + + NCR5380_setup(scsi_ptr); + hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata; + + spin_lock_irqsave(scsi_ptr->host_lock, flags); + PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name); + PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE); + PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE); +#ifdef NCR53C400 + PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE); + PRINTP("NCR53C400 card%s detected\n" ANDP(((struct NCR5380_hostdata *) scsi_ptr->hostdata)->flags & FLAG_NCR53C400) ? "" : " not"); +# if NCR53C400_PSEUDO_DMA + PRINTP("NCR53C400 pseudo DMA used\n"); +# endif +#else + PRINTP("NO NCR53C400 driver extensions\n"); +#endif + PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name); + if (scsi_ptr->irq == SCSI_IRQ_NONE) + PRINTP("no interrupt\n"); + else + PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq); + +#ifdef NCR5380_STATS + if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue) + PRINTP("There are commands pending, transfer rates may be crud\n"); + if (hostdata->pendingr) + PRINTP(" %d pending reads" ANDP hostdata->pendingr); + if (hostdata->pendingw) + PRINTP(" %d pending writes" ANDP hostdata->pendingw); + if (hostdata->pendingr || hostdata->pendingw) + PRINTP("\n"); + list_for_each_entry (dev, &scsi_ptr->my_devices, siblings) { + unsigned long br = hostdata->bytes_read[dev->id]; + unsigned long bw = hostdata->bytes_write[dev->id]; + long tr = hostdata->time_read[dev->id] / HZ; + long tw = hostdata->time_write[dev->id] / HZ; + + PRINTP(" T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown"); + for (i = 0; i < 8; i++) + if (dev->vendor[i] >= 0x20) + *(buffer + (len++)) = dev->vendor[i]; + *(buffer + (len++)) = ' '; + for (i = 0; i < 16; i++) + if (dev->model[i] >= 0x20) + *(buffer + (len++)) = dev->model[i]; + *(buffer + (len++)) = ' '; + for (i = 0; i < 4; i++) + if (dev->rev[i] >= 0x20) + *(buffer + (len++)) = dev->rev[i]; + *(buffer + (len++)) = ' '; + + PRINTP("\n%10ld kb read in %5ld secs" ANDP br / 1024 ANDP tr); + if (tr) + PRINTP(" @ %5ld bps" ANDP br / tr); + + PRINTP("\n%10ld kb written in %5ld secs" ANDP bw / 1024 ANDP tw); + if (tw) + PRINTP(" @ %5ld bps" ANDP bw / tw); + PRINTP("\n"); + } +#endif + + status = NCR5380_read(STATUS_REG); + if (!(status & SR_REQ)) + PRINTP("REQ not asserted, phase unknown.\n"); + else { + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); + PRINTP("Phase %s\n" ANDP phases[i].name); + } + + if (!hostdata->connected) { + PRINTP("No currently connected command\n"); + } else { + len += sprint_Scsi_Cmnd(buffer, len, (Scsi_Cmnd *) hostdata->connected); + } + + PRINTP("issue_queue\n"); + + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + len += sprint_Scsi_Cmnd(buffer, len, ptr); + + PRINTP("disconnected_queue\n"); + + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + len += sprint_Scsi_Cmnd(buffer, len, ptr); + + *start = buffer + offset; + len -= offset; + if (len > length) + len = length; + spin_unlock_irqrestore(scsi_ptr->host_lock, flags); + return len; +} + +#undef PRINTP +#undef ANDP + +static Scsi_Host_Template driver_template = { + .proc_info = generic_NCR5380_proc_info, + .name = "Generic NCR5380/NCR53C400 Scsi Driver", + .detect = generic_NCR5380_detect, + .release = generic_NCR5380_release_resources, + .info = generic_NCR5380_info, + .queuecommand = generic_NCR5380_queue_command, + .eh_abort_handler = generic_NCR5380_abort, + .eh_bus_reset_handler = generic_NCR5380_bus_reset, + .eh_device_reset_handler = generic_NCR5380_device_reset, + .eh_host_reset_handler = generic_NCR5380_host_reset, + .bios_param = NCR5380_BIOSPARAM, + .can_queue = CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = CMD_PER_LUN, + .use_clustering = DISABLE_CLUSTERING, +}; +#include +#include "scsi_module.c" + +MODULE_PARM(ncr_irq, "i"); +MODULE_PARM(ncr_dma, "i"); +MODULE_PARM(ncr_addr, "i"); +MODULE_PARM(ncr_5380, "i"); +MODULE_PARM(ncr_53c400, "i"); +MODULE_PARM(ncr_53c400a, "i"); +MODULE_PARM(dtc_3181e, "i"); +MODULE_LICENSE("GPL"); + + +static struct isapnp_device_id id_table[] __devinitdata = { + { + ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), + 0}, + {0} +}; + +MODULE_DEVICE_TABLE(isapnp, id_table); + + +__setup("ncr5380=", do_NCR5380_setup); +__setup("ncr53c400=", do_NCR53C400_setup); +__setup("ncr53c400a=", do_NCR53C400A_setup); +__setup("dtc3181e=", do_DTC3181E_setup); diff --git a/demos/demo_rule9/g_NCR5380.res b/demos/demo_rule9/g_NCR5380.res new file mode 100644 index 0000000..5fcc2d9 --- /dev/null +++ b/demos/demo_rule9/g_NCR5380.res @@ -0,0 +1,938 @@ +/* + * Generic Generic NCR5380 driver + * + * Copyright 1993, Drew Eckhardt + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@colorado.edu + * +1 (303) 440-4894 + * + * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin + * K.Lentin@cs.monash.edu.au + * + * NCR53C400A extensions (c) 1996, Ingmar Baumgart + * ingmar@gonzo.schwaben.de + * + * DTC3181E extensions (c) 1997, Ronald van Cuijlenborg + * ronald.van.cuijlenborg@tip.nl or nutty@dds.nl + * + * Added ISAPNP support for DTC436 adapters, + * Thomas Sailer, sailer@ife.ee.ethz.ch + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * TODO : flesh out DMA support, find some one actually using this (I have + * a memory mapped Trantor board that works fine) + */ + +/* + * Options : + * + * PARITY - enable parity checking. Not supported. + * + * SCSI2 - enable support for SCSI-II tagged queueing. Untested. + * + * USLEEP - enable support for devices that don't disconnect. Untested. + * + * The card is detected and initialized in one of several ways : + * 1. With command line overrides - NCR5380=port,irq may be + * used on the LILO command line to override the defaults. + * + * 2. With the GENERIC_NCR5380_OVERRIDE compile time define. This is + * specified as an array of address, irq, dma, board tuples. Ie, for + * one board at 0x350, IRQ5, no dma, I could say + * -DGENERIC_NCR5380_OVERRIDE={{0xcc000, 5, DMA_NONE, BOARD_NCR5380}} + * + * -1 should be specified for no or DMA interrupt, -2 to autoprobe for an + * IRQ line if overridden on the command line. + * + * 3. When included as a module, with arguments passed on the command line: + * ncr_irq=xx the interrupt + * ncr_addr=xx the port or base address (for port or memory + * mapped, resp.) + * ncr_dma=xx the DMA + * ncr_5380=1 to set up for a NCR5380 board + * ncr_53c400=1 to set up for a NCR53C400 board + * e.g. + * modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_5380=1 + * for a port mapped NCR5380 board or + * modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1 + * for a memory mapped NCR53C400 board with interrupts disabled. + * + * 255 should be specified for no or DMA interrupt, 254 to autoprobe for an + * IRQ line if overridden on the command line. + * + */ + +/* + * $Log: g_NCR5380.res,v $ + * Revision 1.1 2007/11/01 09:43:07 julia + * *** empty log message *** + * + * Revision 1.1.1.1 2007/03/28 16:38:53 pad + * your commit message + * + * Revision 1.1 2006/09/20 01:30:53 pad + * new files + * + */ + +/* settings for DTC3181E card with only Mustek scanner attached */ +#define USLEEP +#define USLEEP_POLL 1 +#define USLEEP_SLEEP 20 +#define USLEEP_WAITLONG 500 + +#define AUTOPROBE_IRQ +#define AUTOSENSE + +#include + +#ifdef CONFIG_SCSI_GENERIC_NCR53C400 +#define NCR53C400_PSEUDO_DMA 1 +#define PSEUDO_DMA +#define NCR53C400 +#define NCR5380_STATS +#undef NCR5380_STAT_LIMIT +#endif + +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" +#include "g_NCR5380.h" +#include "NCR5380.h" +#include +#include +#include +#include +#include +#include + +#define NCR_NOT_SET 0 +static int ncr_irq = NCR_NOT_SET; +static int ncr_dma = NCR_NOT_SET; +static int ncr_addr = NCR_NOT_SET; +static int ncr_5380 = NCR_NOT_SET; +static int ncr_53c400 = NCR_NOT_SET; +static int ncr_53c400a = NCR_NOT_SET; +static int dtc_3181e = NCR_NOT_SET; + +static struct override { + NCR5380_implementation_fields; + int irq; + int dma; + int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ +} overrides +#ifdef GENERIC_NCR5380_OVERRIDE +[] __initdata = GENERIC_NCR5380_OVERRIDE; +#else +[1] __initdata = { { 0,},}; +#endif + + +#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) + +#ifndef MODULE + +/** + * internal_setup - handle lilo command string override + * @board: BOARD_* identifier for the board + * @str: unused + * @ints: numeric parameters + * + * Do LILO command line initialization of the overrides array. Display + * errors when needed + * + * Locks: none + */ + +static void __init internal_setup(int board, char *str, int *ints) +{ + static int commandline_current = 0; + switch (board) { + case BOARD_NCR5380: + if (ints[0] != 2 && ints[0] != 3) { + printk(KERN_ERR "generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n"); + return; + } + break; + case BOARD_NCR53C400: + if (ints[0] != 2) { + printk(KERN_ERR "generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + case BOARD_NCR53C400A: + if (ints[0] != 2) { + printk(KERN_ERR "generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + case BOARD_DTC3181E: + if (ints[0] != 2) { + printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + } + + if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type) ints[1]; + overrides[commandline_current].irq = ints[2]; + if (ints[0] == 3) + overrides[commandline_current].dma = ints[3]; + else + overrides[commandline_current].dma = DMA_NONE; + overrides[commandline_current].board = board; + ++commandline_current; + } +} + + +/** + * do_NCR53C80_setup - set up entry point + * @str: unused + * + * Setup function invoked at boot to parse the ncr5380= command + * line. + */ + +static int __init do_NCR5380_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR5380, str, ints); + return 1; +} + +/** + * do_NCR53C400_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code + * + * Setup function invoked at boot to parse the ncr53c400= command + * line. + */ + +static int __init do_NCR53C400_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR53C400, str, ints); + return 1; +} + +/** + * do_NCR53C400A_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code + * + * Setup function invoked at boot to parse the ncr53c400a= command + * line. + */ + +static int __init do_NCR53C400A_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR53C400A, str, ints); + return 1; +} + +/** + * do_DTC3181E_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code + * + * Setup function invoked at boot to parse the dtc3181e= command + * line. + */ + +static int __init do_DTC3181E_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_DTC3181E, str, ints); + return 1; +} + +#endif + +/** + * generic_NCR5380_detect - look for NCR5380 controllers + * @tpnt: the scsi template + * + * Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E + * and DTC436(ISAPnP) controllers. If overrides have been set we use + * them. + * + * The caller supplied NCR5380_init function is invoked from here, before + * the interrupt line is taken. + * + * Locks: none + */ + +int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt) +{ + static int current_override = 0; + int count, i; + unsigned int *ports; + static unsigned int __initdata ncr_53c400a_ports[] = { + 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 + }; + static unsigned int __initdata dtc_3181e_ports[] = { + 0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0 + }; + int flags = 0; + struct Scsi_Host *instance; + + if (ncr_irq != NCR_NOT_SET) + overrides[0].irq = ncr_irq; + if (ncr_dma != NCR_NOT_SET) + overrides[0].dma = ncr_dma; + if (ncr_addr != NCR_NOT_SET) + overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr; + if (ncr_5380 != NCR_NOT_SET) + overrides[0].board = BOARD_NCR5380; + else if (ncr_53c400 != NCR_NOT_SET) + overrides[0].board = BOARD_NCR53C400; + else if (ncr_53c400a != NCR_NOT_SET) + overrides[0].board = BOARD_NCR53C400A; + else if (dtc_3181e != NCR_NOT_SET) + overrides[0].board = BOARD_DTC3181E; + + if (!current_override && isapnp_present()) { + struct pnp_dev *dev = NULL; + count = 0; + while ((dev = pnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) { + if (count >= NO_OVERRIDES) + break; + if (pnp_device_attach(dev) < 0) { + printk(KERN_ERR "dtc436e probe: attach failed\n"); + continue; + } + if (pnp_activate_dev(dev) < 0) { + printk(KERN_ERR "dtc436e probe: activate failed\n"); + pnp_device_detach(dev); + continue; + } + if (!pnp_port_valid(dev, 0)) { + printk(KERN_ERR "dtc436e probe: no valid port\n"); + pnp_device_detach(dev); + continue; + } + if (pnp_irq_valid(dev, 0)) + overrides[count].irq = pnp_irq(dev, 0); + else + overrides[count].irq = SCSI_IRQ_NONE; + if (pnp_dma_valid(dev, 0)) + overrides[count].dma = pnp_dma(dev, 0); + else + overrides[count].dma = DMA_NONE; + overrides[count].NCR5380_map_name = (NCR5380_map_type) pnp_port_start(dev, 0); + overrides[count].board = BOARD_DTC3181E; + count++; + } + } + + tpnt->proc_name = "g_NCR5380"; + + for (count = 0; current_override < NO_OVERRIDES; ++current_override) { + if (!(overrides[current_override].NCR5380_map_name)) + continue; + + ports = 0; + switch (overrides[current_override].board) { + case BOARD_NCR5380: + flags = FLAG_NO_PSEUDO_DMA; + break; + case BOARD_NCR53C400: + flags = FLAG_NCR53C400; + break; + case BOARD_NCR53C400A: + flags = FLAG_NO_PSEUDO_DMA; + ports = ncr_53c400a_ports; + break; + case BOARD_DTC3181E: + flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E; + ports = dtc_3181e_ports; + break; + } + +#ifndef CONFIG_SCSI_G_NCR5380_MEM + if (ports) { + /* wakeup sequence for the NCR53C400A and DTC3181E */ + + /* Disable the adapter and look for a free io port */ + outb(0x59, 0x779); + outb(0xb9, 0x379); + outb(0xc5, 0x379); + outb(0xae, 0x379); + outb(0xa6, 0x379); + outb(0x00, 0x379); + + if (overrides[current_override].NCR5380_map_name != PORT_AUTO) + for (i = 0; ports[i]; i++) { + if (overrides[current_override].NCR5380_map_name == ports[i]) + break; + } else + for (i = 0; ports[i]; i++) { + if ((!check_region(ports[i], 16)) && (inb(ports[i]) == 0xff)) + break; + } + if (ports[i]) { + outb(0x59, 0x779); + outb(0xb9, 0x379); + outb(0xc5, 0x379); + outb(0xae, 0x379); + outb(0xa6, 0x379); + outb(0x80 | i, 0x379); /* set io port to be used */ + outb(0xc0, ports[i] + 9); + if (inb(ports[i] + 9) != 0x80) + continue; + else + overrides[current_override].NCR5380_map_name = ports[i]; + } else + continue; + } + + request_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"); +#else + if (check_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size)) + continue; + request_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"); +#endif + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) { +#ifndef CONFIG_SCSI_G_NCR5380_MEM + release_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size); +#else + release_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size); +#endif + continue; + } + + instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name; + + NCR5380_init(instance, flags); + + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, 0xffff); + + if (instance->irq != SCSI_IRQ_NONE) + if (request_irq(instance->irq, generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = SCSI_IRQ_NONE; + } + + if (instance->irq == SCSI_IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + } + + printk(KERN_INFO "scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int) instance->NCR5380_instance_name); + if (instance->irq == SCSI_IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); + + ++current_override; + ++count; + } + return count; +} + +/** + * generic_NCR5380_info - reporting string + * @host: NCR5380 to report on + * + * Report driver information for the NCR5380 + */ + +const char *generic_NCR5380_info(struct Scsi_Host *host) +{ + static const char string[] = "Generic NCR5380/53C400 Driver"; + return string; +} + +/** + * generic_NCR5380_release_resources - free resources + * @instance: host adapter to clean up + * + * Free the generic interface resources from this adapter. + * + * Locks: none + */ + +int generic_NCR5380_release_resources(struct Scsi_Host *instance) +{ + NCR5380_local_declare(); + NCR5380_setup(instance); + +#ifndef CONFIG_SCSI_G_NCR5380_MEM + release_region(instance->NCR5380_instance_name, NCR5380_region_size); +#else + release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); +#endif + + if (instance->irq != SCSI_IRQ_NONE) + free_irq(instance->irq, NULL); + + return 0; +} + +#ifdef BIOSPARAM +/** + * generic_NCR5380_biosparam + * @disk: disk to compute geometry for + * @dev: device identifier for this disk + * @ip: sizes to fill in + * + * Generates a BIOS / DOS compatible H-C-S mapping for the specified + * device / size. + * + * XXX Most SCSI boards use this mapping, I could be incorrect. Someone + * using hard disks on a trantor should verify that this mapping + * corresponds to that used by the BIOS / ASPI driver by running the linux + * fdisk program and matching the H_C_S coordinates to what DOS uses. + * + * Locks: none + */ + +int generic_NCR5380_biosparam(struct scsi_device *sdev, + struct block_device *bdev, sector_t capacity, int *ip) +{ + ip[0] = 64; + ip[1] = 32; + ip[2] = capacity >> 11; + return 0; +} +#endif + +#if NCR53C400_PSEUDO_DMA + +/** + * NCR5380_pread - pseudo DMA read + * @instance: adapter to read from + * @dst: buffer to read into + * @len: buffer length + * + * Perform a psuedo DMA mode read from an NCR53C400 or equivalent + * controller + */ + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) +{ + int blocks = len / 128; + int start = 0; + int bl; + + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR); + NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); + while (1) { + if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { + break; + } + if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { + printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); + return -1; + } + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY); + +#ifndef CONFIG_SCSI_G_NCR5380_MEM + { + int i; + for (i = 0; i < 128; i++) + dst[start + i] = NCR5380_read(C400_HOST_BUFFER); + } +#else + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128); +#endif + start += 128; + blocks--; + } + + if (blocks) { + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + { + // FIXME - no timeout + } + +#ifndef CONFIG_SCSI_G_NCR5380_MEM + { + int i; + for (i = 0; i < 128; i++) + dst[start + i] = NCR5380_read(C400_HOST_BUFFER); + } +#else + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128); +#endif + start += 128; + blocks--; + } + + if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) + printk("53C400r: no 53C80 gated irq after transfer"); + +#if 0 + /* + * DON'T DO THIS - THEY NEVER ARRIVE! + */ + printk("53C400r: Waiting for 53C80 registers\n"); + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG) + ; +#endif + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) + printk(KERN_ERR "53C400r: no end dma signal\n"); + + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + return 0; +} + +/** + * NCR5380_write - pseudo DMA write + * @instance: adapter to read from + * @dst: buffer to read into + * @len: buffer length + * + * Perform a psuedo DMA mode read from an NCR53C400 or equivalent + * controller + */ + +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) +{ + int blocks = len / 128; + int start = 0; + int bl; + int i; + + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); + NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); + while (1) { + if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { + printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); + return -1; + } + + if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { + break; + } + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + ; // FIXME - timeout +#ifndef CONFIG_SCSI_G_NCR5380_MEM + { + for (i = 0; i < 128; i++) + NCR5380_write(C400_HOST_BUFFER, src[start + i]); + } +#else + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128); +#endif + start += 128; + blocks--; + } + if (blocks) { + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + ; // FIXME - no timeout + +#ifndef CONFIG_SCSI_G_NCR5380_MEM + { + for (i = 0; i < 128; i++) + NCR5380_write(C400_HOST_BUFFER, src[start + i]); + } +#else + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128); +#endif + start += 128; + blocks--; + } + +#if 0 + printk("53C400w: waiting for registers to be available\n"); + THEY NEVER DO ! while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG); + printk("53C400w: Got em\n"); +#endif + + /* Let's wait for this instead - could be ugly */ + /* All documentation says to check for this. Maybe my hardware is too + * fast. Waiting for it seems to work fine! KLL + */ + while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) + ; // FIXME - no timeout + + /* + * I know. i is certainly != 0 here but the loop is new. See previous + * comment. + */ + if (i) { + if (!((i = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER)) + printk(KERN_ERR "53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n", i); + } else + printk(KERN_ERR "53C400w: no 53C80 gated irq after transfer (last block)\n"); + +#if 0 + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) { + printk(KERN_ERR "53C400w: no end dma signal\n"); + } +#endif + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) + ; // TIMEOUT + return 0; +} +#endif /* PSEUDO_DMA */ + +/* + * Include the NCR5380 core code that we build our driver around + */ + +#include "NCR5380.c" + +#define PRINTP(x) len += sprintf(buffer+len, x) +#define ANDP , + +static int sprint_opcode(char *buffer, int len, int opcode) +{ + int start = len; + PRINTP("0x%02x " ANDP opcode); + return len - start; +} + +static int sprint_command(char *buffer, int len, unsigned char *command) +{ + int i, s, start = len; + len += sprint_opcode(buffer, len, command[0]); + for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + PRINTP("%02x " ANDP command[i]); + PRINTP("\n"); + return len - start; +} + +/** + * sprintf_Scsi_Cmnd - print a scsi command + * @buffer: buffr to print into + * @len: buffer length + * @cmd: SCSI command block + * + * Print out the target and command data in hex + */ + +static int sprint_Scsi_Cmnd(char *buffer, int len, Scsi_Cmnd * cmd) +{ + int start = len; + PRINTP("host number %d destination target %d, lun %d\n" ANDP cmd->device->host->host_no ANDP cmd->device->id ANDP cmd->device->lun); + PRINTP(" command = "); + len += sprint_command(buffer, len, cmd->cmnd); + return len - start; +} + +/** + * generic_NCR5380_proc_info - /proc for NCR5380 driver + * @buffer: buffer to print into + * @start: start position + * @offset: offset into buffer + * @len: length + * @hostno: instance to affect + * @inout: read/write + * + * Provide the procfs information for the 5380 controller. We fill + * this with useful debugging information including the commands + * being executed, disconnected command queue and the statistical + * data + * + * Locks: global cli/lock for queue walk + */ + +int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, char **start, off_t offset, int length, int inout) +{ + int len = 0; + NCR5380_local_declare(); + unsigned long flags; + unsigned char status; + int i; + Scsi_Cmnd *ptr; + struct NCR5380_hostdata *hostdata; +#ifdef NCR5380_STATS + Scsi_Device *dev; + extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; +#endif + + NCR5380_setup(scsi_ptr); + hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata; + + spin_lock_irqsave(scsi_ptr->host_lock, flags); + PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name); + PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE); + PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE); +#ifdef NCR53C400 + PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE); + PRINTP("NCR53C400 card%s detected\n" ANDP(((struct NCR5380_hostdata *) scsi_ptr->hostdata)->flags & FLAG_NCR53C400) ? "" : " not"); +# if NCR53C400_PSEUDO_DMA + PRINTP("NCR53C400 pseudo DMA used\n"); +# endif +#else + PRINTP("NO NCR53C400 driver extensions\n"); +#endif + PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name); + if (scsi_ptr->irq == SCSI_IRQ_NONE) + PRINTP("no interrupt\n"); + else + PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq); + +#ifdef NCR5380_STATS + if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue) + PRINTP("There are commands pending, transfer rates may be crud\n"); + if (hostdata->pendingr) + PRINTP(" %d pending reads" ANDP hostdata->pendingr); + if (hostdata->pendingw) + PRINTP(" %d pending writes" ANDP hostdata->pendingw); + if (hostdata->pendingr || hostdata->pendingw) + PRINTP("\n"); + list_for_each_entry (dev, &scsi_ptr->my_devices, siblings) { + unsigned long br = hostdata->bytes_read[dev->id]; + unsigned long bw = hostdata->bytes_write[dev->id]; + long tr = hostdata->time_read[dev->id] / HZ; + long tw = hostdata->time_write[dev->id] / HZ; + + PRINTP(" T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown"); + for (i = 0; i < 8; i++) + if (dev->vendor[i] >= 0x20) + *(buffer + (len++)) = dev->vendor[i]; + *(buffer + (len++)) = ' '; + for (i = 0; i < 16; i++) + if (dev->model[i] >= 0x20) + *(buffer + (len++)) = dev->model[i]; + *(buffer + (len++)) = ' '; + for (i = 0; i < 4; i++) + if (dev->rev[i] >= 0x20) + *(buffer + (len++)) = dev->rev[i]; + *(buffer + (len++)) = ' '; + + PRINTP("\n%10ld kb read in %5ld secs" ANDP br / 1024 ANDP tr); + if (tr) + PRINTP(" @ %5ld bps" ANDP br / tr); + + PRINTP("\n%10ld kb written in %5ld secs" ANDP bw / 1024 ANDP tw); + if (tw) + PRINTP(" @ %5ld bps" ANDP bw / tw); + PRINTP("\n"); + } +#endif + + status = NCR5380_read(STATUS_REG); + if (!(status & SR_REQ)) + PRINTP("REQ not asserted, phase unknown.\n"); + else { + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); + PRINTP("Phase %s\n" ANDP phases[i].name); + } + + if (!hostdata->connected) { + PRINTP("No currently connected command\n"); + } else { + len += sprint_Scsi_Cmnd(buffer, len, (Scsi_Cmnd *) hostdata->connected); + } + + PRINTP("issue_queue\n"); + + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + len += sprint_Scsi_Cmnd(buffer, len, ptr); + + PRINTP("disconnected_queue\n"); + + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + len += sprint_Scsi_Cmnd(buffer, len, ptr); + + *start = buffer + offset; + len -= offset; + if (len > length) + len = length; + spin_unlock_irqrestore(scsi_ptr->host_lock, flags); + return len; +} + +#undef PRINTP +#undef ANDP + +static Scsi_Host_Template driver_template = { + .proc_info = generic_NCR5380_proc_info, + .name = "Generic NCR5380/NCR53C400 Scsi Driver", + .detect = generic_NCR5380_detect, + .release = generic_NCR5380_release_resources, + .info = generic_NCR5380_info, + .queuecommand = generic_NCR5380_queue_command, + .eh_abort_handler = generic_NCR5380_abort, + .eh_bus_reset_handler = generic_NCR5380_bus_reset, + .eh_device_reset_handler = generic_NCR5380_device_reset, + .eh_host_reset_handler = generic_NCR5380_host_reset, + .bios_param = NCR5380_BIOSPARAM, + .can_queue = CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = CMD_PER_LUN, + .use_clustering = DISABLE_CLUSTERING, +}; +#include +#include "scsi_module.c" + +MODULE_PARM(ncr_irq, "i"); +MODULE_PARM(ncr_dma, "i"); +MODULE_PARM(ncr_addr, "i"); +MODULE_PARM(ncr_5380, "i"); +MODULE_PARM(ncr_53c400, "i"); +MODULE_PARM(ncr_53c400a, "i"); +MODULE_PARM(dtc_3181e, "i"); +MODULE_LICENSE("GPL"); + + +static struct isapnp_device_id id_table[] __devinitdata = { + { + ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), + 0}, + {0} +}; + +MODULE_DEVICE_TABLE(isapnp, id_table); + + +__setup("ncr5380=", do_NCR5380_setup); +__setup("ncr53c400=", do_NCR53C400_setup); +__setup("ncr53c400a=", do_NCR53C400A_setup); +__setup("dtc3181e=", do_DTC3181E_setup); diff --git a/demos/demo_rule9/nsp_cs.c b/demos/demo_rule9/nsp_cs.c new file mode 100644 index 0000000..7858fe6 --- /dev/null +++ b/demos/demo_rule9/nsp_cs.c @@ -0,0 +1,1958 @@ +/*====================================================================== + + NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver + By: YOKOTA Hiroshi + + Ver.2.8 Support 32bit MMIO mode + Support Synchronous Data TRansfer (SDTR) mode + Ver.2.0 Support 32bit PIO mode + Ver.1.1.2 Fix for scatter list buffer exceeds + Ver.1.1 Support scatter list + Ver.0.1 Initial version + + This software may be used and distributed according to the terms of + the GNU General Public License. + +======================================================================*/ + +/*********************************************************************** + This driver is for these PCcards. + + I-O DATA PCSC-F (Workbit NinjaSCSI-3) + "WBT", "NinjaSCSI-3", "R1.0" + I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode) + "IO DATA", "CBSC16 ", "1" + +***********************************************************************/ + +/* */ + +#ifdef NSP_KERNEL_2_2 +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "scsi.h" +#include "hosts.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "nsp_cs.h" + +MODULE_AUTHOR("YOKOTA Hiroshi "); +MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.1 $"); +MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +MODULE_PARM_DESC(pc_debug, "set debug level"); +static char *version = ""; +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#else +#define DEBUG(n, args...) /* */ +#endif + +#include "nsp_io.h" + +/*====================================================================*/ + +typedef struct scsi_info_t { + dev_link_t link; + dev_node_t node; + struct Scsi_Host *host; + int stop; +} scsi_info_t; + + +/*----------------------------------------------------------------*/ + +#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE) +#define PROC_SCSI_NSP PROC_SCSI_IBMMCA /* bad hack... */ +static struct proc_dir_entry proc_scsi_nsp = { + PROC_SCSI_NSP, 6, "nsp_cs", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +#endif + +/*====================================================================*/ +/* Parameters that can be set with 'insmod' */ + +static unsigned int irq_mask = 0xffff; +MODULE_PARM(irq_mask, "i"); +MODULE_PARM_DESC(irq_mask, "IRQ mask bits (default: 0xffff)"); + +static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM_DESC(irq_list, "Use specified IRQ number. (default: auto select)"); + +static int nsp_burst_mode = 2; +MODULE_PARM(nsp_burst_mode, "i"); +MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))"); + +/* Release IO ports after configuration? */ +static int free_ports = 0; +MODULE_PARM(free_ports, "i"); +MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))"); + +/* /usr/src/linux/drivers/scsi/hosts.h */ +static Scsi_Host_Template nsp_driver_template = { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) + .proc_name = "nsp_cs", /* kernel 2.4 */ +#else + .proc_dir = &proc_scsi_nsp, /* kernel 2.2 */ +#endif + .proc_info = nsp_proc_info, + .name = "WorkBit NinjaSCSI-3/32Bi(16bit)", +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + .detect = nsp_detect, + .release = nsp_release, +#endif + .info = nsp_info, + .queuecommand = nsp_queuecommand, +/* .eh_strategy_handler = nsp_eh_strategy,*/ +/* .eh_abort_handler = nsp_eh_abort,*/ +/* .eh_device_reset_handler = nsp_eh_device_reset,*/ + .eh_bus_reset_handler = nsp_eh_bus_reset, + .eh_host_reset_handler = nsp_eh_host_reset, + .can_queue = 1, + .this_id = NSP_INITIATOR_ID, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2)) + .use_new_eh_code = 1, +#endif +}; + +static dev_link_t *dev_list = NULL; +static dev_info_t dev_info = {"nsp_cs"}; + +static nsp_hw_data nsp_data; + +/***********************************************************/ + +static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ +#ifdef PCMCIA_DEBUG + /*unsigned int host_id = SCpnt->host->this_id;*/ + /*unsigned int base = SCpnt->host->io_port;*/ + unsigned char target = SCpnt->target; +#endif + nsp_hw_data *data = &nsp_data; + + DEBUG(0, "%s: SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n", + __FUNCTION__, SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg); + //DEBUG(0, " before CurrentSC=0x%p\n", data->CurrentSC); + + if(data->CurrentSC != NULL) { + printk(KERN_DEBUG " %s: CurrentSC!=NULL this can't be happen\n", __FUNCTION__); + data->CurrentSC = NULL; + SCpnt->result = DID_BAD_TARGET << 16; + done(SCpnt); + return -1; + } + + show_command(SCpnt); + + SCpnt->scsi_done = done; + data->CurrentSC = SCpnt; + + SCpnt->SCp.Status = CHECK_CONDITION; + SCpnt->SCp.Message = 0; + SCpnt->SCp.have_data_in = IO_UNKNOWN; + SCpnt->SCp.sent_command = 0; + SCpnt->SCp.phase = PH_UNDETERMINED; + RESID = SCpnt->request_bufflen; + + /* setup scratch area + SCp.ptr : buffer pointer + SCp.this_residual : buffer length + SCp.buffer : next buffer + SCp.buffers_residual : left buffers in list + SCp.phase : current state of the command */ + if (SCpnt->use_sg) { + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + SCpnt->SCp.ptr = BUFFER_ADDR; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + } else { + SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + } + + if(nsphw_start_selection(SCpnt, data) == FALSE) { + DEBUG(0, " selection fail\n"); + data->CurrentSC = NULL; + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return -1; + } + + + //DEBUG(0, "%s: out\n", __FUNCTION__); + return 0; +} + +/* + * setup PIO FIFO transfer mode and enable/disable to data out + */ +static void nsp_setup_fifo(nsp_hw_data *data, int enabled) +{ + unsigned int base = data->BaseAddress; + unsigned char transfer_mode_reg; + + //DEBUG(0, "%s: enabled=%d\n", __FUNCTION__, enabled); + + if (enabled != FALSE) { + transfer_mode_reg = TRANSFER_GO | BRAIND; + } else { + transfer_mode_reg = 0; + } + + transfer_mode_reg |= data->TransferMode; + + nsp_index_write(base, TRANSFERMODE, transfer_mode_reg); +} + +static void nsphw_init_sync(nsp_hw_data *data) +{ + sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET, + .SyncPeriod = 0, + .SyncOffset = 0 + }; + int i; + + /* setup sync data */ + for ( i = 0; i < NUMBER(data->Sync); i++ ) { + data->Sync[i] = tmp_sync; + } +} + +/* + * Initialize Ninja hardware + */ +static int nsphw_init(nsp_hw_data *data) +{ + unsigned int base = data->BaseAddress; + + DEBUG(0, "%s: in base=0x%x\n", __FUNCTION__, base); + + data->ScsiClockDiv = CLOCK_40M | FAST_20; + data->CurrentSC = NULL; + data->FifoCount = 0; + data->TransferMode = MODE_IO8; + + nsphw_init_sync(data); + + /* block all interrupts */ + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); + + /* setup SCSI interface */ + nsp_write(base, IFSELECT, IF_IFSEL); + + nsp_index_write(base, SCSIIRQMODE, 0); + + nsp_index_write(base, TRANSFERMODE, MODE_IO8); + nsp_index_write(base, CLOCKDIV, data->ScsiClockDiv); + + nsp_index_write(base, PARITYCTRL, 0); + nsp_index_write(base, POINTERCLR, POINTER_CLEAR | + ACK_COUNTER_CLEAR | + REQ_COUNTER_CLEAR | + HOST_COUNTER_CLEAR); + + /* setup fifo asic */ + nsp_write(base, IFSELECT, IF_REGSEL); + nsp_index_write(base, TERMPWRCTRL, 0); + if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) { + printk(KERN_INFO "nsp_cs: terminator power on\n"); + nsp_index_write(base, TERMPWRCTRL, POWER_ON); + } + + nsp_index_write(base, TIMERCOUNT, 0); + nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */ + + nsp_index_write(base, SYNCREG, 0); + nsp_index_write(base, ACKWIDTH, 0); + + /* enable interrupts and ack them */ + nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI | + RESELECT_EI | + SCSI_RESET_IRQ_EI ); + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); + + nsp_setup_fifo(data, FALSE); + + return TRUE; +} + +/* + * Start selection phase + */ +static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt, + nsp_hw_data *data) +{ + unsigned int host_id = SCpnt->device->host->this_id; + unsigned int base = SCpnt->device->host->io_port; + unsigned char target = SCpnt->device->id; + int time_out; + unsigned char phase, arbit; + + //DEBUG(0, "%s:in\n", __FUNCTION__); + + phase = nsp_index_read(base, SCSIBUSMON); + if(phase != BUSMON_BUS_FREE) { + //DEBUG(0, " bus busy\n"); + return FALSE; + } + + /* start arbitration */ + //DEBUG(0, " start arbit\n"); + SCpnt->SCp.phase = PH_ARBSTART; + nsp_index_write(base, SETARBIT, ARBIT_GO); + + time_out = 1000; + do { + /* XXX: what a stupid chip! */ + arbit = nsp_index_read(base, ARBITSTATUS); + //DEBUG(0, " arbit=%d, wait_count=%d\n", arbit, wait_count); + udelay(1); /* hold 1.2us */ + } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 && + (time_out-- != 0)); + + if((arbit & ARBIT_WIN) == 0) { + //DEBUG(0, " arbit fail\n"); + nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); + return FALSE; + } + + /* assert select line */ + //DEBUG(0, " assert SEL line\n"); + SCpnt->SCp.phase = PH_SELSTART; + udelay(3); + nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target)); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN); + udelay(3); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN); + nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); + udelay(3); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN); + + /* check selection timeout */ + nsp_start_timer(SCpnt, data, 1000/51); + data->SelectionTimeOut = 1; + + return TRUE; +} + +struct nsp_sync_table { + unsigned int min_period; + unsigned int max_period; + unsigned int chip_period; + unsigned int ack_width; +}; + +static struct nsp_sync_table nsp_sync_table_40M[] = { + {0x0c,0x0c,0x1,0}, /* 20MB 50ns*/ + {0x19,0x19,0x3,1}, /* 10MB 100ns*/ + {0x1a,0x25,0x5,2}, /* 7.5MB 150ns*/ + {0x26,0x32,0x7,3}, /* 5MB 200ns*/ + {0x0, 0, 0, 0} +}; + +static struct nsp_sync_table nsp_sync_table_20M[] = { + {0x19,0x19,0x1,0}, /* 10MB 100ns*/ + {0x1a,0x25,0x2,0}, /* 7.5MB 150ns*/ + {0x26,0x32,0x3,1}, /* 5MB 200ns*/ + {0x0, 0, 0, 0} +}; + +/* + * setup synchronous data transfer mode + */ +static int nsp_msg(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned char target = SCpnt->device->id; +// unsigned char lun = SCpnt->lun; + sync_data *sync = &(data->Sync[target]); + struct nsp_sync_table *sync_table; + unsigned int period, offset; + int i; + + + DEBUG(0, "%s:\n", __FUNCTION__); + + period = sync->SyncPeriod; + offset = sync->SyncOffset; + + DEBUG(0, " period=0x%x, offset=0x%x\n", period, offset); + + if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) { + sync_table = &nsp_sync_table_20M[0]; + } else { + sync_table = &nsp_sync_table_40M[0]; + } + + for ( i = 0; sync_table->max_period != 0; i++, sync_table++) { + if ( period >= sync_table->min_period && + period <= sync_table->max_period ) { + break; + } + } + + if (period != 0 && sync_table->max_period == 0) { + /* + * No proper period/offset found + */ + DEBUG(0, " no proper period/offset\n"); + + sync->SyncPeriod = 0; + sync->SyncOffset = 0; + sync->SyncRegister = 0; + sync->AckWidth = 0; + + return FALSE; + } + + sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) | + (offset & SYNCREG_OFFSET_MASK); + sync->AckWidth = sync_table->ack_width; + + DEBUG(0, " sync_reg=0x%x, ack_width=0x%x\n", sync->SyncRegister, sync->AckWidth); + + return TRUE; +} + + +/* + * start ninja hardware timer + */ +static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time) +{ + unsigned int base = SCpnt->device->host->io_port; + + //DEBUG(0, "%s: in SCpnt=0x%p, time=%d\n", __FUNCTION__, SCpnt, time); + data->TimerCount = time; + nsp_index_write(base, TIMERCOUNT, time); +} + +/* + * wait for bus phase change + */ +static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str) +{ + unsigned int base = SCpnt->device->host->io_port; + unsigned char reg; + int time_out; + + //DEBUG(0, "%s:\n", __FUNCTION__); + + time_out = 100; + + do { + reg = nsp_index_read(base, SCSIBUSMON); + if (reg == 0xff) { + break; + } + } while ((time_out-- != 0) && (reg & mask) != 0); + + if (time_out == 0) { + printk(KERN_DEBUG "%s:: %s signal off timeut\n", __FUNCTION__, str); + } + + return 0; +} + +/* + * expect Ninja Irq + */ +static int nsp_expect_signal(Scsi_Cmnd *SCpnt, + unsigned char current_phase, + unsigned char mask) +{ + unsigned int base = SCpnt->device->host->io_port; + int time_out; + unsigned char phase, i_src; + + //DEBUG(0, "%s: current_phase=0x%x, mask=0x%x\n", __FUNCTION__, current_phase, mask); + + time_out = 100; + do { + phase = nsp_index_read(base, SCSIBUSMON); + if (phase == 0xff) { + //DEBUG(0, " ret -1\n"); + return -1; + } + i_src = nsp_read(base, IRQSTATUS); + if (i_src & IRQSTATUS_SCSI) { + //DEBUG(0, " ret 0 found scsi signal\n"); + return 0; + } + if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) { + //DEBUG(0, " ret 1 phase=0x%x\n", phase); + return 1; + } + } while(time_out-- != 0); + + //DEBUG(0, "%s: timeout\n", __FUNCTION__); + return -1; +} + +/* + * transfer SCSI message + */ +static int nsp_xfer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int phase) +{ + unsigned int base = SCpnt->device->host->io_port; + char *buf = data->MsgBuffer; + int len = MIN(MSGBUF_SIZE, data->MsgLen); + int ptr; + int ret; + + //DEBUG(0, "%s:\n", __FUNCTION__); + for (ptr = 0; len > 0; len --, ptr ++) { + + ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ); + if (ret <= 0) { + DEBUG(0, " xfer quit\n"); + return 0; + } + + /* if last byte, negate ATN */ + if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) { + nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB); + } + + /* read & write message */ + if (phase & BUSMON_IO) { + DEBUG(0, " read msg\n"); + buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK); + } else { + DEBUG(0, " write msg\n"); + nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]); + } + nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer"); + + } + return len; +} + +/* + * get extra SCSI data from fifo + */ +static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned int count; + + //DEBUG(0, "%s:\n", __FUNCTION__); + + if (SCpnt->SCp.have_data_in != IO_IN) { + return 0; + } + + count = nsp_fifo_count(SCpnt); + if (data->FifoCount == count) { + //DEBUG(0, " not use bypass quirk\n"); + return 0; + } + + /* + * XXX: NSP_QUIRK + * data phase skip only occures in case of SCSI_LOW_READ + */ + DEBUG(0, " use bypass quirk\n"); + SCpnt->SCp.phase = PH_DATA; + nsp_pio_read(SCpnt, data); + nsp_setup_fifo(data, FALSE); + + return 0; +} + +/* + * accept reselection + */ +static int nsp_reselected(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned int base = SCpnt->device->host->io_port; + unsigned char reg; + + //DEBUG(0, "%s:\n", __FUNCTION__); + + nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect"); + + nsp_nexus(SCpnt, data); + reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN); + nsp_index_write(base, SCSIBUSCTRL, reg); + nsp_index_write(base, SCSIBUSCTRL, reg | AUTODIRECTION | ACKENB); + + return TRUE; +} + +/* + * count how many data transferd + */ +static int nsp_fifo_count(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->device->host->io_port; + unsigned int count; + unsigned int l, m, h, dummy; + + nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER); + + l = nsp_index_read(base, TRANSFERCOUNT); + m = nsp_index_read(base, TRANSFERCOUNT); + h = nsp_index_read(base, TRANSFERCOUNT); + dummy = nsp_index_read(base, TRANSFERCOUNT); + + count = (h << 16) | (m << 8) | (l << 0); + + //DEBUG(0, "%s: =0x%x\n", __FUNCTION__, count); + + return count; +} + +/* fifo size */ +#define RFIFO_CRIT 64 +#define WFIFO_CRIT 64 + +/* + * read data in DATA IN phase + */ +static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned int base = SCpnt->device->host->io_port; + unsigned long mmio_base = SCpnt->device->host->base; + long time_out; + int ocount, res; + unsigned char stat, fifo_stat; + + ocount = data->FifoCount; + + DEBUG(0, "%s: in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n", + __FUNCTION__, SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual); + + time_out = 1000; + + while ((time_out-- != 0) && + (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) { + + stat = nsp_index_read(base, SCSIBUSMON); + stat &= BUSMON_PHASE_MASK; + + + res = nsp_fifo_count(SCpnt) - ocount; + //DEBUG(0, " ptr=0x%p this=0x%x ocount=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res); + if (res == 0) { /* if some data avilable ? */ + if (stat == BUSPHASE_DATA_IN) { /* phase changed? */ + //DEBUG(0, " wait for data this=%d\n", SCpnt->SCp.this_residual); + continue; + } else { + DEBUG(0, " phase changed stat=0x%x\n", stat); + break; + } + } + + fifo_stat = nsp_read(base, FIFOSTATUS); + if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 && + stat == BUSPHASE_DATA_IN) { + continue; + } + + res = MIN(res, SCpnt->SCp.this_residual); + + switch (data->TransferMode) { + case MODE_IO32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2); + break; + case MODE_IO8: + nsp_fifo8_read (base, SCpnt->SCp.ptr, res ); + break; + + case MODE_MEM32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2); + break; + + default: + DEBUG(0, "unknown read mode\n"); + return; + } + + RESID -= res; + SCpnt->SCp.ptr += res; + SCpnt->SCp.this_residual -= res; + ocount += res; + //DEBUG(0, " ptr=0x%p this_residual=0x%x ocount=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount); + + /* go to next scatter list if availavle */ + if (SCpnt->SCp.this_residual == 0 && + SCpnt->SCp.buffers_residual != 0 ) { + //DEBUG(0, " scatterlist next timeout=%d\n", time_out); + SCpnt->SCp.buffers_residual--; + SCpnt->SCp.buffer++; + SCpnt->SCp.ptr = BUFFER_ADDR; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + time_out = 1000; + + //DEBUG(0, "page: 0x%p, off: 0x%x\n", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset); + } + } + + data->FifoCount = ocount; + + if (time_out == 0) { + printk(KERN_DEBUG "%s: pio read timeout resid=%d this_residual=%d buffers_residual=%d\n", + __FUNCTION__, RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual); + } + DEBUG(0, " read ocount=0x%x\n", ocount); +} + +/* + * write data in DATA OUT phase + */ +static void nsp_pio_write(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned int base = SCpnt->device->host->io_port; + unsigned long mmio_base = SCpnt->device->host->base; + int time_out; + int ocount, res; + unsigned char stat; + + ocount = data->FifoCount; + + DEBUG(0, "%s: in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", + __FUNCTION__, data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, RESID); + + time_out = 1000; + + while ((time_out-- != 0) && + (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) { + stat = nsp_index_read(base, SCSIBUSMON); + stat &= BUSMON_PHASE_MASK; + + if (stat != BUSPHASE_DATA_OUT) { + res = ocount - nsp_fifo_count(SCpnt); + + DEBUG(0, " phase changed stat=0x%x, res=%d\n", stat, res); + /* Put back pointer */ + RESID += res; + SCpnt->SCp.ptr -= res; + SCpnt->SCp.this_residual += res; + ocount -= res; + + break; + } + + res = ocount - nsp_fifo_count(SCpnt); + if (res > 0) { /* write all data? */ + DEBUG(0, " wait for all data out. ocount=0x%x res=%d\n", ocount, res); + continue; + } + + res = MIN(SCpnt->SCp.this_residual, WFIFO_CRIT); + + //DEBUG(0, " ptr=0x%p this=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res); + switch (data->TransferMode) { + case MODE_IO32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2); + break; + case MODE_IO8: + nsp_fifo8_write (base, SCpnt->SCp.ptr, res ); + break; + + case MODE_MEM32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2); + break; + + default: + DEBUG(0, "unknown write mode\n"); + break; + } + + RESID -= res; + SCpnt->SCp.ptr += res; + SCpnt->SCp.this_residual -= res; + ocount += res; + + /* go to next scatter list if availavle */ + if (SCpnt->SCp.this_residual == 0 && + SCpnt->SCp.buffers_residual != 0 ) { + //DEBUG(0, " scatterlist next\n"); + SCpnt->SCp.buffers_residual--; + SCpnt->SCp.buffer++; + SCpnt->SCp.ptr = BUFFER_ADDR; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + time_out = 1000; + } + } + + data->FifoCount = ocount; + + if (time_out == 0) { + printk(KERN_DEBUG "%s: pio write timeout resid=0x%x\n", __FUNCTION__, RESID); + } + DEBUG(0, " write ocount=0x%x\n", ocount); +} + +#undef RFIFO_CRIT +#undef WFIFO_CRIT + +/* + * setup synchronous/asynchronous data transfer mode + */ +static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned int base = SCpnt->device->host->io_port; + unsigned char target = SCpnt->device->id; +// unsigned char lun = SCpnt->lun; + sync_data *sync = &(data->Sync[target]); + + //DEBUG(0, "%s: in SCpnt=0x%p\n", __FUNCTION__, SCpnt); + + /* setup synch transfer registers */ + nsp_index_write(base, SYNCREG, sync->SyncRegister); + nsp_index_write(base, ACKWIDTH, sync->AckWidth); + + if (SCpnt->use_sg == 0 || + RESID % 4 != 0 || + RESID <= PAGE_SIZE ) { + data->TransferMode = MODE_IO8; + } else if (nsp_burst_mode == BURST_MEM32) { + data->TransferMode = MODE_MEM32; + } else if (nsp_burst_mode == BURST_IO32) { + data->TransferMode = MODE_IO32; + } else { + data->TransferMode = MODE_IO8; + } + + /* setup pdma fifo */ + nsp_setup_fifo(data, TRUE); + + /* clear ack counter */ + data->FifoCount = 0; + nsp_index_write(base, POINTERCLR, POINTER_CLEAR | + ACK_COUNTER_CLEAR | + REQ_COUNTER_CLEAR | + HOST_COUNTER_CLEAR); + + return 0; +} + +#include "nsp_message.c" +/* + * interrupt handler + */ +static void nspintr(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int base; + unsigned char i_src, irq_phase, phase; + Scsi_Cmnd *tmpSC; + unsigned char target, lun; + unsigned int *sync_neg; + int i, tmp; + nsp_hw_data *data = dev_id; + + //printk("&nsp_data=0x%p, dev_id=0x%p\n", &nsp_data, dev_id); + + base = data->BaseAddress; + //DEBUG(0, " base=0x%x\n", base); + + /* + * interrupt check + */ + nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE); + i_src = nsp_read(base, IRQSTATUS); + //DEBUG(0, " i_src=0x%x\n", i_src); + if ((i_src == 0xff) || ((i_src & IRQSTATUS_MASK) == 0)) { + nsp_write(base, IRQCONTROL, 0); + //DEBUG(0, " no irq/shared irq\n"); + return; + } + + + /* XXX: IMPORTANT + * Do not read an irq_phase register if no scsi phase interrupt. + * Unless, you should lose a scsi phase interrupt. + */ + phase = nsp_index_read(base, SCSIBUSMON); + if((i_src & IRQSTATUS_SCSI) != 0) { + irq_phase = nsp_index_read(base, IRQPHASESENCE); + } else { + irq_phase = 0; + } + + //DEBUG(0, " irq_phase=0x%x\n", irq_phase); + + /* + * timer interrupt handler (scsi vs timer interrupts) + */ + //DEBUG(0, " timercount=%d\n", data->TimerCount); + if (data->TimerCount != 0) { + //DEBUG(0, " stop timer\n"); + nsp_index_write(base, TIMERCOUNT, 0); + nsp_index_write(base, TIMERCOUNT, 0); + data->TimerCount = 0; + } + + if ((i_src & IRQSTATUS_MASK) == IRQSTATUS_TIMER && + data->SelectionTimeOut == 0) { + //DEBUG(0, " timer start\n"); + nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR); + return; + } + + nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR); + + if (data->CurrentSC == NULL) { + printk(KERN_DEBUG "%s: CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen\n", __FUNCTION__, i_src, phase, irq_phase); + return; + } else { + tmpSC = data->CurrentSC; + target = tmpSC->device->id; + lun = tmpSC->device->lun; + sync_neg = &(data->Sync[target].SyncNegotiation); + } + + /* + * parse hardware SCSI irq reasons register + */ + if ((i_src & IRQSTATUS_SCSI) != 0) { + if ((irq_phase & SCSI_RESET_IRQ) != 0) { + printk(KERN_DEBUG " %s: bus reset (power off?)\n", __FUNCTION__); + *sync_neg = SYNC_NOT_YET; + data->CurrentSC = NULL; + tmpSC->result = (DID_RESET << 16) | + ((tmpSC->SCp.Message & 0xff) << 8) | + ((tmpSC->SCp.Status & 0xff) << 0); + tmpSC->scsi_done(tmpSC); + return; + } + + if ((irq_phase & RESELECT_IRQ) != 0) { + DEBUG(0, " reselect\n"); + nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR); + if (nsp_reselected(tmpSC, data) != FALSE) { + return; + } + } + + if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) { + return; + } + } + + //show_phase(tmpSC); + + switch(tmpSC->SCp.phase) { + case PH_SELSTART: + //*sync_neg = SYNC_NOT_YET; + if ((phase & BUSMON_BSY) == 0) { + //DEBUG(0, " selection count=%d\n", data->SelectionTimeOut); + if (data->SelectionTimeOut >= NSP_SELTIMEOUT) { + DEBUG(0, " selection time out\n"); + data->SelectionTimeOut = 0; + nsp_index_write(base, SCSIBUSCTRL, 0); + + data->CurrentSC = NULL; + tmpSC->result = DID_NO_CONNECT << 16; + tmpSC->scsi_done(tmpSC); + + return; + } + data->SelectionTimeOut += 1; + nsp_start_timer(tmpSC, data, 1000/51); + return; + } + + /* attention assert */ + //DEBUG(0, " attention assert\n"); + data->SelectionTimeOut = 0; + tmpSC->SCp.phase = PH_SELECTED; + nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN); + udelay(1); + nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB); + return; + + break; + + case PH_RESELECT: + //DEBUG(0, " phase reselect\n"); + //*sync_neg = SYNC_NOT_YET; + if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) { + + data->CurrentSC = NULL; + tmpSC->result = DID_ABORT << 16; + tmpSC->scsi_done(tmpSC); + return; + } + /* fall thru */ + default: + if ((i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { + return; + } + break; + } + + /* + * SCSI sequencer + */ + //DEBUG(0, " start scsi seq\n"); + + /* normal disconnect */ + if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) && + (irq_phase & LATCHED_BUS_FREE) != 0 ) { + DEBUG(0, " normal disconnect i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase); + if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */ + //*sync_neg = SYNC_NOT_YET; + data->CurrentSC = NULL; + tmpSC->result = (DID_OK << 16) | + ((tmpSC->SCp.Message & 0xff) << 8) | + ((tmpSC->SCp.Status & 0xff) << 0); + DEBUG(0, " command complete result=0x%x\n", tmpSC->result); + tmpSC->scsi_done(tmpSC); + + return; + } + + return; + } + + + /* check unexpected bus free state */ + if (phase == 0) { + printk(KERN_DEBUG " %s: unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", __FUNCTION__, i_src, phase, irq_phase); + + *sync_neg = SYNC_NOT_YET; + data->CurrentSC = NULL; + tmpSC->result = DID_ERROR << 16; + tmpSC->scsi_done(tmpSC); + return; + } + + switch (phase & BUSMON_PHASE_MASK) { + case BUSPHASE_COMMAND: + DEBUG(0, " BUSPHASE_COMMAND\n"); + if ((phase & BUSMON_REQ) == 0) { + DEBUG(0, " REQ == 0\n"); + return; + } + + tmpSC->SCp.phase = PH_COMMAND; + + nsp_nexus(tmpSC, data); + + /* write scsi command */ + DEBUG(0, " cmd_len=%d\n", tmpSC->cmd_len); + nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER); + for (i = 0; i < tmpSC->cmd_len; i++) { + nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]); + } + nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO); + break; + + case BUSPHASE_DATA_OUT: + DEBUG(0, " BUSPHASE_DATA_OUT\n"); + + tmpSC->SCp.phase = PH_DATA; + tmpSC->SCp.have_data_in = IO_OUT; + + nsp_pio_write(tmpSC, data); + + break; + + case BUSPHASE_DATA_IN: + DEBUG(0, " BUSPHASE_DATA_IN\n"); + + tmpSC->SCp.phase = PH_DATA; + tmpSC->SCp.have_data_in = IO_IN; + + nsp_pio_read(tmpSC, data); + + break; + + case BUSPHASE_STATUS: + nsp_dataphase_bypass(tmpSC, data); + DEBUG(0, " BUSPHASE_STATUS\n"); + + tmpSC->SCp.phase = PH_STATUS; + + tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK); + DEBUG(0, " message=0x%x status=0x%x\n", tmpSC->SCp.Message, tmpSC->SCp.Status); + + break; + + case BUSPHASE_MESSAGE_OUT: + DEBUG(0, " BUSPHASE_MESSAGE_OUT\n"); + if ((phase & BUSMON_REQ) == 0) { + goto timer_out; + } + + tmpSC->SCp.phase = PH_MSG_OUT; + + data->MsgLen = i = 0; + data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++; + + if (*sync_neg == SYNC_NOT_YET) { + data->Sync[target].SyncPeriod = 0; + data->Sync[target].SyncOffset = 0; + + /**/ + data->MsgBuffer[i] = MSG_EXTENDED; i++; + data->MsgBuffer[i] = 3; i++; + data->MsgBuffer[i] = MSG_EXT_SDTR; i++; + data->MsgBuffer[i] = 0x0c; i++; + data->MsgBuffer[i] = 15; i++; + /**/ + } + data->MsgLen = i; + + nsp_msg(tmpSC, data); + show_message(data); + nsp_message_out(tmpSC, data); + break; + + case BUSPHASE_MESSAGE_IN: + nsp_dataphase_bypass(tmpSC, data); + DEBUG(0, " BUSPHASE_MESSAGE_IN\n"); + if ((phase & BUSMON_REQ) == 0) { + goto timer_out; + } + + tmpSC->SCp.phase = PH_MSG_IN; + nsp_message_in(tmpSC, data); + + /**/ + if (*sync_neg == SYNC_NOT_YET) { + //printk("%d,%d\n",target,lun); + + if (data->MsgLen >= 5 && + data->MsgBuffer[0] == MSG_EXTENDED && + data->MsgBuffer[1] == 3 && + data->MsgBuffer[2] == MSG_EXT_SDTR ) { + data->Sync[target].SyncPeriod = data->MsgBuffer[3]; + data->Sync[target].SyncOffset = data->MsgBuffer[4]; + //printk("sync ok, %d %d\n", data->MsgBuffer[3], data->MsgBuffer[4]); + *sync_neg = SYNC_OK; + } else { + data->Sync[target].SyncPeriod = 0; + data->Sync[target].SyncOffset = 0; + *sync_neg = SYNC_NG; + } + nsp_msg(tmpSC, data); + } + /**/ + + /* search last messeage byte */ + tmp = -1; + for (i = 0; i < data->MsgLen; i++) { + tmp = data->MsgBuffer[i]; + if (data->MsgBuffer[i] == MSG_EXTENDED) { + i += (1 + data->MsgBuffer[i+1]); + } + } + tmpSC->SCp.Message = tmp; + + DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, data->MsgLen); + show_message(data); + + break; + + case BUSPHASE_SELECT: + default: + DEBUG(0, " BUSPHASE other\n"); + + break; + } + + //DEBUG(0, "%s: out\n", __FUNCTION__); + return; + +timer_out: + nsp_start_timer(tmpSC, data, 1000/102); + return; +} + +#ifdef PCMCIA_DEBUG +#include "nsp_debug.c" +#endif /* DBG_SHOWCOMMAND */ + +/*----------------------------------------------------------------*/ +/* look for ninja3 card and init if found */ +/*----------------------------------------------------------------*/ +static struct Scsi_Host *__nsp_detect(Scsi_Host_Template *sht) +{ + struct Scsi_Host *host; /* registered host structure */ + nsp_hw_data *data = &nsp_data; + + DEBUG(0, "%s: this_id=%d\n", __FUNCTION__, sht->this_id); + + request_region(data->BaseAddress, data->NumAddress, "nsp_cs"); + host = scsi_register(sht, 0); + if(host == NULL) + return NULL; + + host->unique_id = data->BaseAddress; + host->io_port = data->BaseAddress; + host->n_io_port = data->NumAddress; + host->irq = data->IrqNumber; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) + host->base = data->MmioAddress; /* kernel 2.4 */ +#else + host->base = (char *)(data->MmioAddress); /* 2.2 */ +#endif + + spin_lock_init(&(data->Lock)); + + snprintf(data->nspinfo, + sizeof(data->nspinfo), + "NinjaSCSI-3/32Bi Driver $Revision: 1.1 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d", + host->io_port, host->io_port + host->n_io_port - 1, + host->base, + host->irq); + data->nspinfo[sizeof(data->nspinfo) - 1] = '\0'; + sht->name = data->nspinfo; + + DEBUG(0, "%s: end\n", __FUNCTION__); + + //MOD_INC_USE_COUNT; + + return host; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static int nsp_detect(Scsi_Host_Template *sht) +{ + return (__nsp_detect(sht) != NULL); +} + +static int nsp_release(struct Scsi_Host *shpnt) +{ + //nsp_hw_data *data = &nsp_data; + + /* PCMCIA Card Service dose same things */ + //if (shpnt->irq) { + // free_irq(shpnt->irq, data); + //} + //if (shpnt->io_port) { + // release_region(shpnt->io_port, shpnt->n_io_port); + //} + + //MOD_DEC_USE_COUNT; + + return 0; +} +#endif + +/*----------------------------------------------------------------*/ +/* return info string */ +/*----------------------------------------------------------------*/ +static const char *nsp_info(struct Scsi_Host *shpnt) +{ + nsp_hw_data *data = &nsp_data; + + return data->nspinfo; +} + +#undef SPRINTF +#define SPRINTF(args...) \ + do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) +static int nsp_proc_info(char *buffer, + char **start, + off_t offset, + int length, + int hostno, + int inout) +{ + int id; + char *pos = buffer; + int thislength; + int speed; + unsigned long flags; + nsp_hw_data *data = &nsp_data; + struct Scsi_Host *host = NULL; + + if (inout) { + return -EINVAL; + } + + /* search this HBA host */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)) + host = scsi_host_hn_get(hostno); +#else + for (host=scsi_hostlist; host; host=host->next) { + if (host->host_no == hostno) { + break; + } + } +#endif + if (host == NULL) { + return -ESRCH; + } + + SPRINTF("NinjaSCSI status\n\n"); + SPRINTF("Driver version: $Revision: 1.1 $\n"); + SPRINTF("SCSI host No.: %d\n", hostno); + SPRINTF("IRQ: %d\n", host->irq); + SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); + SPRINTF("MMIO(virtual address): 0x%lx\n", host->base); + SPRINTF("sg_tablesize: %d\n", host->sg_tablesize); + + SPRINTF("burst transfer mode: "); + switch (nsp_burst_mode) { + case BURST_IO8: + SPRINTF("io8"); + break; + case BURST_IO32: + SPRINTF("io32"); + break; + case BURST_MEM32: + SPRINTF("mem32"); + break; + default: + SPRINTF("???"); + break; + } + SPRINTF("\n"); + + + spin_lock_irqsave(&(data->Lock), flags); + SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC); + spin_unlock_irqrestore(&(data->Lock), flags); + + SPRINTF("SDTR status\n"); + for(id = 0; id < N_TARGET; id++) { + + SPRINTF("id %d: ", id); + + if (id == host->this_id) { + SPRINTF("----- NinjaSCSI-3 host adapter\n"); + continue; + } + + switch(data->Sync[id].SyncNegotiation) { + case SYNC_OK: + SPRINTF(" sync"); + break; + case SYNC_NG: + SPRINTF("async"); + break; + case SYNC_NOT_YET: + SPRINTF(" none"); + break; + default: + SPRINTF("?????"); + break; + } + + if (data->Sync[id].SyncPeriod != 0) { + speed = 1000000 / (data->Sync[id].SyncPeriod * 4); + + SPRINTF(" transfer %d.%dMB/s, offset %d", + speed / 1000, + speed % 1000, + data->Sync[id].SyncOffset + ); + } + SPRINTF("\n"); + } + + thislength = pos - (buffer + offset); + + if(thislength < 0) { + *start = 0; + return 0; + } + + + thislength = MIN(thislength, length); + *start = buffer + offset; + + return thislength; +} +#undef SPRINTF + + +/*static int nsp_eh_strategy(struct Scsi_Host *Shost) +{ + return FAILED; +}*/ + +/* +static int nsp_eh_abort(Scsi_Cmnd *SCpnt) +{ + DEBUG(0, "%s: SCpnt=0x%p\n", __FUNCTION__, SCpnt); + + return nsp_eh_bus_reset(SCpnt); +}*/ + +/* +static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt) +{ + DEBUG(0, "%s: SCpnt=0x%p\n", __FUNCTION__, SCpnt); + + return FAILED; +}*/ + +static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt) +{ + nsp_hw_data *data = &nsp_data; + unsigned int base = SCpnt->device->host->io_port; + int i; + + DEBUG(0, "%s: SCpnt=0x%p base=0x%x\n", __FUNCTION__, SCpnt, base); + + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); + + nsp_index_write(base, SCSIBUSCTRL, SCSI_RST); + mdelay(100); /* 100ms */ + nsp_index_write(base, SCSIBUSCTRL, 0); + for(i = 0; i < 5; i++) { + nsp_index_read(base, IRQPHASESENCE); /* dummy read */ + } + + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); + + nsphw_init_sync(data); + + return SUCCESS; +} + +static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt) +{ + nsp_hw_data *data = &nsp_data; + + DEBUG(0, "%s:\n", __FUNCTION__); + + nsphw_init(data); + + return SUCCESS; +} + + +/********************************************************************** + PCMCIA functions +**********************************************************************/ + +/*====================================================================== + nsp_cs_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. +======================================================================*/ +static dev_link_t *nsp_cs_attach(void) +{ + scsi_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int ret, i; + + DEBUG(0, "%s:\n", __FUNCTION__); + + /* Create new SCSI device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) { return NULL; } + memset(info, 0, sizeof(*info)); + link = &info->link; + link->priv = info; + + /* Initialize the dev_link_t structure */ + link->release.function = &nsp_cs_release; + link->release.data = (u_long)link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 0x10; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 10; /* not used */ + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) { + link->irq.IRQInfo2 = irq_mask; + } else { + for (i = 0; i < 4; i++) { + link->irq.IRQInfo2 |= 1 << irq_list[i]; + } + } + + /* IRQ $B$N3NJ]$O$3$3$G(B PCMCIA $B$N4X?t$rMQ$$$F9T$J$&$N$G(B + * host->hostdata $B$r(B irq.Instance $B$KBeF~$G$-$J$$!#(B + * host->hostdata $B$,;H$($l$PJ#?t$N(B NinjaSCSI $B$,(B + * $B;HMQ$G$-$k$N$@$,!#(B + */ + link->irq.Handler = &nspintr; + link->irq.Instance = &nsp_data; + link->irq.Attributes |= (SA_SHIRQ | SA_SAMPLE_RANDOM); + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; + + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME ; + client_reg.event_handler = &nsp_cs_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + nsp_cs_detach(link); + return NULL; + } + + return link; +} /* nsp_cs_attach */ + + +/*====================================================================== + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. +======================================================================*/ +static void nsp_cs_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "%s(0x%p)\n", __FUNCTION__, link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) { + if (*linkp == link) { + break; + } + } + if (*linkp == NULL) { + return; + } + + del_timer(&link->release); + if (link->state & DEV_CONFIG) { + nsp_cs_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + /* Break the link with Card Services */ + if (link->handle) { + CardServices(DeregisterClient, link->handle); + } + + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree(link->priv); + link->priv = NULL; + +} /* nsp_cs_detach */ + + +/*====================================================================== + nsp_cs_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. +======================================================================*/ +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry +/*====================================================================*/ + +static void nsp_cs_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + scsi_info_t *info = link->priv; + tuple_t tuple; + cisparse_t parse; + int last_ret, last_fn; + u_char tuple_data[64]; + config_info_t conf; + win_req_t req; + memreq_t map; + cistpl_cftable_entry_t dflt = { 0 }; + + struct Scsi_Host *host; + nsp_hw_data *data = &nsp_data; + + + DEBUG(0, "%s: in\n", __FUNCTION__); + + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = tuple_data; + tuple.TupleDataMax = sizeof(tuple_data); + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Look up the current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; } + if (cfg->index == 0) { goto next_entry; } + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1<vcc.param[CISTPL_POWER_VNOM]/10000) { + goto next_entry; + } + } else if (dflt.vcc.present & (1<vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + } else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; + } + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) { + link->conf.Attributes |= CONF_ENABLE_IRQ; + } + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + } + + if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { + cistpl_mem_t *mem = + (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; + req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; + req.Attributes |= WIN_ENABLE; + req.Base = mem->win[0].host_addr; + req.Size = mem->win[0].len; + if (req.Size < 0x1000) + req.Size = 0x1000; + req.AccessSpeed = 0; + link->win = (window_handle_t)link->handle; + CFG_CHECK(RequestWindow, &link->win, &req); + map.Page = 0; map.CardOffset = mem->win[0].card_addr; + CFG_CHECK(MapMemPage, link->win, &map); + + data->MmioAddress = (u_long)ioremap_nocache(req.Base, req.Size); + } + /* If we got this far, we're cool! */ + break; + + next_entry: + DEBUG(0, "%s: next\n", __FUNCTION__); + + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + CS_CHECK(GetNextTuple, handle, &tuple); + } + + if (link->conf.Attributes & CONF_ENABLE_IRQ) + CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestConfiguration, handle, &link->conf); + + if (free_ports) { + if (link->io.BasePort1) + release_region(link->io.BasePort1, link->io.NumPorts1); + if (link->io.BasePort2) + release_region(link->io.BasePort2, link->io.NumPorts2); + } + + /* Set port and IRQ */ + data->BaseAddress = link->io.BasePort1; + data->NumAddress = link->io.NumPorts1; + data->IrqNumber = link->irq.AssignedIRQ; + + DEBUG(0, "%s: I/O[0x%x+0x%x] IRQ %d\n", + __FUNCTION__, data->BaseAddress, data->NumAddress, data->IrqNumber); + + if(nsphw_init(data) == FALSE) { + goto cs_failed; + } + + host = __nsp_detect(&nsp_driver_template); + if (!host) + goto cs_failed; + + sprintf(info->node.dev_name, "scsi%d", host->host_no); + link->dev = &info->node; + info->host = host; + + /* Finally, report what we've done */ + printk(KERN_INFO "nsp_cs: index 0x%02x: Vcc %d.%d", + link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) { + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + } + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + printk(", irq %d", link->irq.AssignedIRQ); + } + if (link->io.NumPorts1) { + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + } + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2+link->io.NumPorts2-1); + if (link->win) + printk(", mem 0x%06lx-0x%06lx", req.Base, + req.Base+req.Size-1); + printk("\n"); + + scsi_add_host(host, NULL); + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + nsp_cs_release((u_long)link); + return; + +} /* nsp_cs_config */ +#undef CS_CHECK +#undef CFG_CHECK + +/*====================================================================== + After a card is removed, nsp_cs_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. +======================================================================*/ +static void nsp_cs_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + scsi_info_t *info = link->priv; + + DEBUG(0, "%s(0x%p)\n", __FUNCTION__, link); + + /* + * If the device is currently in use, we won't release until it + * is actually closed. + */ + if (link->open) { + DEBUG(1, "nsp_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Unlink the device chain */ +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,2)) + scsi_unregister_module(MODULE_SCSI_HA, &nsp_driver_template); +#else + scsi_remove_host(info->host); + scsi_unregister(info->host); +#endif + link->dev = NULL; + + if (link->win) { + iounmap((void *)(nsp_data.MmioAddress)); + CardServices(ReleaseWindow, link->win); + } + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) { + CardServices(ReleaseIO, link->handle, &link->io); + } + if (link->irq.AssignedIRQ) { + CardServices(ReleaseIRQ, link->handle, &link->irq); + } + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) { + nsp_cs_detach(link); + } +} /* nsp_cs_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + + When a CARD_REMOVAL event is received, we immediately set a flag + to block future accesses to this device. All the functions that + actually access the device should check this flag to make sure + the card is still present. + +======================================================================*/ +static int nsp_cs_event(event_t event, + int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + scsi_info_t *info = link->priv; + Scsi_Cmnd tmp; + + DEBUG(1, "%s(0x%06x)\n", __FUNCTION__, event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + DEBUG(0, " event: remove\n"); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + ((scsi_info_t *)link->priv)->stop = 1; + mod_timer(&link->release, jiffies + HZ/20); + } + break; + + case CS_EVENT_CARD_INSERTION: + DEBUG(0, " event: insert\n"); + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + nsp_cs_config(link); + break; + + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + /* Mark the device as stopped, to block IO until later */ + info->stop = 1; + if (link->state & DEV_CONFIG) { + CardServices(ReleaseConfiguration, link->handle); + } + break; + + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + DEBUG(0, " event: reset\n"); + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + } + info->stop = 0; + + tmp.device->host = info->host; + nsp_eh_host_reset(&tmp); + nsp_eh_bus_reset(&tmp); + + break; + + default: + DEBUG(0, " event: unknown\n"); + break; + } + DEBUG(0, "%s: end\n", __FUNCTION__); + return 0; +} /* nsp_cs_event */ + +static struct pcmcia_driver nsp_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "nsp_cs", + }, + .attach = nsp_cs_attach, + .detach = nsp_cs_detach, +}; + +static int __init nsp_cs_init(void) +{ + return pcmcia_register_driver(&nsp_driver); +} + + +static void __exit nsp_cs_exit(void) +{ + pcmcia_unregister_driver(&nsp_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) { + nsp_cs_release((u_long)dev_list); + } + nsp_cs_detach(dev_list); + } +} + +module_init(nsp_cs_init) +module_exit(nsp_cs_exit) diff --git a/demos/demo_rule9/nsp_cs.res b/demos/demo_rule9/nsp_cs.res new file mode 100644 index 0000000..0069cc2 --- /dev/null +++ b/demos/demo_rule9/nsp_cs.res @@ -0,0 +1,1942 @@ +/*====================================================================== + + NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver + By: YOKOTA Hiroshi + + Ver.2.8 Support 32bit MMIO mode + Support Synchronous Data TRansfer (SDTR) mode + Ver.2.0 Support 32bit PIO mode + Ver.1.1.2 Fix for scatter list buffer exceeds + Ver.1.1 Support scatter list + Ver.0.1 Initial version + + This software may be used and distributed according to the terms of + the GNU General Public License. + +======================================================================*/ + +/*********************************************************************** + This driver is for these PCcards. + + I-O DATA PCSC-F (Workbit NinjaSCSI-3) + "WBT", "NinjaSCSI-3", "R1.0" + I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode) + "IO DATA", "CBSC16 ", "1" + +***********************************************************************/ + +/* */ + +#ifdef NSP_KERNEL_2_2 +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "scsi.h" +#include "hosts.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "nsp_cs.h" + +MODULE_AUTHOR("YOKOTA Hiroshi "); +MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.1 $"); +MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +MODULE_PARM_DESC(pc_debug, "set debug level"); +static char *version = ""; +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#else +#define DEBUG(n, args...) /* */ +#endif + +#include "nsp_io.h" + +/*====================================================================*/ + +typedef struct scsi_info_t { + dev_link_t link; + dev_node_t node; + struct Scsi_Host *host; + int stop; +} scsi_info_t; + + +/*----------------------------------------------------------------*/ + +#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE) +#define PROC_SCSI_NSP PROC_SCSI_IBMMCA /* bad hack... */ +static struct proc_dir_entry proc_scsi_nsp = { + PROC_SCSI_NSP, 6, "nsp_cs", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +#endif + +/*====================================================================*/ +/* Parameters that can be set with 'insmod' */ + +static unsigned int irq_mask = 0xffff; +MODULE_PARM(irq_mask, "i"); +MODULE_PARM_DESC(irq_mask, "IRQ mask bits (default: 0xffff)"); + +static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM_DESC(irq_list, "Use specified IRQ number. (default: auto select)"); + +static int nsp_burst_mode = 2; +MODULE_PARM(nsp_burst_mode, "i"); +MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))"); + +/* Release IO ports after configuration? */ +static int free_ports = 0; +MODULE_PARM(free_ports, "i"); +MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))"); + +/* /usr/src/linux/drivers/scsi/hosts.h */ +static Scsi_Host_Template nsp_driver_template = { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) + .proc_name = "nsp_cs", /* kernel 2.4 */ +#else + .proc_dir = &proc_scsi_nsp, /* kernel 2.2 */ +#endif + .proc_info = nsp_proc_info, + .name = "WorkBit NinjaSCSI-3/32Bi(16bit)", +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + .detect = nsp_detect, + .release = nsp_release, +#endif + .info = nsp_info, + .queuecommand = nsp_queuecommand, +/* .eh_strategy_handler = nsp_eh_strategy,*/ +/* .eh_abort_handler = nsp_eh_abort,*/ +/* .eh_device_reset_handler = nsp_eh_device_reset,*/ + .eh_bus_reset_handler = nsp_eh_bus_reset, + .eh_host_reset_handler = nsp_eh_host_reset, + .can_queue = 1, + .this_id = NSP_INITIATOR_ID, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2)) + .use_new_eh_code = 1, +#endif +}; + +static dev_link_t *dev_list = NULL; +static dev_info_t dev_info = {"nsp_cs"}; + +static nsp_hw_data nsp_data; + +/***********************************************************/ + +static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ +#ifdef PCMCIA_DEBUG + /*unsigned int host_id = SCpnt->host->this_id;*/ + /*unsigned int base = SCpnt->host->io_port;*/ + unsigned char target = SCpnt->target; +#endif + nsp_hw_data *data = &nsp_data; + + DEBUG(0, "%s: SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n", + __FUNCTION__, SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg); + //DEBUG(0, " before CurrentSC=0x%p\n", data->CurrentSC); + + if(data->CurrentSC != NULL) { + printk(KERN_DEBUG " %s: CurrentSC!=NULL this can't be happen\n", __FUNCTION__); + data->CurrentSC = NULL; + SCpnt->result = DID_BAD_TARGET << 16; + done(SCpnt); + return -1; + } + + show_command(SCpnt); + + SCpnt->scsi_done = done; + data->CurrentSC = SCpnt; + + SCpnt->SCp.Status = CHECK_CONDITION; + SCpnt->SCp.Message = 0; + SCpnt->SCp.have_data_in = IO_UNKNOWN; + SCpnt->SCp.sent_command = 0; + SCpnt->SCp.phase = PH_UNDETERMINED; + RESID = SCpnt->request_bufflen; + + /* setup scratch area + SCp.ptr : buffer pointer + SCp.this_residual : buffer length + SCp.buffer : next buffer + SCp.buffers_residual : left buffers in list + SCp.phase : current state of the command */ + if (SCpnt->use_sg) { + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + SCpnt->SCp.ptr = BUFFER_ADDR; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + } else { + SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + } + + if(nsphw_start_selection(SCpnt, data) == FALSE) { + DEBUG(0, " selection fail\n"); + data->CurrentSC = NULL; + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return -1; + } + + + //DEBUG(0, "%s: out\n", __FUNCTION__); + return 0; +} + +/* + * setup PIO FIFO transfer mode and enable/disable to data out + */ +static void nsp_setup_fifo(nsp_hw_data *data, int enabled) +{ + unsigned int base = data->BaseAddress; + unsigned char transfer_mode_reg; + + //DEBUG(0, "%s: enabled=%d\n", __FUNCTION__, enabled); + + if (enabled != FALSE) { + transfer_mode_reg = TRANSFER_GO | BRAIND; + } else { + transfer_mode_reg = 0; + } + + transfer_mode_reg |= data->TransferMode; + + nsp_index_write(base, TRANSFERMODE, transfer_mode_reg); +} + +static void nsphw_init_sync(nsp_hw_data *data) +{ + sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET, + .SyncPeriod = 0, + .SyncOffset = 0 + }; + int i; + + /* setup sync data */ + for ( i = 0; i < NUMBER(data->Sync); i++ ) { + data->Sync[i] = tmp_sync; + } +} + +/* + * Initialize Ninja hardware + */ +static int nsphw_init(nsp_hw_data *data) +{ + unsigned int base = data->BaseAddress; + + DEBUG(0, "%s: in base=0x%x\n", __FUNCTION__, base); + + data->ScsiClockDiv = CLOCK_40M | FAST_20; + data->CurrentSC = NULL; + data->FifoCount = 0; + data->TransferMode = MODE_IO8; + + nsphw_init_sync(data); + + /* block all interrupts */ + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); + + /* setup SCSI interface */ + nsp_write(base, IFSELECT, IF_IFSEL); + + nsp_index_write(base, SCSIIRQMODE, 0); + + nsp_index_write(base, TRANSFERMODE, MODE_IO8); + nsp_index_write(base, CLOCKDIV, data->ScsiClockDiv); + + nsp_index_write(base, PARITYCTRL, 0); + nsp_index_write(base, POINTERCLR, POINTER_CLEAR | + ACK_COUNTER_CLEAR | + REQ_COUNTER_CLEAR | + HOST_COUNTER_CLEAR); + + /* setup fifo asic */ + nsp_write(base, IFSELECT, IF_REGSEL); + nsp_index_write(base, TERMPWRCTRL, 0); + if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) { + printk(KERN_INFO "nsp_cs: terminator power on\n"); + nsp_index_write(base, TERMPWRCTRL, POWER_ON); + } + + nsp_index_write(base, TIMERCOUNT, 0); + nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */ + + nsp_index_write(base, SYNCREG, 0); + nsp_index_write(base, ACKWIDTH, 0); + + /* enable interrupts and ack them */ + nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI | + RESELECT_EI | + SCSI_RESET_IRQ_EI ); + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); + + nsp_setup_fifo(data, FALSE); + + return TRUE; +} + +/* + * Start selection phase + */ +static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt, + nsp_hw_data *data) +{ + unsigned int host_id = SCpnt->device->host->this_id; + unsigned int base = SCpnt->device->host->io_port; + unsigned char target = SCpnt->device->id; + int time_out; + unsigned char phase, arbit; + + //DEBUG(0, "%s:in\n", __FUNCTION__); + + phase = nsp_index_read(base, SCSIBUSMON); + if(phase != BUSMON_BUS_FREE) { + //DEBUG(0, " bus busy\n"); + return FALSE; + } + + /* start arbitration */ + //DEBUG(0, " start arbit\n"); + SCpnt->SCp.phase = PH_ARBSTART; + nsp_index_write(base, SETARBIT, ARBIT_GO); + + time_out = 1000; + do { + /* XXX: what a stupid chip! */ + arbit = nsp_index_read(base, ARBITSTATUS); + //DEBUG(0, " arbit=%d, wait_count=%d\n", arbit, wait_count); + udelay(1); /* hold 1.2us */ + } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 && + (time_out-- != 0)); + + if((arbit & ARBIT_WIN) == 0) { + //DEBUG(0, " arbit fail\n"); + nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); + return FALSE; + } + + /* assert select line */ + //DEBUG(0, " assert SEL line\n"); + SCpnt->SCp.phase = PH_SELSTART; + udelay(3); + nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target)); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN); + udelay(3); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN); + nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); + udelay(3); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN); + + /* check selection timeout */ + nsp_start_timer(SCpnt, data, 1000/51); + data->SelectionTimeOut = 1; + + return TRUE; +} + +struct nsp_sync_table { + unsigned int min_period; + unsigned int max_period; + unsigned int chip_period; + unsigned int ack_width; +}; + +static struct nsp_sync_table nsp_sync_table_40M[] = { + {0x0c,0x0c,0x1,0}, /* 20MB 50ns*/ + {0x19,0x19,0x3,1}, /* 10MB 100ns*/ + {0x1a,0x25,0x5,2}, /* 7.5MB 150ns*/ + {0x26,0x32,0x7,3}, /* 5MB 200ns*/ + {0x0, 0, 0, 0} +}; + +static struct nsp_sync_table nsp_sync_table_20M[] = { + {0x19,0x19,0x1,0}, /* 10MB 100ns*/ + {0x1a,0x25,0x2,0}, /* 7.5MB 150ns*/ + {0x26,0x32,0x3,1}, /* 5MB 200ns*/ + {0x0, 0, 0, 0} +}; + +/* + * setup synchronous data transfer mode + */ +static int nsp_msg(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned char target = SCpnt->device->id; +// unsigned char lun = SCpnt->lun; + sync_data *sync = &(data->Sync[target]); + struct nsp_sync_table *sync_table; + unsigned int period, offset; + int i; + + + DEBUG(0, "%s:\n", __FUNCTION__); + + period = sync->SyncPeriod; + offset = sync->SyncOffset; + + DEBUG(0, " period=0x%x, offset=0x%x\n", period, offset); + + if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) { + sync_table = &nsp_sync_table_20M[0]; + } else { + sync_table = &nsp_sync_table_40M[0]; + } + + for ( i = 0; sync_table->max_period != 0; i++, sync_table++) { + if ( period >= sync_table->min_period && + period <= sync_table->max_period ) { + break; + } + } + + if (period != 0 && sync_table->max_period == 0) { + /* + * No proper period/offset found + */ + DEBUG(0, " no proper period/offset\n"); + + sync->SyncPeriod = 0; + sync->SyncOffset = 0; + sync->SyncRegister = 0; + sync->AckWidth = 0; + + return FALSE; + } + + sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) | + (offset & SYNCREG_OFFSET_MASK); + sync->AckWidth = sync_table->ack_width; + + DEBUG(0, " sync_reg=0x%x, ack_width=0x%x\n", sync->SyncRegister, sync->AckWidth); + + return TRUE; +} + + +/* + * start ninja hardware timer + */ +static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time) +{ + unsigned int base = SCpnt->device->host->io_port; + + //DEBUG(0, "%s: in SCpnt=0x%p, time=%d\n", __FUNCTION__, SCpnt, time); + data->TimerCount = time; + nsp_index_write(base, TIMERCOUNT, time); +} + +/* + * wait for bus phase change + */ +static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str) +{ + unsigned int base = SCpnt->device->host->io_port; + unsigned char reg; + int time_out; + + //DEBUG(0, "%s:\n", __FUNCTION__); + + time_out = 100; + + do { + reg = nsp_index_read(base, SCSIBUSMON); + if (reg == 0xff) { + break; + } + } while ((time_out-- != 0) && (reg & mask) != 0); + + if (time_out == 0) { + printk(KERN_DEBUG "%s:: %s signal off timeut\n", __FUNCTION__, str); + } + + return 0; +} + +/* + * expect Ninja Irq + */ +static int nsp_expect_signal(Scsi_Cmnd *SCpnt, + unsigned char current_phase, + unsigned char mask) +{ + unsigned int base = SCpnt->device->host->io_port; + int time_out; + unsigned char phase, i_src; + + //DEBUG(0, "%s: current_phase=0x%x, mask=0x%x\n", __FUNCTION__, current_phase, mask); + + time_out = 100; + do { + phase = nsp_index_read(base, SCSIBUSMON); + if (phase == 0xff) { + //DEBUG(0, " ret -1\n"); + return -1; + } + i_src = nsp_read(base, IRQSTATUS); + if (i_src & IRQSTATUS_SCSI) { + //DEBUG(0, " ret 0 found scsi signal\n"); + return 0; + } + if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) { + //DEBUG(0, " ret 1 phase=0x%x\n", phase); + return 1; + } + } while(time_out-- != 0); + + //DEBUG(0, "%s: timeout\n", __FUNCTION__); + return -1; +} + +/* + * transfer SCSI message + */ +static int nsp_xfer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int phase) +{ + unsigned int base = SCpnt->device->host->io_port; + char *buf = data->MsgBuffer; + int len = MIN(MSGBUF_SIZE, data->MsgLen); + int ptr; + int ret; + + //DEBUG(0, "%s:\n", __FUNCTION__); + for (ptr = 0; len > 0; len --, ptr ++) { + + ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ); + if (ret <= 0) { + DEBUG(0, " xfer quit\n"); + return 0; + } + + /* if last byte, negate ATN */ + if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) { + nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB); + } + + /* read & write message */ + if (phase & BUSMON_IO) { + DEBUG(0, " read msg\n"); + buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK); + } else { + DEBUG(0, " write msg\n"); + nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]); + } + nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer"); + + } + return len; +} + +/* + * get extra SCSI data from fifo + */ +static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned int count; + + //DEBUG(0, "%s:\n", __FUNCTION__); + + if (SCpnt->SCp.have_data_in != IO_IN) { + return 0; + } + + count = nsp_fifo_count(SCpnt); + if (data->FifoCount == count) { + //DEBUG(0, " not use bypass quirk\n"); + return 0; + } + + /* + * XXX: NSP_QUIRK + * data phase skip only occures in case of SCSI_LOW_READ + */ + DEBUG(0, " use bypass quirk\n"); + SCpnt->SCp.phase = PH_DATA; + nsp_pio_read(SCpnt, data); + nsp_setup_fifo(data, FALSE); + + return 0; +} + +/* + * accept reselection + */ +static int nsp_reselected(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned int base = SCpnt->device->host->io_port; + unsigned char reg; + + //DEBUG(0, "%s:\n", __FUNCTION__); + + nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect"); + + nsp_nexus(SCpnt, data); + reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN); + nsp_index_write(base, SCSIBUSCTRL, reg); + nsp_index_write(base, SCSIBUSCTRL, reg | AUTODIRECTION | ACKENB); + + return TRUE; +} + +/* + * count how many data transferd + */ +static int nsp_fifo_count(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->device->host->io_port; + unsigned int count; + unsigned int l, m, h, dummy; + + nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER); + + l = nsp_index_read(base, TRANSFERCOUNT); + m = nsp_index_read(base, TRANSFERCOUNT); + h = nsp_index_read(base, TRANSFERCOUNT); + dummy = nsp_index_read(base, TRANSFERCOUNT); + + count = (h << 16) | (m << 8) | (l << 0); + + //DEBUG(0, "%s: =0x%x\n", __FUNCTION__, count); + + return count; +} + +/* fifo size */ +#define RFIFO_CRIT 64 +#define WFIFO_CRIT 64 + +/* + * read data in DATA IN phase + */ +static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned int base = SCpnt->device->host->io_port; + unsigned long mmio_base = SCpnt->device->host->base; + long time_out; + int ocount, res; + unsigned char stat, fifo_stat; + + ocount = data->FifoCount; + + DEBUG(0, "%s: in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n", + __FUNCTION__, SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual); + + time_out = 1000; + + while ((time_out-- != 0) && + (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) { + + stat = nsp_index_read(base, SCSIBUSMON); + stat &= BUSMON_PHASE_MASK; + + + res = nsp_fifo_count(SCpnt) - ocount; + //DEBUG(0, " ptr=0x%p this=0x%x ocount=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res); + if (res == 0) { /* if some data avilable ? */ + if (stat == BUSPHASE_DATA_IN) { /* phase changed? */ + //DEBUG(0, " wait for data this=%d\n", SCpnt->SCp.this_residual); + continue; + } else { + DEBUG(0, " phase changed stat=0x%x\n", stat); + break; + } + } + + fifo_stat = nsp_read(base, FIFOSTATUS); + if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 && + stat == BUSPHASE_DATA_IN) { + continue; + } + + res = MIN(res, SCpnt->SCp.this_residual); + + switch (data->TransferMode) { + case MODE_IO32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2); + break; + case MODE_IO8: + nsp_fifo8_read (base, SCpnt->SCp.ptr, res ); + break; + + case MODE_MEM32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2); + break; + + default: + DEBUG(0, "unknown read mode\n"); + return; + } + + RESID -= res; + SCpnt->SCp.ptr += res; + SCpnt->SCp.this_residual -= res; + ocount += res; + //DEBUG(0, " ptr=0x%p this_residual=0x%x ocount=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount); + + /* go to next scatter list if availavle */ + if (SCpnt->SCp.this_residual == 0 && + SCpnt->SCp.buffers_residual != 0 ) { + //DEBUG(0, " scatterlist next timeout=%d\n", time_out); + SCpnt->SCp.buffers_residual--; + SCpnt->SCp.buffer++; + SCpnt->SCp.ptr = BUFFER_ADDR; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + time_out = 1000; + + //DEBUG(0, "page: 0x%p, off: 0x%x\n", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset); + } + } + + data->FifoCount = ocount; + + if (time_out == 0) { + printk(KERN_DEBUG "%s: pio read timeout resid=%d this_residual=%d buffers_residual=%d\n", + __FUNCTION__, RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual); + } + DEBUG(0, " read ocount=0x%x\n", ocount); +} + +/* + * write data in DATA OUT phase + */ +static void nsp_pio_write(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned int base = SCpnt->device->host->io_port; + unsigned long mmio_base = SCpnt->device->host->base; + int time_out; + int ocount, res; + unsigned char stat; + + ocount = data->FifoCount; + + DEBUG(0, "%s: in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", + __FUNCTION__, data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, RESID); + + time_out = 1000; + + while ((time_out-- != 0) && + (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) { + stat = nsp_index_read(base, SCSIBUSMON); + stat &= BUSMON_PHASE_MASK; + + if (stat != BUSPHASE_DATA_OUT) { + res = ocount - nsp_fifo_count(SCpnt); + + DEBUG(0, " phase changed stat=0x%x, res=%d\n", stat, res); + /* Put back pointer */ + RESID += res; + SCpnt->SCp.ptr -= res; + SCpnt->SCp.this_residual += res; + ocount -= res; + + break; + } + + res = ocount - nsp_fifo_count(SCpnt); + if (res > 0) { /* write all data? */ + DEBUG(0, " wait for all data out. ocount=0x%x res=%d\n", ocount, res); + continue; + } + + res = MIN(SCpnt->SCp.this_residual, WFIFO_CRIT); + + //DEBUG(0, " ptr=0x%p this=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res); + switch (data->TransferMode) { + case MODE_IO32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2); + break; + case MODE_IO8: + nsp_fifo8_write (base, SCpnt->SCp.ptr, res ); + break; + + case MODE_MEM32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2); + break; + + default: + DEBUG(0, "unknown write mode\n"); + break; + } + + RESID -= res; + SCpnt->SCp.ptr += res; + SCpnt->SCp.this_residual -= res; + ocount += res; + + /* go to next scatter list if availavle */ + if (SCpnt->SCp.this_residual == 0 && + SCpnt->SCp.buffers_residual != 0 ) { + //DEBUG(0, " scatterlist next\n"); + SCpnt->SCp.buffers_residual--; + SCpnt->SCp.buffer++; + SCpnt->SCp.ptr = BUFFER_ADDR; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + time_out = 1000; + } + } + + data->FifoCount = ocount; + + if (time_out == 0) { + printk(KERN_DEBUG "%s: pio write timeout resid=0x%x\n", __FUNCTION__, RESID); + } + DEBUG(0, " write ocount=0x%x\n", ocount); +} + +#undef RFIFO_CRIT +#undef WFIFO_CRIT + +/* + * setup synchronous/asynchronous data transfer mode + */ +static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data) +{ + unsigned int base = SCpnt->device->host->io_port; + unsigned char target = SCpnt->device->id; +// unsigned char lun = SCpnt->lun; + sync_data *sync = &(data->Sync[target]); + + //DEBUG(0, "%s: in SCpnt=0x%p\n", __FUNCTION__, SCpnt); + + /* setup synch transfer registers */ + nsp_index_write(base, SYNCREG, sync->SyncRegister); + nsp_index_write(base, ACKWIDTH, sync->AckWidth); + + if (SCpnt->use_sg == 0 || + RESID % 4 != 0 || + RESID <= PAGE_SIZE ) { + data->TransferMode = MODE_IO8; + } else if (nsp_burst_mode == BURST_MEM32) { + data->TransferMode = MODE_MEM32; + } else if (nsp_burst_mode == BURST_IO32) { + data->TransferMode = MODE_IO32; + } else { + data->TransferMode = MODE_IO8; + } + + /* setup pdma fifo */ + nsp_setup_fifo(data, TRUE); + + /* clear ack counter */ + data->FifoCount = 0; + nsp_index_write(base, POINTERCLR, POINTER_CLEAR | + ACK_COUNTER_CLEAR | + REQ_COUNTER_CLEAR | + HOST_COUNTER_CLEAR); + + return 0; +} + +#include "nsp_message.c" +/* + * interrupt handler + */ +static void nspintr(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int base; + unsigned char i_src, irq_phase, phase; + Scsi_Cmnd *tmpSC; + unsigned char target, lun; + unsigned int *sync_neg; + int i, tmp; + nsp_hw_data *data = dev_id; + + //printk("&nsp_data=0x%p, dev_id=0x%p\n", &nsp_data, dev_id); + + base = data->BaseAddress; + //DEBUG(0, " base=0x%x\n", base); + + /* + * interrupt check + */ + nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE); + i_src = nsp_read(base, IRQSTATUS); + //DEBUG(0, " i_src=0x%x\n", i_src); + if ((i_src == 0xff) || ((i_src & IRQSTATUS_MASK) == 0)) { + nsp_write(base, IRQCONTROL, 0); + //DEBUG(0, " no irq/shared irq\n"); + return; + } + + + /* XXX: IMPORTANT + * Do not read an irq_phase register if no scsi phase interrupt. + * Unless, you should lose a scsi phase interrupt. + */ + phase = nsp_index_read(base, SCSIBUSMON); + if((i_src & IRQSTATUS_SCSI) != 0) { + irq_phase = nsp_index_read(base, IRQPHASESENCE); + } else { + irq_phase = 0; + } + + //DEBUG(0, " irq_phase=0x%x\n", irq_phase); + + /* + * timer interrupt handler (scsi vs timer interrupts) + */ + //DEBUG(0, " timercount=%d\n", data->TimerCount); + if (data->TimerCount != 0) { + //DEBUG(0, " stop timer\n"); + nsp_index_write(base, TIMERCOUNT, 0); + nsp_index_write(base, TIMERCOUNT, 0); + data->TimerCount = 0; + } + + if ((i_src & IRQSTATUS_MASK) == IRQSTATUS_TIMER && + data->SelectionTimeOut == 0) { + //DEBUG(0, " timer start\n"); + nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR); + return; + } + + nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR); + + if (data->CurrentSC == NULL) { + printk(KERN_DEBUG "%s: CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen\n", __FUNCTION__, i_src, phase, irq_phase); + return; + } else { + tmpSC = data->CurrentSC; + target = tmpSC->device->id; + lun = tmpSC->device->lun; + sync_neg = &(data->Sync[target].SyncNegotiation); + } + + /* + * parse hardware SCSI irq reasons register + */ + if ((i_src & IRQSTATUS_SCSI) != 0) { + if ((irq_phase & SCSI_RESET_IRQ) != 0) { + printk(KERN_DEBUG " %s: bus reset (power off?)\n", __FUNCTION__); + *sync_neg = SYNC_NOT_YET; + data->CurrentSC = NULL; + tmpSC->result = (DID_RESET << 16) | + ((tmpSC->SCp.Message & 0xff) << 8) | + ((tmpSC->SCp.Status & 0xff) << 0); + tmpSC->scsi_done(tmpSC); + return; + } + + if ((irq_phase & RESELECT_IRQ) != 0) { + DEBUG(0, " reselect\n"); + nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR); + if (nsp_reselected(tmpSC, data) != FALSE) { + return; + } + } + + if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) { + return; + } + } + + //show_phase(tmpSC); + + switch(tmpSC->SCp.phase) { + case PH_SELSTART: + //*sync_neg = SYNC_NOT_YET; + if ((phase & BUSMON_BSY) == 0) { + //DEBUG(0, " selection count=%d\n", data->SelectionTimeOut); + if (data->SelectionTimeOut >= NSP_SELTIMEOUT) { + DEBUG(0, " selection time out\n"); + data->SelectionTimeOut = 0; + nsp_index_write(base, SCSIBUSCTRL, 0); + + data->CurrentSC = NULL; + tmpSC->result = DID_NO_CONNECT << 16; + tmpSC->scsi_done(tmpSC); + + return; + } + data->SelectionTimeOut += 1; + nsp_start_timer(tmpSC, data, 1000/51); + return; + } + + /* attention assert */ + //DEBUG(0, " attention assert\n"); + data->SelectionTimeOut = 0; + tmpSC->SCp.phase = PH_SELECTED; + nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN); + udelay(1); + nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB); + return; + + break; + + case PH_RESELECT: + //DEBUG(0, " phase reselect\n"); + //*sync_neg = SYNC_NOT_YET; + if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) { + + data->CurrentSC = NULL; + tmpSC->result = DID_ABORT << 16; + tmpSC->scsi_done(tmpSC); + return; + } + /* fall thru */ + default: + if ((i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { + return; + } + break; + } + + /* + * SCSI sequencer + */ + //DEBUG(0, " start scsi seq\n"); + + /* normal disconnect */ + if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) && + (irq_phase & LATCHED_BUS_FREE) != 0 ) { + DEBUG(0, " normal disconnect i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase); + if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */ + //*sync_neg = SYNC_NOT_YET; + data->CurrentSC = NULL; + tmpSC->result = (DID_OK << 16) | + ((tmpSC->SCp.Message & 0xff) << 8) | + ((tmpSC->SCp.Status & 0xff) << 0); + DEBUG(0, " command complete result=0x%x\n", tmpSC->result); + tmpSC->scsi_done(tmpSC); + + return; + } + + return; + } + + + /* check unexpected bus free state */ + if (phase == 0) { + printk(KERN_DEBUG " %s: unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", __FUNCTION__, i_src, phase, irq_phase); + + *sync_neg = SYNC_NOT_YET; + data->CurrentSC = NULL; + tmpSC->result = DID_ERROR << 16; + tmpSC->scsi_done(tmpSC); + return; + } + + switch (phase & BUSMON_PHASE_MASK) { + case BUSPHASE_COMMAND: + DEBUG(0, " BUSPHASE_COMMAND\n"); + if ((phase & BUSMON_REQ) == 0) { + DEBUG(0, " REQ == 0\n"); + return; + } + + tmpSC->SCp.phase = PH_COMMAND; + + nsp_nexus(tmpSC, data); + + /* write scsi command */ + DEBUG(0, " cmd_len=%d\n", tmpSC->cmd_len); + nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER); + for (i = 0; i < tmpSC->cmd_len; i++) { + nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]); + } + nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO); + break; + + case BUSPHASE_DATA_OUT: + DEBUG(0, " BUSPHASE_DATA_OUT\n"); + + tmpSC->SCp.phase = PH_DATA; + tmpSC->SCp.have_data_in = IO_OUT; + + nsp_pio_write(tmpSC, data); + + break; + + case BUSPHASE_DATA_IN: + DEBUG(0, " BUSPHASE_DATA_IN\n"); + + tmpSC->SCp.phase = PH_DATA; + tmpSC->SCp.have_data_in = IO_IN; + + nsp_pio_read(tmpSC, data); + + break; + + case BUSPHASE_STATUS: + nsp_dataphase_bypass(tmpSC, data); + DEBUG(0, " BUSPHASE_STATUS\n"); + + tmpSC->SCp.phase = PH_STATUS; + + tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK); + DEBUG(0, " message=0x%x status=0x%x\n", tmpSC->SCp.Message, tmpSC->SCp.Status); + + break; + + case BUSPHASE_MESSAGE_OUT: + DEBUG(0, " BUSPHASE_MESSAGE_OUT\n"); + if ((phase & BUSMON_REQ) == 0) { + goto timer_out; + } + + tmpSC->SCp.phase = PH_MSG_OUT; + + data->MsgLen = i = 0; + data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++; + + if (*sync_neg == SYNC_NOT_YET) { + data->Sync[target].SyncPeriod = 0; + data->Sync[target].SyncOffset = 0; + + /**/ + data->MsgBuffer[i] = MSG_EXTENDED; i++; + data->MsgBuffer[i] = 3; i++; + data->MsgBuffer[i] = MSG_EXT_SDTR; i++; + data->MsgBuffer[i] = 0x0c; i++; + data->MsgBuffer[i] = 15; i++; + /**/ + } + data->MsgLen = i; + + nsp_msg(tmpSC, data); + show_message(data); + nsp_message_out(tmpSC, data); + break; + + case BUSPHASE_MESSAGE_IN: + nsp_dataphase_bypass(tmpSC, data); + DEBUG(0, " BUSPHASE_MESSAGE_IN\n"); + if ((phase & BUSMON_REQ) == 0) { + goto timer_out; + } + + tmpSC->SCp.phase = PH_MSG_IN; + nsp_message_in(tmpSC, data); + + /**/ + if (*sync_neg == SYNC_NOT_YET) { + //printk("%d,%d\n",target,lun); + + if (data->MsgLen >= 5 && + data->MsgBuffer[0] == MSG_EXTENDED && + data->MsgBuffer[1] == 3 && + data->MsgBuffer[2] == MSG_EXT_SDTR ) { + data->Sync[target].SyncPeriod = data->MsgBuffer[3]; + data->Sync[target].SyncOffset = data->MsgBuffer[4]; + //printk("sync ok, %d %d\n", data->MsgBuffer[3], data->MsgBuffer[4]); + *sync_neg = SYNC_OK; + } else { + data->Sync[target].SyncPeriod = 0; + data->Sync[target].SyncOffset = 0; + *sync_neg = SYNC_NG; + } + nsp_msg(tmpSC, data); + } + /**/ + + /* search last messeage byte */ + tmp = -1; + for (i = 0; i < data->MsgLen; i++) { + tmp = data->MsgBuffer[i]; + if (data->MsgBuffer[i] == MSG_EXTENDED) { + i += (1 + data->MsgBuffer[i+1]); + } + } + tmpSC->SCp.Message = tmp; + + DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, data->MsgLen); + show_message(data); + + break; + + case BUSPHASE_SELECT: + default: + DEBUG(0, " BUSPHASE other\n"); + + break; + } + + //DEBUG(0, "%s: out\n", __FUNCTION__); + return; + +timer_out: + nsp_start_timer(tmpSC, data, 1000/102); + return; +} + +#ifdef PCMCIA_DEBUG +#include "nsp_debug.c" +#endif /* DBG_SHOWCOMMAND */ + +/*----------------------------------------------------------------*/ +/* look for ninja3 card and init if found */ +/*----------------------------------------------------------------*/ +static struct Scsi_Host *__nsp_detect(Scsi_Host_Template *sht) +{ + struct Scsi_Host *host; /* registered host structure */ + nsp_hw_data *data = &nsp_data; + + DEBUG(0, "%s: this_id=%d\n", __FUNCTION__, sht->this_id); + + request_region(data->BaseAddress, data->NumAddress, "nsp_cs"); + host = scsi_register(sht, 0); + if(host == NULL) + return NULL; + + host->unique_id = data->BaseAddress; + host->io_port = data->BaseAddress; + host->n_io_port = data->NumAddress; + host->irq = data->IrqNumber; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) + host->base = data->MmioAddress; /* kernel 2.4 */ +#else + host->base = (char *)(data->MmioAddress); /* 2.2 */ +#endif + + spin_lock_init(&(data->Lock)); + + snprintf(data->nspinfo, + sizeof(data->nspinfo), + "NinjaSCSI-3/32Bi Driver $Revision: 1.1 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d", + host->io_port, host->io_port + host->n_io_port - 1, + host->base, + host->irq); + data->nspinfo[sizeof(data->nspinfo) - 1] = '\0'; + sht->name = data->nspinfo; + + DEBUG(0, "%s: end\n", __FUNCTION__); + + //MOD_INC_USE_COUNT; + + return host; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static int nsp_detect(Scsi_Host_Template *sht) +{ + return (__nsp_detect(sht) != NULL); +} + +static int nsp_release(struct Scsi_Host *shpnt) +{ + //nsp_hw_data *data = &nsp_data; + + /* PCMCIA Card Service dose same things */ + //if (shpnt->irq) { + // free_irq(shpnt->irq, data); + //} + //if (shpnt->io_port) { + // release_region(shpnt->io_port, shpnt->n_io_port); + //} + + //MOD_DEC_USE_COUNT; + + return 0; +} +#endif + +/*----------------------------------------------------------------*/ +/* return info string */ +/*----------------------------------------------------------------*/ +static const char *nsp_info(struct Scsi_Host *shpnt) +{ + nsp_hw_data *data = &nsp_data; + + return data->nspinfo; +} + +#undef SPRINTF +#define SPRINTF(args...) \ + do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) +static int nsp_proc_info(struct Scsi_Host *host, char *buffer, + char **start, + off_t offset, + int length, + int inout) +{ + int id; + char *pos = buffer; + int thislength; + int speed; + unsigned long flags; + nsp_hw_data *data = &nsp_data; + + if (inout) { + return -EINVAL; + } + + SPRINTF("NinjaSCSI status\n\n"); + SPRINTF("Driver version: $Revision: 1.1 $\n"); + SPRINTF("SCSI host No.: %d\n", host->host_no); + SPRINTF("IRQ: %d\n", host->irq); + SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); + SPRINTF("MMIO(virtual address): 0x%lx\n", host->base); + SPRINTF("sg_tablesize: %d\n", host->sg_tablesize); + + SPRINTF("burst transfer mode: "); + switch (nsp_burst_mode) { + case BURST_IO8: + SPRINTF("io8"); + break; + case BURST_IO32: + SPRINTF("io32"); + break; + case BURST_MEM32: + SPRINTF("mem32"); + break; + default: + SPRINTF("???"); + break; + } + SPRINTF("\n"); + + + spin_lock_irqsave(&(data->Lock), flags); + SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC); + spin_unlock_irqrestore(&(data->Lock), flags); + + SPRINTF("SDTR status\n"); + for(id = 0; id < N_TARGET; id++) { + + SPRINTF("id %d: ", id); + + if (id == host->this_id) { + SPRINTF("----- NinjaSCSI-3 host adapter\n"); + continue; + } + + switch(data->Sync[id].SyncNegotiation) { + case SYNC_OK: + SPRINTF(" sync"); + break; + case SYNC_NG: + SPRINTF("async"); + break; + case SYNC_NOT_YET: + SPRINTF(" none"); + break; + default: + SPRINTF("?????"); + break; + } + + if (data->Sync[id].SyncPeriod != 0) { + speed = 1000000 / (data->Sync[id].SyncPeriod * 4); + + SPRINTF(" transfer %d.%dMB/s, offset %d", + speed / 1000, + speed % 1000, + data->Sync[id].SyncOffset + ); + } + SPRINTF("\n"); + } + + thislength = pos - (buffer + offset); + + if(thislength < 0) { + *start = 0; + return 0; + } + + + thislength = MIN(thislength, length); + *start = buffer + offset; + + return thislength; +} +#undef SPRINTF + + +/*static int nsp_eh_strategy(struct Scsi_Host *Shost) +{ + return FAILED; +}*/ + +/* +static int nsp_eh_abort(Scsi_Cmnd *SCpnt) +{ + DEBUG(0, "%s: SCpnt=0x%p\n", __FUNCTION__, SCpnt); + + return nsp_eh_bus_reset(SCpnt); +}*/ + +/* +static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt) +{ + DEBUG(0, "%s: SCpnt=0x%p\n", __FUNCTION__, SCpnt); + + return FAILED; +}*/ + +static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt) +{ + nsp_hw_data *data = &nsp_data; + unsigned int base = SCpnt->device->host->io_port; + int i; + + DEBUG(0, "%s: SCpnt=0x%p base=0x%x\n", __FUNCTION__, SCpnt, base); + + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); + + nsp_index_write(base, SCSIBUSCTRL, SCSI_RST); + mdelay(100); /* 100ms */ + nsp_index_write(base, SCSIBUSCTRL, 0); + for(i = 0; i < 5; i++) { + nsp_index_read(base, IRQPHASESENCE); /* dummy read */ + } + + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); + + nsphw_init_sync(data); + + return SUCCESS; +} + +static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt) +{ + nsp_hw_data *data = &nsp_data; + + DEBUG(0, "%s:\n", __FUNCTION__); + + nsphw_init(data); + + return SUCCESS; +} + + +/********************************************************************** + PCMCIA functions +**********************************************************************/ + +/*====================================================================== + nsp_cs_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. +======================================================================*/ +static dev_link_t *nsp_cs_attach(void) +{ + scsi_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int ret, i; + + DEBUG(0, "%s:\n", __FUNCTION__); + + /* Create new SCSI device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) { return NULL; } + memset(info, 0, sizeof(*info)); + link = &info->link; + link->priv = info; + + /* Initialize the dev_link_t structure */ + link->release.function = &nsp_cs_release; + link->release.data = (u_long)link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 0x10; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 10; /* not used */ + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) { + link->irq.IRQInfo2 = irq_mask; + } else { + for (i = 0; i < 4; i++) { + link->irq.IRQInfo2 |= 1 << irq_list[i]; + } + } + + /* IRQ $B$N3NJ]$O$3$3$G(B PCMCIA $B$N4X?t$rMQ$$$F9T$J$&$N$G(B + * host->hostdata $B$r(B irq.Instance $B$KBeF~$G$-$J$$!#(B + * host->hostdata $B$,;H$($l$PJ#?t$N(B NinjaSCSI $B$,(B + * $B;HMQ$G$-$k$N$@$,!#(B + */ + link->irq.Handler = &nspintr; + link->irq.Instance = &nsp_data; + link->irq.Attributes |= (SA_SHIRQ | SA_SAMPLE_RANDOM); + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; + + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME ; + client_reg.event_handler = &nsp_cs_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + nsp_cs_detach(link); + return NULL; + } + + return link; +} /* nsp_cs_attach */ + + +/*====================================================================== + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. +======================================================================*/ +static void nsp_cs_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "%s(0x%p)\n", __FUNCTION__, link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) { + if (*linkp == link) { + break; + } + } + if (*linkp == NULL) { + return; + } + + del_timer(&link->release); + if (link->state & DEV_CONFIG) { + nsp_cs_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + /* Break the link with Card Services */ + if (link->handle) { + CardServices(DeregisterClient, link->handle); + } + + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree(link->priv); + link->priv = NULL; + +} /* nsp_cs_detach */ + + +/*====================================================================== + nsp_cs_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. +======================================================================*/ +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry +/*====================================================================*/ + +static void nsp_cs_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + scsi_info_t *info = link->priv; + tuple_t tuple; + cisparse_t parse; + int last_ret, last_fn; + u_char tuple_data[64]; + config_info_t conf; + win_req_t req; + memreq_t map; + cistpl_cftable_entry_t dflt = { 0 }; + + struct Scsi_Host *host; + nsp_hw_data *data = &nsp_data; + + + DEBUG(0, "%s: in\n", __FUNCTION__); + + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = tuple_data; + tuple.TupleDataMax = sizeof(tuple_data); + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Look up the current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; } + if (cfg->index == 0) { goto next_entry; } + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1<vcc.param[CISTPL_POWER_VNOM]/10000) { + goto next_entry; + } + } else if (dflt.vcc.present & (1<vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + } else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; + } + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) { + link->conf.Attributes |= CONF_ENABLE_IRQ; + } + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + } + + if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { + cistpl_mem_t *mem = + (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; + req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; + req.Attributes |= WIN_ENABLE; + req.Base = mem->win[0].host_addr; + req.Size = mem->win[0].len; + if (req.Size < 0x1000) + req.Size = 0x1000; + req.AccessSpeed = 0; + link->win = (window_handle_t)link->handle; + CFG_CHECK(RequestWindow, &link->win, &req); + map.Page = 0; map.CardOffset = mem->win[0].card_addr; + CFG_CHECK(MapMemPage, link->win, &map); + + data->MmioAddress = (u_long)ioremap_nocache(req.Base, req.Size); + } + /* If we got this far, we're cool! */ + break; + + next_entry: + DEBUG(0, "%s: next\n", __FUNCTION__); + + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + CS_CHECK(GetNextTuple, handle, &tuple); + } + + if (link->conf.Attributes & CONF_ENABLE_IRQ) + CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestConfiguration, handle, &link->conf); + + if (free_ports) { + if (link->io.BasePort1) + release_region(link->io.BasePort1, link->io.NumPorts1); + if (link->io.BasePort2) + release_region(link->io.BasePort2, link->io.NumPorts2); + } + + /* Set port and IRQ */ + data->BaseAddress = link->io.BasePort1; + data->NumAddress = link->io.NumPorts1; + data->IrqNumber = link->irq.AssignedIRQ; + + DEBUG(0, "%s: I/O[0x%x+0x%x] IRQ %d\n", + __FUNCTION__, data->BaseAddress, data->NumAddress, data->IrqNumber); + + if(nsphw_init(data) == FALSE) { + goto cs_failed; + } + + host = __nsp_detect(&nsp_driver_template); + if (!host) + goto cs_failed; + + sprintf(info->node.dev_name, "scsi%d", host->host_no); + link->dev = &info->node; + info->host = host; + + /* Finally, report what we've done */ + printk(KERN_INFO "nsp_cs: index 0x%02x: Vcc %d.%d", + link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) { + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + } + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + printk(", irq %d", link->irq.AssignedIRQ); + } + if (link->io.NumPorts1) { + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + } + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2+link->io.NumPorts2-1); + if (link->win) + printk(", mem 0x%06lx-0x%06lx", req.Base, + req.Base+req.Size-1); + printk("\n"); + + scsi_add_host(host, NULL); + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + nsp_cs_release((u_long)link); + return; + +} /* nsp_cs_config */ +#undef CS_CHECK +#undef CFG_CHECK + +/*====================================================================== + After a card is removed, nsp_cs_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. +======================================================================*/ +static void nsp_cs_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + scsi_info_t *info = link->priv; + + DEBUG(0, "%s(0x%p)\n", __FUNCTION__, link); + + /* + * If the device is currently in use, we won't release until it + * is actually closed. + */ + if (link->open) { + DEBUG(1, "nsp_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Unlink the device chain */ +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,2)) + scsi_unregister_module(MODULE_SCSI_HA, &nsp_driver_template); +#else + scsi_remove_host(info->host); + scsi_unregister(info->host); +#endif + link->dev = NULL; + + if (link->win) { + iounmap((void *)(nsp_data.MmioAddress)); + CardServices(ReleaseWindow, link->win); + } + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) { + CardServices(ReleaseIO, link->handle, &link->io); + } + if (link->irq.AssignedIRQ) { + CardServices(ReleaseIRQ, link->handle, &link->irq); + } + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) { + nsp_cs_detach(link); + } +} /* nsp_cs_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + + When a CARD_REMOVAL event is received, we immediately set a flag + to block future accesses to this device. All the functions that + actually access the device should check this flag to make sure + the card is still present. + +======================================================================*/ +static int nsp_cs_event(event_t event, + int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + scsi_info_t *info = link->priv; + Scsi_Cmnd tmp; + + DEBUG(1, "%s(0x%06x)\n", __FUNCTION__, event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + DEBUG(0, " event: remove\n"); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + ((scsi_info_t *)link->priv)->stop = 1; + mod_timer(&link->release, jiffies + HZ/20); + } + break; + + case CS_EVENT_CARD_INSERTION: + DEBUG(0, " event: insert\n"); + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + nsp_cs_config(link); + break; + + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + /* Mark the device as stopped, to block IO until later */ + info->stop = 1; + if (link->state & DEV_CONFIG) { + CardServices(ReleaseConfiguration, link->handle); + } + break; + + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + DEBUG(0, " event: reset\n"); + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + } + info->stop = 0; + + tmp.device->host = info->host; + nsp_eh_host_reset(&tmp); + nsp_eh_bus_reset(&tmp); + + break; + + default: + DEBUG(0, " event: unknown\n"); + break; + } + DEBUG(0, "%s: end\n", __FUNCTION__); + return 0; +} /* nsp_cs_event */ + +static struct pcmcia_driver nsp_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "nsp_cs", + }, + .attach = nsp_cs_attach, + .detach = nsp_cs_detach, +}; + +static int __init nsp_cs_init(void) +{ + return pcmcia_register_driver(&nsp_driver); +} + + +static void __exit nsp_cs_exit(void) +{ + pcmcia_unregister_driver(&nsp_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) { + nsp_cs_release((u_long)dev_list); + } + nsp_cs_detach(dev_list); + } +} + +module_init(nsp_cs_init) +module_exit(nsp_cs_exit) diff --git a/demos/demo_rule9/rule9.cocci b/demos/demo_rule9/rule9.cocci new file mode 100644 index 0000000..6d12e33 --- /dev/null +++ b/demos/demo_rule9/rule9.cocci @@ -0,0 +1,59 @@ +// the order of rules in standard.iso is important to makes this SP works. + +@ rule1 @ +typedef Scsi_Host_Template; +{struct SHT, Scsi_Host_Template} fops; +identifier proc_info_func; +@@ + fops.proc_info = proc_info_func; + +@ rule2 @ +identifier rule1.proc_info_func; +identifier buffer, start, offset, length, inout, hostno; +identifier hostptr; +typedef off_t; +@@ + proc_info_func ( ++ struct Scsi_Host *hostptr, + char *buffer, char **start, off_t offset, int length, +- int hostno, + int inout) { + ... +- struct Scsi_Host *hostptr; + ... +- hostptr = scsi_host_hn_get(hostno); + ... +?- if (!hostptr) { ... return ...; } + ... +?- scsi_host_put(hostptr); + ... + } + +@ rule3 @ +identifier rule1.proc_info_func; +identifier rule2.hostno; +identifier rule2.hostptr; +@@ + proc_info_func(...) { + <... +- hostno ++ hostptr->host_no + ...> + } + +@ rule4 @ +identifier rule1.proc_info_func; +identifier func; +expression buffer, start, offset, length, inout, hostno; +identifier hostptr; +@@ + + func(..., struct Scsi_Host *hostptr, ...) { + <... + proc_info_func( ++ hostptr, + buffer, start, offset, length, +- hostno, + inout) + ...> + } diff --git a/demos/demo_rule9/rule9_1.cocci b/demos/demo_rule9/rule9_1.cocci new file mode 100644 index 0000000..d38c4e9 --- /dev/null +++ b/demos/demo_rule9/rule9_1.cocci @@ -0,0 +1,21 @@ +@@ +identifier proc_info_func; +identifier buffer, start, offset, length, inout, hostno; +identifier hostptr; +typedef off_t; +@@ + proc_info_func ( ++ struct Scsi_Host *hostptr, + char *buffer, char **start, off_t offset, int length, +- int hostno, + int inout) { + ... +- struct Scsi_Host *hostptr; + ... +- hostptr = scsi_host_hn_get(hostno); + ... +- if (!hostptr) { ... return ...; } + ... +- scsi_host_put(hostptr); + ... + } diff --git a/demos/demo_rule9/rule9_2.cocci b/demos/demo_rule9/rule9_2.cocci new file mode 100644 index 0000000..260ffa4 --- /dev/null +++ b/demos/demo_rule9/rule9_2.cocci @@ -0,0 +1,21 @@ +@@ +identifier proc_info_func; +identifier buffer, start, offset, length, inout, hostno; +identifier hostptr; +typedef off_t; +@@ + proc_info_func ( ++ struct Scsi_Host *hostptr, + char *buffer, char **start, off_t offset, int length, +- int hostno, + int inout) { + ... +- struct Scsi_Host *hostptr; + ... +- hostptr = scsi_host_hn_get(hostno); + ... +?- if (!hostptr) { ... return ...; } + ... +?- scsi_host_put(hostptr); + ... + } diff --git a/demos/demo_rule9/rule9_3.cocci b/demos/demo_rule9/rule9_3.cocci new file mode 100644 index 0000000..5057665 --- /dev/null +++ b/demos/demo_rule9/rule9_3.cocci @@ -0,0 +1,28 @@ +@ rule1 @ +typedef Scsi_Host_Template; +{struct SHT, Scsi_Host_Template} fops; +identifier proc_info_func; +@@ + fops.proc_info = proc_info_func; + +@@ +identifier rule1.proc_info_func; +identifier buffer, start, offset, length, inout, hostno; +identifier hostptr; +typedef off_t; +@@ + proc_info_func ( ++ struct Scsi_Host *hostptr, + char *buffer, char **start, off_t offset, int length, +- int hostno, + int inout) { + ... +- struct Scsi_Host *hostptr; + ... +- hostptr = scsi_host_hn_get(hostno); + ... +?- if (!hostptr) { ... return ...; } + ... +?- scsi_host_put(hostptr); + ... + } diff --git a/demos/demo_rule9/rule9_4.cocci b/demos/demo_rule9/rule9_4.cocci new file mode 100644 index 0000000..a6dc0d7 --- /dev/null +++ b/demos/demo_rule9/rule9_4.cocci @@ -0,0 +1,40 @@ +@ rule1 @ +typedef Scsi_Host_Template; +{struct SHT, Scsi_Host_Template} fops; +identifier proc_info_func; +@@ + fops.proc_info = proc_info_func; + +@ rule2 @ +identifier rule1.proc_info_func; +identifier buffer, start, offset, length, inout, hostno; +identifier hostptr; +typedef off_t; +@@ + proc_info_func ( ++ struct Scsi_Host *hostptr, + char *buffer, char **start, off_t offset, int length, +- int hostno, + int inout) { + ... +- struct Scsi_Host *hostptr; + ... +- hostptr = scsi_host_hn_get(hostno); + ... +?- if (!hostptr) { ... return ...; } + ... +?- scsi_host_put(hostptr); + ... + } + +@@ +identifier rule1.proc_info_func; +identifier rule2.hostno; +identifier rule2.hostptr; +@@ + proc_info_func(...) { + <... +- hostno ++ hostptr->host_no + ...> + } diff --git a/demos/demo_rule9/rule9_5.cocci b/demos/demo_rule9/rule9_5.cocci new file mode 100644 index 0000000..0964820 --- /dev/null +++ b/demos/demo_rule9/rule9_5.cocci @@ -0,0 +1,57 @@ +@ rule1 @ +typedef Scsi_Host_Template; +{struct SHT, Scsi_Host_Template} fops; +identifier proc_info_func; +@@ + fops.proc_info = proc_info_func; + +@ rule2 @ +identifier rule1.proc_info_func; +identifier buffer, start, offset, length, inout, hostno; +identifier hostptr; +typedef off_t; +@@ + proc_info_func ( ++ struct Scsi_Host *hostptr, + char *buffer, char **start, off_t offset, int length, +- int hostno, + int inout) { + ... +- struct Scsi_Host *hostptr; + ... +- hostptr = scsi_host_hn_get(hostno); + ... +?- if (!hostptr) { ... return ...; } + ... +?- scsi_host_put(hostptr); + ... + } + +@@ +identifier rule1.proc_info_func; +identifier rule2.hostno; +identifier rule2.hostptr; +@@ + proc_info_func(...) { + <... +- hostno ++ hostptr->host_no + ...> + } + +@@ +identifier rule1.proc_info_func; +identifier func; +expression buffer, start, offset, length, inout, hostno; +identifier hostptr; +@@ + + func(..., struct Scsi_Host *hostptr, ...) { + <... + proc_info_func( ++ hostptr, + buffer, start, offset, length, +- hostno, + inout) + ...> + } diff --git a/demos/demo_rule9/scsiglue.c b/demos/demo_rule9/scsiglue.c new file mode 100644 index 0000000..716af87 --- /dev/null +++ b/demos/demo_rule9/scsiglue.c @@ -0,0 +1,916 @@ +/* Driver for USB Mass Storage compliant devices + * SCSI layer glue code + * + * + * + * Current development and maintenance by: + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * + * Developed with the assistance of: + * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) + * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) + * + * Initial work by: + * (c) 1999 Michael Gee (michael@linuxspecific.com) + * + * This driver is based on the 'USB Mass Storage Class' document. This + * describes in detail the protocol used to communicate with such + * devices. Clearly, the designers had SCSI and ATAPI commands in + * mind when they created this document. The commands are all very + * similar to commands in the SCSI-II and ATAPI specifications. + * + * It is important to note that in a number of cases this class + * exhibits class-specific exemptions from the USB specification. + * Notably the usage of NAK, STALL and ACK differs from the norm, in + * that they are used to communicate wait, failed and OK on commands. + * + * Also, for certain devices, the interrupt endpoint is used to convey + * status of a command. + * + * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more + * information about this driver. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "scsiglue.h" +#include "usb.h" +#include "debug.h" +#include "transport.h" + +#include +#include + + +/*********************************************************************** + * Host functions + ***********************************************************************/ + +static const char* usb_storage_info(struct Scsi_Host *host) +{ + return "SCSI emulation for USB Mass Storage devices"; +} + +#if 0 +/* detect a virtual adapter (always works) + * Synchronization: 2.4: with the io_request_lock + * 2.5: no locks. + * fortunately we don't care. + * */ +static int usb_storage_detect(struct SHT *sht) +{ + struct us_data *us; + char local_name[32]; + + /* This is not nice at all, but how else are we to get the + * data here? */ + us = (struct us_data *)sht->proc_dir; + + /* set up the name of our subdirectory under /proc/scsi/ */ + sprintf(local_name, "usb-storage-%d", us->host_number); + sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_ATOMIC); + if (!sht->proc_name) + return 0; + strcpy(sht->proc_name, local_name); + + /* we start with no /proc directory entry */ + sht->proc_dir = NULL; + + /* register the host */ + us->host = scsi_register(sht, sizeof(us)); + if (us->host) { + struct usb_interface *iface; + us->host->hostdata[0] = (unsigned long)us; + us->host_no = us->host->host_no; + iface = usb_ifnum_to_if(us->pusb_dev, us->ifnum); + if (iface) + scsi_set_device(us->host, &iface->dev); + return 1; + } + + /* odd... didn't register properly. Abort and free pointers */ + kfree(sht->proc_name); + sht->proc_name = NULL; + return 0; +} + +/* Release all resources used by the virtual host + * + * NOTE: There is no contention here, because we're already deregistered + * the driver and we're doing each virtual host in turn, not in parallel + * Synchronization: BKL, no spinlock. + */ +static int usb_storage_release(struct Scsi_Host *psh) +{ + struct us_data *us = (struct us_data *)psh->hostdata[0]; + + US_DEBUGP("release() called for host %s\n", us->htmplt.name); + + /* Kill the control threads + * + * Enqueue the command, wake up the thread, and wait for + * notification that it has exited. + */ + US_DEBUGP("-- sending exit command to thread\n"); + BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE); + us->srb = NULL; + up(&(us->sema)); + wait_for_completion(&(us->notify)); + + /* remove the pointer to the data structure we were using */ + (struct us_data*)psh->hostdata[0] = NULL; + + /* we always have a successful release */ + return 0; +} +#endif + +/* queue a command */ +/* This is always called with scsi_lock(srb->host) held */ +static int usb_storage_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) +{ + struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; + int state = atomic_read(&us->sm_state); + + US_DEBUGP("queuecommand() called\n"); + srb->host_scribble = (unsigned char *)us; + + /* enqueue the command */ + if (state != US_STATE_IDLE || us->srb != NULL) { + printk(KERN_ERR USB_STORAGE "Error in %s: " + "state = %d, us->srb = %p\n", + __FUNCTION__, state, us->srb); + return SCSI_MLQUEUE_HOST_BUSY; + } + + srb->scsi_done = done; + us->srb = srb; + + /* wake up the process task */ + up(&(us->sema)); + + return 0; +} + +/*********************************************************************** + * Error handling functions + ***********************************************************************/ + +/* Command abort */ +/* This is always called with scsi_lock(srb->host) held */ +static int usb_storage_command_abort( Scsi_Cmnd *srb ) +{ + struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; + + US_DEBUGP("command_abort() called\n"); + + /* Is this command still active? */ + if (us->srb != srb) { + US_DEBUGP ("-- nothing to abort\n"); + return FAILED; + } + + return usb_stor_abort_transport(us); +} + +/* This invokes the transport reset mechanism to reset the state of the + * device */ +/* This is always called with scsi_lock(srb->host) held */ +static int usb_storage_device_reset( Scsi_Cmnd *srb ) +{ + struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; + int state = atomic_read(&us->sm_state); + int result; + + US_DEBUGP("device_reset() called\n" ); + if (state != US_STATE_IDLE) { + printk(KERN_ERR USB_STORAGE "Error in %s: " + "invalid state %d\n", __FUNCTION__, state); + return FAILED; + } + + /* set the state and release the lock */ + atomic_set(&us->sm_state, US_STATE_RESETTING); + scsi_unlock(srb->device->host); + + /* lock the device pointers */ + down(&(us->dev_semaphore)); + + /* do the reset */ + result = us->transport_reset(us); + + /* unlock */ + up(&(us->dev_semaphore)); + + /* lock access to the state and clear it */ + scsi_lock(srb->device->host); + atomic_set(&us->sm_state, US_STATE_IDLE); + return result; +} + +/* This resets the device port */ +/* It refuses to work if there's more than one interface in + this device, so that other users are not affected. */ +/* This is always called with scsi_lock(srb->host) held */ + +static int usb_storage_bus_reset( Scsi_Cmnd *srb ) +{ + struct us_data *us; + int result; + + /* we use the usb_reset_device() function to handle this for us */ + US_DEBUGP("bus_reset() called\n"); + scsi_unlock(srb->device->host); + us = (struct us_data *)srb->device->host->hostdata[0]; + + /* The USB subsystem doesn't handle synchronisation between + a device's several drivers. Therefore we reset only devices + with one interface which we of course own. + */ + + //FIXME: needs locking against config changes + + if ( us->pusb_dev->actconfig->desc.bNumInterfaces == 1) { + /* attempt to reset the port */ + result = usb_reset_device(us->pusb_dev); + US_DEBUGP("usb_reset_device returns %d\n", result); + } else { + result = -EBUSY; + US_DEBUGP("cannot reset a multiinterface device. failing to reset.\n"); + } + + US_DEBUGP("bus_reset() complete\n"); + scsi_lock(srb->device->host); + return result < 0 ? FAILED : SUCCESS; +} + +/*********************************************************************** + * /proc/scsi/ functions + ***********************************************************************/ + +/* we use this macro to help us write into the buffer */ +#undef SPRINTF +#define SPRINTF(args...) \ + do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) + +static int usb_storage_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +{ + struct us_data *us; + char *pos = buffer; + struct Scsi_Host *hostptr; + unsigned long f; + + /* if someone is sending us data, just throw it away */ + if (inout) + return length; + + /* find our data from the given hostno */ + hostptr = scsi_host_hn_get(hostno); + if (!hostptr) { /* if we couldn't find it, we return an error */ + return -ESRCH; + } + us = (struct us_data*)hostptr->hostdata[0]; + + /* if we couldn't find it, we return an error */ + if (!us) { + scsi_host_put(hostptr); + return -ESRCH; + } + + /* print the controller name */ + SPRINTF(" Host scsi%d: usb-storage\n", hostno); + + /* print product, vendor, and serial number strings */ + SPRINTF(" Vendor: %s\n", us->vendor); + SPRINTF(" Product: %s\n", us->product); + SPRINTF("Serial Number: %s\n", us->serial); + + /* show the protocol and transport */ + SPRINTF(" Protocol: %s\n", us->protocol_name); + SPRINTF(" Transport: %s\n", us->transport_name); + + /* show the device flags */ + if (pos < buffer + length) { + pos += sprintf(pos, " Quirks:"); + f = us->flags; + +#define DO_FLAG(a) if (f & US_FL_##a) pos += sprintf(pos, " " #a) + DO_FLAG(SINGLE_LUN); + DO_FLAG(MODE_XLATE); + DO_FLAG(START_STOP); + DO_FLAG(IGNORE_SER); + DO_FLAG(SCM_MULT_TARG); + DO_FLAG(FIX_INQUIRY); + DO_FLAG(FIX_CAPACITY); +#undef DO_FLAG + + *(pos++) = '\n'; + } + + /* release the reference count on this host */ + scsi_host_put(hostptr); + + /* + * Calculate start of next buffer, and return value. + */ + *start = buffer + offset; + + if ((pos - buffer) < offset) + return (0); + else if ((pos - buffer - offset) < length) + return (pos - buffer - offset); + else + return (length); +} + +/* + * this defines our host template, with which we'll allocate hosts + */ + +struct SHT usb_stor_host_template = { + /* basic userland interface stuff */ + .name = "usb-storage", + .proc_name = "usb-storage", + .proc_info = usb_storage_proc_info, + .proc_dir = NULL, + .info = usb_storage_info, + .ioctl = NULL, + + /* old-style detect and release */ + .detect = NULL, + .release = NULL, + + /* command interface -- queued only */ + .command = NULL, + .queuecommand = usb_storage_queuecommand, + + /* error and abort handlers */ + .eh_abort_handler = usb_storage_command_abort, + .eh_device_reset_handler = usb_storage_device_reset, + .eh_bus_reset_handler = usb_storage_bus_reset, + .eh_host_reset_handler = NULL, + .eh_strategy_handler = NULL, + + /* queue commands only, only one command per LUN */ + .can_queue = 1, + .cmd_per_lun = 1, + + /* unknown initiator id */ + .this_id = -1, + + /* no limit on commands */ + .max_sectors = 0, + + /* pre- and post- device scan functions */ + .slave_alloc = NULL, + .slave_configure = NULL, + .slave_destroy = NULL, + + /* lots of sg segments can be handled */ + .sg_tablesize = SG_ALL, + + /* use 32-bit address space for DMA */ + .unchecked_isa_dma = FALSE, + .highmem_io = FALSE, + + /* merge commands... this seems to help performance, but + * periodically someone should test to see which setting is more + * optimal. + */ + .use_clustering = TRUE, + + /* emulated HBA */ + .emulated = TRUE, + + /* sorry, no BIOS to help us */ + .bios_param = NULL, + + /* module management */ + .module = THIS_MODULE +}; + +/* For a device that is "Not Ready" */ +unsigned char usb_stor_sense_notready[18] = { + [0] = 0x70, /* current error */ + [2] = 0x02, /* not ready */ + [7] = 0x0a, /* additional length */ + [12] = 0x04, /* not ready */ + [13] = 0x03 /* manual intervention */ +}; + +/* To Report "Illegal Request: Invalid Field in CDB */ +unsigned char usb_stor_sense_invalidCDB[18] = { + [0] = 0x70, /* current error */ + [2] = ILLEGAL_REQUEST, /* Illegal Request = 0x05 */ + [7] = 0x0a, /* additional length */ + [12] = 0x24 /* Invalid Field in CDB */ +}; + +#define USB_STOR_SCSI_SENSE_HDRSZ 4 +#define USB_STOR_SCSI_SENSE_10_HDRSZ 8 + +struct usb_stor_scsi_sense_hdr +{ + __u8* dataLength; + __u8* mediumType; + __u8* devSpecParms; + __u8* blkDescLength; +}; + +typedef struct usb_stor_scsi_sense_hdr Usb_Stor_Scsi_Sense_Hdr; + +union usb_stor_scsi_sense_hdr_u +{ + Usb_Stor_Scsi_Sense_Hdr hdr; + __u8* array[USB_STOR_SCSI_SENSE_HDRSZ]; +}; + +typedef union usb_stor_scsi_sense_hdr_u Usb_Stor_Scsi_Sense_Hdr_u; + +struct usb_stor_scsi_sense_hdr_10 +{ + __u8* dataLengthMSB; + __u8* dataLengthLSB; + __u8* mediumType; + __u8* devSpecParms; + __u8* reserved1; + __u8* reserved2; + __u8* blkDescLengthMSB; + __u8* blkDescLengthLSB; +}; + +typedef struct usb_stor_scsi_sense_hdr_10 Usb_Stor_Scsi_Sense_Hdr_10; + +union usb_stor_scsi_sense_hdr_10_u +{ + Usb_Stor_Scsi_Sense_Hdr_10 hdr; + __u8* array[USB_STOR_SCSI_SENSE_10_HDRSZ]; +}; + +typedef union usb_stor_scsi_sense_hdr_10_u Usb_Stor_Scsi_Sense_Hdr_10_u; + +void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* , Usb_Stor_Scsi_Sense_Hdr_u*, + Usb_Stor_Scsi_Sense_Hdr_10_u*, int* ); + +int usb_stor_scsiSense10to6( Scsi_Cmnd* the10 ) +{ + __u8 *buffer=0; + int outputBufferSize = 0; + int length=0; + struct scatterlist *sg = 0; + int i=0, j=0, element=0; + Usb_Stor_Scsi_Sense_Hdr_u the6Locations; + Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; + int sb=0,si=0,db=0,di=0; + int sgLength=0; + + US_DEBUGP("-- converting 10 byte sense data to 6 byte\n"); + the10->cmnd[0] = the10->cmnd[0] & 0xBF; + + /* Determine buffer locations */ + usb_stor_scsiSenseParseBuffer( the10, &the6Locations, &the10Locations, + &length ); + + /* Work out minimum buffer to output */ + outputBufferSize = *the10Locations.hdr.dataLengthLSB; + outputBufferSize += USB_STOR_SCSI_SENSE_HDRSZ; + + /* Check to see if we need to trucate the output */ + if ( outputBufferSize > length ) + { + printk( KERN_WARNING USB_STORAGE + "Had to truncate MODE_SENSE_10 buffer into MODE_SENSE.\n" ); + printk( KERN_WARNING USB_STORAGE + "outputBufferSize is %d and length is %d.\n", + outputBufferSize, length ); + } + outputBufferSize = length; + + /* Data length */ + if ( *the10Locations.hdr.dataLengthMSB != 0 ) /* MSB must be zero */ + { + printk( KERN_WARNING USB_STORAGE + "Command will be truncated to fit in SENSE6 buffer.\n" ); + *the6Locations.hdr.dataLength = 0xff; + } + else + { + *the6Locations.hdr.dataLength = *the10Locations.hdr.dataLengthLSB; + } + + /* Medium type and DevSpecific parms */ + *the6Locations.hdr.mediumType = *the10Locations.hdr.mediumType; + *the6Locations.hdr.devSpecParms = *the10Locations.hdr.devSpecParms; + + /* Block descriptor length */ + if ( *the10Locations.hdr.blkDescLengthMSB != 0 ) /* MSB must be zero */ + { + printk( KERN_WARNING USB_STORAGE + "Command will be truncated to fit in SENSE6 buffer.\n" ); + *the6Locations.hdr.blkDescLength = 0xff; + } + else + { + *the6Locations.hdr.blkDescLength = *the10Locations.hdr.blkDescLengthLSB; + } + + if ( the10->use_sg == 0 ) + { + buffer = the10->request_buffer; + /* Copy the rest of the data */ + memmove( &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), + &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), + outputBufferSize - USB_STOR_SCSI_SENSE_HDRSZ ); + /* initialise last bytes left in buffer due to smaller header */ + memset( &(buffer[outputBufferSize + -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ)]), + 0, + USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); + } + else + { + sg = (struct scatterlist *) the10->request_buffer; + /* scan through this scatterlist and figure out starting positions */ + for ( i=0; i < the10->use_sg; i++) + { + sgLength = sg[i].length; + for ( j=0; juse_sg; + } + element++; + } + } + + /* Now we know where to start the copy from */ + element = USB_STOR_SCSI_SENSE_HDRSZ; + while ( element < outputBufferSize + -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) + { + /* check limits */ + if ( sb >= the10->use_sg || + si >= sg[sb].length || + db >= the10->use_sg || + di >= sg[db].length ) + { + printk( KERN_ERR USB_STORAGE + "Buffer overrun averted, this shouldn't happen!\n" ); + break; + } + + /* copy one byte */ + { + char *src = sg_address(sg[sb]) + si; + char *dst = sg_address(sg[db]) + di; + + *dst = *src; + } + + /* get next destination */ + if ( sg[db].length-1 == di ) + { + db++; + di=0; + } + else + { + di++; + } + + /* get next source */ + if ( sg[sb].length-1 == si ) + { + sb++; + si=0; + } + else + { + si++; + } + + element++; + } + /* zero the remaining bytes */ + while ( element < outputBufferSize ) + { + /* check limits */ + if ( db >= the10->use_sg || + di >= sg[db].length ) + { + printk( KERN_ERR USB_STORAGE + "Buffer overrun averted, this shouldn't happen!\n" ); + break; + } + + *(char*)(sg_address(sg[db])) = 0; + + /* get next destination */ + if ( sg[db].length-1 == di ) + { + db++; + di=0; + } + else + { + di++; + } + element++; + } + } + + /* All done any everything was fine */ + return 0; +} + +int usb_stor_scsiSense6to10( Scsi_Cmnd* the6 ) +{ + /* will be used to store part of buffer */ + __u8 tempBuffer[USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ], + *buffer=0; + int outputBufferSize = 0; + int length=0; + struct scatterlist *sg = 0; + int i=0, j=0, element=0; + Usb_Stor_Scsi_Sense_Hdr_u the6Locations; + Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; + int sb=0,si=0,db=0,di=0; + int lsb=0,lsi=0,ldb=0,ldi=0; + + US_DEBUGP("-- converting 6 byte sense data to 10 byte\n"); + the6->cmnd[0] = the6->cmnd[0] | 0x40; + + /* Determine buffer locations */ + usb_stor_scsiSenseParseBuffer( the6, &the6Locations, &the10Locations, + &length ); + + /* Work out minimum buffer to output */ + outputBufferSize = *the6Locations.hdr.dataLength; + outputBufferSize += USB_STOR_SCSI_SENSE_10_HDRSZ; + + /* Check to see if we need to trucate the output */ + if ( outputBufferSize > length ) + { + printk( KERN_WARNING USB_STORAGE + "Had to truncate MODE_SENSE into MODE_SENSE_10 buffer.\n" ); + printk( KERN_WARNING USB_STORAGE + "outputBufferSize is %d and length is %d.\n", + outputBufferSize, length ); + } + outputBufferSize = length; + + /* Block descriptor length - save these before overwriting */ + tempBuffer[2] = *the10Locations.hdr.blkDescLengthMSB; + tempBuffer[3] = *the10Locations.hdr.blkDescLengthLSB; + *the10Locations.hdr.blkDescLengthLSB = *the6Locations.hdr.blkDescLength; + *the10Locations.hdr.blkDescLengthMSB = 0; + + /* reserved - save these before overwriting */ + tempBuffer[0] = *the10Locations.hdr.reserved1; + tempBuffer[1] = *the10Locations.hdr.reserved2; + *the10Locations.hdr.reserved1 = *the10Locations.hdr.reserved2 = 0; + + /* Medium type and DevSpecific parms */ + *the10Locations.hdr.devSpecParms = *the6Locations.hdr.devSpecParms; + *the10Locations.hdr.mediumType = *the6Locations.hdr.mediumType; + + /* Data length */ + *the10Locations.hdr.dataLengthLSB = *the6Locations.hdr.dataLength; + *the10Locations.hdr.dataLengthMSB = 0; + + if ( !the6->use_sg ) + { + buffer = the6->request_buffer; + /* Copy the rest of the data */ + memmove( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), + &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), + outputBufferSize-USB_STOR_SCSI_SENSE_10_HDRSZ ); + /* Put the first four bytes (after header) in place */ + memcpy( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), + tempBuffer, + USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); + } + else + { + sg = (struct scatterlist *) the6->request_buffer; + /* scan through this scatterlist and figure out ending positions */ + for ( i=0; i < the6->use_sg; i++) + { + for ( j=0; juse_sg; + break; + } + element++; + } + } + /* scan through this scatterlist and figure out starting positions */ + element = length-1; + /* destination is the last element */ + db=the6->use_sg-1; + di=sg[db].length-1; + for ( i=the6->use_sg-1; i >= 0; i--) + { + for ( j=sg[i].length-1; j>=0; j-- ) + { + /* get to end of header and find source for copy */ + if ( element == length - 1 + - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) + { + sb=i; + si=j; + /* we've found both sets now, exit loops */ + j=-1; + i=-1; + } + element--; + } + } + /* Now we know where to start the copy from */ + element = length-1 + - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ); + while ( element >= USB_STOR_SCSI_SENSE_10_HDRSZ ) + { + /* check limits */ + if ( ( sb <= lsb && si < lsi ) || + ( db <= ldb && di < ldi ) ) + { + printk( KERN_ERR USB_STORAGE + "Buffer overrun averted, this shouldn't happen!\n" ); + break; + } + + /* copy one byte */ + { + char *src = sg_address(sg[sb]) + si; + char *dst = sg_address(sg[db]) + di; + + *dst = *src; + } + + /* get next destination */ + if ( di == 0 ) + { + db--; + di=sg[db].length-1; + } + else + { + di--; + } + + /* get next source */ + if ( si == 0 ) + { + sb--; + si=sg[sb].length-1; + } + else + { + si--; + } + + element--; + } + /* copy the remaining four bytes */ + while ( element >= USB_STOR_SCSI_SENSE_HDRSZ ) + { + /* check limits */ + if ( db <= ldb && di < ldi ) + { + printk( KERN_ERR USB_STORAGE + "Buffer overrun averted, this shouldn't happen!\n" ); + break; + } + + { + char *dst = sg_address(sg[db]) + di; + + *dst = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ]; + } + + + /* get next destination */ + if ( di == 0 ) + { + db--; + di=sg[db].length-1; + } + else + { + di--; + } + element--; + } + } + + /* All done and everything was fine */ + return 0; +} + +void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* the6, + Usb_Stor_Scsi_Sense_Hdr_10_u* the10, + int* length_p ) + +{ + int i = 0, j=0, element=0; + struct scatterlist *sg = 0; + int length = 0; + __u8* buffer=0; + + /* are we scatter-gathering? */ + if ( srb->use_sg != 0 ) + { + /* loop over all the scatter gather structures and + * get pointer to the data members in the headers + * (also work out the length while we're here) + */ + sg = (struct scatterlist *) srb->request_buffer; + for (i = 0; i < srb->use_sg; i++) + { + length += sg[i].length; + /* We only do the inner loop for the headers */ + if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) + { + /* scan through this scatterlist */ + for ( j=0; jarray[element] = sg_address(sg[i]) + j; + the10->array[element] = sg_address(sg[i]) + j; + + } + else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) + { + /* only the longer headers still cares now */ + the10->array[element] = sg_address(sg[i]) + j; + + } + /* increase element counter */ + element++; + } + } + } + } + else + { + length = srb->request_bufflen; + buffer = srb->request_buffer; + if ( length < USB_STOR_SCSI_SENSE_10_HDRSZ ) + printk( KERN_ERR USB_STORAGE + "Buffer length smaller than header!!" ); + for( i=0; iarray[i] = &(buffer[i]); + the10->array[i] = &(buffer[i]); + } + else + { + the10->array[i] = &(buffer[i]); + } + } + } + + /* Set value of length passed in */ + *length_p = length; +} + diff --git a/demos/demo_rule9/scsiglue.res b/demos/demo_rule9/scsiglue.res new file mode 100644 index 0000000..7f2711b --- /dev/null +++ b/demos/demo_rule9/scsiglue.res @@ -0,0 +1,901 @@ +/* Driver for USB Mass Storage compliant devices + * SCSI layer glue code + * + * + * + * Current development and maintenance by: + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * + * Developed with the assistance of: + * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) + * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) + * + * Initial work by: + * (c) 1999 Michael Gee (michael@linuxspecific.com) + * + * This driver is based on the 'USB Mass Storage Class' document. This + * describes in detail the protocol used to communicate with such + * devices. Clearly, the designers had SCSI and ATAPI commands in + * mind when they created this document. The commands are all very + * similar to commands in the SCSI-II and ATAPI specifications. + * + * It is important to note that in a number of cases this class + * exhibits class-specific exemptions from the USB specification. + * Notably the usage of NAK, STALL and ACK differs from the norm, in + * that they are used to communicate wait, failed and OK on commands. + * + * Also, for certain devices, the interrupt endpoint is used to convey + * status of a command. + * + * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more + * information about this driver. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "scsiglue.h" +#include "usb.h" +#include "debug.h" +#include "transport.h" + +#include +#include + + +/*********************************************************************** + * Host functions + ***********************************************************************/ + +static const char* usb_storage_info(struct Scsi_Host *host) +{ + return "SCSI emulation for USB Mass Storage devices"; +} + +#if 0 +/* detect a virtual adapter (always works) + * Synchronization: 2.4: with the io_request_lock + * 2.5: no locks. + * fortunately we don't care. + * */ +static int usb_storage_detect(struct SHT *sht) +{ + struct us_data *us; + char local_name[32]; + + /* This is not nice at all, but how else are we to get the + * data here? */ + us = (struct us_data *)sht->proc_dir; + + /* set up the name of our subdirectory under /proc/scsi/ */ + sprintf(local_name, "usb-storage-%d", us->host_number); + sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_ATOMIC); + if (!sht->proc_name) + return 0; + strcpy(sht->proc_name, local_name); + + /* we start with no /proc directory entry */ + sht->proc_dir = NULL; + + /* register the host */ + us->host = scsi_register(sht, sizeof(us)); + if (us->host) { + struct usb_interface *iface; + us->host->hostdata[0] = (unsigned long)us; + us->host_no = us->host->host_no; + iface = usb_ifnum_to_if(us->pusb_dev, us->ifnum); + if (iface) + scsi_set_device(us->host, &iface->dev); + return 1; + } + + /* odd... didn't register properly. Abort and free pointers */ + kfree(sht->proc_name); + sht->proc_name = NULL; + return 0; +} + +/* Release all resources used by the virtual host + * + * NOTE: There is no contention here, because we're already deregistered + * the driver and we're doing each virtual host in turn, not in parallel + * Synchronization: BKL, no spinlock. + */ +static int usb_storage_release(struct Scsi_Host *psh) +{ + struct us_data *us = (struct us_data *)psh->hostdata[0]; + + US_DEBUGP("release() called for host %s\n", us->htmplt.name); + + /* Kill the control threads + * + * Enqueue the command, wake up the thread, and wait for + * notification that it has exited. + */ + US_DEBUGP("-- sending exit command to thread\n"); + BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE); + us->srb = NULL; + up(&(us->sema)); + wait_for_completion(&(us->notify)); + + /* remove the pointer to the data structure we were using */ + (struct us_data*)psh->hostdata[0] = NULL; + + /* we always have a successful release */ + return 0; +} +#endif + +/* queue a command */ +/* This is always called with scsi_lock(srb->host) held */ +static int usb_storage_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) +{ + struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; + int state = atomic_read(&us->sm_state); + + US_DEBUGP("queuecommand() called\n"); + srb->host_scribble = (unsigned char *)us; + + /* enqueue the command */ + if (state != US_STATE_IDLE || us->srb != NULL) { + printk(KERN_ERR USB_STORAGE "Error in %s: " + "state = %d, us->srb = %p\n", + __FUNCTION__, state, us->srb); + return SCSI_MLQUEUE_HOST_BUSY; + } + + srb->scsi_done = done; + us->srb = srb; + + /* wake up the process task */ + up(&(us->sema)); + + return 0; +} + +/*********************************************************************** + * Error handling functions + ***********************************************************************/ + +/* Command abort */ +/* This is always called with scsi_lock(srb->host) held */ +static int usb_storage_command_abort( Scsi_Cmnd *srb ) +{ + struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; + + US_DEBUGP("command_abort() called\n"); + + /* Is this command still active? */ + if (us->srb != srb) { + US_DEBUGP ("-- nothing to abort\n"); + return FAILED; + } + + return usb_stor_abort_transport(us); +} + +/* This invokes the transport reset mechanism to reset the state of the + * device */ +/* This is always called with scsi_lock(srb->host) held */ +static int usb_storage_device_reset( Scsi_Cmnd *srb ) +{ + struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; + int state = atomic_read(&us->sm_state); + int result; + + US_DEBUGP("device_reset() called\n" ); + if (state != US_STATE_IDLE) { + printk(KERN_ERR USB_STORAGE "Error in %s: " + "invalid state %d\n", __FUNCTION__, state); + return FAILED; + } + + /* set the state and release the lock */ + atomic_set(&us->sm_state, US_STATE_RESETTING); + scsi_unlock(srb->device->host); + + /* lock the device pointers */ + down(&(us->dev_semaphore)); + + /* do the reset */ + result = us->transport_reset(us); + + /* unlock */ + up(&(us->dev_semaphore)); + + /* lock access to the state and clear it */ + scsi_lock(srb->device->host); + atomic_set(&us->sm_state, US_STATE_IDLE); + return result; +} + +/* This resets the device port */ +/* It refuses to work if there's more than one interface in + this device, so that other users are not affected. */ +/* This is always called with scsi_lock(srb->host) held */ + +static int usb_storage_bus_reset( Scsi_Cmnd *srb ) +{ + struct us_data *us; + int result; + + /* we use the usb_reset_device() function to handle this for us */ + US_DEBUGP("bus_reset() called\n"); + scsi_unlock(srb->device->host); + us = (struct us_data *)srb->device->host->hostdata[0]; + + /* The USB subsystem doesn't handle synchronisation between + a device's several drivers. Therefore we reset only devices + with one interface which we of course own. + */ + + //FIXME: needs locking against config changes + + if ( us->pusb_dev->actconfig->desc.bNumInterfaces == 1) { + /* attempt to reset the port */ + result = usb_reset_device(us->pusb_dev); + US_DEBUGP("usb_reset_device returns %d\n", result); + } else { + result = -EBUSY; + US_DEBUGP("cannot reset a multiinterface device. failing to reset.\n"); + } + + US_DEBUGP("bus_reset() complete\n"); + scsi_lock(srb->device->host); + return result < 0 ? FAILED : SUCCESS; +} + +/*********************************************************************** + * /proc/scsi/ functions + ***********************************************************************/ + +/* we use this macro to help us write into the buffer */ +#undef SPRINTF +#define SPRINTF(args...) \ + do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) + +static int usb_storage_proc_info (struct Scsi_Host *hostptr, char *buffer, char **start, off_t offset, + int length, int inout) +{ + struct us_data *us; + char *pos = buffer; + unsigned long f; + + /* if someone is sending us data, just throw it away */ + if (inout) + return length; + + us = (struct us_data*)hostptr->hostdata[0]; + + /* print the controller name */ + SPRINTF(" Host scsi%d: usb-storage\n", hostptr->host_no); + + /* print product, vendor, and serial number strings */ + SPRINTF(" Vendor: %s\n", us->vendor); + SPRINTF(" Product: %s\n", us->product); + SPRINTF("Serial Number: %s\n", us->serial); + + /* show the protocol and transport */ + SPRINTF(" Protocol: %s\n", us->protocol_name); + SPRINTF(" Transport: %s\n", us->transport_name); + + /* show the device flags */ + if (pos < buffer + length) { + pos += sprintf(pos, " Quirks:"); + f = us->flags; + +#define DO_FLAG(a) if (f & US_FL_##a) pos += sprintf(pos, " " #a) + DO_FLAG(SINGLE_LUN); + DO_FLAG(MODE_XLATE); + DO_FLAG(START_STOP); + DO_FLAG(IGNORE_SER); + DO_FLAG(SCM_MULT_TARG); + DO_FLAG(FIX_INQUIRY); + DO_FLAG(FIX_CAPACITY); +#undef DO_FLAG + + *(pos++) = '\n'; + } + + /* + * Calculate start of next buffer, and return value. + */ + *start = buffer + offset; + + if ((pos - buffer) < offset) + return (0); + else if ((pos - buffer - offset) < length) + return (pos - buffer - offset); + else + return (length); +} + +/* + * this defines our host template, with which we'll allocate hosts + */ + +struct SHT usb_stor_host_template = { + /* basic userland interface stuff */ + .name = "usb-storage", + .proc_name = "usb-storage", + .proc_info = usb_storage_proc_info, + .proc_dir = NULL, + .info = usb_storage_info, + .ioctl = NULL, + + /* old-style detect and release */ + .detect = NULL, + .release = NULL, + + /* command interface -- queued only */ + .command = NULL, + .queuecommand = usb_storage_queuecommand, + + /* error and abort handlers */ + .eh_abort_handler = usb_storage_command_abort, + .eh_device_reset_handler = usb_storage_device_reset, + .eh_bus_reset_handler = usb_storage_bus_reset, + .eh_host_reset_handler = NULL, + .eh_strategy_handler = NULL, + + /* queue commands only, only one command per LUN */ + .can_queue = 1, + .cmd_per_lun = 1, + + /* unknown initiator id */ + .this_id = -1, + + /* no limit on commands */ + .max_sectors = 0, + + /* pre- and post- device scan functions */ + .slave_alloc = NULL, + .slave_configure = NULL, + .slave_destroy = NULL, + + /* lots of sg segments can be handled */ + .sg_tablesize = SG_ALL, + + /* use 32-bit address space for DMA */ + .unchecked_isa_dma = FALSE, + .highmem_io = FALSE, + + /* merge commands... this seems to help performance, but + * periodically someone should test to see which setting is more + * optimal. + */ + .use_clustering = TRUE, + + /* emulated HBA */ + .emulated = TRUE, + + /* sorry, no BIOS to help us */ + .bios_param = NULL, + + /* module management */ + .module = THIS_MODULE +}; + +/* For a device that is "Not Ready" */ +unsigned char usb_stor_sense_notready[18] = { + [0] = 0x70, /* current error */ + [2] = 0x02, /* not ready */ + [7] = 0x0a, /* additional length */ + [12] = 0x04, /* not ready */ + [13] = 0x03 /* manual intervention */ +}; + +/* To Report "Illegal Request: Invalid Field in CDB */ +unsigned char usb_stor_sense_invalidCDB[18] = { + [0] = 0x70, /* current error */ + [2] = ILLEGAL_REQUEST, /* Illegal Request = 0x05 */ + [7] = 0x0a, /* additional length */ + [12] = 0x24 /* Invalid Field in CDB */ +}; + +#define USB_STOR_SCSI_SENSE_HDRSZ 4 +#define USB_STOR_SCSI_SENSE_10_HDRSZ 8 + +struct usb_stor_scsi_sense_hdr +{ + __u8* dataLength; + __u8* mediumType; + __u8* devSpecParms; + __u8* blkDescLength; +}; + +typedef struct usb_stor_scsi_sense_hdr Usb_Stor_Scsi_Sense_Hdr; + +union usb_stor_scsi_sense_hdr_u +{ + Usb_Stor_Scsi_Sense_Hdr hdr; + __u8* array[USB_STOR_SCSI_SENSE_HDRSZ]; +}; + +typedef union usb_stor_scsi_sense_hdr_u Usb_Stor_Scsi_Sense_Hdr_u; + +struct usb_stor_scsi_sense_hdr_10 +{ + __u8* dataLengthMSB; + __u8* dataLengthLSB; + __u8* mediumType; + __u8* devSpecParms; + __u8* reserved1; + __u8* reserved2; + __u8* blkDescLengthMSB; + __u8* blkDescLengthLSB; +}; + +typedef struct usb_stor_scsi_sense_hdr_10 Usb_Stor_Scsi_Sense_Hdr_10; + +union usb_stor_scsi_sense_hdr_10_u +{ + Usb_Stor_Scsi_Sense_Hdr_10 hdr; + __u8* array[USB_STOR_SCSI_SENSE_10_HDRSZ]; +}; + +typedef union usb_stor_scsi_sense_hdr_10_u Usb_Stor_Scsi_Sense_Hdr_10_u; + +void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* , Usb_Stor_Scsi_Sense_Hdr_u*, + Usb_Stor_Scsi_Sense_Hdr_10_u*, int* ); + +int usb_stor_scsiSense10to6( Scsi_Cmnd* the10 ) +{ + __u8 *buffer=0; + int outputBufferSize = 0; + int length=0; + struct scatterlist *sg = 0; + int i=0, j=0, element=0; + Usb_Stor_Scsi_Sense_Hdr_u the6Locations; + Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; + int sb=0,si=0,db=0,di=0; + int sgLength=0; + + US_DEBUGP("-- converting 10 byte sense data to 6 byte\n"); + the10->cmnd[0] = the10->cmnd[0] & 0xBF; + + /* Determine buffer locations */ + usb_stor_scsiSenseParseBuffer( the10, &the6Locations, &the10Locations, + &length ); + + /* Work out minimum buffer to output */ + outputBufferSize = *the10Locations.hdr.dataLengthLSB; + outputBufferSize += USB_STOR_SCSI_SENSE_HDRSZ; + + /* Check to see if we need to trucate the output */ + if ( outputBufferSize > length ) + { + printk( KERN_WARNING USB_STORAGE + "Had to truncate MODE_SENSE_10 buffer into MODE_SENSE.\n" ); + printk( KERN_WARNING USB_STORAGE + "outputBufferSize is %d and length is %d.\n", + outputBufferSize, length ); + } + outputBufferSize = length; + + /* Data length */ + if ( *the10Locations.hdr.dataLengthMSB != 0 ) /* MSB must be zero */ + { + printk( KERN_WARNING USB_STORAGE + "Command will be truncated to fit in SENSE6 buffer.\n" ); + *the6Locations.hdr.dataLength = 0xff; + } + else + { + *the6Locations.hdr.dataLength = *the10Locations.hdr.dataLengthLSB; + } + + /* Medium type and DevSpecific parms */ + *the6Locations.hdr.mediumType = *the10Locations.hdr.mediumType; + *the6Locations.hdr.devSpecParms = *the10Locations.hdr.devSpecParms; + + /* Block descriptor length */ + if ( *the10Locations.hdr.blkDescLengthMSB != 0 ) /* MSB must be zero */ + { + printk( KERN_WARNING USB_STORAGE + "Command will be truncated to fit in SENSE6 buffer.\n" ); + *the6Locations.hdr.blkDescLength = 0xff; + } + else + { + *the6Locations.hdr.blkDescLength = *the10Locations.hdr.blkDescLengthLSB; + } + + if ( the10->use_sg == 0 ) + { + buffer = the10->request_buffer; + /* Copy the rest of the data */ + memmove( &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), + &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), + outputBufferSize - USB_STOR_SCSI_SENSE_HDRSZ ); + /* initialise last bytes left in buffer due to smaller header */ + memset( &(buffer[outputBufferSize + -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ)]), + 0, + USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); + } + else + { + sg = (struct scatterlist *) the10->request_buffer; + /* scan through this scatterlist and figure out starting positions */ + for ( i=0; i < the10->use_sg; i++) + { + sgLength = sg[i].length; + for ( j=0; juse_sg; + } + element++; + } + } + + /* Now we know where to start the copy from */ + element = USB_STOR_SCSI_SENSE_HDRSZ; + while ( element < outputBufferSize + -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) + { + /* check limits */ + if ( sb >= the10->use_sg || + si >= sg[sb].length || + db >= the10->use_sg || + di >= sg[db].length ) + { + printk( KERN_ERR USB_STORAGE + "Buffer overrun averted, this shouldn't happen!\n" ); + break; + } + + /* copy one byte */ + { + char *src = sg_address(sg[sb]) + si; + char *dst = sg_address(sg[db]) + di; + + *dst = *src; + } + + /* get next destination */ + if ( sg[db].length-1 == di ) + { + db++; + di=0; + } + else + { + di++; + } + + /* get next source */ + if ( sg[sb].length-1 == si ) + { + sb++; + si=0; + } + else + { + si++; + } + + element++; + } + /* zero the remaining bytes */ + while ( element < outputBufferSize ) + { + /* check limits */ + if ( db >= the10->use_sg || + di >= sg[db].length ) + { + printk( KERN_ERR USB_STORAGE + "Buffer overrun averted, this shouldn't happen!\n" ); + break; + } + + *(char*)(sg_address(sg[db])) = 0; + + /* get next destination */ + if ( sg[db].length-1 == di ) + { + db++; + di=0; + } + else + { + di++; + } + element++; + } + } + + /* All done any everything was fine */ + return 0; +} + +int usb_stor_scsiSense6to10( Scsi_Cmnd* the6 ) +{ + /* will be used to store part of buffer */ + __u8 tempBuffer[USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ], + *buffer=0; + int outputBufferSize = 0; + int length=0; + struct scatterlist *sg = 0; + int i=0, j=0, element=0; + Usb_Stor_Scsi_Sense_Hdr_u the6Locations; + Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; + int sb=0,si=0,db=0,di=0; + int lsb=0,lsi=0,ldb=0,ldi=0; + + US_DEBUGP("-- converting 6 byte sense data to 10 byte\n"); + the6->cmnd[0] = the6->cmnd[0] | 0x40; + + /* Determine buffer locations */ + usb_stor_scsiSenseParseBuffer( the6, &the6Locations, &the10Locations, + &length ); + + /* Work out minimum buffer to output */ + outputBufferSize = *the6Locations.hdr.dataLength; + outputBufferSize += USB_STOR_SCSI_SENSE_10_HDRSZ; + + /* Check to see if we need to trucate the output */ + if ( outputBufferSize > length ) + { + printk( KERN_WARNING USB_STORAGE + "Had to truncate MODE_SENSE into MODE_SENSE_10 buffer.\n" ); + printk( KERN_WARNING USB_STORAGE + "outputBufferSize is %d and length is %d.\n", + outputBufferSize, length ); + } + outputBufferSize = length; + + /* Block descriptor length - save these before overwriting */ + tempBuffer[2] = *the10Locations.hdr.blkDescLengthMSB; + tempBuffer[3] = *the10Locations.hdr.blkDescLengthLSB; + *the10Locations.hdr.blkDescLengthLSB = *the6Locations.hdr.blkDescLength; + *the10Locations.hdr.blkDescLengthMSB = 0; + + /* reserved - save these before overwriting */ + tempBuffer[0] = *the10Locations.hdr.reserved1; + tempBuffer[1] = *the10Locations.hdr.reserved2; + *the10Locations.hdr.reserved1 = *the10Locations.hdr.reserved2 = 0; + + /* Medium type and DevSpecific parms */ + *the10Locations.hdr.devSpecParms = *the6Locations.hdr.devSpecParms; + *the10Locations.hdr.mediumType = *the6Locations.hdr.mediumType; + + /* Data length */ + *the10Locations.hdr.dataLengthLSB = *the6Locations.hdr.dataLength; + *the10Locations.hdr.dataLengthMSB = 0; + + if ( !the6->use_sg ) + { + buffer = the6->request_buffer; + /* Copy the rest of the data */ + memmove( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), + &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), + outputBufferSize-USB_STOR_SCSI_SENSE_10_HDRSZ ); + /* Put the first four bytes (after header) in place */ + memcpy( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), + tempBuffer, + USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); + } + else + { + sg = (struct scatterlist *) the6->request_buffer; + /* scan through this scatterlist and figure out ending positions */ + for ( i=0; i < the6->use_sg; i++) + { + for ( j=0; juse_sg; + break; + } + element++; + } + } + /* scan through this scatterlist and figure out starting positions */ + element = length-1; + /* destination is the last element */ + db=the6->use_sg-1; + di=sg[db].length-1; + for ( i=the6->use_sg-1; i >= 0; i--) + { + for ( j=sg[i].length-1; j>=0; j-- ) + { + /* get to end of header and find source for copy */ + if ( element == length - 1 + - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) + { + sb=i; + si=j; + /* we've found both sets now, exit loops */ + j=-1; + i=-1; + } + element--; + } + } + /* Now we know where to start the copy from */ + element = length-1 + - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ); + while ( element >= USB_STOR_SCSI_SENSE_10_HDRSZ ) + { + /* check limits */ + if ( ( sb <= lsb && si < lsi ) || + ( db <= ldb && di < ldi ) ) + { + printk( KERN_ERR USB_STORAGE + "Buffer overrun averted, this shouldn't happen!\n" ); + break; + } + + /* copy one byte */ + { + char *src = sg_address(sg[sb]) + si; + char *dst = sg_address(sg[db]) + di; + + *dst = *src; + } + + /* get next destination */ + if ( di == 0 ) + { + db--; + di=sg[db].length-1; + } + else + { + di--; + } + + /* get next source */ + if ( si == 0 ) + { + sb--; + si=sg[sb].length-1; + } + else + { + si--; + } + + element--; + } + /* copy the remaining four bytes */ + while ( element >= USB_STOR_SCSI_SENSE_HDRSZ ) + { + /* check limits */ + if ( db <= ldb && di < ldi ) + { + printk( KERN_ERR USB_STORAGE + "Buffer overrun averted, this shouldn't happen!\n" ); + break; + } + + { + char *dst = sg_address(sg[db]) + di; + + *dst = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ]; + } + + + /* get next destination */ + if ( di == 0 ) + { + db--; + di=sg[db].length-1; + } + else + { + di--; + } + element--; + } + } + + /* All done and everything was fine */ + return 0; +} + +void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* the6, + Usb_Stor_Scsi_Sense_Hdr_10_u* the10, + int* length_p ) + +{ + int i = 0, j=0, element=0; + struct scatterlist *sg = 0; + int length = 0; + __u8* buffer=0; + + /* are we scatter-gathering? */ + if ( srb->use_sg != 0 ) + { + /* loop over all the scatter gather structures and + * get pointer to the data members in the headers + * (also work out the length while we're here) + */ + sg = (struct scatterlist *) srb->request_buffer; + for (i = 0; i < srb->use_sg; i++) + { + length += sg[i].length; + /* We only do the inner loop for the headers */ + if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) + { + /* scan through this scatterlist */ + for ( j=0; jarray[element] = sg_address(sg[i]) + j; + the10->array[element] = sg_address(sg[i]) + j; + + } + else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) + { + /* only the longer headers still cares now */ + the10->array[element] = sg_address(sg[i]) + j; + + } + /* increase element counter */ + element++; + } + } + } + } + else + { + length = srb->request_bufflen; + buffer = srb->request_buffer; + if ( length < USB_STOR_SCSI_SENSE_10_HDRSZ ) + printk( KERN_ERR USB_STORAGE + "Buffer length smaller than header!!" ); + for( i=0; iarray[i] = &(buffer[i]); + the10->array[i] = &(buffer[i]); + } + else + { + the10->array[i] = &(buffer[i]); + } + } + } + + /* Set value of length passed in */ + *length_p = length; +} + diff --git a/demos/demo_rule9/sym53c8xx.c b/demos/demo_rule9/sym53c8xx.c new file mode 100644 index 0000000..e229c5e --- /dev/null +++ b/demos/demo_rule9/sym53c8xx.c @@ -0,0 +1,14738 @@ +/****************************************************************************** +** High Performance device driver for the Symbios 53C896 controller. +** +** Copyright (C) 1998-2001 Gerard Roudier +** +** This driver also supports all the Symbios 53C8XX controller family, +** except 53C810 revisions < 16, 53C825 revisions < 16 and all +** revisions of 53C815 controllers. +** +** This driver is based on the Linux port of the FreeBSD ncr driver. +** +** Copyright (C) 1994 Wolfgang Stanglmeier +** +**----------------------------------------------------------------------------- +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- +** +** The Linux port of the FreeBSD ncr driver has been achieved in +** november 1995 by: +** +** Gerard Roudier +** +** Being given that this driver originates from the FreeBSD version, and +** in order to keep synergy on both, any suggested enhancements and corrections +** received on Linux are automatically a potential candidate for the FreeBSD +** version. +** +** The original driver has been written for 386bsd and FreeBSD by +** Wolfgang Stanglmeier +** Stefan Esser +** +**----------------------------------------------------------------------------- +** +** Major contributions: +** -------------------- +** +** NVRAM detection and reading. +** Copyright (C) 1997 Richard Waltham +** +******************************************************************************* +*/ + +/* +** Supported SCSI features: +** Synchronous data transfers +** Wide16 SCSI BUS +** Disconnection/Reselection +** Tagged command queuing +** SCSI Parity checking +** +** Supported NCR/SYMBIOS chips: +** 53C810A (8 bits, Fast 10, no rom BIOS) +** 53C825A (Wide, Fast 10, on-board rom BIOS) +** 53C860 (8 bits, Fast 20, no rom BIOS) +** 53C875 (Wide, Fast 20, on-board rom BIOS) +** 53C876 (Wide, Fast 20 Dual, on-board rom BIOS) +** 53C895 (Wide, Fast 40, on-board rom BIOS) +** 53C895A (Wide, Fast 40, on-board rom BIOS) +** 53C896 (Wide, Fast 40 Dual, on-board rom BIOS) +** 53C897 (Wide, Fast 40 Dual, on-board rom BIOS) +** 53C1510D (Wide, Fast 40 Dual, on-board rom BIOS) +** 53C1010 (Wide, Fast 80 Dual, on-board rom BIOS) +** 53C1010_66(Wide, Fast 80 Dual, on-board rom BIOS, 33/66MHz PCI) +** +** Other features: +** Memory mapped IO +** Module +** Shared IRQ +*/ + +/* +** Name and version of the driver +*/ +#define SCSI_NCR_DRIVER_NAME "sym53c8xx-1.7.3c-20010512" + +#define SCSI_NCR_DEBUG_FLAGS (0) + +#define NAME53C "sym53c" +#define NAME53C8XX "sym53c8xx" + +/*========================================================== +** +** Include files +** +**========================================================== +*/ + +#include + +#include + +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,17) +#include +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,35) +#include +#endif + +#ifndef __init +#define __init +#endif +#ifndef __initdata +#define __initdata +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92) +#include +#endif + +#include "scsi.h" +#include "hosts.h" + +#include + +/* +** Define BITS_PER_LONG for earlier linux versions. +*/ +#ifndef BITS_PER_LONG +#if (~0UL) == 0xffffffffUL +#define BITS_PER_LONG 32 +#else +#define BITS_PER_LONG 64 +#endif +#endif + +/* +** Define the BSD style u_int32 and u_int64 type. +** Are in fact u_int32_t and u_int64_t :-) +*/ +typedef u32 u_int32; +typedef u64 u_int64; + +#include "sym53c8xx.h" + +/* +** Donnot compile integrity checking code for Linux-2.3.0 +** and above since SCSI data structures are not ready yet. +*/ +/* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) */ +#if 0 +#define SCSI_NCR_INTEGRITY_CHECKING +#endif + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +/* +** Hmmm... What complex some PCI-HOST bridges actually are, +** despite the fact that the PCI specifications are looking +** so smart and simple! ;-) +*/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,47) +#define SCSI_NCR_DYNAMIC_DMA_MAPPING +#endif + +/*========================================================== +** +** A la VMS/CAM-3 queue management. +** Implemented from linux list management. +** +**========================================================== +*/ + +typedef struct xpt_quehead { + struct xpt_quehead *flink; /* Forward pointer */ + struct xpt_quehead *blink; /* Backward pointer */ +} XPT_QUEHEAD; + +#define xpt_que_init(ptr) do { \ + (ptr)->flink = (ptr); (ptr)->blink = (ptr); \ +} while (0) + +static inline void __xpt_que_add(struct xpt_quehead * new, + struct xpt_quehead * blink, + struct xpt_quehead * flink) +{ + flink->blink = new; + new->flink = flink; + new->blink = blink; + blink->flink = new; +} + +static inline void __xpt_que_del(struct xpt_quehead * blink, + struct xpt_quehead * flink) +{ + flink->blink = blink; + blink->flink = flink; +} + +static inline int xpt_que_empty(struct xpt_quehead *head) +{ + return head->flink == head; +} + +static inline void xpt_que_splice(struct xpt_quehead *list, + struct xpt_quehead *head) +{ + struct xpt_quehead *first = list->flink; + + if (first != list) { + struct xpt_quehead *last = list->blink; + struct xpt_quehead *at = head->flink; + + first->blink = head; + head->flink = first; + + last->flink = at; + at->blink = last; + } +} + +#define xpt_que_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + + +#define xpt_insque(new, pos) __xpt_que_add(new, pos, (pos)->flink) + +#define xpt_remque(el) __xpt_que_del((el)->blink, (el)->flink) + +#define xpt_insque_head(new, head) __xpt_que_add(new, head, (head)->flink) + +static inline struct xpt_quehead *xpt_remque_head(struct xpt_quehead *head) +{ + struct xpt_quehead *elem = head->flink; + + if (elem != head) + __xpt_que_del(head, elem->flink); + else + elem = 0; + return elem; +} + +#define xpt_insque_tail(new, head) __xpt_que_add(new, (head)->blink, head) + +static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head) +{ + struct xpt_quehead *elem = head->blink; + + if (elem != head) + __xpt_que_del(elem->blink, head); + else + elem = 0; + return elem; +} + +/*========================================================== +** +** Configuration and Debugging +** +**========================================================== +*/ + +/* +** SCSI address of this device. +** The boot routines should have set it. +** If not, use this. +*/ + +#ifndef SCSI_NCR_MYADDR +#define SCSI_NCR_MYADDR (7) +#endif + +/* +** The maximum number of tags per logic unit. +** Used only for devices that support tags. +*/ + +#ifndef SCSI_NCR_MAX_TAGS +#define SCSI_NCR_MAX_TAGS (8) +#endif + +/* +** TAGS are actually unlimited (256 tags/lun). +** But Linux only supports 255. :) +*/ +#if SCSI_NCR_MAX_TAGS > 255 +#define MAX_TAGS 255 +#else +#define MAX_TAGS SCSI_NCR_MAX_TAGS +#endif + +/* +** Since the ncr chips only have a 8 bit ALU, we try to be clever +** about offset calculation in the TASK TABLE per LUN that is an +** array of DWORDS = 4 bytes. +*/ +#if MAX_TAGS > (512/4) +#define MAX_TASKS (1024/4) +#elif MAX_TAGS > (256/4) +#define MAX_TASKS (512/4) +#else +#define MAX_TASKS (256/4) +#endif + +/* +** This one means 'NO TAG for this job' +*/ +#define NO_TAG (256) + +/* +** Number of targets supported by the driver. +** n permits target numbers 0..n-1. +** Default is 16, meaning targets #0..#15. +** #7 .. is myself. +*/ + +#ifdef SCSI_NCR_MAX_TARGET +#define MAX_TARGET (SCSI_NCR_MAX_TARGET) +#else +#define MAX_TARGET (16) +#endif + +/* +** Number of logic units supported by the driver. +** n enables logic unit numbers 0..n-1. +** The common SCSI devices require only +** one lun, so take 1 as the default. +*/ + +#ifdef SCSI_NCR_MAX_LUN +#define MAX_LUN 64 +#else +#define MAX_LUN (1) +#endif + +/* +** Asynchronous pre-scaler (ns). Shall be 40 for +** the SCSI timings to be compliant. +*/ + +#ifndef SCSI_NCR_MIN_ASYNC +#define SCSI_NCR_MIN_ASYNC (40) +#endif + +/* +** The maximum number of jobs scheduled for starting. +** We allocate 4 entries more than the value we announce +** to the SCSI upper layer. Guess why ! :-) +*/ + +#ifdef SCSI_NCR_CAN_QUEUE +#define MAX_START (SCSI_NCR_CAN_QUEUE + 4) +#else +#define MAX_START (MAX_TARGET + 7 * MAX_TAGS) +#endif + +/* +** We donnot want to allocate more than 1 PAGE for the +** the start queue and the done queue. We hard-code entry +** size to 8 in order to let cpp do the checking. +** Allows 512-4=508 pending IOs for i386 but Linux seems for +** now not able to provide the driver with this amount of IOs. +*/ +#if MAX_START > PAGE_SIZE/8 +#undef MAX_START +#define MAX_START (PAGE_SIZE/8) +#endif + +/* +** The maximum number of segments a transfer is split into. +** We support up to 127 segments for both read and write. +*/ + +#define MAX_SCATTER (SCSI_NCR_MAX_SCATTER) +#define SCR_SG_SIZE (2) + +/* +** other +*/ + +#define NCR_SNOOP_TIMEOUT (1000000) + +/*========================================================== +** +** Miscallaneous BSDish defines. +** +**========================================================== +*/ + +#define u_char unsigned char +#define u_short unsigned short +#define u_int unsigned int +#define u_long unsigned long + +#ifndef bcopy +#define bcopy(s, d, n) memcpy((d), (s), (n)) +#endif + +#ifndef bzero +#define bzero(d, n) memset((d), 0, (n)) +#endif + +#ifndef offsetof +#define offsetof(t, m) ((size_t) (&((t *)0)->m)) +#endif + +/* +** Simple Wrapper to kernel PCI bus interface. +** +** This wrapper allows to get rid of old kernel PCI interface +** and still allows to preserve linux-2.0 compatibilty. +** In fact, it is mostly an incomplete emulation of the new +** PCI code for pre-2.2 kernels. When kernel-2.0 support +** will be dropped, we will just have to remove most of this +** code. +*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) + +typedef struct pci_dev *pcidev_t; +#define PCIDEV_NULL (0) +#define PciBusNumber(d) (d)->bus->number +#define PciDeviceFn(d) (d)->devfn +#define PciVendorId(d) (d)->vendor +#define PciDeviceId(d) (d)->device +#define PciIrqLine(d) (d)->irq + +static u_long __init +pci_get_base_cookie(struct pci_dev *pdev, int index) +{ + u_long base; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,12) + base = pdev->resource[index].start; +#else + base = pdev->base_address[index]; +#if BITS_PER_LONG > 32 + if ((base & 0x7) == 0x4) + *base |= (((u_long)pdev->base_address[++index]) << 32); +#endif +#endif + return (base & ~0x7ul); +} + +static int __init +pci_get_base_address(struct pci_dev *pdev, int index, u_long *base) +{ + u32 tmp; +#define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2)) + + pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp); + *base = tmp; + ++index; + if ((tmp & 0x7) == 0x4) { +#if BITS_PER_LONG > 32 + pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp); + *base |= (((u_long)tmp) << 32); +#endif + ++index; + } + return index; +#undef PCI_BAR_OFFSET +} + +#else /* Incomplete emulation of current PCI code for pre-2.2 kernels */ + +typedef unsigned int pcidev_t; +#define PCIDEV_NULL (~0u) +#define PciBusNumber(d) ((d)>>8) +#define PciDeviceFn(d) ((d)&0xff) +#define __PciDev(busn, devfn) (((busn)<<8)+(devfn)) + +#define pci_present pcibios_present + +#define pci_read_config_byte(d, w, v) \ + pcibios_read_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v) +#define pci_read_config_word(d, w, v) \ + pcibios_read_config_word(PciBusNumber(d), PciDeviceFn(d), w, v) +#define pci_read_config_dword(d, w, v) \ + pcibios_read_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v) + +#define pci_write_config_byte(d, w, v) \ + pcibios_write_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v) +#define pci_write_config_word(d, w, v) \ + pcibios_write_config_word(PciBusNumber(d), PciDeviceFn(d), w, v) +#define pci_write_config_dword(d, w, v) \ + pcibios_write_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v) + +static pcidev_t __init +pci_find_device(unsigned int vendor, unsigned int device, pcidev_t prev) +{ + static unsigned short pci_index; + int retv; + unsigned char bus_number, device_fn; + + if (prev == PCIDEV_NULL) + pci_index = 0; + else + ++pci_index; + retv = pcibios_find_device (vendor, device, pci_index, + &bus_number, &device_fn); + return retv ? PCIDEV_NULL : __PciDev(bus_number, device_fn); +} + +static u_short __init PciVendorId(pcidev_t dev) +{ + u_short vendor_id; + pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); + return vendor_id; +} + +static u_short __init PciDeviceId(pcidev_t dev) +{ + u_short device_id; + pci_read_config_word(dev, PCI_DEVICE_ID, &device_id); + return device_id; +} + +static u_int __init PciIrqLine(pcidev_t dev) +{ + u_char irq; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + return irq; +} + +static int __init +pci_get_base_address(pcidev_t dev, int offset, u_long *base) +{ + u_int32 tmp; + + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp); + *base = tmp; + offset += sizeof(u_int32); + if ((tmp & 0x7) == 0x4) { +#if BITS_PER_LONG > 32 + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp); + *base |= (((u_long)tmp) << 32); +#endif + offset += sizeof(u_int32); + } + return offset; +} +static u_long __init +pci_get_base_cookie(struct pci_dev *pdev, int offset) +{ + u_long base; + + (void) pci_get_base_address(dev, offset, &base); + + return base; +} + +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) */ + +/* Does not make sense in earlier kernels */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +#define pci_enable_device(pdev) (0) +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) +#define scsi_set_pci_device(inst, pdev) (0) +#endif + +/*========================================================== +** +** Debugging tags +** +**========================================================== +*/ + +#define DEBUG_ALLOC (0x0001) +#define DEBUG_PHASE (0x0002) +#define DEBUG_QUEUE (0x0008) +#define DEBUG_RESULT (0x0010) +#define DEBUG_POINTER (0x0020) +#define DEBUG_SCRIPT (0x0040) +#define DEBUG_TINY (0x0080) +#define DEBUG_TIMING (0x0100) +#define DEBUG_NEGO (0x0200) +#define DEBUG_TAGS (0x0400) +#define DEBUG_IC (0x0800) + +/* +** Enable/Disable debug messages. +** Can be changed at runtime too. +*/ + +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT +static int ncr_debug = SCSI_NCR_DEBUG_FLAGS; + #define DEBUG_FLAGS ncr_debug +#else + #define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS +#endif + +/* +** SMP threading. +** +** Assuming that SMP systems are generally high end systems and may +** use several SCSI adapters, we are using one lock per controller +** instead of some global one. For the moment (linux-2.1.95), driver's +** entry points are called with the 'io_request_lock' lock held, so: +** - We are uselessly loosing a couple of micro-seconds to lock the +** controller data structure. +** - But the driver is not broken by design for SMP and so can be +** more resistant to bugs or bad changes in the IO sub-system code. +** - A small advantage could be that the interrupt code is grained as +** wished (e.g.: threaded by controller). +*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) + +spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED; +#define NCR_LOCK_DRIVER(flags) spin_lock_irqsave(&sym53c8xx_lock, flags) +#define NCR_UNLOCK_DRIVER(flags) spin_unlock_irqrestore(&sym53c8xx_lock,flags) + +#define NCR_INIT_LOCK_NCB(np) spin_lock_init(&np->smp_lock); +#define NCR_LOCK_NCB(np, flags) spin_lock_irqsave(&np->smp_lock, flags) +#define NCR_UNLOCK_NCB(np, flags) spin_unlock_irqrestore(&np->smp_lock, flags) + +#define NCR_LOCK_SCSI_DONE(host, flags) \ + spin_lock_irqsave(((host)->host_lock), flags) +#define NCR_UNLOCK_SCSI_DONE(host, flags) \ + spin_unlock_irqrestore(((host)->host_lock), flags) + +#else + +#define NCR_LOCK_DRIVER(flags) do { save_flags(flags); cli(); } while (0) +#define NCR_UNLOCK_DRIVER(flags) do { restore_flags(flags); } while (0) + +#define NCR_INIT_LOCK_NCB(np) do { } while (0) +#define NCR_LOCK_NCB(np, flags) do { save_flags(flags); cli(); } while (0) +#define NCR_UNLOCK_NCB(np, flags) do { restore_flags(flags); } while (0) + +#define NCR_LOCK_SCSI_DONE(host, flags) do {;} while (0) +#define NCR_UNLOCK_SCSI_DONE(host, flags) do {;} while (0) + +#endif + +/* +** Memory mapped IO +** +** Since linux-2.1, we must use ioremap() to map the io memory space. +** iounmap() to unmap it. That allows portability. +** Linux 1.3.X and 2.0.X allow to remap physical pages addresses greater +** than the highest physical memory address to kernel virtual pages with +** vremap() / vfree(). That was not portable but worked with i386 +** architecture. +*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +#define ioremap vremap +#define iounmap vfree +#endif + +#ifdef __sparc__ +# include +# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) +#elif defined(__alpha__) +# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) +#else /* others */ +# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) +#endif + +#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED +static u_long __init remap_pci_mem(u_long base, u_long size) +{ + u_long page_base = ((u_long) base) & PAGE_MASK; + u_long page_offs = ((u_long) base) - page_base; + u_long page_remapped = (u_long) ioremap(page_base, page_offs+size); + + return page_remapped? (page_remapped + page_offs) : 0UL; +} + +static void __init unmap_pci_mem(u_long vaddr, u_long size) +{ + if (vaddr) + iounmap((void *) (vaddr & PAGE_MASK)); +} + +#endif /* not def SCSI_NCR_PCI_MEM_NOT_SUPPORTED */ + +/* +** Insert a delay in micro-seconds and milli-seconds. +** ------------------------------------------------- +** Under Linux, udelay() is restricted to delay < 1 milli-second. +** In fact, it generally works for up to 1 second delay. +** Since 2.1.105, the mdelay() function is provided for delays +** in milli-seconds. +** Under 2.0 kernels, udelay() is an inline function that is very +** inaccurate on Pentium processors. +*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,105) +#define UDELAY udelay +#define MDELAY mdelay +#else +static void UDELAY(long us) { udelay(us); } +static void MDELAY(long ms) { while (ms--) UDELAY(1000); } +#endif + +/* +** Simple power of two buddy-like allocator +** ---------------------------------------- +** This simple code is not intended to be fast, but to provide +** power of 2 aligned memory allocations. +** Since the SCRIPTS processor only supplies 8 bit arithmetic, +** this allocator allows simple and fast address calculations +** from the SCRIPTS code. In addition, cache line alignment +** is guaranteed for power of 2 cache line size. +** Enhanced in linux-2.3.44 to provide a memory pool per pcidev +** to support dynamic dma mapping. (I would have preferred a +** real bus astraction, btw). +*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) +#define __GetFreePages(flags, order) __get_free_pages(flags, order) +#else +#define __GetFreePages(flags, order) __get_free_pages(flags, order, 0) +#endif + +#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ +#if PAGE_SIZE >= 8192 +#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum */ +#else +#define MEMO_PAGE_ORDER 1 /* 2 PAGES maximum */ +#endif +#define MEMO_FREE_UNUSED /* Free unused pages immediately */ +#define MEMO_WARN 1 +#define MEMO_GFP_FLAGS GFP_ATOMIC +#define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER) +#define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT) +#define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1) + +typedef u_long m_addr_t; /* Enough bits to bit-hack addresses */ +typedef pcidev_t m_bush_t; /* Something that addresses DMAable */ + +typedef struct m_link { /* Link between free memory chunks */ + struct m_link *next; +} m_link_s; + +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING +typedef struct m_vtob { /* Virtual to Bus address translation */ + struct m_vtob *next; + m_addr_t vaddr; + m_addr_t baddr; +} m_vtob_s; +#define VTOB_HASH_SHIFT 5 +#define VTOB_HASH_SIZE (1UL << VTOB_HASH_SHIFT) +#define VTOB_HASH_MASK (VTOB_HASH_SIZE-1) +#define VTOB_HASH_CODE(m) \ + ((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK) +#endif + +typedef struct m_pool { /* Memory pool of a given kind */ +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + m_bush_t bush; + m_addr_t (*getp)(struct m_pool *); + void (*freep)(struct m_pool *, m_addr_t); +#define M_GETP() mp->getp(mp) +#define M_FREEP(p) mp->freep(mp, p) +#define GetPages() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER) +#define FreePages(p) free_pages(p, MEMO_PAGE_ORDER) + int nump; + m_vtob_s *(vtob[VTOB_HASH_SIZE]); + struct m_pool *next; +#else +#define M_GETP() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER) +#define M_FREEP(p) free_pages(p, MEMO_PAGE_ORDER) +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1]; +} m_pool_s; + +static void *___m_alloc(m_pool_s *mp, int size) +{ + int i = 0; + int s = (1 << MEMO_SHIFT); + int j; + m_addr_t a; + m_link_s *h = mp->h; + + if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) + return 0; + + while (size > s) { + s <<= 1; + ++i; + } + + j = i; + while (!h[j].next) { + if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { + h[j].next = (m_link_s *) M_GETP(); + if (h[j].next) + h[j].next->next = 0; + break; + } + ++j; + s <<= 1; + } + a = (m_addr_t) h[j].next; + if (a) { + h[j].next = h[j].next->next; + while (j > i) { + j -= 1; + s >>= 1; + h[j].next = (m_link_s *) (a+s); + h[j].next->next = 0; + } + } +#ifdef DEBUG + printk("___m_alloc(%d) = %p\n", size, (void *) a); +#endif + return (void *) a; +} + +static void ___m_free(m_pool_s *mp, void *ptr, int size) +{ + int i = 0; + int s = (1 << MEMO_SHIFT); + m_link_s *q; + m_addr_t a, b; + m_link_s *h = mp->h; + +#ifdef DEBUG + printk("___m_free(%p, %d)\n", ptr, size); +#endif + + if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) + return; + + while (size > s) { + s <<= 1; + ++i; + } + + a = (m_addr_t) ptr; + + while (1) { +#ifdef MEMO_FREE_UNUSED + if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { + M_FREEP(a); + break; + } +#endif + b = a ^ s; + q = &h[i]; + while (q->next && q->next != (m_link_s *) b) { + q = q->next; + } + if (!q->next) { + ((m_link_s *) a)->next = h[i].next; + h[i].next = (m_link_s *) a; + break; + } + q->next = q->next->next; + a = a & b; + s <<= 1; + ++i; + } +} + +static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags) +{ + void *p; + + p = ___m_alloc(mp, size); + + if (DEBUG_FLAGS & DEBUG_ALLOC) + printk ("new %-10s[%4d] @%p.\n", name, size, p); + + if (p) + bzero(p, size); + else if (uflags & MEMO_WARN) + printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size); + + return p; +} + +#define __m_calloc(mp, s, n) __m_calloc2(mp, s, n, MEMO_WARN) + +static void __m_free(m_pool_s *mp, void *ptr, int size, char *name) +{ + if (DEBUG_FLAGS & DEBUG_ALLOC) + printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr); + + ___m_free(mp, ptr, size); + +} + +/* + * With pci bus iommu support, we use a default pool of unmapped memory + * for memory we donnot need to DMA from/to and one pool per pcidev for + * memory accessed by the PCI chip. `mp0' is the default not DMAable pool. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +static m_pool_s mp0; + +#else + +static m_addr_t ___mp0_getp(m_pool_s *mp) +{ + m_addr_t m = GetPages(); + if (m) + ++mp->nump; + return m; +} + +static void ___mp0_freep(m_pool_s *mp, m_addr_t m) +{ + FreePages(m); + --mp->nump; +} + +static m_pool_s mp0 = {0, ___mp0_getp, ___mp0_freep}; + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +static void *m_calloc(int size, char *name) +{ + u_long flags; + void *m; + NCR_LOCK_DRIVER(flags); + m = __m_calloc(&mp0, size, name); + NCR_UNLOCK_DRIVER(flags); + return m; +} + +static void m_free(void *ptr, int size, char *name) +{ + u_long flags; + NCR_LOCK_DRIVER(flags); + __m_free(&mp0, ptr, size, name); + NCR_UNLOCK_DRIVER(flags); +} + +/* + * DMAable pools. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +/* Without pci bus iommu support, all the memory is assumed DMAable */ + +#define __m_calloc_dma(b, s, n) m_calloc(s, n) +#define __m_free_dma(b, p, s, n) m_free(p, s, n) +#define __vtobus(b, p) virt_to_bus(p) + +#else + +/* + * With pci bus iommu support, we maintain one pool per pcidev and a + * hashed reverse table for virtual to bus physical address translations. + */ +static m_addr_t ___dma_getp(m_pool_s *mp) +{ + m_addr_t vp; + m_vtob_s *vbp; + + vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB"); + if (vbp) { + dma_addr_t daddr; + vp = (m_addr_t) pci_alloc_consistent(mp->bush, + PAGE_SIZE<vaddr = vp; + vbp->baddr = daddr; + vbp->next = mp->vtob[hc]; + mp->vtob[hc] = vbp; + ++mp->nump; + return vp; + } + else + __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); + } + return 0; +} + +static void ___dma_freep(m_pool_s *mp, m_addr_t m) +{ + m_vtob_s **vbpp, *vbp; + int hc = VTOB_HASH_CODE(m); + + vbpp = &mp->vtob[hc]; + while (*vbpp && (*vbpp)->vaddr != m) + vbpp = &(*vbpp)->next; + if (*vbpp) { + vbp = *vbpp; + *vbpp = (*vbpp)->next; + pci_free_consistent(mp->bush, PAGE_SIZE<vaddr, (dma_addr_t)vbp->baddr); + __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); + --mp->nump; + } +} + +static inline m_pool_s *___get_dma_pool(m_bush_t bush) +{ + m_pool_s *mp; + for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next); + return mp; +} + +static m_pool_s *___cre_dma_pool(m_bush_t bush) +{ + m_pool_s *mp; + mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL"); + if (mp) { + bzero(mp, sizeof(*mp)); + mp->bush = bush; + mp->getp = ___dma_getp; + mp->freep = ___dma_freep; + mp->next = mp0.next; + mp0.next = mp; + } + return mp; +} + +static void ___del_dma_pool(m_pool_s *p) +{ + struct m_pool **pp = &mp0.next; + + while (*pp && *pp != p) + pp = &(*pp)->next; + if (*pp) { + *pp = (*pp)->next; + __m_free(&mp0, p, sizeof(*p), "MPOOL"); + } +} + +static void *__m_calloc_dma(m_bush_t bush, int size, char *name) +{ + u_long flags; + struct m_pool *mp; + void *m = 0; + + NCR_LOCK_DRIVER(flags); + mp = ___get_dma_pool(bush); + if (!mp) + mp = ___cre_dma_pool(bush); + if (mp) + m = __m_calloc(mp, size, name); + if (mp && !mp->nump) + ___del_dma_pool(mp); + NCR_UNLOCK_DRIVER(flags); + + return m; +} + +static void __m_free_dma(m_bush_t bush, void *m, int size, char *name) +{ + u_long flags; + struct m_pool *mp; + + NCR_LOCK_DRIVER(flags); + mp = ___get_dma_pool(bush); + if (mp) + __m_free(mp, m, size, name); + if (mp && !mp->nump) + ___del_dma_pool(mp); + NCR_UNLOCK_DRIVER(flags); +} + +static m_addr_t __vtobus(m_bush_t bush, void *m) +{ + u_long flags; + m_pool_s *mp; + int hc = VTOB_HASH_CODE(m); + m_vtob_s *vp = 0; + m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK; + + NCR_LOCK_DRIVER(flags); + mp = ___get_dma_pool(bush); + if (mp) { + vp = mp->vtob[hc]; + while (vp && (m_addr_t) vp->vaddr != a) + vp = vp->next; + } + NCR_UNLOCK_DRIVER(flags); + return vp ? vp->baddr + (((m_addr_t) m) - a) : 0; +} + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +#define _m_calloc_dma(np, s, n) __m_calloc_dma(np->pdev, s, n) +#define _m_free_dma(np, p, s, n) __m_free_dma(np->pdev, p, s, n) +#define m_calloc_dma(s, n) _m_calloc_dma(np, s, n) +#define m_free_dma(p, s, n) _m_free_dma(np, p, s, n) +#define _vtobus(np, p) __vtobus(np->pdev, p) +#define vtobus(p) _vtobus(np, p) + +/* + * Deal with DMA mapping/unmapping. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +/* Linux versions prior to pci bus iommu kernel interface */ + +#define __unmap_scsi_data(pdev, cmd) do {; } while (0) +#define __map_scsi_single_data(pdev, cmd) (__vtobus(pdev,(cmd)->request_buffer)) +#define __map_scsi_sg_data(pdev, cmd) ((cmd)->use_sg) +#define __sync_scsi_data(pdev, cmd) do {; } while (0) + +#define scsi_sg_dma_address(sc) vtobus((sc)->address) +#define scsi_sg_dma_len(sc) ((sc)->length) + +#else + +/* Linux version with pci bus iommu kernel interface */ + +/* To keep track of the dma mapping (sg/single) that has been set */ +#define __data_mapped(cmd) (cmd)->SCp.phase +#define __data_mapping(cmd) (cmd)->SCp.dma_handle + +static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(__data_mapped(cmd)) { + case 2: + pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + pci_unmap_page(pdev, __data_mapping(cmd), + cmd->request_bufflen, dma_dir); + break; + } + __data_mapped(cmd) = 0; +} + +static dma_addr_t __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + dma_addr_t mapping; + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + if (cmd->request_bufflen == 0) + return 0; + + mapping = pci_map_page(pdev, + virt_to_page(cmd->request_buffer), + ((unsigned long)cmd->request_buffer & + ~PAGE_MASK), + cmd->request_bufflen, dma_dir); + __data_mapped(cmd) = 1; + __data_mapping(cmd) = mapping; + + return mapping; +} + +static int __map_scsi_sg_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int use_sg; + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + if (cmd->use_sg == 0) + return 0; + + use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + __data_mapped(cmd) = 2; + __data_mapping(cmd) = use_sg; + + return use_sg; +} + +static void __sync_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(__data_mapped(cmd)) { + case 2: + pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + pci_dma_sync_single(pdev, __data_mapping(cmd), + cmd->request_bufflen, dma_dir); + break; + } +} + +#define scsi_sg_dma_address(sc) sg_dma_address(sc) +#define scsi_sg_dma_len(sc) sg_dma_len(sc) + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->pdev, cmd) +#define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->pdev, cmd) +#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->pdev, cmd) +#define sync_scsi_data(np, cmd) __sync_scsi_data(np->pdev, cmd) + + +/* + * Print out some buffer. + */ +static void ncr_print_hex(u_char *p, int n) +{ + while (n-- > 0) + printk (" %x", *p++); +} + +static void ncr_printl_hex(char *label, u_char *p, int n) +{ + printk("%s", label); + ncr_print_hex(p, n); + printk (".\n"); +} + +/* +** Transfer direction +** +** Until some linux kernel version near 2.3.40, low-level scsi +** drivers were not told about data transfer direction. +** We check the existence of this feature that has been expected +** for a _long_ time by all SCSI driver developers by just +** testing against the definition of SCSI_DATA_UNKNOWN. Indeed +** this is a hack, but testing against a kernel version would +** have been a shame. ;-) +*/ +#ifdef SCSI_DATA_UNKNOWN + +#define scsi_data_direction(cmd) (cmd->sc_data_direction) + +#else + +#define SCSI_DATA_UNKNOWN 0 +#define SCSI_DATA_WRITE 1 +#define SCSI_DATA_READ 2 +#define SCSI_DATA_NONE 3 + +static __inline__ int scsi_data_direction(Scsi_Cmnd *cmd) +{ + int direction; + + switch((int) cmd->cmnd[0]) { + case 0x08: /* READ(6) 08 */ + case 0x28: /* READ(10) 28 */ + case 0xA8: /* READ(12) A8 */ + direction = SCSI_DATA_READ; + break; + case 0x0A: /* WRITE(6) 0A */ + case 0x2A: /* WRITE(10) 2A */ + case 0xAA: /* WRITE(12) AA */ + direction = SCSI_DATA_WRITE; + break; + default: + direction = SCSI_DATA_UNKNOWN; + break; + } + + return direction; +} + +#endif /* SCSI_DATA_UNKNOWN */ + + +/* +** /proc directory entry and proc_info function +*/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,27) +static struct proc_dir_entry proc_scsi_sym53c8xx = { + PROC_SCSI_SYM53C8XX, 9, NAME53C8XX, + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +#endif +#ifdef SCSI_NCR_PROC_INFO_SUPPORT +static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int func); +#endif + +/* +** Driver setup. +** +** This structure is initialized from linux config options. +** It can be overridden at boot-up by the boot command line. +*/ +static struct ncr_driver_setup + driver_setup = SCSI_NCR_DRIVER_SETUP; + +#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT +static struct ncr_driver_setup + driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP; +# ifdef MODULE +char *sym53c8xx = 0; /* command line passed by insmod */ +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) +MODULE_PARM(sym53c8xx, "s"); +# endif +# endif +#endif + +/* +** Other Linux definitions +*/ +#define SetScsiResult(cmd, h_sts, s_sts) \ + cmd->result = (((h_sts) << 16) + ((s_sts) & 0x7f)) + +/* We may have to remind our amnesiac SCSI layer of the reason of the abort */ +#if 0 +#define SetScsiAbortResult(cmd) \ + SetScsiResult( \ + cmd, \ + (cmd)->abort_reason == DID_TIME_OUT ? DID_TIME_OUT : DID_ABORT, \ + 0xff) +#else +#define SetScsiAbortResult(cmd) SetScsiResult(cmd, DID_ABORT, 0xff) +#endif + +static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs); +static void sym53c8xx_timeout(unsigned long np); + +#define initverbose (driver_setup.verbose) +#define bootverbose (np->verbose) + +#ifdef SCSI_NCR_NVRAM_SUPPORT +static u_char Tekram_sync[16] __initdata = + {25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10}; +#endif /* SCSI_NCR_NVRAM_SUPPORT */ + +/* +** Structures used by sym53c8xx_detect/sym53c8xx_pci_init to +** transmit device configuration to the ncr_attach() function. +*/ +typedef struct { + int bus; + u_char device_fn; + u_long base; + u_long base_2; + u_long io_port; + u_long base_c; + u_long base_2_c; + int irq; +/* port and reg fields to use INB, OUTB macros */ + u_long base_io; + volatile struct ncr_reg *reg; +} ncr_slot; + +typedef struct { + int type; +#define SCSI_NCR_SYMBIOS_NVRAM (1) +#define SCSI_NCR_TEKRAM_NVRAM (2) +#ifdef SCSI_NCR_NVRAM_SUPPORT + union { + Symbios_nvram Symbios; + Tekram_nvram Tekram; + } data; +#endif +} ncr_nvram; + +/* +** Structure used by sym53c8xx_detect/sym53c8xx_pci_init +** to save data on each detected board for ncr_attach(). +*/ +typedef struct { + pcidev_t pdev; + ncr_slot slot; + ncr_chip chip; + ncr_nvram *nvram; + u_char host_id; +#ifdef SCSI_NCR_PQS_PDS_SUPPORT + u_char pqs_pds; +#endif + int attach_done; +} ncr_device; + +/*========================================================== +** +** assert () +** +**========================================================== +** +** modified copy from 386bsd:/usr/include/sys/assert.h +** +**---------------------------------------------------------- +*/ + +#define assert(expression) { \ + if (!(expression)) { \ + (void)panic( \ + "assertion \"%s\" failed: file \"%s\", line %d\n", \ + #expression, \ + __FILE__, __LINE__); \ + } \ +} + +/*========================================================== +** +** Command control block states. +** +**========================================================== +*/ + +#define HS_IDLE (0) +#define HS_BUSY (1) +#define HS_NEGOTIATE (2) /* sync/wide data transfer*/ +#define HS_DISCONNECT (3) /* Disconnected by target */ + +#define HS_DONEMASK (0x80) +#define HS_COMPLETE (4|HS_DONEMASK) +#define HS_SEL_TIMEOUT (5|HS_DONEMASK) /* Selection timeout */ +#define HS_RESET (6|HS_DONEMASK) /* SCSI reset */ +#define HS_ABORTED (7|HS_DONEMASK) /* Transfer aborted */ +#define HS_TIMEOUT (8|HS_DONEMASK) /* Software timeout */ +#define HS_FAIL (9|HS_DONEMASK) /* SCSI or PCI bus errors */ +#define HS_UNEXPECTED (10|HS_DONEMASK)/* Unexpected disconnect */ + +#define DSA_INVALID 0xffffffff + +/*========================================================== +** +** Software Interrupt Codes +** +**========================================================== +*/ + +#define SIR_BAD_STATUS (1) +#define SIR_SEL_ATN_NO_MSG_OUT (2) +#define SIR_MSG_RECEIVED (3) +#define SIR_MSG_WEIRD (4) +#define SIR_NEGO_FAILED (5) +#define SIR_NEGO_PROTO (6) +#define SIR_SCRIPT_STOPPED (7) +#define SIR_REJECT_TO_SEND (8) +#define SIR_SWIDE_OVERRUN (9) +#define SIR_SODL_UNDERRUN (10) +#define SIR_RESEL_NO_MSG_IN (11) +#define SIR_RESEL_NO_IDENTIFY (12) +#define SIR_RESEL_BAD_LUN (13) +#define SIR_TARGET_SELECTED (14) +#define SIR_RESEL_BAD_I_T_L (15) +#define SIR_RESEL_BAD_I_T_L_Q (16) +#define SIR_ABORT_SENT (17) +#define SIR_RESEL_ABORTED (18) +#define SIR_MSG_OUT_DONE (19) +#define SIR_AUTO_SENSE_DONE (20) +#define SIR_DUMMY_INTERRUPT (21) +#define SIR_DATA_OVERRUN (22) +#define SIR_BAD_PHASE (23) +#define SIR_MAX (23) + +/*========================================================== +** +** Extended error bits. +** xerr_status field of struct ccb. +** +**========================================================== +*/ + +#define XE_EXTRA_DATA (1) /* unexpected data phase */ +#define XE_BAD_PHASE (2) /* illegal phase (4/5) */ +#define XE_PARITY_ERR (4) /* unrecovered SCSI parity error */ +#define XE_SODL_UNRUN (1<<3) +#define XE_SWIDE_OVRUN (1<<4) + +/*========================================================== +** +** Negotiation status. +** nego_status field of struct ccb. +** +**========================================================== +*/ + +#define NS_NOCHANGE (0) +#define NS_SYNC (1) +#define NS_WIDE (2) +#define NS_PPR (4) + +/*========================================================== +** +** "Special features" of targets. +** quirks field of struct tcb. +** actualquirks field of struct ccb. +** +**========================================================== +*/ + +#define QUIRK_AUTOSAVE (0x01) + +/*========================================================== +** +** Capability bits in Inquire response byte 7. +** +**========================================================== +*/ + +#define INQ7_QUEUE (0x02) +#define INQ7_SYNC (0x10) +#define INQ7_WIDE16 (0x20) + +/*========================================================== +** +** A CCB hashed table is used to retrieve CCB address +** from DSA value. +** +**========================================================== +*/ + +#define CCB_HASH_SHIFT 8 +#define CCB_HASH_SIZE (1UL << CCB_HASH_SHIFT) +#define CCB_HASH_MASK (CCB_HASH_SIZE-1) +#define CCB_HASH_CODE(dsa) (((dsa) >> 11) & CCB_HASH_MASK) + +/*========================================================== +** +** Declaration of structs. +** +**========================================================== +*/ + +struct tcb; +struct lcb; +struct ccb; +struct ncb; +struct script; + +typedef struct ncb * ncb_p; +typedef struct tcb * tcb_p; +typedef struct lcb * lcb_p; +typedef struct ccb * ccb_p; + +struct link { + ncrcmd l_cmd; + ncrcmd l_paddr; +}; + +struct usrcmd { + u_long target; + u_long lun; + u_long data; + u_long cmd; +}; + +#define UC_SETSYNC 10 +#define UC_SETTAGS 11 +#define UC_SETDEBUG 12 +#define UC_SETORDER 13 +#define UC_SETWIDE 14 +#define UC_SETFLAG 15 +#define UC_SETVERBOSE 17 +#define UC_RESETDEV 18 +#define UC_CLEARDEV 19 + +#define UF_TRACE (0x01) +#define UF_NODISC (0x02) +#define UF_NOSCAN (0x04) + +/*======================================================================== +** +** Declaration of structs: target control block +** +**======================================================================== +*/ +struct tcb { + /*---------------------------------------------------------------- + ** LUN tables. + ** An array of bus addresses is used on reselection by + ** the SCRIPT. + **---------------------------------------------------------------- + */ + u_int32 *luntbl; /* lcbs bus address table */ + u_int32 b_luntbl; /* bus address of this table */ + u_int32 b_lun0; /* bus address of lun0 */ + lcb_p l0p; /* lcb of LUN #0 (normal case) */ +#if MAX_LUN > 1 + lcb_p *lmp; /* Other lcb's [1..MAX_LUN] */ +#endif + /*---------------------------------------------------------------- + ** Target capabilities. + **---------------------------------------------------------------- + */ + u_char inq_done; /* Target capabilities received */ + u_char inq_byte7; /* Contains these capabilities */ + + /*---------------------------------------------------------------- + ** Some flags. + **---------------------------------------------------------------- + */ + u_char to_reset; /* This target is to be reset */ + + /*---------------------------------------------------------------- + ** Pointer to the ccb used for negotiation. + ** Prevent from starting a negotiation for all queued commands + ** when tagged command queuing is enabled. + **---------------------------------------------------------------- + */ + ccb_p nego_cp; + + /*---------------------------------------------------------------- + ** negotiation of wide and synch transfer and device quirks. + ** sval, wval and uval are read from SCRIPTS and so have alignment + ** constraints. + **---------------------------------------------------------------- + */ +/*0*/ u_char uval; +/*1*/ u_char sval; +/*2*/ u_char filler2; +/*3*/ u_char wval; + u_short period; + u_char minsync; + u_char maxoffs; + u_char quirks; + u_char widedone; + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + u_char ic_min_sync; + u_char ic_max_width; + u_char ic_done; +#endif + u_char ic_maximums_set; + u_char ppr_negotiation; + + /*---------------------------------------------------------------- + ** User settable limits and options. + ** These limits are read from the NVRAM if present. + **---------------------------------------------------------------- + */ + u_char usrsync; + u_char usrwide; + u_short usrtags; + u_char usrflag; +}; + +/*======================================================================== +** +** Declaration of structs: lun control block +** +**======================================================================== +*/ +struct lcb { + /*---------------------------------------------------------------- + ** On reselection, SCRIPTS use this value as a JUMP address + ** after the IDENTIFY has been successfully received. + ** This field is set to 'resel_tag' if TCQ is enabled and + ** to 'resel_notag' if TCQ is disabled. + ** (Must be at zero due to bad lun handling on reselection) + **---------------------------------------------------------------- + */ +/*0*/ u_int32 resel_task; + + /*---------------------------------------------------------------- + ** Task table used by the script processor to retrieve the + ** task corresponding to a reselected nexus. The TAG is used + ** as offset to determine the corresponding entry. + ** Each entry contains the associated CCB bus address. + **---------------------------------------------------------------- + */ + u_int32 tasktbl_0; /* Used if TCQ not enabled */ + u_int32 *tasktbl; + u_int32 b_tasktbl; + + /*---------------------------------------------------------------- + ** CCB queue management. + **---------------------------------------------------------------- + */ + XPT_QUEHEAD busy_ccbq; /* Queue of busy CCBs */ + XPT_QUEHEAD wait_ccbq; /* Queue of waiting for IO CCBs */ + u_short busyccbs; /* CCBs busy for this lun */ + u_short queuedccbs; /* CCBs queued to the controller*/ + u_short queuedepth; /* Queue depth for this lun */ + u_short scdev_depth; /* SCSI device queue depth */ + u_short maxnxs; /* Max possible nexuses */ + + /*---------------------------------------------------------------- + ** Control of tagged command queuing. + ** Tags allocation is performed using a circular buffer. + ** This avoids using a loop for tag allocation. + **---------------------------------------------------------------- + */ + u_short ia_tag; /* Tag allocation index */ + u_short if_tag; /* Tag release index */ + u_char *cb_tags; /* Circular tags buffer */ + u_char inq_byte7; /* Store unit CmdQ capability */ + u_char usetags; /* Command queuing is active */ + u_char to_clear; /* User wants to clear all tasks*/ + u_short maxtags; /* Max NR of tags asked by user */ + u_short numtags; /* Current number of tags */ + + /*---------------------------------------------------------------- + ** QUEUE FULL and ORDERED tag control. + **---------------------------------------------------------------- + */ + u_short num_good; /* Nr of GOOD since QUEUE FULL */ + u_short tags_sum[2]; /* Tags sum counters */ + u_char tags_si; /* Current index to tags sum */ + u_long tags_stime; /* Last time we switch tags_sum */ +}; + +/*======================================================================== +** +** Declaration of structs: actions for a task. +** +**======================================================================== +** +** It is part of the CCB and is called by the scripts processor to +** start or restart the data structure (nexus). +** +**------------------------------------------------------------------------ +*/ +struct action { + u_int32 start; + u_int32 restart; +}; + +/*======================================================================== +** +** Declaration of structs: Phase mismatch context. +** +**======================================================================== +** +** It is part of the CCB and is used as parameters for the DATA +** pointer. We need two contexts to handle correctly the SAVED +** DATA POINTER. +** +**------------------------------------------------------------------------ +*/ +struct pm_ctx { + struct scr_tblmove sg; /* Updated interrupted SG block */ + u_int32 ret; /* SCRIPT return address */ +}; + +/*======================================================================== +** +** Declaration of structs: global HEADER. +** +**======================================================================== +** +** In earlier driver versions, this substructure was copied from the +** ccb to a global address after selection (or reselection) and copied +** back before disconnect. Since we are now using LOAD/STORE DSA +** RELATIVE instructions, the script is able to access directly these +** fields, and so, this header is no more copied. +** +**------------------------------------------------------------------------ +*/ + +struct head { + /*---------------------------------------------------------------- + ** Start and restart SCRIPTS addresses (must be at 0). + **---------------------------------------------------------------- + */ + struct action go; + + /*---------------------------------------------------------------- + ** Saved data pointer. + ** Points to the position in the script responsible for the + ** actual transfer of data. + ** It's written after reception of a SAVE_DATA_POINTER message. + ** The goalpointer points after the last transfer command. + **---------------------------------------------------------------- + */ + u_int32 savep; + u_int32 lastp; + u_int32 goalp; + + /*---------------------------------------------------------------- + ** Alternate data pointer. + ** They are copied back to savep/lastp/goalp by the SCRIPTS + ** when the direction is unknown and the device claims data out. + **---------------------------------------------------------------- + */ + u_int32 wlastp; + u_int32 wgoalp; + + /*---------------------------------------------------------------- + ** Status fields. + **---------------------------------------------------------------- + */ + u_char status[4]; /* host status */ +}; + +/* +** LUN control block lookup. +** We use a direct pointer for LUN #0, and a table of pointers +** which is only allocated for devices that support LUN(s) > 0. +*/ +#if MAX_LUN <= 1 +#define ncr_lp(np, tp, lun) (!lun) ? (tp)->l0p : 0 +#else +#define ncr_lp(np, tp, lun) \ + (!lun) ? (tp)->l0p : (tp)->lmp ? (tp)->lmp[(lun)] : 0 +#endif + +/* +** The status bytes are used by the host and the script processor. +** +** The four bytes (status[4]) are copied to the scratchb register +** (declared as scr0..scr3 in ncr_reg.h) just after the select/reselect, +** and copied back just after disconnecting. +** Inside the script the XX_REG are used. +*/ + +/* +** Last four bytes (script) +*/ +#define QU_REG scr0 +#define HS_REG scr1 +#define HS_PRT nc_scr1 +#define SS_REG scr2 +#define SS_PRT nc_scr2 +#define HF_REG scr3 +#define HF_PRT nc_scr3 + +/* +** Last four bytes (host) +*/ +#define actualquirks phys.header.status[0] +#define host_status phys.header.status[1] +#define scsi_status phys.header.status[2] +#define host_flags phys.header.status[3] + +/* +** Host flags +*/ +#define HF_IN_PM0 1u +#define HF_IN_PM1 (1u<<1) +#define HF_ACT_PM (1u<<2) +#define HF_DP_SAVED (1u<<3) +#define HF_AUTO_SENSE (1u<<4) +#define HF_DATA_IN (1u<<5) +#define HF_PM_TO_C (1u<<6) +#define HF_EXT_ERR (1u<<7) + +#ifdef SCSI_NCR_IARB_SUPPORT +#define HF_HINT_IARB (1u<<7) +#endif + +/* +** This one is stolen from QU_REG.:) +*/ +#define HF_DATA_ST (1u<<7) + +/*========================================================== +** +** Declaration of structs: Data structure block +** +**========================================================== +** +** During execution of a ccb by the script processor, +** the DSA (data structure address) register points +** to this substructure of the ccb. +** This substructure contains the header with +** the script-processor-changable data and +** data blocks for the indirect move commands. +** +**---------------------------------------------------------- +*/ + +struct dsb { + + /* + ** Header. + */ + + struct head header; + + /* + ** Table data for Script + */ + + struct scr_tblsel select; + struct scr_tblmove smsg ; + struct scr_tblmove smsg_ext ; + struct scr_tblmove cmd ; + struct scr_tblmove sense ; + struct scr_tblmove wresid; + struct scr_tblmove data [MAX_SCATTER]; + + /* + ** Phase mismatch contexts. + ** We need two to handle correctly the + ** SAVED DATA POINTER. + */ + + struct pm_ctx pm0; + struct pm_ctx pm1; +}; + + +/*======================================================================== +** +** Declaration of structs: Command control block. +** +**======================================================================== +*/ +struct ccb { + /*---------------------------------------------------------------- + ** This is the data structure which is pointed by the DSA + ** register when it is executed by the script processor. + ** It must be the first entry. + **---------------------------------------------------------------- + */ + struct dsb phys; + + /*---------------------------------------------------------------- + ** The general SCSI driver provides a + ** pointer to a control block. + **---------------------------------------------------------------- + */ + Scsi_Cmnd *cmd; /* SCSI command */ + u_char cdb_buf[16]; /* Copy of CDB */ + u_char sense_buf[64]; + int data_len; /* Total data length */ + int segments; /* Number of SG segments */ + + /*---------------------------------------------------------------- + ** Message areas. + ** We prepare a message to be sent after selection. + ** We may use a second one if the command is rescheduled + ** due to CHECK_CONDITION or QUEUE FULL status. + ** Contents are IDENTIFY and SIMPLE_TAG. + ** While negotiating sync or wide transfer, + ** a SDTR or WDTR message is appended. + **---------------------------------------------------------------- + */ + u_char scsi_smsg [12]; + u_char scsi_smsg2[12]; + + /*---------------------------------------------------------------- + ** Miscellaneous status'. + **---------------------------------------------------------------- + */ + u_char nego_status; /* Negotiation status */ + u_char xerr_status; /* Extended error flags */ + u_int32 extra_bytes; /* Extraneous bytes transferred */ + + /*---------------------------------------------------------------- + ** Saved info for auto-sense + **---------------------------------------------------------------- + */ + u_char sv_scsi_status; + u_char sv_xerr_status; + + /*---------------------------------------------------------------- + ** Other fields. + **---------------------------------------------------------------- + */ + u_long p_ccb; /* BUS address of this CCB */ + u_char sensecmd[6]; /* Sense command */ + u_char to_abort; /* This CCB is to be aborted */ + u_short tag; /* Tag for this transfer */ + /* NO_TAG means no tag */ + u_char tags_si; /* Lun tags sum index (0,1) */ + + u_char target; + u_char lun; + u_short queued; + ccb_p link_ccb; /* Host adapter CCB chain */ + ccb_p link_ccbh; /* Host adapter CCB hash chain */ + XPT_QUEHEAD link_ccbq; /* Link to unit CCB queue */ + u_int32 startp; /* Initial data pointer */ + u_int32 lastp0; /* Initial 'lastp' */ + int ext_sg; /* Extreme data pointer, used */ + int ext_ofs; /* to calculate the residual. */ + int resid; +}; + +#define CCB_PHYS(cp,lbl) (cp->p_ccb + offsetof(struct ccb, lbl)) + + +/*======================================================================== +** +** Declaration of structs: NCR device descriptor +** +**======================================================================== +*/ +struct ncb { + /*---------------------------------------------------------------- + ** Idle task and invalid task actions and their bus + ** addresses. + **---------------------------------------------------------------- + */ + struct action idletask; + struct action notask; + struct action bad_i_t_l; + struct action bad_i_t_l_q; + u_long p_idletask; + u_long p_notask; + u_long p_bad_i_t_l; + u_long p_bad_i_t_l_q; + + /*---------------------------------------------------------------- + ** Dummy lun table to protect us against target returning bad + ** lun number on reselection. + **---------------------------------------------------------------- + */ + u_int32 *badluntbl; /* Table physical address */ + u_int32 resel_badlun; /* SCRIPT handler BUS address */ + + /*---------------------------------------------------------------- + ** Bit 32-63 of the on-chip RAM bus address in LE format. + ** The START_RAM64 script loads the MMRS and MMWS from this + ** field. + **---------------------------------------------------------------- + */ + u_int32 scr_ram_seg; + + /*---------------------------------------------------------------- + ** CCBs management queues. + **---------------------------------------------------------------- + */ + Scsi_Cmnd *waiting_list; /* Commands waiting for a CCB */ + /* when lcb is not allocated. */ + Scsi_Cmnd *done_list; /* Commands waiting for done() */ + /* callback to be invoked. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) + spinlock_t smp_lock; /* Lock for SMP threading */ +#endif + + /*---------------------------------------------------------------- + ** Chip and controller indentification. + **---------------------------------------------------------------- + */ + int unit; /* Unit number */ + char chip_name[8]; /* Chip name */ + char inst_name[16]; /* ncb instance name */ + + /*---------------------------------------------------------------- + ** Initial value of some IO register bits. + ** These values are assumed to have been set by BIOS, and may + ** be used for probing adapter implementation differences. + **---------------------------------------------------------------- + */ + u_char sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4, + sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_stest1, sv_scntl4; + + /*---------------------------------------------------------------- + ** Actual initial value of IO register bits used by the + ** driver. They are loaded at initialisation according to + ** features that are to be enabled. + **---------------------------------------------------------------- + */ + u_char rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4, + rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1, rv_scntl4; + + /*---------------------------------------------------------------- + ** Target data. + ** Target control block bus address array used by the SCRIPT + ** on reselection. + **---------------------------------------------------------------- + */ + struct tcb target[MAX_TARGET]; + u_int32 *targtbl; + + /*---------------------------------------------------------------- + ** Virtual and physical bus addresses of the chip. + **---------------------------------------------------------------- + */ +#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + u_long base_va; /* MMIO base virtual address */ + u_long base2_va; /* On-chip RAM virtual address */ +#endif + u_long base_ba; /* MMIO base bus address */ + u_long base_io; /* IO space base address */ + u_long base_ws; /* (MM)IO window size */ + u_long base2_ba; /* On-chip RAM bus address */ + u_long base2_ws; /* On-chip RAM window size */ + u_int irq; /* IRQ number */ + volatile /* Pointer to volatile for */ + struct ncr_reg *reg; /* memory mapped IO. */ + + /*---------------------------------------------------------------- + ** SCRIPTS virtual and physical bus addresses. + ** 'script' is loaded in the on-chip RAM if present. + ** 'scripth' stays in main memory for all chips except the + ** 53C895A and 53C896 that provide 8K on-chip RAM. + **---------------------------------------------------------------- + */ + struct script *script0; /* Copies of script and scripth */ + struct scripth *scripth0; /* relocated for this ncb. */ + u_long p_script; /* Actual script and scripth */ + u_long p_scripth; /* bus addresses. */ + u_long p_scripth0; + + /*---------------------------------------------------------------- + ** General controller parameters and configuration. + **---------------------------------------------------------------- + */ + pcidev_t pdev; + u_short device_id; /* PCI device id */ + u_char revision_id; /* PCI device revision id */ + u_char bus; /* PCI BUS number */ + u_char device_fn; /* PCI BUS device and function */ + u_char myaddr; /* SCSI id of the adapter */ + u_char maxburst; /* log base 2 of dwords burst */ + u_char maxwide; /* Maximum transfer width */ + u_char minsync; /* Minimum sync period factor */ + u_char maxsync; /* Maximum sync period factor */ + u_char maxoffs; /* Max scsi offset */ + u_char maxoffs_st; /* Max scsi offset in ST mode */ + u_char multiplier; /* Clock multiplier (1,2,4) */ + u_char clock_divn; /* Number of clock divisors */ + u_long clock_khz; /* SCSI clock frequency in KHz */ + u_int features; /* Chip features map */ + + /*---------------------------------------------------------------- + ** Range for the PCI clock frequency measurement result + ** that ensures the algorithm used by the driver can be + ** trusted for the SCSI clock frequency measurement. + ** (Assuming a PCI clock frequency of 33 MHz). + **---------------------------------------------------------------- + */ + u_int pciclock_min; + u_int pciclock_max; + + /*---------------------------------------------------------------- + ** Start queue management. + ** It is filled up by the host processor and accessed by the + ** SCRIPTS processor in order to start SCSI commands. + **---------------------------------------------------------------- + */ + u_long p_squeue; /* Start queue BUS address */ + u_int32 *squeue; /* Start queue virtual address */ + u_short squeueput; /* Next free slot of the queue */ + u_short actccbs; /* Number of allocated CCBs */ + u_short queuedepth; /* Start queue depth */ + + /*---------------------------------------------------------------- + ** Command completion queue. + ** It is the same size as the start queue to avoid overflow. + **---------------------------------------------------------------- + */ + u_short dqueueget; /* Next position to scan */ + u_int32 *dqueue; /* Completion (done) queue */ + + /*---------------------------------------------------------------- + ** Timeout handler. + **---------------------------------------------------------------- + */ + struct timer_list timer; /* Timer handler link header */ + u_long lasttime; + u_long settle_time; /* Resetting the SCSI BUS */ + + /*---------------------------------------------------------------- + ** Debugging and profiling. + **---------------------------------------------------------------- + */ + struct ncr_reg regdump; /* Register dump */ + u_long regtime; /* Time it has been done */ + + /*---------------------------------------------------------------- + ** Miscellaneous buffers accessed by the scripts-processor. + ** They shall be DWORD aligned, because they may be read or + ** written with a script command. + **---------------------------------------------------------------- + */ + u_char msgout[12]; /* Buffer for MESSAGE OUT */ + u_char msgin [12]; /* Buffer for MESSAGE IN */ + u_int32 lastmsg; /* Last SCSI message sent */ + u_char scratch; /* Scratch for SCSI receive */ + + /*---------------------------------------------------------------- + ** Miscellaneous configuration and status parameters. + **---------------------------------------------------------------- + */ + u_char scsi_mode; /* Current SCSI BUS mode */ + u_char order; /* Tag order to use */ + u_char verbose; /* Verbosity for this controller*/ + u_int32 ncr_cache; /* Used for cache test at init. */ + u_long p_ncb; /* BUS address of this NCB */ + + /*---------------------------------------------------------------- + ** CCB lists and queue. + **---------------------------------------------------------------- + */ + ccb_p ccbh[CCB_HASH_SIZE]; /* CCB hashed by DSA value */ + struct ccb *ccbc; /* CCB chain */ + XPT_QUEHEAD free_ccbq; /* Queue of available CCBs */ + + /*---------------------------------------------------------------- + ** IMMEDIATE ARBITRATION (IARB) control. + ** We keep track in 'last_cp' of the last CCB that has been + ** queued to the SCRIPTS processor and clear 'last_cp' when + ** this CCB completes. If last_cp is not zero at the moment + ** we queue a new CCB, we set a flag in 'last_cp' that is + ** used by the SCRIPTS as a hint for setting IARB. + ** We donnot set more than 'iarb_max' consecutive hints for + ** IARB in order to leave devices a chance to reselect. + ** By the way, any non zero value of 'iarb_max' is unfair. :) + **---------------------------------------------------------------- + */ +#ifdef SCSI_NCR_IARB_SUPPORT + struct ccb *last_cp; /* Last queud CCB used for IARB */ + u_short iarb_max; /* Max. # consecutive IARB hints*/ + u_short iarb_count; /* Actual # of these hints */ +#endif + + /*---------------------------------------------------------------- + ** We need the LCB in order to handle disconnections and + ** to count active CCBs for task management. So, we use + ** a unique CCB for LUNs we donnot have the LCB yet. + ** This queue normally should have at most 1 element. + **---------------------------------------------------------------- + */ + XPT_QUEHEAD b0_ccbq; + + /*---------------------------------------------------------------- + ** We use a different scatter function for 896 rev 1. + **---------------------------------------------------------------- + */ + int (*scatter) (ncb_p, ccb_p, Scsi_Cmnd *); + + /*---------------------------------------------------------------- + ** Command abort handling. + ** We need to synchronize tightly with the SCRIPTS + ** processor in order to handle things correctly. + **---------------------------------------------------------------- + */ + u_char abrt_msg[4]; /* Message to send buffer */ + struct scr_tblmove abrt_tbl; /* Table for the MOV of it */ + struct scr_tblsel abrt_sel; /* Sync params for selection */ + u_char istat_sem; /* Tells the chip to stop (SEM) */ + + /*---------------------------------------------------------------- + ** Fields that should be removed or changed. + **---------------------------------------------------------------- + */ + struct usrcmd user; /* Command from user */ + volatile u_char release_stage; /* Synchronisation stage on release */ + + /*---------------------------------------------------------------- + ** Fields that are used (primarily) for integrity check + **---------------------------------------------------------------- + */ + unsigned char check_integrity; /* Enable midlayer integ. check on + * bus scan. */ +#ifdef SCSI_NCR_INTEGRITY_CHECKING + unsigned char check_integ_par; /* Set if par or Init. Det. error + * used only during integ check */ +#endif +}; + +#define NCB_PHYS(np, lbl) (np->p_ncb + offsetof(struct ncb, lbl)) +#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl)) +#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl)) +#define NCB_SCRIPTH0_PHYS(np,lbl) (np->p_scripth0+offsetof (struct scripth,lbl)) + +/*========================================================== +** +** +** Script for NCR-Processor. +** +** Use ncr_script_fill() to create the variable parts. +** Use ncr_script_copy_and_bind() to make a copy and +** bind to physical addresses. +** +** +**========================================================== +** +** We have to know the offsets of all labels before +** we reach them (for forward jumps). +** Therefore we declare a struct here. +** If you make changes inside the script, +** DONT FORGET TO CHANGE THE LENGTHS HERE! +** +**---------------------------------------------------------- +*/ + +/* +** Script fragments which are loaded into the on-chip RAM +** of 825A, 875, 876, 895, 895A and 896 chips. +*/ +struct script { + ncrcmd start [ 14]; + ncrcmd getjob_begin [ 4]; + ncrcmd getjob_end [ 4]; + ncrcmd select [ 8]; + ncrcmd wf_sel_done [ 2]; + ncrcmd send_ident [ 2]; +#ifdef SCSI_NCR_IARB_SUPPORT + ncrcmd select2 [ 8]; +#else + ncrcmd select2 [ 2]; +#endif + ncrcmd command [ 2]; + ncrcmd dispatch [ 28]; + ncrcmd sel_no_cmd [ 10]; + ncrcmd init [ 6]; + ncrcmd clrack [ 4]; + ncrcmd disp_status [ 4]; + ncrcmd datai_done [ 26]; + ncrcmd datao_done [ 12]; + ncrcmd ign_i_w_r_msg [ 4]; + ncrcmd datai_phase [ 2]; + ncrcmd datao_phase [ 4]; + ncrcmd msg_in [ 2]; + ncrcmd msg_in2 [ 10]; +#ifdef SCSI_NCR_IARB_SUPPORT + ncrcmd status [ 14]; +#else + ncrcmd status [ 10]; +#endif + ncrcmd complete [ 8]; +#ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES + ncrcmd complete2 [ 12]; +#else + ncrcmd complete2 [ 10]; +#endif +#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR + ncrcmd done [ 18]; +#else + ncrcmd done [ 14]; +#endif + ncrcmd done_end [ 2]; + ncrcmd save_dp [ 8]; + ncrcmd restore_dp [ 4]; + ncrcmd disconnect [ 20]; +#ifdef SCSI_NCR_IARB_SUPPORT + ncrcmd idle [ 4]; +#else + ncrcmd idle [ 2]; +#endif +#ifdef SCSI_NCR_IARB_SUPPORT + ncrcmd ungetjob [ 6]; +#else + ncrcmd ungetjob [ 4]; +#endif + ncrcmd reselect [ 4]; + ncrcmd reselected [ 20]; + ncrcmd resel_scntl4 [ 30]; +#if MAX_TASKS*4 > 512 + ncrcmd resel_tag [ 18]; +#elif MAX_TASKS*4 > 256 + ncrcmd resel_tag [ 12]; +#else + ncrcmd resel_tag [ 8]; +#endif + ncrcmd resel_go [ 6]; + ncrcmd resel_notag [ 2]; + ncrcmd resel_dsa [ 8]; + ncrcmd data_in [MAX_SCATTER * SCR_SG_SIZE]; + ncrcmd data_in2 [ 4]; + ncrcmd data_out [MAX_SCATTER * SCR_SG_SIZE]; + ncrcmd data_out2 [ 4]; + ncrcmd pm0_data [ 12]; + ncrcmd pm0_data_out [ 6]; + ncrcmd pm0_data_end [ 6]; + ncrcmd pm1_data [ 12]; + ncrcmd pm1_data_out [ 6]; + ncrcmd pm1_data_end [ 6]; +}; + +/* +** Script fragments which stay in main memory for all chips +** except for the 895A and 896 that support 8K on-chip RAM. +*/ +struct scripth { + ncrcmd start64 [ 2]; + ncrcmd no_data [ 2]; + ncrcmd sel_for_abort [ 18]; + ncrcmd sel_for_abort_1 [ 2]; + ncrcmd select_no_atn [ 8]; + ncrcmd wf_sel_done_no_atn [ 4]; + + ncrcmd msg_in_etc [ 14]; + ncrcmd msg_received [ 4]; + ncrcmd msg_weird_seen [ 4]; + ncrcmd msg_extended [ 20]; + ncrcmd msg_bad [ 6]; + ncrcmd msg_weird [ 4]; + ncrcmd msg_weird1 [ 8]; + + ncrcmd wdtr_resp [ 6]; + ncrcmd send_wdtr [ 4]; + ncrcmd sdtr_resp [ 6]; + ncrcmd send_sdtr [ 4]; + ncrcmd ppr_resp [ 6]; + ncrcmd send_ppr [ 4]; + ncrcmd nego_bad_phase [ 4]; + ncrcmd msg_out [ 4]; + ncrcmd msg_out_done [ 4]; + ncrcmd data_ovrun [ 2]; + ncrcmd data_ovrun1 [ 22]; + ncrcmd data_ovrun2 [ 8]; + ncrcmd abort_resel [ 16]; + ncrcmd resend_ident [ 4]; + ncrcmd ident_break [ 4]; + ncrcmd ident_break_atn [ 4]; + ncrcmd sdata_in [ 6]; + ncrcmd data_io [ 2]; + ncrcmd data_io_com [ 8]; + ncrcmd data_io_out [ 12]; + ncrcmd resel_bad_lun [ 4]; + ncrcmd bad_i_t_l [ 4]; + ncrcmd bad_i_t_l_q [ 4]; + ncrcmd bad_status [ 6]; + ncrcmd tweak_pmj [ 12]; + ncrcmd pm_handle [ 20]; + ncrcmd pm_handle1 [ 4]; + ncrcmd pm_save [ 4]; + ncrcmd pm0_save [ 14]; + ncrcmd pm1_save [ 14]; + + /* WSR handling */ +#ifdef SYM_DEBUG_PM_WITH_WSR + ncrcmd pm_wsr_handle [ 44]; +#else + ncrcmd pm_wsr_handle [ 42]; +#endif + ncrcmd wsr_ma_helper [ 4]; + + /* Data area */ + ncrcmd zero [ 1]; + ncrcmd scratch [ 1]; + ncrcmd scratch1 [ 1]; + ncrcmd pm0_data_addr [ 1]; + ncrcmd pm1_data_addr [ 1]; + ncrcmd saved_dsa [ 1]; + ncrcmd saved_drs [ 1]; + ncrcmd done_pos [ 1]; + ncrcmd startpos [ 1]; + ncrcmd targtbl [ 1]; + /* End of data area */ + +#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + ncrcmd start_ram [ 1]; + ncrcmd script0_ba [ 4]; + ncrcmd start_ram64 [ 3]; + ncrcmd script0_ba64 [ 3]; + ncrcmd scripth0_ba64 [ 6]; + ncrcmd ram_seg64 [ 1]; +#endif + ncrcmd snooptest [ 6]; + ncrcmd snoopend [ 2]; +}; + +/*========================================================== +** +** +** Function headers. +** +** +**========================================================== +*/ + +static ccb_p ncr_alloc_ccb (ncb_p np); +static void ncr_complete (ncb_p np, ccb_p cp); +static void ncr_exception (ncb_p np); +static void ncr_free_ccb (ncb_p np, ccb_p cp); +static ccb_p ncr_ccb_from_dsa(ncb_p np, u_long dsa); +static void ncr_init_tcb (ncb_p np, u_char tn); +static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln); +static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, + u_char *inq_data); +static void ncr_getclock (ncb_p np, int mult); +static u_int ncr_getpciclock (ncb_p np); +static void ncr_selectclock (ncb_p np, u_char scntl3); +static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln); +static void ncr_init (ncb_p np, int reset, char * msg, u_long code); +static void ncr_int_sbmc (ncb_p np); +static void ncr_int_par (ncb_p np, u_short sist); +static void ncr_int_ma (ncb_p np); +static void ncr_int_sir (ncb_p np); +static void ncr_int_sto (ncb_p np); +static void ncr_int_udc (ncb_p np); +static void ncr_negotiate (ncb_p np, tcb_p tp); +static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr); +#ifdef SCSI_NCR_INTEGRITY_CHECKING +static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr); +#endif +static void ncr_script_copy_and_bind + (ncb_p np, ncrcmd *src, ncrcmd *dst, int len); +static void ncr_script_fill (struct script * scr, struct scripth * scripth); +static int ncr_scatter_896R1 (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd); +static int ncr_scatter (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd); +static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p); +static void ncr_get_xfer_info(ncb_p np, tcb_p tp, u_char *factor, u_char *offset, u_char *width); +static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, u_char scntl4); +static void ncr_set_sync_wide_status (ncb_p np, u_char target); +static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln); +static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack); +static void ncr_setsyncwide (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, u_char scntl4, u_char wide); +static int ncr_show_msg (u_char * msg); +static void ncr_print_msg (ccb_p cp, char *label, u_char * msg); +static int ncr_snooptest (ncb_p np); +static void ncr_timeout (ncb_p np); +static void ncr_wakeup (ncb_p np, u_long code); +static int ncr_wakeup_done (ncb_p np); +static void ncr_start_next_ccb (ncb_p np, lcb_p lp, int maxn); +static void ncr_put_start_queue(ncb_p np, ccb_p cp); +static void ncr_chip_reset (ncb_p np); +static void ncr_soft_reset (ncb_p np); +static void ncr_start_reset (ncb_p np); +static int ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay); +static int ncr_compute_residual (ncb_p np, ccb_p cp); + +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT +static void ncr_usercmd (ncb_p np); +#endif + +static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device); +static void ncr_free_resources(ncb_p np); + +static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd); +static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd); +static void process_waiting_list(ncb_p np, int sts); + +#define remove_from_waiting_list(np, cmd) \ + retrieve_from_waiting_list(1, (np), (cmd)) +#define requeue_waiting_list(np) process_waiting_list((np), DID_OK) +#define reset_waiting_list(np) process_waiting_list((np), DID_RESET) + +#ifdef SCSI_NCR_NVRAM_SUPPORT +static void ncr_get_nvram (ncr_device *devp, ncr_nvram *nvp); +static int sym_read_Tekram_nvram (ncr_slot *np, u_short device_id, + Tekram_nvram *nvram); +static int sym_read_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram); +#endif + +/*========================================================== +** +** +** Global static data. +** +** +**========================================================== +*/ + +static inline char *ncr_name (ncb_p np) +{ + return np->inst_name; +} + + +/*========================================================== +** +** +** Scripts for NCR-Processor. +** +** Use ncr_script_bind for binding to physical addresses. +** +** +**========================================================== +** +** NADDR generates a reference to a field of the controller data. +** PADDR generates a reference to another part of the script. +** RADDR generates a reference to a script processor register. +** FADDR generates a reference to a script processor register +** with offset. +** +**---------------------------------------------------------- +*/ + +#define RELOC_SOFTC 0x40000000 +#define RELOC_LABEL 0x50000000 +#define RELOC_REGISTER 0x60000000 +#if 0 +#define RELOC_KVAR 0x70000000 +#endif +#define RELOC_LABELH 0x80000000 +#define RELOC_MASK 0xf0000000 + +#define NADDR(label) (RELOC_SOFTC | offsetof(struct ncb, label)) +#define PADDR(label) (RELOC_LABEL | offsetof(struct script, label)) +#define PADDRH(label) (RELOC_LABELH | offsetof(struct scripth, label)) +#define RADDR(label) (RELOC_REGISTER | REG(label)) +#define FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs))) +#define KVAR(which) (RELOC_KVAR | (which)) + +#define SCR_DATA_ZERO 0xf00ff00f + +#ifdef RELOC_KVAR +#define SCRIPT_KVAR_JIFFIES (0) +#define SCRIPT_KVAR_FIRST SCRIPT_KVAR_JIFFIES +#define SCRIPT_KVAR_LAST SCRIPT_KVAR_JIFFIES +/* + * Kernel variables referenced in the scripts. + * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY. + */ +static void *script_kvars[] __initdata = + { (void *)&jiffies }; +#endif + +static struct script script0 __initdata = { +/*--------------------------< START >-----------------------*/ { + /* + ** This NOP will be patched with LED ON + ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) + */ + SCR_NO_OP, + 0, + /* + ** Clear SIGP. + */ + SCR_FROM_REG (ctest2), + 0, + + /* + ** Stop here if the C code wants to perform + ** some error recovery procedure manually. + ** (Indicate this by setting SEM in ISTAT) + */ + SCR_FROM_REG (istat), + 0, + /* + ** Report to the C code the next position in + ** the start queue the SCRIPTS will schedule. + ** The C code must not change SCRATCHA. + */ + SCR_LOAD_ABS (scratcha, 4), + PADDRH (startpos), + SCR_INT ^ IFTRUE (MASK (SEM, SEM)), + SIR_SCRIPT_STOPPED, + + /* + ** Start the next job. + ** + ** @DSA = start point for this job. + ** SCRATCHA = address of this job in the start queue. + ** + ** We will restore startpos with SCRATCHA if we fails the + ** arbitration or if it is the idle job. + ** + ** The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS + ** is a critical path. If it is partially executed, it then + ** may happen that the job address is not yet in the DSA + ** and the next queue position points to the next JOB. + */ + SCR_LOAD_ABS (dsa, 4), + PADDRH (startpos), + SCR_LOAD_REL (temp, 4), + 4, +}/*-------------------------< GETJOB_BEGIN >------------------*/,{ + SCR_STORE_ABS (temp, 4), + PADDRH (startpos), + SCR_LOAD_REL (dsa, 4), + 0, +}/*-------------------------< GETJOB_END >--------------------*/,{ + SCR_LOAD_REL (temp, 4), + 0, + SCR_RETURN, + 0, + +}/*-------------------------< SELECT >----------------------*/,{ + /* + ** DSA contains the address of a scheduled + ** data structure. + ** + ** SCRATCHA contains the address of the start queue + ** entry which points to the next job. + ** + ** Set Initiator mode. + ** + ** (Target mode is left as an exercise for the reader) + */ + + SCR_CLR (SCR_TRG), + 0, + /* + ** And try to select this target. + */ + SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select), + PADDR (ungetjob), + /* + ** Now there are 4 possibilities: + ** + ** (1) The ncr loses arbitration. + ** This is ok, because it will try again, + ** when the bus becomes idle. + ** (But beware of the timeout function!) + ** + ** (2) The ncr is reselected. + ** Then the script processor takes the jump + ** to the RESELECT label. + ** + ** (3) The ncr wins arbitration. + ** Then it will execute SCRIPTS instruction until + ** the next instruction that checks SCSI phase. + ** Then will stop and wait for selection to be + ** complete or selection time-out to occur. + ** + ** After having won arbitration, the ncr SCRIPTS + ** processor is able to execute instructions while + ** the SCSI core is performing SCSI selection. But + ** some script instruction that is not waiting for + ** a valid phase (or selection timeout) to occur + ** breaks the selection procedure, by probably + ** affecting timing requirements. + ** So we have to wait immediately for the next phase + ** or the selection to complete or time-out. + */ + + /* + ** load the savep (saved pointer) into + ** the actual data pointer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + /* + ** Initialize the status registers + */ + SCR_LOAD_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + +}/*-------------------------< WF_SEL_DONE >----------------------*/,{ + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), + SIR_SEL_ATN_NO_MSG_OUT, +}/*-------------------------< SEND_IDENT >----------------------*/,{ + /* + ** Selection complete. + ** Send the IDENTIFY and SIMPLE_TAG messages + ** (and the M_X_SYNC_REQ / M_X_WIDE_REQ message) + */ + SCR_MOVE_TBL ^ SCR_MSG_OUT, + offsetof (struct dsb, smsg), +}/*-------------------------< SELECT2 >----------------------*/,{ +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** Set IMMEDIATE ARBITRATION if we have been given + ** a hint to do so. (Some job to do after this one). + */ + SCR_FROM_REG (HF_REG), + 0, + SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)), + 8, + SCR_REG_REG (scntl1, SCR_OR, IARB), + 0, +#endif + /* + ** Anticipate the COMMAND phase. + ** This is the PHASE we expect at this point. + */ + SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)), + PADDR (sel_no_cmd), + +}/*-------------------------< COMMAND >--------------------*/,{ + /* + ** ... and send the command + */ + SCR_MOVE_TBL ^ SCR_COMMAND, + offsetof (struct dsb, cmd), + +}/*-----------------------< DISPATCH >----------------------*/,{ + /* + ** MSG_IN is the only phase that shall be + ** entered at least once for each (re)selection. + ** So we test it first. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), + PADDR (msg_in), + SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)), + PADDR (datao_phase), + SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)), + PADDR (datai_phase), + SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)), + PADDR (status), + SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)), + PADDR (command), + SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)), + PADDRH (msg_out), + /* + * Discard as many illegal phases as + * required and tell the C code about. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)), + 16, + SCR_MOVE_ABS (1) ^ SCR_ILG_OUT, + NADDR (scratch), + SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)), + -16, + SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)), + 16, + SCR_MOVE_ABS (1) ^ SCR_ILG_IN, + NADDR (scratch), + SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)), + -16, + SCR_INT, + SIR_BAD_PHASE, + SCR_JUMP, + PADDR (dispatch), +}/*---------------------< SEL_NO_CMD >----------------------*/,{ + /* + ** The target does not switch to command + ** phase after IDENTIFY has been sent. + ** + ** If it stays in MSG OUT phase send it + ** the IDENTIFY again. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), + PADDRH (resend_ident), + /* + ** If target does not switch to MSG IN phase + ** and we sent a negotiation, assert the + ** failure immediately. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + SCR_FROM_REG (HS_REG), + 0, + SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), + SIR_NEGO_FAILED, + /* + ** Jump to dispatcher. + */ + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< INIT >------------------------*/,{ + /* + ** Wait for the SCSI RESET signal to be + ** inactive before restarting operations, + ** since the chip may hang on SEL_ATN + ** if SCSI RESET is active. + */ + SCR_FROM_REG (sstat0), + 0, + SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)), + -16, + SCR_JUMP, + PADDR (start), +}/*-------------------------< CLRACK >----------------------*/,{ + /* + ** Terminate possible pending message phase. + */ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< DISP_STATUS >----------------------*/,{ + /* + ** Anticipate STATUS phase. + ** + ** Does spare 3 SCRIPTS instructions when we have + ** completed the INPUT of the data. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)), + PADDR (status), + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< DATAI_DONE >-------------------*/,{ + /* + * If the device wants us to send more data, + * we must count the extra bytes. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_IN)), + PADDRH (data_ovrun), + /* + ** If the SWIDE is not full, jump to dispatcher. + ** We anticipate a STATUS phase. + ** If we get later an IGNORE WIDE RESIDUE, we + ** will alias it as a MODIFY DP (-1). + */ + SCR_FROM_REG (scntl2), + 0, + SCR_JUMP ^ IFFALSE (MASK (WSR, WSR)), + PADDR (disp_status), + /* + ** The SWIDE is full. + ** Clear this condition. + */ + SCR_REG_REG (scntl2, SCR_OR, WSR), + 0, + /* + * We are expecting an IGNORE RESIDUE message + * from the device, otherwise we are in data + * overrun condition. Check against MSG_IN phase. + */ + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), + SIR_SWIDE_OVERRUN, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (disp_status), + /* + * We are in MSG_IN phase, + * Read the first byte of the message. + * If it is not an IGNORE RESIDUE message, + * signal overrun and jump to message + * processing. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[0]), + SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)), + SIR_SWIDE_OVERRUN, + SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)), + PADDR (msg_in2), + + /* + * We got the message we expected. + * Read the 2nd byte, and jump to dispatcher. + */ + SCR_CLR (SCR_ACK), + 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[1]), + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP, + PADDR (disp_status), + +}/*-------------------------< DATAO_DONE >-------------------*/,{ + /* + * If the device wants us to send more data, + * we must count the extra bytes. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)), + PADDRH (data_ovrun), + /* + ** If the SODL is not full jump to dispatcher. + ** We anticipate a MSG IN phase or a STATUS phase. + */ + SCR_FROM_REG (scntl2), + 0, + SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)), + PADDR (disp_status), + /* + ** The SODL is full, clear this condition. + */ + SCR_REG_REG (scntl2, SCR_OR, WSS), + 0, + /* + ** And signal a DATA UNDERRUN condition + ** to the C code. + */ + SCR_INT, + SIR_SODL_UNDERRUN, + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< IGN_I_W_R_MSG >--------------*/,{ + /* + ** We jump here from the phase mismatch interrupt, + ** When we have a SWIDE and the device has presented + ** a IGNORE WIDE RESIDUE message on the BUS. + ** We just have to throw away this message and then + ** to jump to dispatcher. + */ + SCR_MOVE_ABS (2) ^ SCR_MSG_IN, + NADDR (scratch), + /* + ** Clear ACK and jump to dispatcher. + */ + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< DATAI_PHASE >------------------*/,{ + SCR_RETURN, + 0, +}/*-------------------------< DATAO_PHASE >------------------*/,{ + /* + ** Patch for 53c1010_66 only - to allow A0 part + ** to operate properly in a 33MHz PCI bus. + ** + ** SCR_REG_REG(scntl4, SCR_OR, 0x0c), + ** 0, + */ + SCR_NO_OP, + 0, + SCR_RETURN, + 0, +}/*-------------------------< MSG_IN >--------------------*/,{ + /* + ** Get the first byte of the message. + ** + ** The script processor doesn't negate the + ** ACK signal after this transfer. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[0]), +}/*-------------------------< MSG_IN2 >--------------------*/,{ + /* + ** Check first against 1 byte messages + ** that we handle from SCRIPTS. + */ + SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)), + PADDR (complete), + SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)), + PADDR (disconnect), + SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)), + PADDR (save_dp), + SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)), + PADDR (restore_dp), + /* + ** We handle all other messages from the + ** C code, so no need to waste on-chip RAM + ** for those ones. + */ + SCR_JUMP, + PADDRH (msg_in_etc), + +}/*-------------------------< STATUS >--------------------*/,{ + /* + ** get the status + */ + SCR_MOVE_ABS (1) ^ SCR_STATUS, + NADDR (scratch), +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** If STATUS is not GOOD, clear IMMEDIATE ARBITRATION, + ** since we may have to tamper the start queue from + ** the C code. + */ + SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)), + 8, + SCR_REG_REG (scntl1, SCR_AND, ~IARB), + 0, +#endif + /* + ** save status to scsi_status. + ** mark as complete. + */ + SCR_TO_REG (SS_REG), + 0, + SCR_LOAD_REG (HS_REG, HS_COMPLETE), + 0, + /* + ** Anticipate the MESSAGE PHASE for + ** the TASK COMPLETE message. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), + PADDR (msg_in), + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< COMPLETE >-----------------*/,{ + /* + ** Complete message. + ** + ** Copy the data pointer to LASTP in header. + */ + SCR_STORE_REL (temp, 4), + offsetof (struct ccb, phys.header.lastp), + /* + ** When we terminate the cycle by clearing ACK, + ** the target may disconnect immediately. + ** + ** We don't want to be told of an + ** "unexpected disconnect", + ** so we disable this feature. + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + /* + ** Terminate cycle ... + */ + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + /* + ** ... and wait for the disconnect. + */ + SCR_WAIT_DISC, + 0, +}/*-------------------------< COMPLETE2 >-----------------*/,{ + /* + ** Save host status to header. + */ + SCR_STORE_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + +#ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES + /* + ** Some bridges may reorder DMA writes to memory. + ** We donnot want the CPU to deal with completions + ** without all the posted write having been flushed + ** to memory. This DUMMY READ should flush posted + ** buffers prior to the CPU having to deal with + ** completions. + */ + SCR_LOAD_REL (scr0, 4), /* DUMMY READ */ + offsetof (struct ccb, phys.header.status), +#endif + /* + ** If command resulted in not GOOD status, + ** call the C code if needed. + */ + SCR_FROM_REG (SS_REG), + 0, + SCR_CALL ^ IFFALSE (DATA (S_GOOD)), + PADDRH (bad_status), + + /* + ** If we performed an auto-sense, call + ** the C code to synchronyze task aborts + ** with UNIT ATTENTION conditions. + */ + SCR_FROM_REG (HF_REG), + 0, + SCR_INT ^ IFTRUE (MASK (HF_AUTO_SENSE, HF_AUTO_SENSE)), + SIR_AUTO_SENSE_DONE, + +}/*------------------------< DONE >-----------------*/,{ +#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR + /* + ** It seems that some bridges flush everything + ** when the INTR line is raised. For these ones, + ** we can just ensure that the INTR line will be + ** raised before each completion. So, if it happens + ** that we have been faster that the CPU, we just + ** have to synchronize with it. A dummy programmed + ** interrupt will do the trick. + ** Note that we overlap at most 1 IO with the CPU + ** in this situation and that the IRQ line must not + ** be shared. + */ + SCR_FROM_REG (istat), + 0, + SCR_INT ^ IFTRUE (MASK (INTF, INTF)), + SIR_DUMMY_INTERRUPT, +#endif + /* + ** Copy the DSA to the DONE QUEUE and + ** signal completion to the host. + ** If we are interrupted between DONE + ** and DONE_END, we must reset, otherwise + ** the completed CCB will be lost. + */ + SCR_STORE_ABS (dsa, 4), + PADDRH (saved_dsa), + SCR_LOAD_ABS (dsa, 4), + PADDRH (done_pos), + SCR_LOAD_ABS (scratcha, 4), + PADDRH (saved_dsa), + SCR_STORE_REL (scratcha, 4), + 0, + /* + ** The instruction below reads the DONE QUEUE next + ** free position from memory. + ** In addition it ensures that all PCI posted writes + ** are flushed and so the DSA value of the done + ** CCB is visible by the CPU before INTFLY is raised. + */ + SCR_LOAD_REL (temp, 4), + 4, + SCR_INT_FLY, + 0, + SCR_STORE_ABS (temp, 4), + PADDRH (done_pos), +}/*------------------------< DONE_END >-----------------*/,{ + SCR_JUMP, + PADDR (start), + +}/*-------------------------< SAVE_DP >------------------*/,{ + /* + ** Clear ACK immediately. + ** No need to delay it. + */ + SCR_CLR (SCR_ACK), + 0, + /* + ** Keep track we received a SAVE DP, so + ** we will switch to the other PM context + ** on the next PM since the DP may point + ** to the current PM context. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED), + 0, + /* + ** SAVE_DP message: + ** Copy the data pointer to SAVEP in header. + */ + SCR_STORE_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + SCR_JUMP, + PADDR (dispatch), +}/*-------------------------< RESTORE_DP >---------------*/,{ + /* + ** RESTORE_DP message: + ** Copy SAVEP in header to actual data pointer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< DISCONNECT >---------------*/,{ + /* + ** DISCONNECTing ... + ** + ** disable the "unexpected disconnect" feature, + ** and remove the ACK signal. + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + /* + ** Wait for the disconnect. + */ + SCR_WAIT_DISC, + 0, + /* + ** Status is: DISCONNECTED. + */ + SCR_LOAD_REG (HS_REG, HS_DISCONNECT), + 0, + /* + ** Save host status to header. + */ + SCR_STORE_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + /* + ** If QUIRK_AUTOSAVE is set, + ** do an "save pointer" operation. + */ + SCR_FROM_REG (QU_REG), + 0, + SCR_JUMP ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)), + PADDR (start), + /* + ** like SAVE_DP message: + ** Remember we saved the data pointer. + ** Copy data pointer to SAVEP in header. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED), + 0, + SCR_STORE_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + SCR_JUMP, + PADDR (start), + +}/*-------------------------< IDLE >------------------------*/,{ + /* + ** Nothing to do? + ** Wait for reselect. + ** This NOP will be patched with LED OFF + ** SCR_REG_REG (gpreg, SCR_OR, 0x01) + */ + SCR_NO_OP, + 0, +#ifdef SCSI_NCR_IARB_SUPPORT + SCR_JUMPR, + 8, +#endif +}/*-------------------------< UNGETJOB >-----------------*/,{ +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** Set IMMEDIATE ARBITRATION, for the next time. + ** This will give us better chance to win arbitration + ** for the job we just wanted to do. + */ + SCR_REG_REG (scntl1, SCR_OR, IARB), + 0, +#endif + /* + ** We are not able to restart the SCRIPTS if we are + ** interrupted and these instruction haven't been + ** all executed. BTW, this is very unlikely to + ** happen, but we check that from the C code. + */ + SCR_LOAD_REG (dsa, 0xff), + 0, + SCR_STORE_ABS (scratcha, 4), + PADDRH (startpos), +}/*-------------------------< RESELECT >--------------------*/,{ + /* + ** make the host status invalid. + */ + SCR_CLR (SCR_TRG), + 0, + /* + ** Sleep waiting for a reselection. + ** If SIGP is set, special treatment. + ** + ** Zu allem bereit .. + */ + SCR_WAIT_RESEL, + PADDR(start), +}/*-------------------------< RESELECTED >------------------*/,{ + /* + ** This NOP will be patched with LED ON + ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) + */ + SCR_NO_OP, + 0, + /* + ** load the target id into the sdid + */ + SCR_REG_SFBR (ssid, SCR_AND, 0x8F), + 0, + SCR_TO_REG (sdid), + 0, + /* + ** load the target control block address + */ + SCR_LOAD_ABS (dsa, 4), + PADDRH (targtbl), + SCR_SFBR_REG (dsa, SCR_SHL, 0), + 0, + SCR_REG_REG (dsa, SCR_SHL, 0), + 0, + SCR_REG_REG (dsa, SCR_AND, 0x3c), + 0, + SCR_LOAD_REL (dsa, 4), + 0, + /* + ** Load the synchronous transfer registers. + */ + SCR_LOAD_REL (scntl3, 1), + offsetof(struct tcb, wval), + SCR_LOAD_REL (sxfer, 1), + offsetof(struct tcb, sval), +}/*-------------------------< RESEL_SCNTL4 >------------------*/,{ + /* + ** Write with uval value. Patch if device + ** does not support Ultra3. + ** + ** SCR_LOAD_REL (scntl4, 1), + ** offsetof(struct tcb, uval), + */ + + SCR_NO_OP, + 0, + /* + * We expect MESSAGE IN phase. + * If not, get help from the C code. + */ + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), + SIR_RESEL_NO_MSG_IN, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin), + + /* + * If IDENTIFY LUN #0, use a faster path + * to find the LCB structure. + */ + SCR_JUMPR ^ IFTRUE (MASK (0x80, 0xbf)), + 56, + /* + * If message isn't an IDENTIFY, + * tell the C code about. + */ + SCR_INT ^ IFFALSE (MASK (0x80, 0x80)), + SIR_RESEL_NO_IDENTIFY, + /* + * It is an IDENTIFY message, + * Load the LUN control block address. + */ + SCR_LOAD_REL (dsa, 4), + offsetof(struct tcb, b_luntbl), + SCR_SFBR_REG (dsa, SCR_SHL, 0), + 0, + SCR_REG_REG (dsa, SCR_SHL, 0), + 0, + SCR_REG_REG (dsa, SCR_AND, 0xfc), + 0, + SCR_LOAD_REL (dsa, 4), + 0, + SCR_JUMPR, + 8, + /* + ** LUN 0 special case (but usual one :)) + */ + SCR_LOAD_REL (dsa, 4), + offsetof(struct tcb, b_lun0), + + /* + ** Load the reselect task action for this LUN. + ** Load the tasks DSA array for this LUN. + ** Call the action. + */ + SCR_LOAD_REL (temp, 4), + offsetof(struct lcb, resel_task), + SCR_LOAD_REL (dsa, 4), + offsetof(struct lcb, b_tasktbl), + SCR_RETURN, + 0, +}/*-------------------------< RESEL_TAG >-------------------*/,{ + /* + ** ACK the IDENTIFY or TAG previously received + */ + + SCR_CLR (SCR_ACK), + 0, + /* + ** Read IDENTIFY + SIMPLE + TAG using a single MOVE. + ** Agressive optimization, is'nt it? + ** No need to test the SIMPLE TAG message, since the + ** driver only supports conformant devices for tags. ;-) + */ + SCR_MOVE_ABS (2) ^ SCR_MSG_IN, + NADDR (msgin), + /* + ** Read the TAG from the SIDL. + ** Still an aggressive optimization. ;-) + ** Compute the CCB indirect jump address which + ** is (#TAG*2 & 0xfc) due to tag numbering using + ** 1,3,5..MAXTAGS*2+1 actual values. + */ + SCR_REG_SFBR (sidl, SCR_SHL, 0), + 0, +#if MAX_TASKS*4 > 512 + SCR_JUMPR ^ IFFALSE (CARRYSET), + 8, + SCR_REG_REG (dsa1, SCR_OR, 2), + 0, + SCR_REG_REG (sfbr, SCR_SHL, 0), + 0, + SCR_JUMPR ^ IFFALSE (CARRYSET), + 8, + SCR_REG_REG (dsa1, SCR_OR, 1), + 0, +#elif MAX_TASKS*4 > 256 + SCR_JUMPR ^ IFFALSE (CARRYSET), + 8, + SCR_REG_REG (dsa1, SCR_OR, 1), + 0, +#endif + /* + ** Retrieve the DSA of this task. + ** JUMP indirectly to the restart point of the CCB. + */ + SCR_SFBR_REG (dsa, SCR_AND, 0xfc), + 0, +}/*-------------------------< RESEL_GO >-------------------*/,{ + SCR_LOAD_REL (dsa, 4), + 0, + SCR_LOAD_REL (temp, 4), + offsetof(struct ccb, phys.header.go.restart), + SCR_RETURN, + 0, + /* In normal situations we branch to RESEL_DSA */ +}/*-------------------------< RESEL_NOTAG >-------------------*/,{ + /* + ** JUMP indirectly to the restart point of the CCB. + */ + SCR_JUMP, + PADDR (resel_go), + +}/*-------------------------< RESEL_DSA >-------------------*/,{ + /* + ** Ack the IDENTIFY or TAG previously received. + */ + SCR_CLR (SCR_ACK), + 0, + /* + ** load the savep (saved pointer) into + ** the actual data pointer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + /* + ** Initialize the status registers + */ + SCR_LOAD_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + /* + ** Jump to dispatcher. + */ + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< DATA_IN >--------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTER parameter, +** it is filled in at runtime. +** +** ##===========< i=0; i========= +** || SCR_CHMOV_TBL ^ SCR_DATA_IN, +** || offsetof (struct dsb, data[ i]), +** ##========================================== +** +**--------------------------------------------------------- +*/ +0 +}/*-------------------------< DATA_IN2 >-------------------*/,{ + SCR_CALL, + PADDR (datai_done), + SCR_JUMP, + PADDRH (data_ovrun), +}/*-------------------------< DATA_OUT >--------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTER parameter, +** it is filled in at runtime. +** +** ##===========< i=0; i========= +** || SCR_CHMOV_TBL ^ SCR_DATA_OUT, +** || offsetof (struct dsb, data[ i]), +** ##========================================== +** +**--------------------------------------------------------- +*/ +0 +}/*-------------------------< DATA_OUT2 >-------------------*/,{ + SCR_CALL, + PADDR (datao_done), + SCR_JUMP, + PADDRH (data_ovrun), + +}/*-------------------------< PM0_DATA >--------------------*/,{ + /* + ** Read our host flags to SFBR, so we will be able + ** to check against the data direction we expect. + */ + SCR_FROM_REG (HF_REG), + 0, + /* + ** Check against actual DATA PHASE. + */ + SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), + PADDR (pm0_data_out), + /* + ** Actual phase is DATA IN. + ** Check against expected direction. + */ + SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)), + PADDRH (data_ovrun), + /* + ** Keep track we are moving data from the + ** PM0 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0), + 0, + /* + ** Move the data to memory. + */ + SCR_CHMOV_TBL ^ SCR_DATA_IN, + offsetof (struct ccb, phys.pm0.sg), + SCR_JUMP, + PADDR (pm0_data_end), +}/*-------------------------< PM0_DATA_OUT >----------------*/,{ + /* + ** Actual phase is DATA OUT. + ** Check against expected direction. + */ + SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)), + PADDRH (data_ovrun), + /* + ** Keep track we are moving data from the + ** PM0 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0), + 0, + /* + ** Move the data from memory. + */ + SCR_CHMOV_TBL ^ SCR_DATA_OUT, + offsetof (struct ccb, phys.pm0.sg), +}/*-------------------------< PM0_DATA_END >----------------*/,{ + /* + ** Clear the flag that told we were moving + ** data from the PM0 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)), + 0, + /* + ** Return to the previous DATA script which + ** is guaranteed by design (if no bug) to be + ** the main DATA script for this transfer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.pm0.ret), + SCR_RETURN, + 0, +}/*-------------------------< PM1_DATA >--------------------*/,{ + /* + ** Read our host flags to SFBR, so we will be able + ** to check against the data direction we expect. + */ + SCR_FROM_REG (HF_REG), + 0, + /* + ** Check against actual DATA PHASE. + */ + SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), + PADDR (pm1_data_out), + /* + ** Actual phase is DATA IN. + ** Check against expected direction. + */ + SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)), + PADDRH (data_ovrun), + /* + ** Keep track we are moving data from the + ** PM1 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1), + 0, + /* + ** Move the data to memory. + */ + SCR_CHMOV_TBL ^ SCR_DATA_IN, + offsetof (struct ccb, phys.pm1.sg), + SCR_JUMP, + PADDR (pm1_data_end), +}/*-------------------------< PM1_DATA_OUT >----------------*/,{ + /* + ** Actual phase is DATA OUT. + ** Check against expected direction. + */ + SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)), + PADDRH (data_ovrun), + /* + ** Keep track we are moving data from the + ** PM1 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1), + 0, + /* + ** Move the data from memory. + */ + SCR_CHMOV_TBL ^ SCR_DATA_OUT, + offsetof (struct ccb, phys.pm1.sg), +}/*-------------------------< PM1_DATA_END >----------------*/,{ + /* + ** Clear the flag that told we were moving + ** data from the PM1 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)), + 0, + /* + ** Return to the previous DATA script which + ** is guaranteed by design (if no bug) to be + ** the main DATA script for this transfer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.pm1.ret), + SCR_RETURN, + 0, +}/*---------------------------------------------------------*/ +}; + + +static struct scripth scripth0 __initdata = { +/*------------------------< START64 >-----------------------*/{ + /* + ** SCRIPT entry point for the 895A and the 896. + ** For now, there is no specific stuff for that + ** chip at this point, but this may come. + */ + SCR_JUMP, + PADDR (init), +}/*-------------------------< NO_DATA >-------------------*/,{ + SCR_JUMP, + PADDRH (data_ovrun), +}/*-----------------------< SEL_FOR_ABORT >------------------*/,{ + /* + ** We are jumped here by the C code, if we have + ** some target to reset or some disconnected + ** job to abort. Since error recovery is a serious + ** busyness, we will really reset the SCSI BUS, if + ** case of a SCSI interrupt occurring in this path. + */ + + /* + ** Set initiator mode. + */ + SCR_CLR (SCR_TRG), + 0, + /* + ** And try to select this target. + */ + SCR_SEL_TBL_ATN ^ offsetof (struct ncb, abrt_sel), + PADDR (reselect), + + /* + ** Wait for the selection to complete or + ** the selection to time out. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)), + -8, + /* + ** Call the C code. + */ + SCR_INT, + SIR_TARGET_SELECTED, + /* + ** The C code should let us continue here. + ** Send the 'kiss of death' message. + ** We expect an immediate disconnect once + ** the target has eaten the message. + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_MOVE_TBL ^ SCR_MSG_OUT, + offsetof (struct ncb, abrt_tbl), + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + SCR_WAIT_DISC, + 0, + /* + ** Tell the C code that we are done. + */ + SCR_INT, + SIR_ABORT_SENT, +}/*-----------------------< SEL_FOR_ABORT_1 >--------------*/,{ + /* + ** Jump at scheduler. + */ + SCR_JUMP, + PADDR (start), + +}/*------------------------< SELECT_NO_ATN >-----------------*/,{ + /* + ** Set Initiator mode. + ** And try to select this target without ATN. + */ + + SCR_CLR (SCR_TRG), + 0, + SCR_SEL_TBL ^ offsetof (struct dsb, select), + PADDR (ungetjob), + /* + ** load the savep (saved pointer) into + ** the actual data pointer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + /* + ** Initialize the status registers + */ + SCR_LOAD_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + +}/*------------------------< WF_SEL_DONE_NO_ATN >-----------------*/,{ + /* + ** Wait immediately for the next phase or + ** the selection to complete or time-out. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)), + 0, + SCR_JUMP, + PADDR (select2), + +}/*-------------------------< MSG_IN_ETC >--------------------*/,{ + /* + ** If it is an EXTENDED (variable size message) + ** Handle it. + */ + SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)), + PADDRH (msg_extended), + /* + ** Let the C code handle any other + ** 1 byte message. + */ + SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)), + PADDRH (msg_received), + SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)), + PADDRH (msg_received), + /* + ** We donnot handle 2 bytes messages from SCRIPTS. + ** So, let the C code deal with these ones too. + */ + SCR_JUMP ^ IFFALSE (MASK (0x20, 0xf0)), + PADDRH (msg_weird_seen), + SCR_CLR (SCR_ACK), + 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[1]), + SCR_JUMP, + PADDRH (msg_received), + +}/*-------------------------< MSG_RECEIVED >--------------------*/,{ + SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */ + 0, + SCR_INT, + SIR_MSG_RECEIVED, + +}/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{ + SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */ + 0, + SCR_INT, + SIR_MSG_WEIRD, + +}/*-------------------------< MSG_EXTENDED >--------------------*/,{ + /* + ** Clear ACK and get the next byte + ** assumed to be the message length. + */ + SCR_CLR (SCR_ACK), + 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[1]), + /* + ** Try to catch some unlikely situations as 0 length + ** or too large the length. + */ + SCR_JUMP ^ IFTRUE (DATA (0)), + PADDRH (msg_weird_seen), + SCR_TO_REG (scratcha), + 0, + SCR_REG_REG (sfbr, SCR_ADD, (256-8)), + 0, + SCR_JUMP ^ IFTRUE (CARRYSET), + PADDRH (msg_weird_seen), + /* + ** We donnot handle extended messages from SCRIPTS. + ** Read the amount of data correponding to the + ** message length and call the C code. + */ + SCR_STORE_REL (scratcha, 1), + offsetof (struct dsb, smsg_ext.size), + SCR_CLR (SCR_ACK), + 0, + SCR_MOVE_TBL ^ SCR_MSG_IN, + offsetof (struct dsb, smsg_ext), + SCR_JUMP, + PADDRH (msg_received), + +}/*-------------------------< MSG_BAD >------------------*/,{ + /* + ** unimplemented message - reject it. + */ + SCR_INT, + SIR_REJECT_TO_SEND, + SCR_SET (SCR_ATN), + 0, + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< MSG_WEIRD >--------------------*/,{ + /* + ** weird message received + ** ignore all MSG IN phases and reject it. + */ + SCR_INT, + SIR_REJECT_TO_SEND, + SCR_SET (SCR_ATN), + 0, +}/*-------------------------< MSG_WEIRD1 >--------------------*/,{ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (scratch), + SCR_JUMP, + PADDRH (msg_weird1), +}/*-------------------------< WDTR_RESP >----------------*/,{ + /* + ** let the target fetch our answer. + */ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), + PADDRH (nego_bad_phase), + +}/*-------------------------< SEND_WDTR >----------------*/,{ + /* + ** Send the M_X_WIDE_REQ + */ + SCR_MOVE_ABS (4) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_JUMP, + PADDRH (msg_out_done), + +}/*-------------------------< SDTR_RESP >-------------*/,{ + /* + ** let the target fetch our answer. + */ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), + PADDRH (nego_bad_phase), + +}/*-------------------------< SEND_SDTR >-------------*/,{ + /* + ** Send the M_X_SYNC_REQ + */ + SCR_MOVE_ABS (5) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_JUMP, + PADDRH (msg_out_done), + +}/*-------------------------< PPR_RESP >-------------*/,{ + /* + ** let the target fetch our answer. + */ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), + PADDRH (nego_bad_phase), + +}/*-------------------------< SEND_PPR >-------------*/,{ + /* + ** Send the M_X_PPR_REQ + */ + SCR_MOVE_ABS (8) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_JUMP, + PADDRH (msg_out_done), + +}/*-------------------------< NEGO_BAD_PHASE >------------*/,{ + SCR_INT, + SIR_NEGO_PROTO, + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< MSG_OUT >-------------------*/,{ + /* + ** The target requests a message. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, + NADDR (msgout), + /* + ** ... wait for the next phase + ** if it's a message out, send it again, ... + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), + PADDRH (msg_out), +}/*-------------------------< MSG_OUT_DONE >--------------*/,{ + /* + ** ... else clear the message ... + */ + SCR_INT, + SIR_MSG_OUT_DONE, + /* + ** ... and process the next phase + */ + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< DATA_OVRUN >-----------------------*/,{ + /* + * Use scratcha to count the extra bytes. + */ + SCR_LOAD_ABS (scratcha, 4), + PADDRH (zero), +}/*-------------------------< DATA_OVRUN1 >----------------------*/,{ + /* + * The target may want to transfer too much data. + * + * If phase is DATA OUT write 1 byte and count it. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)), + 16, + SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT, + NADDR (scratch), + SCR_JUMP, + PADDRH (data_ovrun2), + /* + * If WSR is set, clear this condition, and + * count this byte. + */ + SCR_FROM_REG (scntl2), + 0, + SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)), + 16, + SCR_REG_REG (scntl2, SCR_OR, WSR), + 0, + SCR_JUMP, + PADDRH (data_ovrun2), + /* + * Finally check against DATA IN phase. + * Signal data overrun to the C code + * and jump to dispatcher if not so. + * Read 1 byte otherwise and count it. + */ + SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)), + 16, + SCR_INT, + SIR_DATA_OVERRUN, + SCR_JUMP, + PADDR (dispatch), + SCR_CHMOV_ABS (1) ^ SCR_DATA_IN, + NADDR (scratch), +}/*-------------------------< DATA_OVRUN2 >----------------------*/,{ + /* + * Count this byte. + * This will allow to return a negative + * residual to user. + */ + SCR_REG_REG (scratcha, SCR_ADD, 0x01), + 0, + SCR_REG_REG (scratcha1, SCR_ADDC, 0), + 0, + SCR_REG_REG (scratcha2, SCR_ADDC, 0), + 0, + /* + * .. and repeat as required. + */ + SCR_JUMP, + PADDRH (data_ovrun1), + +}/*-------------------------< ABORT_RESEL >----------------*/,{ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + /* + ** send the abort/abortag/reset message + ** we expect an immediate disconnect + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + SCR_WAIT_DISC, + 0, + SCR_INT, + SIR_RESEL_ABORTED, + SCR_JUMP, + PADDR (start), +}/*-------------------------< RESEND_IDENT >-------------------*/,{ + /* + ** The target stays in MSG OUT phase after having acked + ** Identify [+ Tag [+ Extended message ]]. Targets shall + ** behave this way on parity error. + ** We must send it again all the messages. + */ + SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the */ + 0, /* 1rst ACK = 90 ns. Hope the NCR is'nt too fast */ + SCR_JUMP, + PADDR (send_ident), +}/*-------------------------< IDENT_BREAK >-------------------*/,{ + SCR_CLR (SCR_ATN), + 0, + SCR_JUMP, + PADDR (select2), +}/*-------------------------< IDENT_BREAK_ATN >----------------*/,{ + SCR_SET (SCR_ATN), + 0, + SCR_JUMP, + PADDR (select2), +}/*-------------------------< SDATA_IN >-------------------*/,{ + SCR_CHMOV_TBL ^ SCR_DATA_IN, + offsetof (struct dsb, sense), + SCR_CALL, + PADDR (datai_done), + SCR_JUMP, + PADDRH (data_ovrun), +}/*-------------------------< DATA_IO >--------------------*/,{ + /* + ** We jump here if the data direction was unknown at the + ** time we had to queue the command to the scripts processor. + ** Pointers had been set as follow in this situation: + ** savep --> DATA_IO + ** lastp --> start pointer when DATA_IN + ** goalp --> goal pointer when DATA_IN + ** wlastp --> start pointer when DATA_OUT + ** wgoalp --> goal pointer when DATA_OUT + ** This script sets savep/lastp/goalp according to the + ** direction chosen by the target. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)), + PADDRH(data_io_out), +}/*-------------------------< DATA_IO_COM >-----------------*/,{ + /* + ** Direction is DATA IN. + ** Warning: we jump here, even when phase is DATA OUT. + */ + SCR_LOAD_REL (scratcha, 4), + offsetof (struct ccb, phys.header.lastp), + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.header.savep), + + /* + ** Jump to the SCRIPTS according to actual direction. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + SCR_RETURN, + 0, +}/*-------------------------< DATA_IO_OUT >-----------------*/,{ + /* + ** Direction is DATA OUT. + */ + SCR_REG_REG (HF_REG, SCR_AND, (~HF_DATA_IN)), + 0, + SCR_LOAD_REL (scratcha, 4), + offsetof (struct ccb, phys.header.wlastp), + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.header.lastp), + SCR_LOAD_REL (scratcha, 4), + offsetof (struct ccb, phys.header.wgoalp), + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.header.goalp), + SCR_JUMP, + PADDRH(data_io_com), + +}/*-------------------------< RESEL_BAD_LUN >---------------*/,{ + /* + ** Message is an IDENTIFY, but lun is unknown. + ** Signal problem to C code for logging the event. + ** Send a M_ABORT to clear all pending tasks. + */ + SCR_INT, + SIR_RESEL_BAD_LUN, + SCR_JUMP, + PADDRH (abort_resel), +}/*-------------------------< BAD_I_T_L >------------------*/,{ + /* + ** We donnot have a task for that I_T_L. + ** Signal problem to C code for logging the event. + ** Send a M_ABORT message. + */ + SCR_INT, + SIR_RESEL_BAD_I_T_L, + SCR_JUMP, + PADDRH (abort_resel), +}/*-------------------------< BAD_I_T_L_Q >----------------*/,{ + /* + ** We donnot have a task that matches the tag. + ** Signal problem to C code for logging the event. + ** Send a M_ABORTTAG message. + */ + SCR_INT, + SIR_RESEL_BAD_I_T_L_Q, + SCR_JUMP, + PADDRH (abort_resel), +}/*-------------------------< BAD_STATUS >-----------------*/,{ + /* + ** Anything different from INTERMEDIATE + ** CONDITION MET should be a bad SCSI status, + ** given that GOOD status has already been tested. + ** Call the C code. + */ + SCR_LOAD_ABS (scratcha, 4), + PADDRH (startpos), + SCR_INT ^ IFFALSE (DATA (S_COND_MET)), + SIR_BAD_STATUS, + SCR_RETURN, + 0, + +}/*-------------------------< TWEAK_PMJ >------------------*/,{ + /* + ** Disable PM handling from SCRIPTS for the data phase + ** and so force PM to be handled from C code if HF_PM_TO_C + ** flag is set. + */ + SCR_FROM_REG(HF_REG), + 0, + SCR_JUMPR ^ IFTRUE (MASK (HF_PM_TO_C, HF_PM_TO_C)), + 16, + SCR_REG_REG (ccntl0, SCR_OR, ENPMJ), + 0, + SCR_RETURN, + 0, + SCR_REG_REG (ccntl0, SCR_AND, (~ENPMJ)), + 0, + SCR_RETURN, + 0, + +}/*-------------------------< PM_HANDLE >------------------*/,{ + /* + ** Phase mismatch handling. + ** + ** Since we have to deal with 2 SCSI data pointers + ** (current and saved), we need at least 2 contexts. + ** Each context (pm0 and pm1) has a saved area, a + ** SAVE mini-script and a DATA phase mini-script. + */ + /* + ** Get the PM handling flags. + */ + SCR_FROM_REG (HF_REG), + 0, + /* + ** If no flags (1rst PM for example), avoid + ** all the below heavy flags testing. + ** This makes the normal case a bit faster. + */ + SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED))), + PADDRH (pm_handle1), + /* + ** If we received a SAVE DP, switch to the + ** other PM context since the savep may point + ** to the current PM context. + */ + SCR_JUMPR ^ IFFALSE (MASK (HF_DP_SAVED, HF_DP_SAVED)), + 8, + SCR_REG_REG (sfbr, SCR_XOR, HF_ACT_PM), + 0, + /* + ** If we have been interrupt in a PM DATA mini-script, + ** we take the return address from the corresponding + ** saved area. + ** This ensure the return address always points to the + ** main DATA script for this transfer. + */ + SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1))), + PADDRH (pm_handle1), + SCR_JUMPR ^ IFFALSE (MASK (HF_IN_PM0, HF_IN_PM0)), + 16, + SCR_LOAD_REL (ia, 4), + offsetof(struct ccb, phys.pm0.ret), + SCR_JUMP, + PADDRH (pm_save), + SCR_LOAD_REL (ia, 4), + offsetof(struct ccb, phys.pm1.ret), + SCR_JUMP, + PADDRH (pm_save), +}/*-------------------------< PM_HANDLE1 >-----------------*/,{ + /* + ** Normal case. + ** Update the return address so that it + ** will point after the interrupted MOVE. + */ + SCR_REG_REG (ia, SCR_ADD, 8), + 0, + SCR_REG_REG (ia1, SCR_ADDC, 0), + 0, +}/*-------------------------< PM_SAVE >--------------------*/,{ + /* + ** Clear all the flags that told us if we were + ** interrupted in a PM DATA mini-script and/or + ** we received a SAVE DP. + */ + SCR_SFBR_REG (HF_REG, SCR_AND, (~(HF_IN_PM0|HF_IN_PM1|HF_DP_SAVED))), + 0, + /* + ** Choose the current PM context. + */ + SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)), + PADDRH (pm1_save), +}/*-------------------------< PM0_SAVE >-------------------*/,{ + SCR_STORE_REL (ia, 4), + offsetof(struct ccb, phys.pm0.ret), + /* + ** If WSR bit is set, either UA and RBC may + ** have to be changed whatever the device wants + ** to ignore this residue ot not. + */ + SCR_FROM_REG (scntl2), + 0, + SCR_CALL ^ IFTRUE (MASK (WSR, WSR)), + PADDRH (pm_wsr_handle), + /* + ** Save the remaining byte count, the updated + ** address and the return address. + */ + SCR_STORE_REL (rbc, 4), + offsetof(struct ccb, phys.pm0.sg.size), + SCR_STORE_REL (ua, 4), + offsetof(struct ccb, phys.pm0.sg.addr), + /* + ** Set the current pointer at the PM0 DATA mini-script. + */ + SCR_LOAD_ABS (temp, 4), + PADDRH (pm0_data_addr), + SCR_JUMP, + PADDR (dispatch), +}/*-------------------------< PM1_SAVE >-------------------*/,{ + SCR_STORE_REL (ia, 4), + offsetof(struct ccb, phys.pm1.ret), + /* + ** If WSR bit is set, either UA and RBC may + ** have been changed whatever the device wants + ** to ignore this residue or not. + */ + SCR_FROM_REG (scntl2), + 0, + SCR_CALL ^ IFTRUE (MASK (WSR, WSR)), + PADDRH (pm_wsr_handle), + /* + ** Save the remaining byte count, the updated + ** address and the return address. + */ + SCR_STORE_REL (rbc, 4), + offsetof(struct ccb, phys.pm1.sg.size), + SCR_STORE_REL (ua, 4), + offsetof(struct ccb, phys.pm1.sg.addr), + /* + ** Set the current pointer at the PM1 DATA mini-script. + */ + SCR_LOAD_ABS (temp, 4), + PADDRH (pm1_data_addr), + SCR_JUMP, + PADDR (dispatch), +}/*--------------------------< PM_WSR_HANDLE >-----------------------*/,{ + /* + * Phase mismatch handling from SCRIPT with WSR set. + * Such a condition can occur if the chip wants to + * execute a CHMOV(size > 1) when the WSR bit is + * set and the target changes PHASE. + */ +#ifdef SYM_DEBUG_PM_WITH_WSR + /* + * Some debugging may still be needed.:) + */ + SCR_INT, + SIR_PM_WITH_WSR, +#endif + /* + * We must move the residual byte to memory. + * + * UA contains bit 0..31 of the address to + * move the residual byte. + * Move it to the table indirect. + */ + SCR_STORE_REL (ua, 4), + offsetof (struct ccb, phys.wresid.addr), + /* + * Increment UA (move address to next position). + */ + SCR_REG_REG (ua, SCR_ADD, 1), + 0, + SCR_REG_REG (ua1, SCR_ADDC, 0), + 0, + SCR_REG_REG (ua2, SCR_ADDC, 0), + 0, + SCR_REG_REG (ua3, SCR_ADDC, 0), + 0, + /* + * Compute SCRATCHA as: + * - size to transfer = 1 byte. + * - bit 24..31 = high address bit [32...39]. + */ + SCR_LOAD_ABS (scratcha, 4), + PADDRH (zero), + SCR_REG_REG (scratcha, SCR_OR, 1), + 0, + SCR_FROM_REG (rbc3), + 0, + SCR_TO_REG (scratcha3), + 0, + /* + * Move this value to the table indirect. + */ + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.wresid.size), + /* + * Wait for a valid phase. + * While testing with bogus QUANTUM drives, the C1010 + * sometimes raised a spurious phase mismatch with + * WSR and the CHMOV(1) triggered another PM. + * Waiting explicitely for the PHASE seemed to avoid + * the nested phase mismatch. Btw, this didn't happen + * using my IBM drives. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)), + 0, + /* + * Perform the move of the residual byte. + */ + SCR_CHMOV_TBL ^ SCR_DATA_IN, + offsetof (struct ccb, phys.wresid), + /* + * We can now handle the phase mismatch with UA fixed. + * RBC[0..23]=0 is a special case that does not require + * a PM context. The C code also checks against this. + */ + SCR_FROM_REG (rbc), + 0, + SCR_RETURN ^ IFFALSE (DATA (0)), + 0, + SCR_FROM_REG (rbc1), + 0, + SCR_RETURN ^ IFFALSE (DATA (0)), + 0, + SCR_FROM_REG (rbc2), + 0, + SCR_RETURN ^ IFFALSE (DATA (0)), + 0, + /* + * RBC[0..23]=0. + * Not only we donnot need a PM context, but this would + * lead to a bogus CHMOV(0). This condition means that + * the residual was the last byte to move from this CHMOV. + * So, we just have to move the current data script pointer + * (i.e. TEMP) to the SCRIPTS address following the + * interrupted CHMOV and jump to dispatcher. + */ + SCR_STORE_ABS (ia, 4), + PADDRH (scratch), + SCR_LOAD_ABS (temp, 4), + PADDRH (scratch), + SCR_JUMP, + PADDR (dispatch), +}/*--------------------------< WSR_MA_HELPER >-----------------------*/,{ + /* + * Helper for the C code when WSR bit is set. + * Perform the move of the residual byte. + */ + SCR_CHMOV_TBL ^ SCR_DATA_IN, + offsetof (struct ccb, phys.wresid), + SCR_JUMP, + PADDR (dispatch), +}/*-------------------------< ZERO >------------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< SCRATCH >---------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< SCRATCH1 >--------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< PM0_DATA_ADDR >---------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< PM1_DATA_ADDR >---------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< SAVED_DSA >-------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< SAVED_DRS >-------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< DONE_POS >--------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< STARTPOS >--------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< TARGTBL >---------------------*/,{ + SCR_DATA_ZERO, + + +/* +** We may use MEMORY MOVE instructions to load the on chip-RAM, +** if it happens that mapping PCI memory is not possible. +** But writing the RAM from the CPU is the preferred method, +** since PCI 2.2 seems to disallow PCI self-mastering. +*/ + +#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + +}/*-------------------------< START_RAM >-------------------*/,{ + /* + ** Load the script into on-chip RAM, + ** and jump to start point. + */ + SCR_COPY (sizeof (struct script)), +}/*-------------------------< SCRIPT0_BA >--------------------*/,{ + 0, + PADDR (start), + SCR_JUMP, + PADDR (init), + +}/*-------------------------< START_RAM64 >--------------------*/,{ + /* + ** Load the RAM and start for 64 bit PCI (895A,896). + ** Both scripts (script and scripth) are loaded into + ** the RAM which is 8K (4K for 825A/875/895). + ** We also need to load some 32-63 bit segments + ** address of the SCRIPTS processor. + ** LOAD/STORE ABSOLUTE always refers to on-chip RAM + ** in our implementation. The main memory is + ** accessed using LOAD/STORE DSA RELATIVE. + */ + SCR_LOAD_REL (mmws, 4), + offsetof (struct ncb, scr_ram_seg), + SCR_COPY (sizeof(struct script)), +}/*-------------------------< SCRIPT0_BA64 >--------------------*/,{ + 0, + PADDR (start), + SCR_COPY (sizeof(struct scripth)), +}/*-------------------------< SCRIPTH0_BA64 >--------------------*/,{ + 0, + PADDRH (start64), + SCR_LOAD_REL (mmrs, 4), + offsetof (struct ncb, scr_ram_seg), + SCR_JUMP64, + PADDRH (start64), +}/*-------------------------< RAM_SEG64 >--------------------*/,{ + 0, + +#endif /* SCSI_NCR_PCI_MEM_NOT_SUPPORTED */ + +}/*-------------------------< SNOOPTEST >-------------------*/,{ + /* + ** Read the variable. + */ + SCR_LOAD_REL (scratcha, 4), + offsetof(struct ncb, ncr_cache), + SCR_STORE_REL (temp, 4), + offsetof(struct ncb, ncr_cache), + SCR_LOAD_REL (temp, 4), + offsetof(struct ncb, ncr_cache), +}/*-------------------------< SNOOPEND >-------------------*/,{ + /* + ** And stop. + */ + SCR_INT, + 99, +}/*--------------------------------------------------------*/ +}; + +/*========================================================== +** +** +** Fill in #define dependent parts of the script +** +** +**========================================================== +*/ + +void __init ncr_script_fill (struct script * scr, struct scripth * scrh) +{ + int i; + ncrcmd *p; + + p = scr->data_in; + for (i=0; idata_in + sizeof (scr->data_in)); + + p = scr->data_out; + + for (i=0; idata_out + sizeof (scr->data_out)); +} + +/*========================================================== +** +** +** Copy and rebind a script. +** +** +**========================================================== +*/ + +static void __init +ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len) +{ + ncrcmd opcode, new, old, tmp1, tmp2; + ncrcmd *start, *end; + int relocs; + int opchanged = 0; + + start = src; + end = src + len/4; + + while (src < end) { + + opcode = *src++; + *dst++ = cpu_to_scr(opcode); + + /* + ** If we forget to change the length + ** in struct script, a field will be + ** padded with 0. This is an illegal + ** command. + */ + + if (opcode == 0) { + printk (KERN_INFO "%s: ERROR0 IN SCRIPT at %d.\n", + ncr_name(np), (int) (src-start-1)); + MDELAY (10000); + continue; + }; + + /* + ** We use the bogus value 0xf00ff00f ;-) + ** to reserve data area in SCRIPTS. + */ + if (opcode == SCR_DATA_ZERO) { + dst[-1] = 0; + continue; + } + + if (DEBUG_FLAGS & DEBUG_SCRIPT) + printk (KERN_INFO "%p: <%x>\n", + (src-1), (unsigned)opcode); + + /* + ** We don't have to decode ALL commands + */ + switch (opcode >> 28) { + + case 0xf: + /* + ** LOAD / STORE DSA relative, don't relocate. + */ + relocs = 0; + break; + case 0xe: + /* + ** LOAD / STORE absolute. + */ + relocs = 1; + break; + case 0xc: + /* + ** COPY has TWO arguments. + */ + relocs = 2; + tmp1 = src[0]; + tmp2 = src[1]; +#ifdef RELOC_KVAR + if ((tmp1 & RELOC_MASK) == RELOC_KVAR) + tmp1 = 0; + if ((tmp2 & RELOC_MASK) == RELOC_KVAR) + tmp2 = 0; +#endif + if ((tmp1 ^ tmp2) & 3) { + printk (KERN_ERR"%s: ERROR1 IN SCRIPT at %d.\n", + ncr_name(np), (int) (src-start-1)); + MDELAY (1000); + } + /* + ** If PREFETCH feature not enabled, remove + ** the NO FLUSH bit if present. + */ + if ((opcode & SCR_NO_FLUSH) && + !(np->features & FE_PFEN)) { + dst[-1] = cpu_to_scr(opcode & ~SCR_NO_FLUSH); + ++opchanged; + } + break; + + case 0x0: + /* + ** MOVE/CHMOV (absolute address) + */ + if (!(np->features & FE_WIDE)) + dst[-1] = cpu_to_scr(opcode | OPC_MOVE); + relocs = 1; + break; + + case 0x1: + /* + ** MOVE/CHMOV (table indirect) + */ + if (!(np->features & FE_WIDE)) + dst[-1] = cpu_to_scr(opcode | OPC_MOVE); + relocs = 0; + break; + + case 0x8: + /* + ** JUMP / CALL + ** don't relocate if relative :-) + */ + if (opcode & 0x00800000) + relocs = 0; + else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/ + relocs = 2; + else + relocs = 1; + break; + + case 0x4: + case 0x5: + case 0x6: + case 0x7: + relocs = 1; + break; + + default: + relocs = 0; + break; + }; + + if (!relocs) { + *dst++ = cpu_to_scr(*src++); + continue; + } + while (relocs--) { + old = *src++; + + switch (old & RELOC_MASK) { + case RELOC_REGISTER: + new = (old & ~RELOC_MASK) + np->base_ba; + break; + case RELOC_LABEL: + new = (old & ~RELOC_MASK) + np->p_script; + break; + case RELOC_LABELH: + new = (old & ~RELOC_MASK) + np->p_scripth; + break; + case RELOC_SOFTC: + new = (old & ~RELOC_MASK) + np->p_ncb; + break; +#ifdef RELOC_KVAR + case RELOC_KVAR: + new=0; + if (((old & ~RELOC_MASK) < SCRIPT_KVAR_FIRST) || + ((old & ~RELOC_MASK) > SCRIPT_KVAR_LAST)) + panic("ncr KVAR out of range"); + new = vtobus(script_kvars[old & ~RELOC_MASK]); +#endif + break; + case 0: + /* Don't relocate a 0 address. */ + if (old == 0) { + new = old; + break; + } + /* fall through */ + default: + new = 0; /* For 'cc' not to complain */ + panic("ncr_script_copy_and_bind: " + "weird relocation %x\n", old); + break; + } + + *dst++ = cpu_to_scr(new); + } + }; +} + +/*========================================================== +** +** +** Auto configuration: attach and init a host adapter. +** +** +**========================================================== +*/ + +/* +** Linux host data structure. +*/ + +struct host_data { + struct ncb *ncb; +}; + +/* +** Print something which allows to retrieve the controler type, unit, +** target, lun concerned by a kernel message. +*/ + +static void PRINT_TARGET(ncb_p np, int target) +{ + printk(KERN_INFO "%s-<%d,*>: ", ncr_name(np), target); +} + +static void PRINT_LUN(ncb_p np, int target, int lun) +{ + printk(KERN_INFO "%s-<%d,%d>: ", ncr_name(np), target, lun); +} + +static void PRINT_ADDR(Scsi_Cmnd *cmd) +{ + struct host_data *host_data = (struct host_data *) cmd->device->host->hostdata; + PRINT_LUN(host_data->ncb, cmd->device->id, cmd->device->lun); +} + +/*========================================================== +** +** NCR chip clock divisor table. +** Divisors are multiplied by 10,000,000 in order to make +** calculations more simple. +** +**========================================================== +*/ + +#define _5M 5000000 +static u_long div_10M[] = + {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; + + +/*=============================================================== +** +** Prepare io register values used by ncr_init() according +** to selected and supported features. +** +** NCR/SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64, +** 128 transfers. All chips support at least 16 transfers bursts. +** The 825A, 875 and 895 chips support bursts of up to 128 +** transfers and the 895A and 896 support bursts of up to 64 +** transfers. All other chips support up to 16 transfers bursts. +** +** For PCI 32 bit data transfers each transfer is a DWORD (4 bytes). +** It is a QUADWORD (8 bytes) for PCI 64 bit data transfers. +** Only the 896 is able to perform 64 bit data transfers. +** +** We use log base 2 (burst length) as internal code, with +** value 0 meaning "burst disabled". +** +**=============================================================== +*/ + +/* + * Burst length from burst code. + */ +#define burst_length(bc) (!(bc))? 0 : 1 << (bc) + +/* + * Burst code from io register bits. + */ +#define burst_code(dmode, ctest4, ctest5) \ + (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1 + +/* + * Set initial io register bits from burst code. + */ +static inline void ncr_init_burst(ncb_p np, u_char bc) +{ + np->rv_ctest4 &= ~0x80; + np->rv_dmode &= ~(0x3 << 6); + np->rv_ctest5 &= ~0x4; + + if (!bc) { + np->rv_ctest4 |= 0x80; + } + else { + --bc; + np->rv_dmode |= ((bc & 0x3) << 6); + np->rv_ctest5 |= (bc & 0x4); + } +} + +#ifdef SCSI_NCR_NVRAM_SUPPORT + +/* +** Get target set-up from Symbios format NVRAM. +*/ + +static void __init +ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram) +{ + tcb_p tp = &np->target[target]; + Symbios_target *tn = &nvram->target[target]; + + tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255; + tp->usrwide = tn->bus_width == 0x10 ? 1 : 0; + tp->usrtags = + (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? MAX_TAGS : 0; + + if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE)) + tp->usrflag |= UF_NODISC; + if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)) + tp->usrflag |= UF_NOSCAN; +} + +/* +** Get target set-up from Tekram format NVRAM. +*/ + +static void __init +ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram) +{ + tcb_p tp = &np->target[target]; + struct Tekram_target *tn = &nvram->target[target]; + int i; + + if (tn->flags & TEKRAM_SYNC_NEGO) { + i = tn->sync_index & 0xf; + tp->usrsync = Tekram_sync[i]; + } + + tp->usrwide = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0; + + if (tn->flags & TEKRAM_TAGGED_COMMANDS) { + tp->usrtags = 2 << nvram->max_tags_index; + } + + if (!(tn->flags & TEKRAM_DISCONNECT_ENABLE)) + tp->usrflag = UF_NODISC; + + /* If any device does not support parity, we will not use this option */ + if (!(tn->flags & TEKRAM_PARITY_CHECK)) + np->rv_scntl0 &= ~0x0a; /* SCSI parity checking disabled */ +} +#endif /* SCSI_NCR_NVRAM_SUPPORT */ + +/* +** Save initial settings of some IO registers. +** Assumed to have been set by BIOS. +*/ +static void __init ncr_save_initial_setting(ncb_p np) +{ + np->sv_scntl0 = INB(nc_scntl0) & 0x0a; + np->sv_dmode = INB(nc_dmode) & 0xce; + np->sv_dcntl = INB(nc_dcntl) & 0xa8; + np->sv_ctest3 = INB(nc_ctest3) & 0x01; + np->sv_ctest4 = INB(nc_ctest4) & 0x80; + np->sv_gpcntl = INB(nc_gpcntl); + np->sv_stest2 = INB(nc_stest2) & 0x20; + np->sv_stest4 = INB(nc_stest4); + np->sv_stest1 = INB(nc_stest1); + + np->sv_scntl3 = INB(nc_scntl3) & 0x07; + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66) ){ + /* + ** C1010 always uses large fifo, bit 5 rsvd + ** scntl4 used ONLY with C1010 + */ + np->sv_ctest5 = INB(nc_ctest5) & 0x04 ; + np->sv_scntl4 = INB(nc_scntl4); + } + else { + np->sv_ctest5 = INB(nc_ctest5) & 0x24 ; + np->sv_scntl4 = 0; + } +} + +/* +** Prepare io register values used by ncr_init() +** according to selected and supported features. +*/ +static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram) +{ + u_char burst_max; + u_long period; + int i; + +#ifdef CONFIG_PARISC + char scsi_mode = -1; + struct hardware_path hwpath; +#endif + + /* + ** Wide ? + */ + + np->maxwide = (np->features & FE_WIDE)? 1 : 0; + + /* + * Guess the frequency of the chip's clock. + */ + if (np->features & (FE_ULTRA3 | FE_ULTRA2)) + np->clock_khz = 160000; + else if (np->features & FE_ULTRA) + np->clock_khz = 80000; + else + np->clock_khz = 40000; + + /* + * Get the clock multiplier factor. + */ + if (np->features & FE_QUAD) + np->multiplier = 4; + else if (np->features & FE_DBLR) + np->multiplier = 2; + else + np->multiplier = 1; + + /* + * Measure SCSI clock frequency for chips + * it may vary from assumed one. + */ + if (np->features & FE_VARCLK) + ncr_getclock(np, np->multiplier); + + /* + * Divisor to be used for async (timer pre-scaler). + * + * Note: For C1010 the async divisor is 2(8) if he + * quadrupler is disabled (enabled). + */ + + if ( (np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + + np->rv_scntl3 = 0; + } + else + { + i = np->clock_divn - 1; + while (--i >= 0) { + if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz + > div_10M[i]) { + ++i; + break; + } + } + np->rv_scntl3 = i+1; + } + + + /* + * Save the ultra3 register for the C1010/C1010_66 + */ + + np->rv_scntl4 = np->sv_scntl4; + + /* + * Minimum synchronous period factor supported by the chip. + * Btw, 'period' is in tenths of nanoseconds. + */ + + period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz; + +#ifdef CONFIG_PARISC + /* Host firmware (PDC) keeps a table for crippling SCSI capabilities. + * Many newer machines export one channel of 53c896 chip + * as SE, 50-pin HD. Also used for Multi-initiator SCSI clusters + * to set the SCSI Initiator ID. + */ + get_pci_node_path(np->pdev, &hwpath); + if (pdc_get_initiator(&hwpath, &np->myaddr, &period, &np->maxwide, &scsi_mode)) + { + if (np->maxwide) + np->features |= FE_WIDE; + if (scsi_mode >= 0) { + /* C3000 PDC reports period/mode */ + driver_setup.diff_support = 0; + switch(scsi_mode) { + case 0: np->scsi_mode = SMODE_SE; break; + case 1: np->scsi_mode = SMODE_HVD; break; + case 2: np->scsi_mode = SMODE_LVD; break; + default: break; + } + } + } +#endif + + if (period <= 250) np->minsync = 10; + else if (period <= 303) np->minsync = 11; + else if (period <= 500) np->minsync = 12; + else np->minsync = (period + 40 - 1) / 40; + + /* + * Fix up. If sync. factor is 10 (160000Khz clock) and chip + * supports ultra3, then min. sync. period 12.5ns and the factor is 9 + * Also keep track of the maximum offset in ST mode which may differ + * from the maximum offset in DT mode. For now hardcoded to 31. + */ + + if (np->features & FE_ULTRA3) { + if (np->minsync == 10) + np->minsync = 9; + np->maxoffs_st = 31; + } + else + np->maxoffs_st = np->maxoffs; + + /* + * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2). + * + * Transfer period minimums: SCSI-1 200 (50); Fast 100 (25) + * Ultra 50 (12); Ultra2 (6); Ultra3 (3) + */ + + if (np->minsync < 25 && !(np->features & (FE_ULTRA|FE_ULTRA2|FE_ULTRA3))) + np->minsync = 25; + else if (np->minsync < 12 && (np->features & FE_ULTRA)) + np->minsync = 12; + else if (np->minsync < 10 && (np->features & FE_ULTRA2)) + np->minsync = 10; + else if (np->minsync < 9 && (np->features & FE_ULTRA3)) + np->minsync = 9; + + /* + * Maximum synchronous period factor supported by the chip. + */ + + period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz); + np->maxsync = period > 2540 ? 254 : period / 10; + + /* + ** 64 bit (53C895A or 53C896) ? + */ + if (np->features & FE_DAC) { + if (np->features & FE_DAC_IN_USE) + np->rv_ccntl1 |= (XTIMOD | EXTIBMV); + else + np->rv_ccntl1 |= (DDAC); + } + + /* + ** Phase mismatch handled by SCRIPTS (53C895A, 53C896 or C1010) ? + */ + if (np->features & FE_NOPM) + np->rv_ccntl0 |= (ENPMJ); + + /* + ** Prepare initial value of other IO registers + */ +#if defined SCSI_NCR_TRUST_BIOS_SETTING + np->rv_scntl0 = np->sv_scntl0; + np->rv_dmode = np->sv_dmode; + np->rv_dcntl = np->sv_dcntl; + np->rv_ctest3 = np->sv_ctest3; + np->rv_ctest4 = np->sv_ctest4; + np->rv_ctest5 = np->sv_ctest5; + burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5); +#else + + /* + ** Select burst length (dwords) + */ + burst_max = driver_setup.burst_max; + if (burst_max == 255) + burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5); + if (burst_max > 7) + burst_max = 7; + if (burst_max > np->maxburst) + burst_max = np->maxburst; + + /* + ** DEL 352 - 53C810 Rev x11 - Part Number 609-0392140 - ITEM 2. + ** This chip and the 860 Rev 1 may wrongly use PCI cache line + ** based transactions on LOAD/STORE instructions. So we have + ** to prevent these chips from using such PCI transactions in + ** this driver. The generic sym53c8xx driver that does not use + ** LOAD/STORE instructions does not need this work-around. + */ + if ((np->device_id == PCI_DEVICE_ID_NCR_53C810 && + np->revision_id >= 0x10 && np->revision_id <= 0x11) || + (np->device_id == PCI_DEVICE_ID_NCR_53C860 && + np->revision_id <= 0x1)) + np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP); + + /* + ** DEL ? - 53C1010 Rev 1 - Part Number 609-0393638 + ** 64-bit Slave Cycles must be disabled. + */ + if ( ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) && (np->revision_id < 0x02) ) + || (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 ) ) + np->rv_ccntl1 |= 0x10; + + /* + ** Select all supported special features. + ** If we are using on-board RAM for scripts, prefetch (PFEN) + ** does not help, but burst op fetch (BOF) does. + ** Disabling PFEN makes sure BOF will be used. + */ + if (np->features & FE_ERL) + np->rv_dmode |= ERL; /* Enable Read Line */ + if (np->features & FE_BOF) + np->rv_dmode |= BOF; /* Burst Opcode Fetch */ + if (np->features & FE_ERMP) + np->rv_dmode |= ERMP; /* Enable Read Multiple */ +#if 1 + if ((np->features & FE_PFEN) && !np->base2_ba) +#else + if (np->features & FE_PFEN) +#endif + np->rv_dcntl |= PFEN; /* Prefetch Enable */ + if (np->features & FE_CLSE) + np->rv_dcntl |= CLSE; /* Cache Line Size Enable */ + if (np->features & FE_WRIE) + np->rv_ctest3 |= WRIE; /* Write and Invalidate */ + + + if ( (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && + (np->features & FE_DFS)) + np->rv_ctest5 |= DFS; /* Dma Fifo Size */ + /* C1010/C1010_66 always large fifo */ + + /* + ** Select some other + */ + if (driver_setup.master_parity) + np->rv_ctest4 |= MPEE; /* Master parity checking */ + if (driver_setup.scsi_parity) + np->rv_scntl0 |= 0x0a; /* full arb., ena parity, par->ATN */ + +#ifdef SCSI_NCR_NVRAM_SUPPORT + /* + ** Get parity checking, host ID and verbose mode from NVRAM + **/ + if (nvram) { + switch(nvram->type) { + case SCSI_NCR_TEKRAM_NVRAM: + np->myaddr = nvram->data.Tekram.host_id & 0x0f; + break; + case SCSI_NCR_SYMBIOS_NVRAM: + if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE)) + np->rv_scntl0 &= ~0x0a; + np->myaddr = nvram->data.Symbios.host_id & 0x0f; + if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS) + np->verbose += 1; + break; + } + } +#endif + /* + ** Get SCSI addr of host adapter (set by bios?). + */ + if (np->myaddr == 255) { + np->myaddr = INB(nc_scid) & 0x07; + if (!np->myaddr) + np->myaddr = SCSI_NCR_MYADDR; + } + +#endif /* SCSI_NCR_TRUST_BIOS_SETTING */ + + /* + * Prepare initial io register bits for burst length + */ + ncr_init_burst(np, burst_max); + + /* + ** Set SCSI BUS mode. + ** + ** - ULTRA2 chips (895/895A/896) + ** and ULTRA 3 chips (1010) report the current + ** BUS mode through the STEST4 IO register. + ** - For previous generation chips (825/825A/875), + ** user has to tell us how to check against HVD, + ** since a 100% safe algorithm is not possible. + */ + np->scsi_mode = SMODE_SE; + if (np->features & (FE_ULTRA2 | FE_ULTRA3)) + np->scsi_mode = (np->sv_stest4 & SMODE); + else if (np->features & FE_DIFF) { + switch(driver_setup.diff_support) { + case 4: /* Trust previous settings if present, then GPIO3 */ + if (np->sv_scntl3) { + if (np->sv_stest2 & 0x20) + np->scsi_mode = SMODE_HVD; + break; + } + case 3: /* SYMBIOS controllers report HVD through GPIO3 */ + if (nvram && nvram->type != SCSI_NCR_SYMBIOS_NVRAM) + break; + if (INB(nc_gpreg) & 0x08) + break; + case 2: /* Set HVD unconditionally */ + np->scsi_mode = SMODE_HVD; + case 1: /* Trust previous settings for HVD */ + if (np->sv_stest2 & 0x20) + np->scsi_mode = SMODE_HVD; + break; + default:/* Don't care about HVD */ + break; + } + } + if (np->scsi_mode == SMODE_HVD) + np->rv_stest2 |= 0x20; + + /* + ** Set LED support from SCRIPTS. + ** Ignore this feature for boards known to use a + ** specific GPIO wiring and for the 895A or 896 + ** that drive the LED directly. + ** Also probe initial setting of GPIO0 as output. + */ + if ((driver_setup.led_pin || + (nvram && nvram->type == SCSI_NCR_SYMBIOS_NVRAM)) && + !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01)) + np->features |= FE_LED0; + + /* + ** Set irq mode. + */ + switch(driver_setup.irqm & 3) { + case 2: + np->rv_dcntl |= IRQM; + break; + case 1: + np->rv_dcntl |= (np->sv_dcntl & IRQM); + break; + default: + break; + } + + /* + ** Configure targets according to driver setup. + ** If NVRAM present get targets setup from NVRAM. + ** Allow to override sync, wide and NOSCAN from + ** boot command line. + */ + for (i = 0 ; i < MAX_TARGET ; i++) { + tcb_p tp = &np->target[i]; + + tp->usrsync = 255; +#ifdef SCSI_NCR_NVRAM_SUPPORT + if (nvram) { + switch(nvram->type) { + case SCSI_NCR_TEKRAM_NVRAM: + ncr_Tekram_setup_target(np, i, &nvram->data.Tekram); + break; + case SCSI_NCR_SYMBIOS_NVRAM: + ncr_Symbios_setup_target(np, i, &nvram->data.Symbios); + break; + } + if (driver_setup.use_nvram & 0x2) + tp->usrsync = driver_setup.default_sync; + if (driver_setup.use_nvram & 0x4) + tp->usrwide = driver_setup.max_wide; + if (driver_setup.use_nvram & 0x8) + tp->usrflag &= ~UF_NOSCAN; + } + else { +#else + if (1) { +#endif + tp->usrsync = driver_setup.default_sync; + tp->usrwide = driver_setup.max_wide; + tp->usrtags = MAX_TAGS; + if (!driver_setup.disconnection) + np->target[i].usrflag = UF_NODISC; + } + } + + /* + ** Announce all that stuff to user. + */ + + i = nvram ? nvram->type : 0; + printk(KERN_INFO "%s: %sID %d, Fast-%d%s%s\n", ncr_name(np), + i == SCSI_NCR_SYMBIOS_NVRAM ? "Symbios format NVRAM, " : + (i == SCSI_NCR_TEKRAM_NVRAM ? "Tekram format NVRAM, " : ""), + np->myaddr, + np->minsync < 10 ? 80 : + (np->minsync < 12 ? 40 : (np->minsync < 25 ? 20 : 10) ), + (np->rv_scntl0 & 0xa) ? ", Parity Checking" : ", NO Parity", + (np->rv_stest2 & 0x20) ? ", Differential" : ""); + + if (bootverbose > 1) { + printk (KERN_INFO "%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " + "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", + ncr_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl, + np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); + + printk (KERN_INFO "%s: final SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " + "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", + ncr_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl, + np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); + } + + if (bootverbose && np->base2_ba) + printk (KERN_INFO "%s: on-chip RAM at 0x%lx\n", + ncr_name(np), np->base2_ba); + + return 0; +} + + +#ifdef SCSI_NCR_DEBUG_NVRAM + +void __init ncr_display_Symbios_nvram(ncb_p np, Symbios_nvram *nvram) +{ + int i; + + /* display Symbios nvram host data */ + printk(KERN_DEBUG "%s: HOST ID=%d%s%s%s%s%s\n", + ncr_name(np), nvram->host_id & 0x0f, + (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", + (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"", + (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"", + (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"", + (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :""); + + /* display Symbios nvram drive data */ + for (i = 0 ; i < 15 ; i++) { + struct Symbios_target *tn = &nvram->target[i]; + printk(KERN_DEBUG "%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n", + ncr_name(np), i, + (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "", + (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "", + (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "", + (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "", + tn->bus_width, + tn->sync_period / 4, + tn->timeout); + } +} + +static u_char Tekram_boot_delay[7] __initdata = {3, 5, 10, 20, 30, 60, 120}; + +void __init ncr_display_Tekram_nvram(ncb_p np, Tekram_nvram *nvram) +{ + int i, tags, boot_delay; + char *rem; + + /* display Tekram nvram host data */ + tags = 2 << nvram->max_tags_index; + boot_delay = 0; + if (nvram->boot_delay_index < 6) + boot_delay = Tekram_boot_delay[nvram->boot_delay_index]; + switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) { + default: + case 0: rem = ""; break; + case 1: rem = " REMOVABLE=boot device"; break; + case 2: rem = " REMOVABLE=all"; break; + } + + printk(KERN_DEBUG + "%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n", + ncr_name(np), nvram->host_id & 0x0f, + (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", + (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES" :"", + (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"", + (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"", + (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"", + (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"", + (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"", + (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"", + rem, boot_delay, tags); + + /* display Tekram nvram drive data */ + for (i = 0; i <= 15; i++) { + int sync, j; + struct Tekram_target *tn = &nvram->target[i]; + j = tn->sync_index & 0xf; + sync = Tekram_sync[j]; + printk(KERN_DEBUG "%s-%d:%s%s%s%s%s%s PERIOD=%d\n", + ncr_name(np), i, + (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "", + (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "", + (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "", + (tn->flags & TEKRAM_START_CMD) ? " START" : "", + (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "", + (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "", + sync); + } +} +#endif /* SCSI_NCR_DEBUG_NVRAM */ + +/* +** Host attach and initialisations. +** +** Allocate host data and ncb structure. +** Request IO region and remap MMIO region. +** Do chip initialization. +** If all is OK, install interrupt handling and +** start the timer daemon. +*/ + +static int __init +ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) +{ + struct host_data *host_data; + ncb_p np = 0; + struct Scsi_Host *instance = 0; + u_long flags = 0; + ncr_nvram *nvram = device->nvram; + int i; + + printk(KERN_INFO NAME53C "%s-%d: rev 0x%x on pci bus %d device %d function %d " +#ifdef __sparc__ + "irq %s\n", +#else + "irq %d\n", +#endif + device->chip.name, unit, device->chip.revision_id, + device->slot.bus, (device->slot.device_fn & 0xf8) >> 3, + device->slot.device_fn & 7, +#ifdef __sparc__ + __irq_itoa(device->slot.irq)); +#else + device->slot.irq); +#endif + + /* + ** Allocate host_data structure + */ + if (!(instance = scsi_register(tpnt, sizeof(*host_data)))) + goto attach_error; + host_data = (struct host_data *) instance->hostdata; + + /* + ** Allocate the host control block. + */ + np = __m_calloc_dma(device->pdev, sizeof(struct ncb), "NCB"); + if (!np) + goto attach_error; + NCR_INIT_LOCK_NCB(np); + np->pdev = device->pdev; + np->p_ncb = vtobus(np); + host_data->ncb = np; + + /* + ** Store input informations in the host data structure. + */ + strncpy(np->chip_name, device->chip.name, sizeof(np->chip_name) - 1); + np->unit = unit; + np->verbose = driver_setup.verbose; + sprintf(np->inst_name, NAME53C "%s-%d", np->chip_name, np->unit); + np->device_id = device->chip.device_id; + np->revision_id = device->chip.revision_id; + np->bus = device->slot.bus; + np->device_fn = device->slot.device_fn; + np->features = device->chip.features; + np->clock_divn = device->chip.nr_divisor; + np->maxoffs = device->chip.offset_max; + np->maxburst = device->chip.burst_max; + np->myaddr = device->host_id; + + /* + ** Allocate the start queue. + */ + np->squeue = (ncrcmd *) + m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); + if (!np->squeue) + goto attach_error; + np->p_squeue = vtobus(np->squeue); + + /* + ** Allocate the done queue. + */ + np->dqueue = (ncrcmd *) + m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE"); + if (!np->dqueue) + goto attach_error; + + /* + ** Allocate the target bus address array. + */ + np->targtbl = (u_int32 *) m_calloc_dma(256, "TARGTBL"); + if (!np->targtbl) + goto attach_error; + + /* + ** Allocate SCRIPTS areas + */ + np->script0 = (struct script *) + m_calloc_dma(sizeof(struct script), "SCRIPT"); + if (!np->script0) + goto attach_error; + np->scripth0 = (struct scripth *) + m_calloc_dma(sizeof(struct scripth), "SCRIPTH"); + if (!np->scripth0) + goto attach_error; + + /* + ** Initialyze the CCB free queue and, + ** allocate some CCB. We need at least ONE. + */ + xpt_que_init(&np->free_ccbq); + xpt_que_init(&np->b0_ccbq); + if (!ncr_alloc_ccb(np)) + goto attach_error; + + /* + ** Initialize timer structure + ** + */ + init_timer(&np->timer); + np->timer.data = (unsigned long) np; + np->timer.function = sym53c8xx_timeout; + + /* + ** Try to map the controller chip to + ** virtual and physical memory. + */ + + np->base_ba = device->slot.base; + np->base_ws = (np->features & FE_IO256)? 256 : 128; + np->base2_ba = (np->features & FE_RAM)? device->slot.base_2 : 0; + +#ifndef SCSI_NCR_IOMAPPED + np->base_va = remap_pci_mem(device->slot.base_c, np->base_ws); + if (!np->base_va) { + printk(KERN_ERR "%s: can't map PCI MMIO region\n",ncr_name(np)); + goto attach_error; + } + else if (bootverbose > 1) + printk(KERN_INFO "%s: using memory mapped IO\n", ncr_name(np)); + + /* + ** Make the controller's registers available. + ** Now the INB INW INL OUTB OUTW OUTL macros + ** can be used safely. + */ + + np->reg = (struct ncr_reg *) np->base_va; + +#endif /* !defined SCSI_NCR_IOMAPPED */ + + /* + ** If on-chip RAM is used, make sure SCRIPTS isn't too large. + */ + if (np->base2_ba && sizeof(struct script) > 4096) { + printk(KERN_ERR "%s: script too large.\n", ncr_name(np)); + goto attach_error; + } + + /* + ** Try to map the controller chip into iospace. + */ + + if (device->slot.io_port) { + request_region(device->slot.io_port, np->base_ws, NAME53C8XX); + np->base_io = device->slot.io_port; + } + +#ifdef SCSI_NCR_NVRAM_SUPPORT + if (nvram) { + switch(nvram->type) { + case SCSI_NCR_SYMBIOS_NVRAM: +#ifdef SCSI_NCR_DEBUG_NVRAM + ncr_display_Symbios_nvram(np, &nvram->data.Symbios); +#endif + break; + case SCSI_NCR_TEKRAM_NVRAM: +#ifdef SCSI_NCR_DEBUG_NVRAM + ncr_display_Tekram_nvram(np, &nvram->data.Tekram); +#endif + break; + default: + nvram = 0; +#ifdef SCSI_NCR_DEBUG_NVRAM + printk(KERN_DEBUG "%s: NVRAM: None or invalid data.\n", ncr_name(np)); +#endif + } + } +#endif + + /* + ** Save setting of some IO registers, so we will + ** be able to probe specific implementations. + */ + ncr_save_initial_setting (np); + + /* + ** Reset the chip now, since it has been reported + ** that SCSI clock calibration may not work properly + ** if the chip is currently active. + */ + ncr_chip_reset (np); + + /* + ** Do chip dependent initialization. + */ + (void) ncr_prepare_setting(np, nvram); + + /* + ** Check the PCI clock frequency if needed. + ** + ** Must be done after ncr_prepare_setting since it destroys + ** STEST1 that is used to probe for the clock multiplier. + ** + ** The range is currently [22688 - 45375 Khz], given + ** the values used by ncr_getclock(). + ** This calibration of the frequecy measurement + ** algorithm against the PCI clock frequency is only + ** performed if the driver has had to measure the SCSI + ** clock due to other heuristics not having been enough + ** to deduce the SCSI clock frequency. + ** + ** When the chip has been initialized correctly by the + ** SCSI BIOS, the driver deduces the presence of the + ** clock multiplier and the value of the SCSI clock from + ** initial values of IO registers, and therefore no + ** clock measurement is performed. + ** Normally the driver should never have to measure any + ** clock, unless the controller may use a 80 MHz clock + ** or has a clock multiplier and any of the following + ** condition is met: + ** + ** - No SCSI BIOS is present. + ** - SCSI BIOS did'nt enable the multiplier for some reason. + ** - User has disabled the controller from the SCSI BIOS. + ** - User booted the O/S from another O/S that did'nt enable + ** the multiplier for some reason. + ** + ** As a result, the driver may only have to measure some + ** frequency in very unusual situations. + ** + ** For this reality test against the PCI clock to really + ** protect against flaws in the udelay() calibration or + ** driver problem that affect the clock measurement + ** algorithm, the actual PCI clock frequency must be 33 MHz. + */ + i = np->pciclock_max ? ncr_getpciclock(np) : 0; + if (i && (i < np->pciclock_min || i > np->pciclock_max)) { + printk(KERN_ERR "%s: PCI clock (%u KHz) is out of range " + "[%u KHz - %u KHz].\n", + ncr_name(np), i, np->pciclock_min, np->pciclock_max); + goto attach_error; + } + + /* + ** Patch script to physical addresses + */ + ncr_script_fill (&script0, &scripth0); + + np->p_script = vtobus(np->script0); + np->p_scripth = vtobus(np->scripth0); + np->p_scripth0 = np->p_scripth; + + if (np->base2_ba) { + np->p_script = np->base2_ba; + if (np->features & FE_RAM8K) { + np->base2_ws = 8192; + np->p_scripth = np->p_script + 4096; +#if BITS_PER_LONG > 32 + np->scr_ram_seg = cpu_to_scr(np->base2_ba >> 32); +#endif + } + else + np->base2_ws = 4096; +#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + np->base2_va = + remap_pci_mem(device->slot.base_2_c, np->base2_ws); + if (!np->base2_va) { + printk(KERN_ERR "%s: can't map PCI MEMORY region\n", + ncr_name(np)); + goto attach_error; + } +#endif + } + + ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script)); + ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth)); + + /* + ** Patch some variables in SCRIPTS + */ + np->scripth0->pm0_data_addr[0] = + cpu_to_scr(NCB_SCRIPT_PHYS(np, pm0_data)); + np->scripth0->pm1_data_addr[0] = + cpu_to_scr(NCB_SCRIPT_PHYS(np, pm1_data)); + + /* + ** Patch if not Ultra 3 - Do not write to scntl4 + */ + if (np->features & FE_ULTRA3) { + np->script0->resel_scntl4[0] = cpu_to_scr(SCR_LOAD_REL (scntl4, 1)); + np->script0->resel_scntl4[1] = cpu_to_scr(offsetof(struct tcb, uval)); + } + + +#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + np->scripth0->script0_ba[0] = cpu_to_scr(vtobus(np->script0)); + np->scripth0->script0_ba64[0] = cpu_to_scr(vtobus(np->script0)); + np->scripth0->scripth0_ba64[0] = cpu_to_scr(vtobus(np->scripth0)); + np->scripth0->ram_seg64[0] = np->scr_ram_seg; +#endif + /* + ** Prepare the idle and invalid task actions. + */ + np->idletask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->idletask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); + np->p_idletask = NCB_PHYS(np, idletask); + + np->notask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->notask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); + np->p_notask = NCB_PHYS(np, notask); + + np->bad_i_t_l.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->bad_i_t_l.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); + np->p_bad_i_t_l = NCB_PHYS(np, bad_i_t_l); + + np->bad_i_t_l_q.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->bad_i_t_l_q.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np,bad_i_t_l_q)); + np->p_bad_i_t_l_q = NCB_PHYS(np, bad_i_t_l_q); + + /* + ** Allocate and prepare the bad lun table. + */ + np->badluntbl = m_calloc_dma(256, "BADLUNTBL"); + if (!np->badluntbl) + goto attach_error; + + assert (offsetof(struct lcb, resel_task) == 0); + np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, resel_bad_lun)); + + for (i = 0 ; i < 64 ; i++) + np->badluntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun)); + + /* + ** Prepare the target bus address array. + */ + np->scripth0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl)); + for (i = 0 ; i < MAX_TARGET ; i++) { + np->targtbl[i] = cpu_to_scr(NCB_PHYS(np, target[i])); + np->target[i].b_luntbl = cpu_to_scr(vtobus(np->badluntbl)); + np->target[i].b_lun0 = cpu_to_scr(NCB_PHYS(np, resel_badlun)); + } + + /* + ** Patch the script for LED support. + */ + + if (np->features & FE_LED0) { + np->script0->idle[0] = + cpu_to_scr(SCR_REG_REG(gpreg, SCR_OR, 0x01)); + np->script0->reselected[0] = + cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe)); + np->script0->start[0] = + cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe)); + } + + /* + ** Patch the script to provide an extra clock cycle on + ** data out phase - 53C1010_66MHz part only. + ** (Fixed in rev. 1 of the chip) + */ + if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 && + np->revision_id < 1){ + np->script0->datao_phase[0] = + cpu_to_scr(SCR_REG_REG(scntl4, SCR_OR, 0x0c)); + } + +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** If user does not want to use IMMEDIATE ARBITRATION + ** when we are reselected while attempting to arbitrate, + ** patch the SCRIPTS accordingly with a SCRIPT NO_OP. + */ + if (!(driver_setup.iarb & 1)) + np->script0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); + /* + ** If user wants IARB to be set when we win arbitration + ** and have other jobs, compute the max number of consecutive + ** settings of IARB hint before we leave devices a chance to + ** arbitrate for reselection. + */ + np->iarb_max = (driver_setup.iarb >> 4); +#endif + + /* + ** DEL 472 - 53C896 Rev 1 - Part Number 609-0393055 - ITEM 5. + */ + if (np->device_id == PCI_DEVICE_ID_NCR_53C896 && + np->revision_id <= 0x1 && (np->features & FE_NOPM)) { + np->scatter = ncr_scatter_896R1; + np->script0->datai_phase[0] = cpu_to_scr(SCR_JUMP); + np->script0->datai_phase[1] = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj)); + np->script0->datao_phase[0] = cpu_to_scr(SCR_JUMP); + np->script0->datao_phase[1] = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj)); + } + else +#ifdef DEBUG_896R1 + np->scatter = ncr_scatter_896R1; +#else + np->scatter = ncr_scatter; +#endif + + /* + ** Reset chip. + ** We should use ncr_soft_reset(), but we donnot want to do + ** so, since we may not be safe if ABRT interrupt occurs due + ** to the BIOS or previous O/S having enable this interrupt. + ** + ** For C1010 need to set ABRT bit prior to SRST if SCRIPTs + ** are running. Not true in this case. + */ + ncr_chip_reset(np); + + /* + ** Now check the cache handling of the pci chipset. + */ + + if (ncr_snooptest (np)) { + printk (KERN_ERR "CACHE INCORRECTLY CONFIGURED.\n"); + goto attach_error; + }; + + /* + ** Install the interrupt handler. + ** If we synchonize the C code with SCRIPTS on interrupt, + ** we donnot want to share the INTR line at all. + */ + if (request_irq(device->slot.irq, sym53c8xx_intr, +#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR + ((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT), +#else + ((driver_setup.irqm & 0x10) ? 0 : SA_SHIRQ) | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) + ((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT), +#else + 0, +#endif +#endif + NAME53C8XX, np)) { + printk(KERN_ERR "%s: request irq %d failure\n", + ncr_name(np), device->slot.irq); + goto attach_error; + } + np->irq = device->slot.irq; + + /* + ** After SCSI devices have been opened, we cannot + ** reset the bus safely, so we do it here. + ** Interrupt handler does the real work. + ** Process the reset exception, + ** if interrupts are not enabled yet. + ** Then enable disconnects. + */ + NCR_LOCK_NCB(np, flags); + if (ncr_reset_scsi_bus(np, 0, driver_setup.settle_delay) != 0) { + printk(KERN_ERR "%s: FATAL ERROR: CHECK SCSI BUS - CABLES, TERMINATION, DEVICE POWER etc.!\n", ncr_name(np)); + + NCR_UNLOCK_NCB(np, flags); + goto attach_error; + } + ncr_exception (np); + + /* + ** The middle-level SCSI driver does not + ** wait for devices to settle. + ** Wait synchronously if more than 2 seconds. + */ + if (driver_setup.settle_delay > 2) { + printk(KERN_INFO "%s: waiting %d seconds for scsi devices to settle...\n", + ncr_name(np), driver_setup.settle_delay); + MDELAY (1000 * driver_setup.settle_delay); + } + + /* + ** start the timeout daemon + */ + np->lasttime=0; + ncr_timeout (np); + + /* + ** use SIMPLE TAG messages by default + */ +#ifdef SCSI_NCR_ALWAYS_SIMPLE_TAG + np->order = M_SIMPLE_TAG; +#endif + + /* + ** Done. + ** Fill Linux host instance structure + ** and return success. + */ + instance->max_channel = 0; + instance->this_id = np->myaddr; + instance->max_id = np->maxwide ? 16 : 8; + instance->max_lun = MAX_LUN; +#ifndef SCSI_NCR_IOMAPPED +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29) + instance->base = (unsigned long) np->reg; +#else + instance->base = (char *) np->reg; +#endif +#endif + instance->irq = np->irq; + instance->unique_id = np->base_io; + instance->io_port = np->base_io; + instance->n_io_port = np->base_ws; + instance->dma_channel = 0; + instance->cmd_per_lun = MAX_TAGS; + instance->can_queue = (MAX_START-4); + scsi_set_device(instance, &device->pdev->dev); + + np->check_integrity = 0; + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + instance->check_integrity = 0; + +#ifdef SCSI_NCR_ENABLE_INTEGRITY_CHECK + if ( !(driver_setup.bus_check & 0x04) ) { + np->check_integrity = 1; + instance->check_integrity = 1; + } +#endif +#endif + + NCR_UNLOCK_NCB(np, flags); + + /* + ** Now let the generic SCSI driver + ** look for the SCSI devices on the bus .. + */ + return 0; + +attach_error: + if (!instance) return -1; + printk(KERN_INFO "%s: giving up ...\n", ncr_name(np)); + if (np) + ncr_free_resources(np); + scsi_unregister(instance); + + return -1; + } + + +/* +** Free controller resources. +*/ +static void ncr_free_resources(ncb_p np) +{ + ccb_p cp; + tcb_p tp; + lcb_p lp; + int target, lun; + + if (np->irq) + free_irq(np->irq, np); + if (np->base_io) + release_region(np->base_io, np->base_ws); +#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + if (np->base_va) + unmap_pci_mem(np->base_va, np->base_ws); + if (np->base2_va) + unmap_pci_mem(np->base2_va, np->base2_ws); +#endif + if (np->scripth0) + m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH"); + if (np->script0) + m_free_dma(np->script0, sizeof(struct script), "SCRIPT"); + if (np->squeue) + m_free_dma(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); + if (np->dqueue) + m_free_dma(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE"); + + while ((cp = np->ccbc) != NULL) { + np->ccbc = cp->link_ccb; + m_free_dma(cp, sizeof(*cp), "CCB"); + } + + if (np->badluntbl) + m_free_dma(np->badluntbl, 256,"BADLUNTBL"); + + for (target = 0; target < MAX_TARGET ; target++) { + tp = &np->target[target]; + for (lun = 0 ; lun < MAX_LUN ; lun++) { + lp = ncr_lp(np, tp, lun); + if (!lp) + continue; + if (lp->tasktbl != &lp->tasktbl_0) + m_free_dma(lp->tasktbl, MAX_TASKS*4, "TASKTBL"); + if (lp->cb_tags) + m_free(lp->cb_tags, MAX_TAGS, "CB_TAGS"); + m_free_dma(lp, sizeof(*lp), "LCB"); + } +#if MAX_LUN > 1 + if (tp->lmp) + m_free(tp->lmp, MAX_LUN * sizeof(lcb_p), "LMP"); + if (tp->luntbl) + m_free_dma(tp->luntbl, 256, "LUNTBL"); +#endif + } + + if (np->targtbl) + m_free_dma(np->targtbl, 256, "TARGTBL"); + + m_free_dma(np, sizeof(*np), "NCB"); +} + + +/*========================================================== +** +** +** Done SCSI commands list management. +** +** We donnot enter the scsi_done() callback immediately +** after a command has been seen as completed but we +** insert it into a list which is flushed outside any kind +** of driver critical section. +** This allows to do minimal stuff under interrupt and +** inside critical sections and to also avoid locking up +** on recursive calls to driver entry points under SMP. +** In fact, the only kernel point which is entered by the +** driver with a driver lock set is get_free_pages(GFP_ATOMIC...) +** that shall not reenter the driver under any circumstance. +** +**========================================================== +*/ +static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd) +{ + unmap_scsi_data(np, cmd); + cmd->host_scribble = (char *) np->done_list; + np->done_list = cmd; +} + +static inline void ncr_flush_done_cmds(Scsi_Cmnd *lcmd) +{ + Scsi_Cmnd *cmd; + + while (lcmd) { + cmd = lcmd; + lcmd = (Scsi_Cmnd *) cmd->host_scribble; + cmd->scsi_done(cmd); + } +} + +/*========================================================== +** +** +** Prepare the next negotiation message for integrity check, +** if needed. +** +** Fill in the part of message buffer that contains the +** negotiation and the nego_status field of the CCB. +** Returns the size of the message in bytes. +** +** If tp->ppr_negotiation is 1 and a M_REJECT occurs, then +** we disable ppr_negotiation. If the first ppr_negotiation is +** successful, set this flag to 2. +** +**========================================================== +*/ +#ifdef SCSI_NCR_INTEGRITY_CHECKING +static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr) +{ + tcb_p tp = &np->target[cp->target]; + int msglen = 0; + int nego = 0; + u_char new_width, new_offset, new_period; + u_char no_increase; + + if (tp->ppr_negotiation == 1) /* PPR message successful */ + tp->ppr_negotiation = 2; + + if (tp->inq_done) { + + if (!tp->ic_maximums_set) { + tp->ic_maximums_set = 1; + + /* + * Check against target, host and user limits + */ + if ( (tp->inq_byte7 & INQ7_WIDE16) && + np->maxwide && tp->usrwide) + tp->ic_max_width = 1; + else + tp->ic_max_width = 0; + + + if ((tp->inq_byte7 & INQ7_SYNC) && tp->maxoffs) + tp->ic_min_sync = (tp->minsync < np->minsync) ? + np->minsync : tp->minsync; + else + tp->ic_min_sync = 255; + + tp->period = 1; + tp->widedone = 1; + + /* + * Enable PPR negotiation - only if Ultra3 support + * is accessible. + */ + +#if 0 + if (tp->ic_max_width && (tp->ic_min_sync != 255 )) + tp->ppr_negotiation = 1; +#endif + tp->ppr_negotiation = 0; + if (np->features & FE_ULTRA3) { + if (tp->ic_max_width && (tp->ic_min_sync == 0x09)) + tp->ppr_negotiation = 1; + } + + if (!tp->ppr_negotiation) + cmd->ic_nego &= ~NS_PPR; + } + + if (DEBUG_FLAGS & DEBUG_IC) { + printk("%s: cmd->ic_nego %d, 1st byte 0x%2X\n", + ncr_name(np), cmd->ic_nego, cmd->cmnd[0]); + } + + /* Previous command recorded a parity or an initiator + * detected error condition. Force bus to narrow for this + * target. Clear flag. Negotation on request sense. + * Note: kernel forces 2 bus resets :o( but clears itself out. + * Minor bug? in scsi_obsolete.c (ugly) + */ + if (np->check_integ_par) { + printk("%s: Parity Error. Target set to narrow.\n", + ncr_name(np)); + tp->ic_max_width = 0; + tp->widedone = tp->period = 0; + } + + /* Initializing: + * If ic_nego == NS_PPR, we are in the initial test for + * PPR messaging support. If driver flag is clear, then + * either we don't support PPR nego (narrow or async device) + * or this is the second TUR and we have had a M. REJECT + * or unexpected disconnect on the first PPR negotiation. + * Do not negotiate, reset nego flags (in case a reset has + * occurred), clear ic_nego and return. + * General case: Kernel will clear flag on a fallback. + * Do only SDTR or WDTR in the future. + */ + if (!tp->ppr_negotiation && (cmd->ic_nego == NS_PPR )) { + tp->ppr_negotiation = 0; + cmd->ic_nego &= ~NS_PPR; + tp->widedone = tp->period = 1; + return msglen; + } + else if (( tp->ppr_negotiation && !(cmd->ic_nego & NS_PPR )) || + (!tp->ppr_negotiation && (cmd->ic_nego & NS_PPR )) ) { + tp->ppr_negotiation = 0; + cmd->ic_nego &= ~NS_PPR; + } + + /* + * Always check the PPR nego. flag bit if ppr_negotiation + * is set. If the ic_nego PPR bit is clear, + * there must have been a fallback. Do only + * WDTR / SDTR in the future. + */ + if ((tp->ppr_negotiation) && (!(cmd->ic_nego & NS_PPR))) + tp->ppr_negotiation = 0; + + /* In case of a bus reset, ncr_negotiate will reset + * the flags tp->widedone and tp->period to 0, forcing + * a new negotiation. Do WDTR then SDTR. If PPR, do both. + * Do NOT increase the period. It is possible for the Scsi_Cmnd + * flags to be set to increase the period when a bus reset + * occurs - we don't want to change anything. + */ + + no_increase = 0; + + if (tp->ppr_negotiation && (!tp->widedone) && (!tp->period) ) { + cmd->ic_nego = NS_PPR; + tp->widedone = tp->period = 1; + no_increase = 1; + } + else if (!tp->widedone) { + cmd->ic_nego = NS_WIDE; + tp->widedone = 1; + no_increase = 1; + } + else if (!tp->period) { + cmd->ic_nego = NS_SYNC; + tp->period = 1; + no_increase = 1; + } + + new_width = cmd->ic_nego_width & tp->ic_max_width; + + switch (cmd->ic_nego_sync) { + case 2: /* increase the period */ + if (!no_increase) { + if (tp->ic_min_sync <= 0x09) + tp->ic_min_sync = 0x0A; + else if (tp->ic_min_sync <= 0x0A) + tp->ic_min_sync = 0x0C; + else if (tp->ic_min_sync <= 0x0C) + tp->ic_min_sync = 0x19; + else if (tp->ic_min_sync <= 0x19) + tp->ic_min_sync *= 2; + else { + tp->ic_min_sync = 255; + cmd->ic_nego_sync = 0; + tp->maxoffs = 0; + } + } + new_period = tp->maxoffs?tp->ic_min_sync:0; + new_offset = tp->maxoffs; + break; + + case 1: /* nego. to maximum */ + new_period = tp->maxoffs?tp->ic_min_sync:0; + new_offset = tp->maxoffs; + break; + + case 0: /* nego to async */ + default: + new_period = 0; + new_offset = 0; + break; + }; + + + nego = NS_NOCHANGE; + if (tp->ppr_negotiation) { + u_char options_byte = 0; + + /* + ** Must make sure data is consistent. + ** If period is 9 and sync, must be wide and DT bit set. + ** else period must be larger. If the width is 0, + ** reset bus to wide but increase the period to 0x0A. + ** Note: The strange else clause is due to the integrity check. + ** If fails at 0x09, wide, the I.C. code will redo at the same + ** speed but a narrow bus. The driver must take care of slowing + ** the bus speed down. + ** + ** The maximum offset in ST mode is 31, in DT mode 62 (1010/1010_66 only) + */ + if ( (new_period==0x09) && new_offset) { + if (new_width) + options_byte = 0x02; + else { + tp->ic_min_sync = 0x0A; + new_period = 0x0A; + cmd->ic_nego_width = 1; + new_width = 1; + } + } + if (!options_byte && new_offset > np->maxoffs_st) + new_offset = np->maxoffs_st; + + nego = NS_PPR; + + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 6; + msgptr[msglen++] = M_X_PPR_REQ; + msgptr[msglen++] = new_period; + msgptr[msglen++] = 0; + msgptr[msglen++] = new_offset; + msgptr[msglen++] = new_width; + msgptr[msglen++] = options_byte; + + } + else { + switch (cmd->ic_nego & ~NS_PPR) { + case NS_WIDE: + /* + ** WDTR negotiation on if device supports + ** wide or if wide device forced narrow + ** due to a parity error. + */ + + cmd->ic_nego_width &= tp->ic_max_width; + + if (tp->ic_max_width | np->check_integ_par) { + nego = NS_WIDE; + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 2; + msgptr[msglen++] = M_X_WIDE_REQ; + msgptr[msglen++] = new_width; + } + break; + + case NS_SYNC: + /* + ** negotiate synchronous transfers + ** Target must support sync transfers. + ** Min. period = 0x0A, maximum offset of 31=0x1f. + */ + + if (tp->inq_byte7 & INQ7_SYNC) { + + if (new_offset && (new_period < 0x0A)) { + tp->ic_min_sync = 0x0A; + new_period = 0x0A; + } + if (new_offset > np->maxoffs_st) + new_offset = np->maxoffs_st; + nego = NS_SYNC; + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 3; + msgptr[msglen++] = M_X_SYNC_REQ; + msgptr[msglen++] = new_period; + msgptr[msglen++] = new_offset; + } + else + cmd->ic_nego_sync = 0; + break; + + case NS_NOCHANGE: + break; + } + } + + }; + + cp->nego_status = nego; + np->check_integ_par = 0; + + if (nego) { + tp->nego_cp = cp; + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, nego == NS_WIDE ? + "wide/narrow msgout": + (nego == NS_SYNC ? "sync/async msgout" : "ppr msgout"), + msgptr); + }; + }; + + return msglen; +} +#endif /* SCSI_NCR_INTEGRITY_CHECKING */ + +/*========================================================== +** +** +** Prepare the next negotiation message if needed. +** +** Fill in the part of message buffer that contains the +** negotiation and the nego_status field of the CCB. +** Returns the size of the message in bytes. +** +** +**========================================================== +*/ + + +static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr) +{ + tcb_p tp = &np->target[cp->target]; + int msglen = 0; + int nego = 0; + u_char width, offset, factor, last_byte; + + if (!np->check_integrity) { + /* If integrity checking disabled, enable PPR messaging + * if device supports wide, sync and ultra 3 + */ + if (tp->ppr_negotiation == 1) /* PPR message successful */ + tp->ppr_negotiation = 2; + + if ((tp->inq_done) && (!tp->ic_maximums_set)) { + tp->ic_maximums_set = 1; + + /* + * Issue PPR only if board is capable + * and set-up for Ultra3 transfers. + */ + tp->ppr_negotiation = 0; + if ( (np->features & FE_ULTRA3) && + (tp->usrwide) && (tp->maxoffs) && + (tp->minsync == 0x09) ) + tp->ppr_negotiation = 1; + } + } + + if (tp->inq_done) { + /* + * Get the current width, offset and period + */ + ncr_get_xfer_info( np, tp, &factor, + &offset, &width); + + /* + ** negotiate wide transfers ? + */ + + if (!tp->widedone) { + if (tp->inq_byte7 & INQ7_WIDE16) { + if (tp->ppr_negotiation) + nego = NS_PPR; + else + nego = NS_WIDE; + + width = tp->usrwide; +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if (tp->ic_done) + width &= tp->ic_max_width; +#endif + } else + tp->widedone=1; + + }; + + /* + ** negotiate synchronous transfers? + */ + + if ((nego != NS_WIDE) && !tp->period) { + if (tp->inq_byte7 & INQ7_SYNC) { + if (tp->ppr_negotiation) + nego = NS_PPR; + else + nego = NS_SYNC; + + /* Check for async flag */ + if (tp->maxoffs == 0) { + offset = 0; + factor = 0; + } + else { + offset = tp->maxoffs; + factor = tp->minsync; +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if ((tp->ic_done) && + (factor < tp->ic_min_sync)) + factor = tp->ic_min_sync; +#endif + } + + } else { + offset = 0; + factor = 0; + tp->period =0xffff; + PRINT_TARGET(np, cp->target); + printk ("target did not report SYNC.\n"); + }; + }; + }; + + switch (nego) { + case NS_PPR: + /* + ** Must make sure data is consistent. + ** If period is 9 and sync, must be wide and DT bit set + ** else period must be larger. + ** Maximum offset is 31=0x1f is ST mode, 62 if DT mode + */ + last_byte = 0; + if ( (factor==9) && offset) { + if (!width) { + factor = 0x0A; + } + else + last_byte = 0x02; + } + if (!last_byte && offset > np->maxoffs_st) + offset = np->maxoffs_st; + + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 6; + msgptr[msglen++] = M_X_PPR_REQ; + msgptr[msglen++] = factor; + msgptr[msglen++] = 0; + msgptr[msglen++] = offset; + msgptr[msglen++] = width; + msgptr[msglen++] = last_byte; + break; + case NS_SYNC: + /* + ** Never negotiate faster than Ultra 2 (25ns periods) + */ + if (offset && (factor < 0x0A)) { + factor = 0x0A; + tp->minsync = 0x0A; + } + if (offset > np->maxoffs_st) + offset = np->maxoffs_st; + + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 3; + msgptr[msglen++] = M_X_SYNC_REQ; + msgptr[msglen++] = factor; + msgptr[msglen++] = offset; + break; + case NS_WIDE: + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 2; + msgptr[msglen++] = M_X_WIDE_REQ; + msgptr[msglen++] = width; + break; + }; + + cp->nego_status = nego; + + if (nego) { + tp->nego_cp = cp; + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, nego == NS_WIDE ? + "wide msgout": + (nego == NS_SYNC ? "sync msgout" : "ppr msgout"), + msgptr); + }; + }; + + return msglen; +} + +/*========================================================== +** +** +** Start execution of a SCSI command. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) +{ +/* Scsi_Device *device = cmd->device; */ + tcb_p tp = &np->target[cmd->device->id]; + lcb_p lp = ncr_lp(np, tp, cmd->device->lun); + ccb_p cp; + + u_char idmsg, *msgptr; + u_int msglen; + int direction; + u_int32 lastp, goalp; + + /*--------------------------------------------- + ** + ** Some shortcuts ... + ** + **--------------------------------------------- + */ + if ((cmd->device->id == np->myaddr ) || + (cmd->device->id >= MAX_TARGET) || + (cmd->device->lun >= MAX_LUN )) { + return(DID_BAD_TARGET); + } + + /*--------------------------------------------- + ** + ** Complete the 1st TEST UNIT READY command + ** with error condition if the device is + ** flagged NOSCAN, in order to speed up + ** the boot. + ** + **--------------------------------------------- + */ + if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12) && + (tp->usrflag & UF_NOSCAN)) { + tp->usrflag &= ~UF_NOSCAN; + return DID_BAD_TARGET; + } + + if (DEBUG_FLAGS & DEBUG_TINY) { + PRINT_ADDR(cmd); + printk ("CMD=%x ", cmd->cmnd[0]); + } + + /*--------------------------------------------------- + ** + ** Assign a ccb / bind cmd. + ** If resetting, shorten settle_time if necessary + ** in order to avoid spurious timeouts. + ** If resetting or no free ccb, + ** insert cmd into the waiting list. + ** + **---------------------------------------------------- + */ + if (np->settle_time && cmd->timeout_per_command >= HZ) { + u_long tlimit = ktime_get(cmd->timeout_per_command - HZ); + if (ktime_dif(np->settle_time, tlimit) > 0) + np->settle_time = tlimit; + } + + if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->device->id, cmd->device->lun))) { + insert_into_waiting_list(np, cmd); + return(DID_OK); + } + cp->cmd = cmd; + + /*--------------------------------------------------- + ** + ** Enable tagged queue if asked by scsi ioctl + ** + **---------------------------------------------------- + */ +#if 0 /* This stuff was only useful for linux-1.2.13 */ + if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) { + lp->numtags = tp->usrtags; + ncr_setup_tags (np, cp->target, cp->lun); + } +#endif + + /*---------------------------------------------------- + ** + ** Build the identify / tag / sdtr message + ** + **---------------------------------------------------- + */ + + idmsg = M_IDENTIFY | cp->lun; + + if (cp ->tag != NO_TAG || (lp && !(tp->usrflag & UF_NODISC))) + idmsg |= 0x40; + + msgptr = cp->scsi_smsg; + msglen = 0; + msgptr[msglen++] = idmsg; + + if (cp->tag != NO_TAG) { + char order = np->order; + + /* + ** Force ordered tag if necessary to avoid timeouts + ** and to preserve interactivity. + */ + if (lp && ktime_exp(lp->tags_stime)) { + lp->tags_si = !(lp->tags_si); + if (lp->tags_sum[lp->tags_si]) { + order = M_ORDERED_TAG; + if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>0){ + PRINT_ADDR(cmd); + printk("ordered tag forced.\n"); + } + } + lp->tags_stime = ktime_get(3*HZ); + } + + if (order == 0) { + /* + ** Ordered write ops, unordered read ops. + */ + switch (cmd->cmnd[0]) { + case 0x08: /* READ_SMALL (6) */ + case 0x28: /* READ_BIG (10) */ + case 0xa8: /* READ_HUGE (12) */ + order = M_SIMPLE_TAG; + break; + default: + order = M_ORDERED_TAG; + } + } + msgptr[msglen++] = order; + /* + ** For less than 128 tags, actual tags are numbered + ** 1,3,5,..2*MAXTAGS+1,since we may have to deal + ** with devices that have problems with #TAG 0 or too + ** great #TAG numbers. For more tags (up to 256), + ** we use directly our tag number. + */ +#if MAX_TASKS > (512/4) + msgptr[msglen++] = cp->tag; +#else + msgptr[msglen++] = (cp->tag << 1) + 1; +#endif + } + + cp->host_flags = 0; + + /*---------------------------------------------------- + ** + ** Build the data descriptors + ** + **---------------------------------------------------- + */ + + direction = scsi_data_direction(cmd); + if (direction != SCSI_DATA_NONE) { + cp->segments = np->scatter (np, cp, cp->cmd); + if (cp->segments < 0) { + ncr_free_ccb(np, cp); + return(DID_ERROR); + } + } + else { + cp->data_len = 0; + cp->segments = 0; + } + + /*--------------------------------------------------- + ** + ** negotiation required? + ** + ** (nego_status is filled by ncr_prepare_nego()) + ** + **--------------------------------------------------- + */ + + cp->nego_status = 0; + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if ((np->check_integrity && tp->ic_done) || !np->check_integrity) { + if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) { + msglen += ncr_prepare_nego (np, cp, msgptr + msglen); + } + } + else if (np->check_integrity && (cmd->ic_in_progress)) { + msglen += ncr_ic_nego (np, cp, cmd, msgptr + msglen); + } + else if (np->check_integrity && cmd->ic_complete) { + u_long current_period; + u_char current_offset, current_width, current_factor; + + ncr_get_xfer_info (np, tp, ¤t_factor, + ¤t_offset, ¤t_width); + + tp->ic_max_width = current_width; + tp->ic_min_sync = current_factor; + + if (current_factor == 9) current_period = 125; + else if (current_factor == 10) current_period = 250; + else if (current_factor == 11) current_period = 303; + else if (current_factor == 12) current_period = 500; + else current_period = current_factor * 40; + + /* + * Negotiation for this target is complete. Update flags. + */ + tp->period = current_period; + tp->widedone = 1; + tp->ic_done = 1; + + printk("%s: Integrity Check Complete: \n", ncr_name(np)); + + printk("%s: %s %s SCSI", ncr_name(np), + current_offset?"SYNC":"ASYNC", + tp->ic_max_width?"WIDE":"NARROW"); + if (current_offset) { + u_long mbs = 10000 * (tp->ic_max_width + 1); + + printk(" %d.%d MB/s", + (int) (mbs / current_period), (int) (mbs % current_period)); + + printk(" (%d ns, %d offset)\n", + (int) current_period/10, current_offset); + } + else + printk(" %d MB/s. \n ", (tp->ic_max_width+1)*5); + } +#else + if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) { + msglen += ncr_prepare_nego (np, cp, msgptr + msglen); + } +#endif /* SCSI_NCR_INTEGRITY_CHECKING */ + + + /*---------------------------------------------------- + ** + ** Determine xfer direction. + ** + **---------------------------------------------------- + */ + if (!cp->data_len) + direction = SCSI_DATA_NONE; + + /* + ** If data direction is UNKNOWN, speculate DATA_READ + ** but prepare alternate pointers for WRITE in case + ** of our speculation will be just wrong. + ** SCRIPTS will swap values if needed. + */ + switch(direction) { + case SCSI_DATA_UNKNOWN: + case SCSI_DATA_WRITE: + goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8; + lastp = goalp - 8 - (cp->segments * (SCR_SG_SIZE*4)); + if (direction != SCSI_DATA_UNKNOWN) + break; + cp->phys.header.wgoalp = cpu_to_scr(goalp); + cp->phys.header.wlastp = cpu_to_scr(lastp); + /* fall through */ + case SCSI_DATA_READ: + cp->host_flags |= HF_DATA_IN; + goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8; + lastp = goalp - 8 - (cp->segments * (SCR_SG_SIZE*4)); + break; + default: + case SCSI_DATA_NONE: + lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data); + break; + } + + /* + ** Set all pointers values needed by SCRIPTS. + ** If direction is unknown, start at data_io. + */ + cp->phys.header.lastp = cpu_to_scr(lastp); + cp->phys.header.goalp = cpu_to_scr(goalp); + + if (direction == SCSI_DATA_UNKNOWN) + cp->phys.header.savep = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io)); + else + cp->phys.header.savep= cpu_to_scr(lastp); + + /* + ** Save the initial data pointer in order to be able + ** to redo the command. + ** We also have to save the initial lastp, since it + ** will be changed to DATA_IO if we don't know the data + ** direction and the device completes the command with + ** QUEUE FULL status (without entering the data phase). + */ + cp->startp = cp->phys.header.savep; + cp->lastp0 = cp->phys.header.lastp; + + /*---------------------------------------------------- + ** + ** fill in ccb + ** + **---------------------------------------------------- + ** + ** + ** physical -> virtual backlink + ** Generic SCSI command + */ + + /* + ** Startqueue + */ + cp->phys.header.go.start = cpu_to_scr(NCB_SCRIPT_PHYS (np,select)); + cp->phys.header.go.restart = cpu_to_scr(NCB_SCRIPT_PHYS (np,resel_dsa)); + /* + ** select + */ + cp->phys.select.sel_id = cp->target; + cp->phys.select.sel_scntl3 = tp->wval; + cp->phys.select.sel_sxfer = tp->sval; + cp->phys.select.sel_scntl4 = tp->uval; + /* + ** message + */ + cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg)); + cp->phys.smsg.size = cpu_to_scr(msglen); + + /* + ** command + */ + memcpy(cp->cdb_buf, cmd->cmnd, MIN(cmd->cmd_len, sizeof(cp->cdb_buf))); + cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, cdb_buf[0])); + cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len); + + /* + ** status + */ + cp->actualquirks = tp->quirks; + cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; + cp->scsi_status = S_ILLEGAL; + cp->xerr_status = 0; + cp->extra_bytes = 0; + + /* + ** extreme data pointer. + ** shall be positive, so -1 is lower than lowest.:) + */ + cp->ext_sg = -1; + cp->ext_ofs = 0; + + /*---------------------------------------------------- + ** + ** Critical region: start this job. + ** + **---------------------------------------------------- + */ + + /* + ** activate this job. + */ + + /* + ** insert next CCBs into start queue. + ** 2 max at a time is enough to flush the CCB wait queue. + */ + if (lp) + ncr_start_next_ccb(np, lp, 2); + else + ncr_put_start_queue(np, cp); + + /* + ** Command is successfully queued. + */ + + return(DID_OK); +} + + +/*========================================================== +** +** +** Insert a CCB into the start queue and wake up the +** SCRIPTS processor. +** +** +**========================================================== +*/ + +static void ncr_start_next_ccb(ncb_p np, lcb_p lp, int maxn) +{ + XPT_QUEHEAD *qp; + ccb_p cp; + + while (maxn-- && lp->queuedccbs < lp->queuedepth) { + qp = xpt_remque_head(&lp->wait_ccbq); + if (!qp) + break; + ++lp->queuedccbs; + cp = xpt_que_entry(qp, struct ccb, link_ccbq); + xpt_insque_tail(qp, &lp->busy_ccbq); + lp->tasktbl[cp->tag == NO_TAG ? 0 : cp->tag] = + cpu_to_scr(cp->p_ccb); + ncr_put_start_queue(np, cp); + } +} + +static void ncr_put_start_queue(ncb_p np, ccb_p cp) +{ + u_short qidx; + +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** If the previously queued CCB is not yet done, + ** set the IARB hint. The SCRIPTS will go with IARB + ** for this job when starting the previous one. + ** We leave devices a chance to win arbitration by + ** not using more than 'iarb_max' consecutive + ** immediate arbitrations. + */ + if (np->last_cp && np->iarb_count < np->iarb_max) { + np->last_cp->host_flags |= HF_HINT_IARB; + ++np->iarb_count; + } + else + np->iarb_count = 0; + np->last_cp = cp; +#endif + + /* + ** insert into start queue. + */ + qidx = np->squeueput + 2; + if (qidx >= MAX_START*2) qidx = 0; + + np->squeue [qidx] = cpu_to_scr(np->p_idletask); + MEMORY_BARRIER(); + np->squeue [np->squeueput] = cpu_to_scr(cp->p_ccb); + + np->squeueput = qidx; + cp->queued = 1; + + if (DEBUG_FLAGS & DEBUG_QUEUE) + printk ("%s: queuepos=%d.\n", ncr_name (np), np->squeueput); + + /* + ** Script processor may be waiting for reselect. + ** Wake it up. + */ + MEMORY_BARRIER(); + OUTB (nc_istat, SIGP|np->istat_sem); +} + + +/*========================================================== +** +** Soft reset the chip. +** +** Some 896 and 876 chip revisions may hang-up if we set +** the SRST (soft reset) bit at the wrong time when SCRIPTS +** are running. +** So, we need to abort the current operation prior to +** soft resetting the chip. +** +**========================================================== +*/ + +static void ncr_chip_reset (ncb_p np) +{ + OUTB (nc_istat, SRST); + UDELAY (10); + OUTB (nc_istat, 0); +} + +static void ncr_soft_reset(ncb_p np) +{ + u_char istat; + int i; + + if (!(np->features & FE_ISTAT1) || !(INB (nc_istat1) & SRUN)) + goto do_chip_reset; + + OUTB (nc_istat, CABRT); + for (i = 100000 ; i ; --i) { + istat = INB (nc_istat); + if (istat & SIP) { + INW (nc_sist); + } + else if (istat & DIP) { + if (INB (nc_dstat) & ABRT) + break; + } + UDELAY(5); + } + OUTB (nc_istat, 0); + if (!i) + printk("%s: unable to abort current chip operation, " + "ISTAT=0x%02x.\n", ncr_name(np), istat); +do_chip_reset: + ncr_chip_reset(np); +} + +/*========================================================== +** +** +** Start reset process. +** The interrupt handler will reinitialize the chip. +** The timeout handler will wait for settle_time before +** clearing it and so resuming command processing. +** +** +**========================================================== +*/ +static void ncr_start_reset(ncb_p np) +{ + (void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay); +} + +static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay) +{ + u_int32 term; + int retv = 0; + + np->settle_time = ktime_get(settle_delay * HZ); + + if (bootverbose > 1) + printk("%s: resetting, " + "command processing suspended for %d seconds\n", + ncr_name(np), settle_delay); + + ncr_soft_reset(np); /* Soft reset the chip */ + UDELAY (2000); /* The 895/6 need time for the bus mode to settle */ + if (enab_int) + OUTW (nc_sien, RST); + /* + ** Enable Tolerant, reset IRQD if present and + ** properly set IRQ mode, prior to resetting the bus. + */ + OUTB (nc_stest3, TE); + OUTB (nc_dcntl, (np->rv_dcntl & IRQM)); + OUTB (nc_scntl1, CRST); + UDELAY (200); + + if (!driver_setup.bus_check) + goto out; + /* + ** Check for no terminators or SCSI bus shorts to ground. + ** Read SCSI data bus, data parity bits and control signals. + ** We are expecting RESET to be TRUE and other signals to be + ** FALSE. + */ + term = INB(nc_sstat0); + term = ((term & 2) << 7) + ((term & 1) << 17); /* rst sdp0 */ + term |= ((INB(nc_sstat2) & 0x01) << 26) | /* sdp1 */ + ((INW(nc_sbdl) & 0xff) << 9) | /* d7-0 */ + ((INW(nc_sbdl) & 0xff00) << 10) | /* d15-8 */ + INB(nc_sbcl); /* req ack bsy sel atn msg cd io */ + + if (!(np->features & FE_WIDE)) + term &= 0x3ffff; + + if (term != (2<<7)) { + printk("%s: suspicious SCSI data while resetting the BUS.\n", + ncr_name(np)); + printk("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = " + "0x%lx, expecting 0x%lx\n", + ncr_name(np), + (np->features & FE_WIDE) ? "dp1,d15-8," : "", + (u_long)term, (u_long)(2<<7)); + if (driver_setup.bus_check == 1) + retv = 1; + } +out: + OUTB (nc_scntl1, 0); + return retv; +} + +/*========================================================== +** +** +** Reset the SCSI BUS. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +static int ncr_reset_bus (ncb_p np, Scsi_Cmnd *cmd, int sync_reset) +{ +/* Scsi_Device *device = cmd->device; */ + ccb_p cp; + int found; + +/* + * Return immediately if reset is in progress. + */ + if (np->settle_time) { + return SCSI_RESET_PUNT; + } +/* + * Start the reset process. + * The script processor is then assumed to be stopped. + * Commands will now be queued in the waiting list until a settle + * delay of 2 seconds will be completed. + */ + ncr_start_reset(np); +/* + * First, look in the wakeup list + */ + for (found=0, cp=np->ccbc; cp; cp=cp->link_ccb) { + /* + ** look for the ccb of this command. + */ + if (cp->host_status == HS_IDLE) continue; + if (cp->cmd == cmd) { + found = 1; + break; + } + } +/* + * Then, look in the waiting list + */ + if (!found && retrieve_from_waiting_list(0, np, cmd)) + found = 1; +/* + * Wake-up all awaiting commands with DID_RESET. + */ + reset_waiting_list(np); +/* + * Wake-up all pending commands with HS_RESET -> DID_RESET. + */ + ncr_wakeup(np, HS_RESET); +/* + * If the involved command was not in a driver queue, and the + * scsi driver told us reset is synchronous, and the command is not + * currently in the waiting list, complete it with DID_RESET status, + * in order to keep it alive. + */ + if (!found && sync_reset && !retrieve_from_waiting_list(0, np, cmd)) { + SetScsiResult(cmd, DID_RESET, 0); + ncr_queue_done_cmd(np, cmd); + } + + return SCSI_RESET_SUCCESS; +} + +/*========================================================== +** +** +** Abort an SCSI command. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +static int ncr_abort_command (ncb_p np, Scsi_Cmnd *cmd) +{ +/* Scsi_Device *device = cmd->device; */ + ccb_p cp; + +/* + * First, look for the scsi command in the waiting list + */ + if (remove_from_waiting_list(np, cmd)) { + SetScsiAbortResult(cmd); + ncr_queue_done_cmd(np, cmd); + return SCSI_ABORT_SUCCESS; + } + +/* + * Then, look in the wakeup list + */ + for (cp=np->ccbc; cp; cp=cp->link_ccb) { + /* + ** look for the ccb of this command. + */ + if (cp->host_status == HS_IDLE) continue; + if (cp->cmd == cmd) + break; + } + + if (!cp) { + return SCSI_ABORT_NOT_RUNNING; + } + + /* + ** Keep track we have to abort this job. + */ + cp->to_abort = 1; + + /* + ** Tell the SCRIPTS processor to stop + ** and synchronize with us. + */ + np->istat_sem = SEM; + + /* + ** If there are no requests, the script + ** processor will sleep on SEL_WAIT_RESEL. + ** Let's wake it up, since it may have to work. + */ + OUTB (nc_istat, SIGP|SEM); + + /* + ** Tell user we are working for him. + */ + return SCSI_ABORT_PENDING; +} + +/*========================================================== +** +** Linux release module stuff. +** +** Called before unloading the module +** Detach the host. +** We have to free resources and halt the NCR chip +** +**========================================================== +*/ + +static int ncr_detach(ncb_p np) +{ + int i; + + printk("%s: detaching ...\n", ncr_name(np)); + +/* +** Stop the ncr_timeout process +** Set release_stage to 1 and wait that ncr_timeout() set it to 2. +*/ + np->release_stage = 1; + for (i = 50 ; i && np->release_stage != 2 ; i--) MDELAY (100); + if (np->release_stage != 2) + printk("%s: the timer seems to be already stopped\n", + ncr_name(np)); + else np->release_stage = 2; + +/* +** Reset NCR chip. +** We should use ncr_soft_reset(), but we donnot want to do +** so, since we may not be safe if interrupts occur. +*/ + + printk("%s: resetting chip\n", ncr_name(np)); + ncr_chip_reset(np); + +/* +** Restore bios setting for automatic clock detection. +*/ + OUTB(nc_dmode, np->sv_dmode); + OUTB(nc_dcntl, np->sv_dcntl); + OUTB(nc_ctest3, np->sv_ctest3); + OUTB(nc_ctest4, np->sv_ctest4); + OUTB(nc_ctest5, np->sv_ctest5); + OUTB(nc_gpcntl, np->sv_gpcntl); + OUTB(nc_stest2, np->sv_stest2); + + ncr_selectclock(np, np->sv_scntl3); +/* +** Free host resources +*/ + ncr_free_resources(np); + + return 1; +} + +/*========================================================== +** +** +** Complete execution of a SCSI command. +** Signal completion to the generic SCSI driver. +** +** +**========================================================== +*/ + +void ncr_complete (ncb_p np, ccb_p cp) +{ + Scsi_Cmnd *cmd; + tcb_p tp; + lcb_p lp; + + /* + ** Sanity check + */ + if (!cp || !cp->cmd) + return; + + /* + ** Print some debugging info. + */ + + if (DEBUG_FLAGS & DEBUG_TINY) + printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp, + cp->host_status,cp->scsi_status); + + /* + ** Get command, target and lun pointers. + */ + + cmd = cp->cmd; + cp->cmd = NULL; + tp = &np->target[cp->target]; + lp = ncr_lp(np, tp, cp->lun); + + /* + ** We donnot queue more than 1 ccb per target + ** with negotiation at any time. If this ccb was + ** used for negotiation, clear this info in the tcb. + */ + + if (cp == tp->nego_cp) + tp->nego_cp = 0; + +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** We just complete the last queued CCB. + ** Clear this info that is no more relevant. + */ + if (cp == np->last_cp) + np->last_cp = 0; +#endif + + /* + ** If auto-sense performed, change scsi status, + ** Otherwise, compute the residual. + */ + if (cp->host_flags & HF_AUTO_SENSE) { + cp->scsi_status = cp->sv_scsi_status; + cp->xerr_status = cp->sv_xerr_status; + } + else { + cp->resid = 0; + if (cp->xerr_status || + cp->phys.header.lastp != cp->phys.header.goalp) + cp->resid = ncr_compute_residual(np, cp); + } + + /* + ** Check for extended errors. + */ + + if (cp->xerr_status) { + if (cp->xerr_status & XE_PARITY_ERR) { + PRINT_ADDR(cmd); + printk ("unrecovered SCSI parity error.\n"); + } + if (cp->xerr_status & XE_EXTRA_DATA) { + PRINT_ADDR(cmd); + printk ("extraneous data discarded.\n"); + } + if (cp->xerr_status & XE_BAD_PHASE) { + PRINT_ADDR(cmd); + printk ("illegal scsi phase (4/5).\n"); + } + if (cp->xerr_status & XE_SODL_UNRUN) { + PRINT_ADDR(cmd); + printk ("ODD transfer in DATA OUT phase.\n"); + } + if (cp->xerr_status & XE_SWIDE_OVRUN){ + PRINT_ADDR(cmd); + printk ("ODD transfer in DATA IN phase.\n"); + } + + if (cp->host_status==HS_COMPLETE) + cp->host_status = HS_FAIL; + } + + /* + ** Print out any error for debugging purpose. + */ + if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { + if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD || + cp->resid) { + PRINT_ADDR(cmd); + printk ("ERROR: cmd=%x host_status=%x scsi_status=%x " + "data_len=%d residual=%d\n", + cmd->cmnd[0], cp->host_status, cp->scsi_status, + cp->data_len, cp->resid); + } + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,99) + /* + ** Move residual byte count to user structure. + */ + cmd->resid = cp->resid; +#endif + /* + ** Check the status. + */ + if ( (cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_GOOD || + cp->scsi_status == S_COND_MET)) { + /* + ** All went well (GOOD status). + ** CONDITION MET status is returned on + ** `Pre-Fetch' or `Search data' success. + */ + SetScsiResult(cmd, DID_OK, cp->scsi_status); + + /* + ** Allocate the lcb if not yet. + */ + if (!lp) + ncr_alloc_lcb (np, cp->target, cp->lun); + + /* + ** On standard INQUIRY response (EVPD and CmDt + ** not set), setup logical unit according to + ** announced capabilities (we need the 1rst 8 bytes). + */ + if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) && + cmd->request_bufflen - cp->resid > 7 && !cmd->use_sg) { + sync_scsi_data(np, cmd); /* SYNC the data */ + ncr_setup_lcb (np, cp->target, cp->lun, + (char *) cmd->request_buffer); + } + + /* + ** If tags was reduced due to queue full, + ** increase tags if 1000 good status received. + */ + if (lp && lp->usetags && lp->numtags < lp->maxtags) { + ++lp->num_good; + if (lp->num_good >= 1000) { + lp->num_good = 0; + ++lp->numtags; + ncr_setup_tags (np, cp->target, cp->lun); + } + } + } else if ((cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_CHECK_COND)) { + /* + ** Check condition code + */ + SetScsiResult(cmd, DID_OK, S_CHECK_COND); + + if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { + PRINT_ADDR(cmd); + ncr_printl_hex("sense data:", cmd->sense_buffer, 14); + } + } else if ((cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_CONFLICT)) { + /* + ** Reservation Conflict condition code + */ + SetScsiResult(cmd, DID_OK, S_CONFLICT); + + } else if ((cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_BUSY || + cp->scsi_status == S_QUEUE_FULL)) { + + /* + ** Target is busy. + */ + SetScsiResult(cmd, DID_OK, cp->scsi_status); + + } else if ((cp->host_status == HS_SEL_TIMEOUT) + || (cp->host_status == HS_TIMEOUT)) { + + /* + ** No response + */ + SetScsiResult(cmd, DID_TIME_OUT, cp->scsi_status); + + } else if (cp->host_status == HS_RESET) { + + /* + ** SCSI bus reset + */ + SetScsiResult(cmd, DID_RESET, cp->scsi_status); + + } else if (cp->host_status == HS_ABORTED) { + + /* + ** Transfer aborted + */ + SetScsiAbortResult(cmd); + + } else { + int did_status; + + /* + ** Other protocol messes + */ + PRINT_ADDR(cmd); + printk ("COMMAND FAILED (%x %x) @%p.\n", + cp->host_status, cp->scsi_status, cp); + + did_status = DID_ERROR; + if (cp->xerr_status & XE_PARITY_ERR) + did_status = DID_PARITY; + + SetScsiResult(cmd, did_status, cp->scsi_status); + } + + /* + ** trace output + */ + + if (tp->usrflag & UF_TRACE) { + PRINT_ADDR(cmd); + printk (" CMD:"); + ncr_print_hex(cmd->cmnd, cmd->cmd_len); + + if (cp->host_status==HS_COMPLETE) { + switch (cp->scsi_status) { + case S_GOOD: + printk (" GOOD"); + break; + case S_CHECK_COND: + printk (" SENSE:"); + ncr_print_hex(cmd->sense_buffer, 14); + break; + default: + printk (" STAT: %x\n", cp->scsi_status); + break; + } + } else printk (" HOSTERROR: %x", cp->host_status); + printk ("\n"); + } + + /* + ** Free this ccb + */ + ncr_free_ccb (np, cp); + + /* + ** requeue awaiting scsi commands for this lun. + */ + if (lp && lp->queuedccbs < lp->queuedepth && + !xpt_que_empty(&lp->wait_ccbq)) + ncr_start_next_ccb(np, lp, 2); + + /* + ** requeue awaiting scsi commands for this controller. + */ + if (np->waiting_list) + requeue_waiting_list(np); + + /* + ** signal completion to generic driver. + */ + ncr_queue_done_cmd(np, cmd); +} + +/*========================================================== +** +** +** Signal all (or one) control block done. +** +** +**========================================================== +*/ + +/* +** The NCR has completed CCBs. +** Look at the DONE QUEUE. +** +** On architectures that may reorder LOAD/STORE operations, +** a memory barrier may be needed after the reading of the +** so-called `flag' and prior to dealing with the data. +*/ +int ncr_wakeup_done (ncb_p np) +{ + ccb_p cp; + int i, n; + u_long dsa; + + n = 0; + i = np->dqueueget; + while (1) { + dsa = scr_to_cpu(np->dqueue[i]); + if (!dsa) + break; + np->dqueue[i] = 0; + if ((i = i+2) >= MAX_START*2) + i = 0; + + cp = ncr_ccb_from_dsa(np, dsa); + if (cp) { + MEMORY_BARRIER(); + ncr_complete (np, cp); + ++n; + } + else + printk (KERN_ERR "%s: bad DSA (%lx) in done queue.\n", + ncr_name(np), dsa); + } + np->dqueueget = i; + + return n; +} + +/* +** Complete all active CCBs. +*/ +void ncr_wakeup (ncb_p np, u_long code) +{ + ccb_p cp = np->ccbc; + + while (cp) { + if (cp->host_status != HS_IDLE) { + cp->host_status = code; + ncr_complete (np, cp); + } + cp = cp->link_ccb; + } +} + +/*========================================================== +** +** +** Start NCR chip. +** +** +**========================================================== +*/ + +void ncr_init (ncb_p np, int reset, char * msg, u_long code) +{ + int i; + u_long phys; + + /* + ** Reset chip if asked, otherwise just clear fifos. + */ + + if (reset) + ncr_soft_reset(np); + else { + OUTB (nc_stest3, TE|CSF); + OUTONB (nc_ctest3, CLF); + } + + /* + ** Message. + */ + + if (msg) printk (KERN_INFO "%s: restart (%s).\n", ncr_name (np), msg); + + /* + ** Clear Start Queue + */ + phys = np->p_squeue; + np->queuedepth = MAX_START - 1; /* 1 entry needed as end marker */ + for (i = 0; i < MAX_START*2; i += 2) { + np->squeue[i] = cpu_to_scr(np->p_idletask); + np->squeue[i+1] = cpu_to_scr(phys + (i+2)*4); + } + np->squeue[MAX_START*2-1] = cpu_to_scr(phys); + + + /* + ** Start at first entry. + */ + np->squeueput = 0; + np->scripth0->startpos[0] = cpu_to_scr(phys); + + /* + ** Clear Done Queue + */ + phys = vtobus(np->dqueue); + for (i = 0; i < MAX_START*2; i += 2) { + np->dqueue[i] = 0; + np->dqueue[i+1] = cpu_to_scr(phys + (i+2)*4); + } + np->dqueue[MAX_START*2-1] = cpu_to_scr(phys); + + /* + ** Start at first entry. + */ + np->scripth0->done_pos[0] = cpu_to_scr(phys); + np->dqueueget = 0; + + /* + ** Wakeup all pending jobs. + */ + ncr_wakeup (np, code); + + /* + ** Init chip. + */ + + OUTB (nc_istat, 0x00 ); /* Remove Reset, abort */ + UDELAY (2000); /* The 895 needs time for the bus mode to settle */ + + OUTB (nc_scntl0, np->rv_scntl0 | 0xc0); + /* full arb., ena parity, par->ATN */ + OUTB (nc_scntl1, 0x00); /* odd parity, and remove CRST!! */ + + ncr_selectclock(np, np->rv_scntl3); /* Select SCSI clock */ + + OUTB (nc_scid , RRE|np->myaddr); /* Adapter SCSI address */ + OUTW (nc_respid, 1ul<myaddr); /* Id to respond to */ + OUTB (nc_istat , SIGP ); /* Signal Process */ + OUTB (nc_dmode , np->rv_dmode); /* Burst length, dma mode */ + OUTB (nc_ctest5, np->rv_ctest5); /* Large fifo + large burst */ + + OUTB (nc_dcntl , NOCOM|np->rv_dcntl); /* Protect SFBR */ + OUTB (nc_ctest3, np->rv_ctest3); /* Write and invalidate */ + OUTB (nc_ctest4, np->rv_ctest4); /* Master parity checking */ + + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)){ + OUTB (nc_stest2, EXT|np->rv_stest2); + /* Extended Sreq/Sack filtering, not supported in C1010/C1010_66 */ + } + OUTB (nc_stest3, TE); /* TolerANT enable */ + OUTB (nc_stime0, 0x0c); /* HTH disabled STO 0.25 sec */ + + /* + ** DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2. + ** Disable overlapped arbitration for all dual-function + ** devices, regardless revision id. + ** We may consider it is a post-chip-design feature. ;-) + ** + ** Errata applies to all 896 and 1010 parts. + */ + if (np->device_id == PCI_DEVICE_ID_NCR_53C875) + OUTB (nc_ctest0, (1<<5)); + else if (np->device_id == PCI_DEVICE_ID_NCR_53C896 || + np->device_id == PCI_DEVICE_ID_LSI_53C1010 || + np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 ) + np->rv_ccntl0 |= DPR; + + /* + ** C1010_66MHz rev 0 part requies AIPCNTL1 bit 3 to be set. + */ + if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66) + OUTB(nc_aipcntl1, (1<<3)); + + /* + ** Write CCNTL0/CCNTL1 for chips capable of 64 bit addressing + ** and/or hardware phase mismatch, since only such chips + ** seem to support those IO registers. + */ + if (np->features & (FE_DAC | FE_NOPM)) { + OUTB (nc_ccntl0, np->rv_ccntl0); + OUTB (nc_ccntl1, np->rv_ccntl1); + } + + /* + ** If phase mismatch handled by scripts (53C895A or 53C896 + ** or 53C1010 or 53C1010_66), set PM jump addresses. + */ + + if (np->features & FE_NOPM) { + printk(KERN_INFO "%s: handling phase mismatch from SCRIPTS.\n", + ncr_name(np)); + OUTL (nc_pmjad1, NCB_SCRIPTH_PHYS (np, pm_handle)); + OUTL (nc_pmjad2, NCB_SCRIPTH_PHYS (np, pm_handle)); + } + + /* + ** Enable GPIO0 pin for writing if LED support from SCRIPTS. + ** Also set GPIO5 and clear GPIO6 if hardware LED control. + */ + + if (np->features & FE_LED0) + OUTB(nc_gpcntl, INB(nc_gpcntl) & ~0x01); + else if (np->features & FE_LEDC) + OUTB(nc_gpcntl, (INB(nc_gpcntl) & ~0x41) | 0x20); + + + /* + ** enable ints + */ + + OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR); + OUTB (nc_dien , MDPE|BF|SSI|SIR|IID); + + /* + ** For 895/895A/896/c1010 + ** Enable SBMC interrupt and save current SCSI bus mode. + */ + if ( (np->features & FE_ULTRA2) || (np->features & FE_ULTRA3) ) { + OUTONW (nc_sien, SBMC); + np->scsi_mode = INB (nc_stest4) & SMODE; + } + + /* + ** Fill in target structure. + ** Reinitialize usrsync. + ** Reinitialize usrwide. + ** Prepare sync negotiation according to actual SCSI bus mode. + */ + + for (i=0;itarget[i]; + + tp->to_reset = 0; + + tp->sval = 0; + tp->wval = np->rv_scntl3; + tp->uval = np->rv_scntl4; + + if (tp->usrsync != 255) { + if (tp->usrsync <= np->maxsync) { + if (tp->usrsync < np->minsync) { + tp->usrsync = np->minsync; + } + } + else + tp->usrsync = 255; + }; + + if (tp->usrwide > np->maxwide) + tp->usrwide = np->maxwide; + + ncr_negotiate (np, tp); + } + + /* + ** Download SCSI SCRIPTS to on-chip RAM if present, + ** and start script processor. + ** We do the download preferently from the CPU. + ** For platforms that may not support PCI memory mapping, + ** we use a simple SCRIPTS that performs MEMORY MOVEs. + */ + if (np->base2_ba) { + if (bootverbose) + printk ("%s: Downloading SCSI SCRIPTS.\n", + ncr_name(np)); +#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + if (np->base2_ws == 8192) + phys = NCB_SCRIPTH0_PHYS (np, start_ram64); + else + phys = NCB_SCRIPTH_PHYS (np, start_ram); +#else + if (np->base2_ws == 8192) { + memcpy_to_pci(np->base2_va + 4096, + np->scripth0, sizeof(struct scripth)); + OUTL (nc_mmws, np->scr_ram_seg); + OUTL (nc_mmrs, np->scr_ram_seg); + OUTL (nc_sfs, np->scr_ram_seg); + phys = NCB_SCRIPTH_PHYS (np, start64); + } + else + phys = NCB_SCRIPT_PHYS (np, init); + memcpy_to_pci(np->base2_va, np->script0, sizeof(struct script)); +#endif /* SCSI_NCR_PCI_MEM_NOT_SUPPORTED */ + } + else + phys = NCB_SCRIPT_PHYS (np, init); + + np->istat_sem = 0; + + OUTL (nc_dsa, np->p_ncb); + OUTL_DSP (phys); +} + +/*========================================================== +** +** Prepare the negotiation values for wide and +** synchronous transfers. +** +**========================================================== +*/ + +static void ncr_negotiate (struct ncb* np, struct tcb* tp) +{ + /* + ** minsync unit is 4ns ! + */ + + u_long minsync = tp->usrsync; + + /* + ** SCSI bus mode limit + */ + + if (np->scsi_mode && np->scsi_mode == SMODE_SE) { + if (minsync < 12) minsync = 12; + } + + /* + ** our limit .. + */ + + if (minsync < np->minsync) + minsync = np->minsync; + + /* + ** divider limit + */ + + if (minsync > np->maxsync) + minsync = 255; + + tp->minsync = minsync; + tp->maxoffs = (minsync<255 ? np->maxoffs : 0); + + /* + ** period=0: has to negotiate sync transfer + */ + + tp->period=0; + + /* + ** widedone=0: has to negotiate wide transfer + */ + tp->widedone=0; +} + +/*========================================================== +** +** Get clock factor and sync divisor for a given +** synchronous factor period. +** Returns the clock factor (in sxfer) and scntl3 +** synchronous divisor field. +** +**========================================================== +*/ + +static void ncr_getsync(ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p) +{ + u_long clk = np->clock_khz; /* SCSI clock frequency in kHz */ + int div = np->clock_divn; /* Number of divisors supported */ + u_long fak; /* Sync factor in sxfer */ + u_long per; /* Period in tenths of ns */ + u_long kpc; /* (per * clk) */ + + /* + ** Compute the synchronous period in tenths of nano-seconds + ** from sfac. + ** + ** Note, if sfac == 9, DT is being used. Double the period of 125 + ** to 250. + */ + if (sfac <= 10) per = 250; + else if (sfac == 11) per = 303; + else if (sfac == 12) per = 500; + else per = 40 * sfac; + + /* + ** Look for the greatest clock divisor that allows an + ** input speed faster than the period. + */ + kpc = per * clk; + while (--div >= 0) + if (kpc >= (div_10M[div] << 2)) break; + + /* + ** Calculate the lowest clock factor that allows an output + ** speed not faster than the period. + */ + fak = (kpc - 1) / div_10M[div] + 1; + +#if 0 /* This optimization does not seem very useful */ + + per = (fak * div_10M[div]) / clk; + + /* + ** Why not to try the immediate lower divisor and to choose + ** the one that allows the fastest output speed ? + ** We don't want input speed too much greater than output speed. + */ + if (div >= 1 && fak < 8) { + u_long fak2, per2; + fak2 = (kpc - 1) / div_10M[div-1] + 1; + per2 = (fak2 * div_10M[div-1]) / clk; + if (per2 < per && fak2 <= 8) { + fak = fak2; + per = per2; + --div; + } + } +#endif + + if (fak < 4) fak = 4; /* Should never happen, too bad ... */ + + /* + ** Compute and return sync parameters for the ncr + */ + *fakp = fak - 4; + + /* + ** If sfac < 25, and 8xx parts, desire that the chip operate at + ** least at Ultra speeds. Must set bit 7 of scntl3. + ** For C1010, do not set this bit. If operating at Ultra3 speeds, + ** set the U3EN bit instead. + */ + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + *scntl3p = (div+1) << 4; + *fakp = 0; + } + else { + *scntl3p = ((div+1) << 4) + (sfac < 25 ? 0x80 : 0); + *fakp = fak - 4; + } +} + +/*========================================================== +** +** Utility routine to return the current bus width +** synchronous period and offset. +** Utilizes target sval, wval and uval +** +**========================================================== +*/ +static void ncr_get_xfer_info(ncb_p np, tcb_p tp, u_char *factor, + u_char *offset, u_char *width) +{ + + u_char idiv; + u_long period; + + *width = (tp->wval & EWS) ? 1 : 0; + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + *offset = (tp->sval & 0x3f); + else + *offset = (tp->sval & 0x1f); + + /* + * Midlayer signal to the driver that all of the scsi commands + * for the integrity check have completed. Save the negotiated + * parameters (extracted from sval, wval and uval). + * See ncr_setsync for alg. details. + */ + + idiv = (tp->wval>>4) & 0x07; + + if ( *offset && idiv ) { + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)){ + if (tp->uval & 0x80) + period = (2*div_10M[idiv-1])/np->clock_khz; + else + period = (4*div_10M[idiv-1])/np->clock_khz; + } + else + period = (((tp->sval>>5)+4)*div_10M[idiv-1])/np->clock_khz; + } + else + period = 0xffff; + + if (period <= 125) *factor = 9; + else if (period <= 250) *factor = 10; + else if (period <= 303) *factor = 11; + else if (period <= 500) *factor = 12; + else *factor = (period + 40 - 1) / 40; + +} + + +/*========================================================== +** +** Set actual values, sync status and patch all ccbs of +** a target according to new sync/wide agreement. +** +**========================================================== +*/ + +static void ncr_set_sync_wide_status (ncb_p np, u_char target) +{ + ccb_p cp = np->ccbc; + tcb_p tp = &np->target[target]; + + /* + ** set actual value and sync_status + ** + ** TEMP register contains current scripts address + ** which is data type/direction/dependent. + */ + OUTB (nc_sxfer, tp->sval); + OUTB (nc_scntl3, tp->wval); + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + OUTB (nc_scntl4, tp->uval); + + /* + ** patch ALL ccbs of this target. + */ + for (cp = np->ccbc; cp; cp = cp->link_ccb) { + if (cp->host_status == HS_IDLE) + continue; + if (cp->target != target) + continue; + cp->phys.select.sel_scntl3 = tp->wval; + cp->phys.select.sel_sxfer = tp->sval; + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + cp->phys.select.sel_scntl4 = tp->uval; + }; +} + +/*========================================================== +** +** Switch sync mode for current job and it's target +** +**========================================================== +*/ + +static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, + u_char scntl4) +{ + tcb_p tp; + u_char target = INB (nc_sdid) & 0x0f; + u_char idiv; + u_char offset; + + assert (cp); + if (!cp) return; + + assert (target == (cp->target & 0xf)); + + tp = &np->target[target]; + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + offset = sxfer & 0x3f; /* bits 5-0 */ + scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS); + scntl4 = (scntl4 & 0x80); + } + else { + offset = sxfer & 0x1f; /* bits 4-0 */ + if (!scntl3 || !offset) + scntl3 = np->rv_scntl3; + + scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS) | + (np->rv_scntl3 & 0x07); + } + + + /* + ** Deduce the value of controller sync period from scntl3. + ** period is in tenths of nano-seconds. + */ + + idiv = ((scntl3 >> 4) & 0x7); + if ( offset && idiv) { + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + /* Note: If extra data hold clocks are used, + * the formulas below must be modified. + * When scntl4 == 0, ST mode. + */ + if (scntl4 & 0x80) + tp->period = (2*div_10M[idiv-1])/np->clock_khz; + else + tp->period = (4*div_10M[idiv-1])/np->clock_khz; + } + else + tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz; + } + else + tp->period = 0xffff; + + + /* + ** Stop there if sync parameters are unchanged + */ + if (tp->sval == sxfer && tp->wval == scntl3 && tp->uval == scntl4) return; + tp->sval = sxfer; + tp->wval = scntl3; + tp->uval = scntl4; + + /* + ** Bells and whistles ;-) + ** Donnot announce negotiations due to auto-sense, + ** unless user really want us to be verbose. :) + */ + if ( bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE)) + goto next; + PRINT_TARGET(np, target); + if (offset) { + unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0); + unsigned mb10 = (f10 + tp->period/2) / tp->period; + char *scsi; + + /* + ** Disable extended Sreq/Sack filtering + */ + if ((tp->period <= 2000) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + OUTOFFB (nc_stest2, EXT); + + /* + ** Bells and whistles ;-) + */ + if (tp->period < 250) scsi = "FAST-80"; + else if (tp->period < 500) scsi = "FAST-40"; + else if (tp->period < 1000) scsi = "FAST-20"; + else if (tp->period < 2000) scsi = "FAST-10"; + else scsi = "FAST-5"; + + printk ("%s %sSCSI %d.%d MB/s (%d.%d ns, offset %d)\n", scsi, + tp->widedone > 1 ? "WIDE " : "", + mb10 / 10, mb10 % 10, tp->period / 10, tp->period % 10, + offset); + } else + printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : ""); +next: + /* + ** set actual value and sync_status + ** patch ALL ccbs of this target. + */ + ncr_set_sync_wide_status(np, target); +} + + +/*========================================================== +** +** Switch wide mode for current job and it's target +** SCSI specs say: a SCSI device that accepts a WDTR +** message shall reset the synchronous agreement to +** asynchronous mode. +** +**========================================================== +*/ + +static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack) +{ + u_short target = INB (nc_sdid) & 0x0f; + tcb_p tp; + u_char scntl3; + u_char sxfer; + + assert (cp); + if (!cp) return; + + assert (target == (cp->target & 0xf)); + + tp = &np->target[target]; + tp->widedone = wide+1; + scntl3 = (tp->wval & (~EWS)) | (wide ? EWS : 0); + + sxfer = ack ? 0 : tp->sval; + + /* + ** Stop there if sync/wide parameters are unchanged + */ + if (tp->sval == sxfer && tp->wval == scntl3) return; + tp->sval = sxfer; + tp->wval = scntl3; + + /* + ** Bells and whistles ;-) + */ + if (bootverbose >= 2) { + PRINT_TARGET(np, target); + if (scntl3 & EWS) + printk ("WIDE SCSI (16 bit) enabled.\n"); + else + printk ("WIDE SCSI disabled.\n"); + } + + /* + ** set actual value and sync_status + ** patch ALL ccbs of this target. + */ + ncr_set_sync_wide_status(np, target); +} + + +/*========================================================== +** +** Switch sync/wide mode for current job and it's target +** PPR negotiations only +** +**========================================================== +*/ + +static void ncr_setsyncwide (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, + u_char scntl4, u_char wide) +{ + tcb_p tp; + u_char target = INB (nc_sdid) & 0x0f; + u_char idiv; + u_char offset; + + assert (cp); + if (!cp) return; + + assert (target == (cp->target & 0xf)); + + tp = &np->target[target]; + tp->widedone = wide+1; + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + offset = sxfer & 0x3f; /* bits 5-0 */ + scntl3 = (scntl3 & 0xf0) | (wide ? EWS : 0); + scntl4 = (scntl4 & 0x80); + } + else { + offset = sxfer & 0x1f; /* bits 4-0 */ + if (!scntl3 || !offset) + scntl3 = np->rv_scntl3; + + scntl3 = (scntl3 & 0xf0) | (wide ? EWS : 0) | + (np->rv_scntl3 & 0x07); + } + + + /* + ** Deduce the value of controller sync period from scntl3. + ** period is in tenths of nano-seconds. + */ + + idiv = ((scntl3 >> 4) & 0x7); + if ( offset && idiv) { + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + /* Note: If extra data hold clocks are used, + * the formulas below must be modified. + * When scntl4 == 0, ST mode. + */ + if (scntl4 & 0x80) + tp->period = (2*div_10M[idiv-1])/np->clock_khz; + else + tp->period = (4*div_10M[idiv-1])/np->clock_khz; + } + else + tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz; + } + else + tp->period = 0xffff; + + + /* + ** Stop there if sync parameters are unchanged + */ + if (tp->sval == sxfer && tp->wval == scntl3 && tp->uval == scntl4) return; + tp->sval = sxfer; + tp->wval = scntl3; + tp->uval = scntl4; + + /* + ** Bells and whistles ;-) + ** Donnot announce negotiations due to auto-sense, + ** unless user really want us to be verbose. :) + */ + if ( bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE)) + goto next; + PRINT_TARGET(np, target); + if (offset) { + unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0); + unsigned mb10 = (f10 + tp->period/2) / tp->period; + char *scsi; + + /* + ** Disable extended Sreq/Sack filtering + */ + if ((tp->period <= 2000) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + OUTOFFB (nc_stest2, EXT); + + /* + ** Bells and whistles ;-) + */ + if (tp->period < 250) scsi = "FAST-80"; + else if (tp->period < 500) scsi = "FAST-40"; + else if (tp->period < 1000) scsi = "FAST-20"; + else if (tp->period < 2000) scsi = "FAST-10"; + else scsi = "FAST-5"; + + printk ("%s %sSCSI %d.%d MB/s (%d.%d ns, offset %d)\n", scsi, + tp->widedone > 1 ? "WIDE " : "", + mb10 / 10, mb10 % 10, tp->period / 10, tp->period % 10, + offset); + } else + printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : ""); +next: + /* + ** set actual value and sync_status + ** patch ALL ccbs of this target. + */ + ncr_set_sync_wide_status(np, target); +} + + + + +/*========================================================== +** +** Switch tagged mode for a target. +** +**========================================================== +*/ + +static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = ncr_lp(np, tp, ln); + u_short reqtags, maxdepth; + + /* + ** Just in case ... + */ + if ((!tp) || (!lp)) + return; + + /* + ** If SCSI device queue depth is not yet set, leave here. + */ + if (!lp->scdev_depth) + return; + + /* + ** Donnot allow more tags than the SCSI driver can queue + ** for this device. + ** Donnot allow more tags than we can handle. + */ + maxdepth = lp->scdev_depth; + if (maxdepth > lp->maxnxs) maxdepth = lp->maxnxs; + if (lp->maxtags > maxdepth) lp->maxtags = maxdepth; + if (lp->numtags > maxdepth) lp->numtags = maxdepth; + + /* + ** only devices conformant to ANSI Version >= 2 + ** only devices capable of tagged commands + ** only if enabled by user .. + */ + if ((lp->inq_byte7 & INQ7_QUEUE) && lp->numtags > 1) { + reqtags = lp->numtags; + } else { + reqtags = 1; + }; + + /* + ** Update max number of tags + */ + lp->numtags = reqtags; + if (lp->numtags > lp->maxtags) + lp->maxtags = lp->numtags; + + /* + ** If we want to switch tag mode, we must wait + ** for no CCB to be active. + */ + if (reqtags > 1 && lp->usetags) { /* Stay in tagged mode */ + if (lp->queuedepth == reqtags) /* Already announced */ + return; + lp->queuedepth = reqtags; + } + else if (reqtags <= 1 && !lp->usetags) { /* Stay in untagged mode */ + lp->queuedepth = reqtags; + return; + } + else { /* Want to switch tag mode */ + if (lp->busyccbs) /* If not yet safe, return */ + return; + lp->queuedepth = reqtags; + lp->usetags = reqtags > 1 ? 1 : 0; + } + + /* + ** Patch the lun mini-script, according to tag mode. + */ + lp->resel_task = lp->usetags? + cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_tag)) : + cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_notag)); + + /* + ** Announce change to user. + */ + if (bootverbose) { + PRINT_LUN(np, tn, ln); + if (lp->usetags) + printk("tagged command queue depth set to %d\n", reqtags); + else + printk("tagged command queueing disabled\n"); + } +} + +/*---------------------------------------------------- +** +** handle user commands +** +**---------------------------------------------------- +*/ + +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT + +static void ncr_usercmd (ncb_p np) +{ + u_char t; + tcb_p tp; + int ln; + u_long size; + + switch (np->user.cmd) { + case 0: return; + + case UC_SETDEBUG: +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT + ncr_debug = np->user.data; +#endif + break; + + case UC_SETORDER: + np->order = np->user.data; + break; + + case UC_SETVERBOSE: + np->verbose = np->user.data; + break; + + default: + /* + ** We assume that other commands apply to targets. + ** This should always be the case and avoid the below + ** 4 lines to be repeated 5 times. + */ + for (t = 0; t < MAX_TARGET; t++) { + if (!((np->user.target >> t) & 1)) + continue; + tp = &np->target[t]; + + switch (np->user.cmd) { + + case UC_SETSYNC: + tp->usrsync = np->user.data; + ncr_negotiate (np, tp); + break; + + case UC_SETWIDE: + size = np->user.data; + if (size > np->maxwide) + size=np->maxwide; + tp->usrwide = size; + ncr_negotiate (np, tp); + break; + + case UC_SETTAGS: + tp->usrtags = np->user.data; + for (ln = 0; ln < MAX_LUN; ln++) { + lcb_p lp; + lp = ncr_lp(np, tp, ln); + if (!lp) + continue; + lp->numtags = np->user.data; + lp->maxtags = lp->numtags; + ncr_setup_tags (np, t, ln); + } + break; + + case UC_RESETDEV: + tp->to_reset = 1; + np->istat_sem = SEM; + OUTB (nc_istat, SIGP|SEM); + break; + + case UC_CLEARDEV: + for (ln = 0; ln < MAX_LUN; ln++) { + lcb_p lp; + lp = ncr_lp(np, tp, ln); + if (lp) + lp->to_clear = 1; + } + np->istat_sem = SEM; + OUTB (nc_istat, SIGP|SEM); + break; + + case UC_SETFLAG: + tp->usrflag = np->user.data; + break; + } + } + break; + } + np->user.cmd=0; +} +#endif + +/*========================================================== +** +** +** ncr timeout handler. +** +** +**========================================================== +** +** Misused to keep the driver running when +** interrupts are not configured correctly. +** +**---------------------------------------------------------- +*/ + +static void ncr_timeout (ncb_p np) +{ + u_long thistime = ktime_get(0); + + /* + ** If release process in progress, let's go + ** Set the release stage from 1 to 2 to synchronize + ** with the release process. + */ + + if (np->release_stage) { + if (np->release_stage == 1) np->release_stage = 2; + return; + } + +#ifdef SCSI_NCR_PCIQ_BROKEN_INTR + np->timer.expires = ktime_get((HZ+9)/10); +#else + np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL); +#endif + add_timer(&np->timer); + + /* + ** If we are resetting the ncr, wait for settle_time before + ** clearing it. Then command processing will be resumed. + */ + if (np->settle_time) { + if (np->settle_time <= thistime) { + if (bootverbose > 1) + printk("%s: command processing resumed\n", ncr_name(np)); + np->settle_time = 0; + requeue_waiting_list(np); + } + return; + } + + /* + ** Nothing to do for now, but that may come. + */ + if (np->lasttime + 4*HZ < thistime) { + np->lasttime = thistime; + } + +#ifdef SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS + /* + ** Some way-broken PCI bridges may lead to + ** completions being lost when the clearing + ** of the INTFLY flag by the CPU occurs + ** concurrently with the chip raising this flag. + ** If this ever happen, lost completions will + ** be reaped here. + */ + ncr_wakeup_done(np); +#endif + +#ifdef SCSI_NCR_PCIQ_BROKEN_INTR + if (INB(nc_istat) & (INTF|SIP|DIP)) { + + /* + ** Process pending interrupts. + */ + if (DEBUG_FLAGS & DEBUG_TINY) printk ("{"); + ncr_exception (np); + if (DEBUG_FLAGS & DEBUG_TINY) printk ("}"); + } +#endif /* SCSI_NCR_PCIQ_BROKEN_INTR */ +} + +/*========================================================== +** +** log message for real hard errors +** +** "ncr0 targ 0?: ERROR (ds:si) (so-si-sd) (sxfer/scntl3) @ name (dsp:dbc)." +** " reg: r0 r1 r2 r3 r4 r5 r6 ..... rf." +** +** exception register: +** ds: dstat +** si: sist +** +** SCSI bus lines: +** so: control lines as driver by NCR. +** si: control lines as seen by NCR. +** sd: scsi data lines as seen by NCR. +** +** wide/fastmode: +** sxfer: (see the manual) +** scntl3: (see the manual) +** +** current script command: +** dsp: script address (relative to start of script). +** dbc: first word of script command. +** +** First 24 register of the chip: +** r0..rf +** +**========================================================== +*/ + +static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat) +{ + u_int32 dsp; + int script_ofs; + int script_size; + char *script_name; + u_char *script_base; + int i; + + dsp = INL (nc_dsp); + + if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) { + script_ofs = dsp - np->p_script; + script_size = sizeof(struct script); + script_base = (u_char *) np->script0; + script_name = "script"; + } + else if (np->p_scripth < dsp && + dsp <= np->p_scripth + sizeof(struct scripth)) { + script_ofs = dsp - np->p_scripth; + script_size = sizeof(struct scripth); + script_base = (u_char *) np->scripth0; + script_name = "scripth"; + } else { + script_ofs = dsp; + script_size = 0; + script_base = 0; + script_name = "mem"; + } + + printk ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n", + ncr_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist, + (unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl), + (unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_name, script_ofs, + (unsigned)INL (nc_dbc)); + + if (((script_ofs & 3) == 0) && + (unsigned)script_ofs < script_size) { + printk ("%s: script cmd = %08x\n", ncr_name(np), + scr_to_cpu((int) *(ncrcmd *)(script_base + script_ofs))); + } + + printk ("%s: regdump:", ncr_name(np)); + for (i=0; i<24;i++) + printk (" %02x", (unsigned)INB_OFF(i)); + printk (".\n"); +} + +/*============================================================ +** +** ncr chip exception handler. +** +**============================================================ +** +** In normal situations, interrupt conditions occur one at +** a time. But when something bad happens on the SCSI BUS, +** the chip may raise several interrupt flags before +** stopping and interrupting the CPU. The additionnal +** interrupt flags are stacked in some extra registers +** after the SIP and/or DIP flag has been raised in the +** ISTAT. After the CPU has read the interrupt condition +** flag from SIST or DSTAT, the chip unstacks the other +** interrupt flags and sets the corresponding bits in +** SIST or DSTAT. Since the chip starts stacking once the +** SIP or DIP flag is set, there is a small window of time +** where the stacking does not occur. +** +** Typically, multiple interrupt conditions may happen in +** the following situations: +** +** - SCSI parity error + Phase mismatch (PAR|MA) +** When an parity error is detected in input phase +** and the device switches to msg-in phase inside a +** block MOV. +** - SCSI parity error + Unexpected disconnect (PAR|UDC) +** When a stupid device does not want to handle the +** recovery of an SCSI parity error. +** - Some combinations of STO, PAR, UDC, ... +** When using non compliant SCSI stuff, when user is +** doing non compliant hot tampering on the BUS, when +** something really bad happens to a device, etc ... +** +** The heuristic suggested by SYMBIOS to handle +** multiple interrupts is to try unstacking all +** interrupts conditions and to handle them on some +** priority based on error severity. +** This will work when the unstacking has been +** successful, but we cannot be 100 % sure of that, +** since the CPU may have been faster to unstack than +** the chip is able to stack. Hmmm ... But it seems that +** such a situation is very unlikely to happen. +** +** If this happen, for example STO catched by the CPU +** then UDC happenning before the CPU have restarted +** the SCRIPTS, the driver may wrongly complete the +** same command on UDC, since the SCRIPTS didn't restart +** and the DSA still points to the same command. +** We avoid this situation by setting the DSA to an +** invalid value when the CCB is completed and before +** restarting the SCRIPTS. +** +** Another issue is that we need some section of our +** recovery procedures to be somehow uninterruptible and +** that the SCRIPTS processor does not provides such a +** feature. For this reason, we handle recovery preferently +** from the C code and check against some SCRIPTS +** critical sections from the C code. +** +** Hopefully, the interrupt handling of the driver is now +** able to resist to weird BUS error conditions, but donnot +** ask me for any guarantee that it will never fail. :-) +** Use at your own decision and risk. +** +**============================================================ +*/ + +void ncr_exception (ncb_p np) +{ + u_char istat, istatc; + u_char dstat; + u_short sist; + int i; + + /* + ** interrupt on the fly ? + ** + ** A `dummy read' is needed to ensure that the + ** clear of the INTF flag reaches the device + ** before the scanning of the DONE queue. + */ + istat = INB (nc_istat); + if (istat & INTF) { + OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem); + istat = INB (nc_istat); /* DUMMY READ */ + if (DEBUG_FLAGS & DEBUG_TINY) printk ("F "); + (void)ncr_wakeup_done (np); + }; + + if (!(istat & (SIP|DIP))) + return; + +#if 0 /* We should never get this one */ + if (istat & CABRT) + OUTB (nc_istat, CABRT); +#endif + + /* + ** Steinbach's Guideline for Systems Programming: + ** Never test for an error condition you don't know how to handle. + */ + + /*======================================================== + ** PAR and MA interrupts may occur at the same time, + ** and we need to know of both in order to handle + ** this situation properly. We try to unstack SCSI + ** interrupts for that reason. BTW, I dislike a LOT + ** such a loop inside the interrupt routine. + ** Even if DMA interrupt stacking is very unlikely to + ** happen, we also try unstacking these ones, since + ** this has no performance impact. + **========================================================= + */ + sist = 0; + dstat = 0; + istatc = istat; + do { + if (istatc & SIP) + sist |= INW (nc_sist); + if (istatc & DIP) + dstat |= INB (nc_dstat); + istatc = INB (nc_istat); + istat |= istatc; + } while (istatc & (SIP|DIP)); + + if (DEBUG_FLAGS & DEBUG_TINY) + printk ("<%d|%x:%x|%x:%x>", + (int)INB(nc_scr0), + dstat,sist, + (unsigned)INL(nc_dsp), + (unsigned)INL(nc_dbc)); + + /* + ** On paper, a memory barrier may be needed here. + ** And since we are paranoid ... :) + */ + MEMORY_BARRIER(); + + /*======================================================== + ** First, interrupts we want to service cleanly. + ** + ** Phase mismatch (MA) is the most frequent interrupt + ** for chip earlier than the 896 and so we have to service + ** it as quickly as possible. + ** A SCSI parity error (PAR) may be combined with a phase + ** mismatch condition (MA). + ** Programmed interrupts (SIR) are used to call the C code + ** from SCRIPTS. + ** The single step interrupt (SSI) is not used in this + ** driver. + **========================================================= + */ + + if (!(sist & (STO|GEN|HTH|SGE|UDC|SBMC|RST)) && + !(dstat & (MDPE|BF|ABRT|IID))) { + if (sist & PAR) ncr_int_par (np, sist); + else if (sist & MA) ncr_int_ma (np); + else if (dstat & SIR) ncr_int_sir (np); + else if (dstat & SSI) OUTONB_STD (); + else goto unknown_int; + return; + }; + + /*======================================================== + ** Now, interrupts that donnot happen in normal + ** situations and that we may need to recover from. + ** + ** On SCSI RESET (RST), we reset everything. + ** On SCSI BUS MODE CHANGE (SBMC), we complete all + ** active CCBs with RESET status, prepare all devices + ** for negotiating again and restart the SCRIPTS. + ** On STO and UDC, we complete the CCB with the corres- + ** ponding status and restart the SCRIPTS. + **========================================================= + */ + + if (sist & RST) { + ncr_init (np, 1, bootverbose ? "scsi reset" : NULL, HS_RESET); + return; + }; + + OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ + OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ + + if (!(sist & (GEN|HTH|SGE)) && + !(dstat & (MDPE|BF|ABRT|IID))) { + if (sist & SBMC) ncr_int_sbmc (np); + else if (sist & STO) ncr_int_sto (np); + else if (sist & UDC) ncr_int_udc (np); + else goto unknown_int; + return; + }; + + /*========================================================= + ** Now, interrupts we are not able to recover cleanly. + ** + ** Do the register dump. + ** Log message for hard errors. + ** Reset everything. + **========================================================= + */ + if (ktime_exp(np->regtime)) { + np->regtime = ktime_get(10*HZ); + for (i = 0; iregdump); i++) + ((char*)&np->regdump)[i] = INB_OFF(i); + np->regdump.nc_dstat = dstat; + np->regdump.nc_sist = sist; + }; + + ncr_log_hard_error(np, sist, dstat); + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + u_char ctest4_o, ctest4_m; + u_char shadow; + + /* + * Get shadow register data + * Write 1 to ctest4 + */ + ctest4_o = INB(nc_ctest4); + + OUTB(nc_ctest4, ctest4_o | 0x10); + + ctest4_m = INB(nc_ctest4); + shadow = INW_OFF(0x42); + + OUTB(nc_ctest4, ctest4_o); + + printk("%s: ctest4/sist original 0x%x/0x%X mod: 0x%X/0x%x\n", + ncr_name(np), ctest4_o, sist, ctest4_m, shadow); + } + + if ((sist & (GEN|HTH|SGE)) || + (dstat & (MDPE|BF|ABRT|IID))) { + ncr_start_reset(np); + return; + }; + +unknown_int: + /*========================================================= + ** We just miss the cause of the interrupt. :( + ** Print a message. The timeout will do the real work. + **========================================================= + */ + printk( "%s: unknown interrupt(s) ignored, " + "ISTAT=0x%x DSTAT=0x%x SIST=0x%x\n", + ncr_name(np), istat, dstat, sist); +} + + +/*========================================================== +** +** generic recovery from scsi interrupt +** +**========================================================== +** +** The doc says that when the chip gets an SCSI interrupt, +** it tries to stop in an orderly fashion, by completing +** an instruction fetch that had started or by flushing +** the DMA fifo for a write to memory that was executing. +** Such a fashion is not enough to know if the instruction +** that was just before the current DSP value has been +** executed or not. +** +** There are 3 small SCRIPTS sections that deal with the +** start queue and the done queue that may break any +** assomption from the C code if we are interrupted +** inside, so we reset if it happens. Btw, since these +** SCRIPTS sections are executed while the SCRIPTS hasn't +** started SCSI operations, it is very unlikely to happen. +** +** All the driver data structures are supposed to be +** allocated from the same 4 GB memory window, so there +** is a 1 to 1 relationship between DSA and driver data +** structures. Since we are careful :) to invalidate the +** DSA when we complete a command or when the SCRIPTS +** pushes a DSA into a queue, we can trust it when it +** points to a CCB. +** +**---------------------------------------------------------- +*/ +static void ncr_recover_scsi_int (ncb_p np, u_char hsts) +{ + u_int32 dsp = INL (nc_dsp); + u_int32 dsa = INL (nc_dsa); + ccb_p cp = ncr_ccb_from_dsa(np, dsa); + + /* + ** If we haven't been interrupted inside the SCRIPTS + ** critical pathes, we can safely restart the SCRIPTS + ** and trust the DSA value if it matches a CCB. + */ + if ((!(dsp > NCB_SCRIPT_PHYS (np, getjob_begin) && + dsp < NCB_SCRIPT_PHYS (np, getjob_end) + 1)) && + (!(dsp > NCB_SCRIPT_PHYS (np, ungetjob) && + dsp < NCB_SCRIPT_PHYS (np, reselect) + 1)) && + (!(dsp > NCB_SCRIPTH_PHYS (np, sel_for_abort) && + dsp < NCB_SCRIPTH_PHYS (np, sel_for_abort_1) + 1)) && + (!(dsp > NCB_SCRIPT_PHYS (np, done) && + dsp < NCB_SCRIPT_PHYS (np, done_end) + 1))) { + if (cp) { + cp->host_status = hsts; + ncr_complete (np, cp); + } + OUTL (nc_dsa, DSA_INVALID); + OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ + OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ + OUTL_DSP (NCB_SCRIPT_PHYS (np, start)); + } + else + goto reset_all; + + return; + +reset_all: + ncr_start_reset(np); +} + +/*========================================================== +** +** ncr chip exception handler for selection timeout +** +**========================================================== +** +** There seems to be a bug in the 53c810. +** Although a STO-Interrupt is pending, +** it continues executing script commands. +** But it will fail and interrupt (IID) on +** the next instruction where it's looking +** for a valid phase. +** +**---------------------------------------------------------- +*/ + +void ncr_int_sto (ncb_p np) +{ + u_int32 dsp = INL (nc_dsp); + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("T"); + + if (dsp == NCB_SCRIPT_PHYS (np, wf_sel_done) + 8 || + !(driver_setup.recovery & 1)) + ncr_recover_scsi_int(np, HS_SEL_TIMEOUT); + else + ncr_start_reset(np); +} + +/*========================================================== +** +** ncr chip exception handler for unexpected disconnect +** +**========================================================== +** +**---------------------------------------------------------- +*/ +void ncr_int_udc (ncb_p np) +{ + u_int32 dsa = INL (nc_dsa); + ccb_p cp = ncr_ccb_from_dsa(np, dsa); + + /* + * Fix Up. Some disks respond to a PPR negotiation with + * a bus free instead of a message reject. + * Disable ppr negotiation if this is first time + * tried ppr negotiation. + */ + if (cp) { + tcb_p tp = &np->target[cp->target]; + if (tp->ppr_negotiation == 1) + tp->ppr_negotiation = 0; + } + + printk ("%s: unexpected disconnect\n", ncr_name(np)); + ncr_recover_scsi_int(np, HS_UNEXPECTED); +} + +/*========================================================== +** +** ncr chip exception handler for SCSI bus mode change +** +**========================================================== +** +** spi2-r12 11.2.3 says a transceiver mode change must +** generate a reset event and a device that detects a reset +** event shall initiate a hard reset. It says also that a +** device that detects a mode change shall set data transfer +** mode to eight bit asynchronous, etc... +** So, just resetting should be enough. +** +** +**---------------------------------------------------------- +*/ + +static void ncr_int_sbmc (ncb_p np) +{ + u_char scsi_mode = INB (nc_stest4) & SMODE; + + printk("%s: SCSI bus mode change from %x to %x.\n", + ncr_name(np), np->scsi_mode, scsi_mode); + + np->scsi_mode = scsi_mode; + + + /* + ** Suspend command processing for 1 second and + ** reinitialize all except the chip. + */ + np->settle_time = ktime_get(1*HZ); + ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET); +} + +/*========================================================== +** +** ncr chip exception handler for SCSI parity error. +** +**========================================================== +** +** When the chip detects a SCSI parity error and is +** currently executing a (CH)MOV instruction, it does +** not interrupt immediately, but tries to finish the +** transfer of the current scatter entry before +** interrupting. The following situations may occur: +** +** - The complete scatter entry has been transferred +** without the device having changed phase. +** The chip will then interrupt with the DSP pointing +** to the instruction that follows the MOV. +** +** - A phase mismatch occurs before the MOV finished +** and phase errors are to be handled by the C code. +** The chip will then interrupt with both PAR and MA +** conditions set. +** +** - A phase mismatch occurs before the MOV finished and +** phase errors are to be handled by SCRIPTS (895A or 896). +** The chip will load the DSP with the phase mismatch +** JUMP address and interrupt the host processor. +** +**---------------------------------------------------------- +*/ + +static void ncr_int_par (ncb_p np, u_short sist) +{ + u_char hsts = INB (HS_PRT); + u_int32 dsp = INL (nc_dsp); + u_int32 dbc = INL (nc_dbc); + u_int32 dsa = INL (nc_dsa); + u_char sbcl = INB (nc_sbcl); + u_char cmd = dbc >> 24; + int phase = cmd & 7; + ccb_p cp = ncr_ccb_from_dsa(np, dsa); + + printk("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n", + ncr_name(np), hsts, dbc, sbcl); + + /* + ** Check that the chip is connected to the SCSI BUS. + */ + if (!(INB (nc_scntl1) & ISCON)) { + if (!(driver_setup.recovery & 1)) { + ncr_recover_scsi_int(np, HS_FAIL); + return; + } + goto reset_all; + } + + /* + ** If the nexus is not clearly identified, reset the bus. + ** We will try to do better later. + */ + if (!cp) + goto reset_all; + + /* + ** Check instruction was a MOV, direction was INPUT and + ** ATN is asserted. + */ + if ((cmd & 0xc0) || !(phase & 1) || !(sbcl & 0x8)) + goto reset_all; + + /* + ** Keep track of the parity error. + */ + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_PARITY_ERR; + + /* + ** Prepare the message to send to the device. + */ + np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR; + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + /* + ** Save error message. For integrity check use only. + */ + if (np->check_integrity) + np->check_integ_par = np->msgout[0]; +#endif + + /* + ** If the old phase was DATA IN or DT DATA IN phase, + ** we have to deal with the 3 situations described above. + ** For other input phases (MSG IN and STATUS), the device + ** must resend the whole thing that failed parity checking + ** or signal error. So, jumping to dispatcher should be OK. + */ + if ((phase == 1) || (phase == 5)) { + /* Phase mismatch handled by SCRIPTS */ + if (dsp == NCB_SCRIPTH_PHYS (np, pm_handle)) + OUTL_DSP (dsp); + /* Phase mismatch handled by the C code */ + else if (sist & MA) + ncr_int_ma (np); + /* No phase mismatch occurred */ + else { + OUTL (nc_temp, dsp); + OUTL_DSP (NCB_SCRIPT_PHYS (np, dispatch)); + } + } + else + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); + return; + +reset_all: + ncr_start_reset(np); + return; +} + +/*========================================================== +** +** +** ncr chip exception handler for phase errors. +** +** +**========================================================== +** +** We have to construct a new transfer descriptor, +** to transfer the rest of the current block. +** +**---------------------------------------------------------- +*/ + +static void ncr_int_ma (ncb_p np) +{ + u_int32 dbc; + u_int32 rest; + u_int32 dsp; + u_int32 dsa; + u_int32 nxtdsp; + u_int32 *vdsp; + u_int32 oadr, olen; + u_int32 *tblp; + u_int32 newcmd; + u_int delta; + u_char cmd; + u_char hflags, hflags0; + struct pm_ctx *pm; + ccb_p cp; + + dsp = INL (nc_dsp); + dbc = INL (nc_dbc); + dsa = INL (nc_dsa); + + cmd = dbc >> 24; + rest = dbc & 0xffffff; + delta = 0; + + /* + ** locate matching cp. + */ + cp = ncr_ccb_from_dsa(np, dsa); + + if (DEBUG_FLAGS & DEBUG_PHASE) + printk("CCB = %2x %2x %2x %2x %2x %2x\n", + cp->cmd->cmnd[0], cp->cmd->cmnd[1], cp->cmd->cmnd[2], + cp->cmd->cmnd[3], cp->cmd->cmnd[4], cp->cmd->cmnd[5]); + + /* + ** Donnot take into account dma fifo and various buffers in + ** INPUT phase since the chip flushes everything before + ** raising the MA interrupt for interrupted INPUT phases. + ** For DATA IN phase, we will check for the SWIDE later. + */ + if ((cmd & 7) != 1 && (cmd & 7) != 5) { + u_int32 dfifo; + u_char ss0, ss2; + + /* + ** If C1010, DFBC contains number of bytes in DMA fifo. + ** else read DFIFO, CTEST[4-6] using 1 PCI bus ownership. + */ + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + delta = INL(nc_dfbc) & 0xffff; + else { + dfifo = INL(nc_dfifo); + + /* + ** Calculate remaining bytes in DMA fifo. + ** C1010 - always large fifo, value in dfbc + ** Otherwise, (CTEST5 = dfifo >> 16) + */ + if (dfifo & (DFS << 16)) + delta = ((((dfifo >> 8) & 0x300) | + (dfifo & 0xff)) - rest) & 0x3ff; + else + delta = ((dfifo & 0xff) - rest) & 0x7f; + + /* + ** The data in the dma fifo has not been + ** transferred to the target -> add the amount + ** to the rest and clear the data. + ** Check the sstat2 register in case of wide + ** transfer. + */ + + } + + rest += delta; + ss0 = INB (nc_sstat0); + if (ss0 & OLF) rest++; + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && (ss0 & ORF)) + rest++; + if (cp && (cp->phys.select.sel_scntl3 & EWS)) { + ss2 = INB (nc_sstat2); + if (ss2 & OLF1) rest++; + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && (ss2 & ORF)) + rest++; + }; + + /* + ** Clear fifos. + */ + OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* dma fifo */ + OUTB (nc_stest3, TE|CSF); /* scsi fifo */ + } + + /* + ** log the information + */ + + if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) + printk ("P%x%x RL=%d D=%d ", cmd&7, INB(nc_sbcl)&7, + (unsigned) rest, (unsigned) delta); + + /* + ** try to find the interrupted script command, + ** and the address at which to continue. + */ + vdsp = 0; + nxtdsp = 0; + if (dsp > np->p_script && + dsp <= np->p_script + sizeof(struct script)) { + vdsp = (u_int32 *)((char*)np->script0 + (dsp-np->p_script-8)); + nxtdsp = dsp; + } + else if (dsp > np->p_scripth && + dsp <= np->p_scripth + sizeof(struct scripth)) { + vdsp = (u_int32 *)((char*)np->scripth0 + (dsp-np->p_scripth-8)); + nxtdsp = dsp; + } + + /* + ** log the information + */ + if (DEBUG_FLAGS & DEBUG_PHASE) { + printk ("\nCP=%p DSP=%x NXT=%x VDSP=%p CMD=%x ", + cp, (unsigned)dsp, (unsigned)nxtdsp, vdsp, cmd); + }; + + if (!vdsp) { + printk ("%s: interrupted SCRIPT address not found.\n", + ncr_name (np)); + goto reset_all; + } + + if (!cp) { + printk ("%s: SCSI phase error fixup: CCB already dequeued.\n", + ncr_name (np)); + goto reset_all; + } + + /* + ** get old startaddress and old length. + */ + + oadr = scr_to_cpu(vdsp[1]); + + if (cmd & 0x10) { /* Table indirect */ + tblp = (u_int32 *) ((char*) &cp->phys + oadr); + olen = scr_to_cpu(tblp[0]); + oadr = scr_to_cpu(tblp[1]); + } else { + tblp = (u_int32 *) 0; + olen = scr_to_cpu(vdsp[0]) & 0xffffff; + }; + + if (DEBUG_FLAGS & DEBUG_PHASE) { + printk ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n", + (unsigned) (scr_to_cpu(vdsp[0]) >> 24), + tblp, + (unsigned) olen, + (unsigned) oadr); + }; + + /* + ** check cmd against assumed interrupted script command. + ** If dt data phase, the MOVE instruction hasn't bit 4 of + ** the phase. + */ + + if (((cmd & 2) ? cmd : (cmd & ~4)) != (scr_to_cpu(vdsp[0]) >> 24)) { + PRINT_ADDR(cp->cmd); + printk ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n", + (unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24); + + goto reset_all; + }; + + /* + ** if old phase not dataphase, leave here. + ** C/D line is low if data. + */ + + if (cmd & 0x02) { + PRINT_ADDR(cp->cmd); + printk ("phase change %x-%x %d@%08x resid=%d.\n", + cmd&7, INB(nc_sbcl)&7, (unsigned)olen, + (unsigned)oadr, (unsigned)rest); + goto unexpected_phase; + }; + + /* + ** Choose the correct PM save area. + ** + ** Look at the PM_SAVE SCRIPT if you want to understand + ** this stuff. The equivalent code is implemented in + ** SCRIPTS for the 895A and 896 that are able to handle + ** PM from the SCRIPTS processor. + */ + + hflags0 = INB (HF_PRT); + hflags = hflags0; + + if (hflags & (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED)) { + if (hflags & HF_IN_PM0) + nxtdsp = scr_to_cpu(cp->phys.pm0.ret); + else if (hflags & HF_IN_PM1) + nxtdsp = scr_to_cpu(cp->phys.pm1.ret); + + if (hflags & HF_DP_SAVED) + hflags ^= HF_ACT_PM; + } + + if (!(hflags & HF_ACT_PM)) { + pm = &cp->phys.pm0; + newcmd = NCB_SCRIPT_PHYS(np, pm0_data); + } + else { + pm = &cp->phys.pm1; + newcmd = NCB_SCRIPT_PHYS(np, pm1_data); + } + + hflags &= ~(HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED); + if (hflags != hflags0) + OUTB (HF_PRT, hflags); + + /* + ** fillin the phase mismatch context + */ + + pm->sg.addr = cpu_to_scr(oadr + olen - rest); + pm->sg.size = cpu_to_scr(rest); + pm->ret = cpu_to_scr(nxtdsp); + + /* + ** If we have a SWIDE, + ** - prepare the address to write the SWIDE from SCRIPTS, + ** - compute the SCRIPTS address to restart from, + ** - move current data pointer context by one byte. + */ + nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); + if ( ((cmd & 7) == 1 || (cmd & 7) == 5) + && cp && (cp->phys.select.sel_scntl3 & EWS) && + (INB (nc_scntl2) & WSR)) { + u32 tmp; + +#ifdef SYM_DEBUG_PM_WITH_WSR + PRINT_ADDR(cp); + printk ("MA interrupt with WSR set - " + "pm->sg.addr=%x - pm->sg.size=%d\n", + pm->sg.addr, pm->sg.size); +#endif + /* + * Set up the table indirect for the MOVE + * of the residual byte and adjust the data + * pointer context. + */ + tmp = scr_to_cpu(pm->sg.addr); + cp->phys.wresid.addr = cpu_to_scr(tmp); + pm->sg.addr = cpu_to_scr(tmp + 1); + tmp = scr_to_cpu(pm->sg.size); + cp->phys.wresid.size = cpu_to_scr((tmp&0xff000000) | 1); + pm->sg.size = cpu_to_scr(tmp - 1); + + /* + * If only the residual byte is to be moved, + * no PM context is needed. + */ + if ((tmp&0xffffff) == 1) + newcmd = pm->ret; + + /* + * Prepare the address of SCRIPTS that will + * move the residual byte to memory. + */ + nxtdsp = NCB_SCRIPTH_PHYS (np, wsr_ma_helper); + } + + if (DEBUG_FLAGS & DEBUG_PHASE) { + PRINT_ADDR(cp->cmd); + printk ("PM %x %x %x / %x %x %x.\n", + hflags0, hflags, newcmd, + (unsigned)scr_to_cpu(pm->sg.addr), + (unsigned)scr_to_cpu(pm->sg.size), + (unsigned)scr_to_cpu(pm->ret)); + } + + /* + ** Restart the SCRIPTS processor. + */ + + OUTL (nc_temp, newcmd); + OUTL_DSP (nxtdsp); + return; + + /* + ** Unexpected phase changes that occurs when the current phase + ** is not a DATA IN or DATA OUT phase are due to error conditions. + ** Such event may only happen when the SCRIPTS is using a + ** multibyte SCSI MOVE. + ** + ** Phase change Some possible cause + ** + ** COMMAND --> MSG IN SCSI parity error detected by target. + ** COMMAND --> STATUS Bad command or refused by target. + ** MSG OUT --> MSG IN Message rejected by target. + ** MSG OUT --> COMMAND Bogus target that discards extended + ** negotiation messages. + ** + ** The code below does not care of the new phase and so + ** trusts the target. Why to annoy it ? + ** If the interrupted phase is COMMAND phase, we restart at + ** dispatcher. + ** If a target does not get all the messages after selection, + ** the code assumes blindly that the target discards extended + ** messages and clears the negotiation status. + ** If the target does not want all our response to negotiation, + ** we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids + ** bloat for such a should_not_happen situation). + ** In all other situation, we reset the BUS. + ** Are these assumptions reasonnable ? (Wait and see ...) + */ +unexpected_phase: + dsp -= 8; + nxtdsp = 0; + + switch (cmd & 7) { + case 2: /* COMMAND phase */ + nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); + break; +#if 0 + case 3: /* STATUS phase */ + nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); + break; +#endif + case 6: /* MSG OUT phase */ + /* + ** If the device may want to use untagged when we want + ** tagged, we prepare an IDENTIFY without disc. granted, + ** since we will not be able to handle reselect. + ** Otherwise, we just don't care. + */ + if (dsp == NCB_SCRIPT_PHYS (np, send_ident)) { + if (cp->tag != NO_TAG && olen - rest <= 3) { + cp->host_status = HS_BUSY; + np->msgout[0] = M_IDENTIFY | cp->lun; + nxtdsp = NCB_SCRIPTH_PHYS (np, ident_break_atn); + } + else + nxtdsp = NCB_SCRIPTH_PHYS (np, ident_break); + } + else if (dsp == NCB_SCRIPTH_PHYS (np, send_wdtr) || + dsp == NCB_SCRIPTH_PHYS (np, send_sdtr) || + dsp == NCB_SCRIPTH_PHYS (np, send_ppr)) { + nxtdsp = NCB_SCRIPTH_PHYS (np, nego_bad_phase); + } + break; +#if 0 + case 7: /* MSG IN phase */ + nxtdsp = NCB_SCRIPT_PHYS (np, clrack); + break; +#endif + } + + if (nxtdsp) { + OUTL_DSP (nxtdsp); + return; + } + +reset_all: + ncr_start_reset(np); +} + +/*========================================================== +** +** ncr chip handler for QUEUE FULL and CHECK CONDITION +** +**========================================================== +** +** On QUEUE FULL status, we set the actual tagged command +** queue depth to the number of disconnected CCBs that is +** hopefully a good value to avoid further QUEUE FULL. +** +** On CHECK CONDITION or COMMAND TERMINATED, we use the +** CCB of the failed command for performing a REQUEST +** SENSE SCSI command. +** +** We do not want to change the order commands will be +** actually queued to the device after we received a +** QUEUE FULL status. We also want to properly deal with +** contingent allegiance condition. For these reasons, +** we remove from the start queue all commands for this +** LUN that haven't been yet queued to the device and +** put them back in the correponding LUN queue, then +** requeue the CCB that failed in front of the LUN queue. +** I just hope this not to be performed too often. :) +** +** If we are using IMMEDIATE ARBITRATION, we clear the +** IARB hint for every commands we encounter in order not +** to be stuck with a won arbitration and no job to queue +** to a device. +**---------------------------------------------------------- +*/ + +static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp) +{ + Scsi_Cmnd *cmd = cp->cmd; + tcb_p tp = &np->target[cp->target]; + lcb_p lp = ncr_lp(np, tp, cp->lun); + ccb_p cp2; + int busyccbs = 1; + u_int32 startp; + u_char s_status = INB (SS_PRT); + int msglen; + int i, j; + + + /* + ** If the LCB is not yet available, then only + ** 1 IO is accepted, so we should have it. + */ + if (!lp) + goto next; + /* + ** Remove all CCBs queued to the chip for that LUN and put + ** them back in the LUN CCB wait queue. + */ + busyccbs = lp->queuedccbs; + i = (INL (nc_scratcha) - np->p_squeue) / 4; + j = i; + while (i != np->squeueput) { + cp2 = ncr_ccb_from_dsa(np, scr_to_cpu(np->squeue[i])); + assert(cp2); +#ifdef SCSI_NCR_IARB_SUPPORT + /* IARB hints may not be relevant any more. Forget them. */ + cp2->host_flags &= ~HF_HINT_IARB; +#endif + if (cp2 && cp2->target == cp->target && cp2->lun == cp->lun) { + xpt_remque(&cp2->link_ccbq); + xpt_insque_head(&cp2->link_ccbq, &lp->wait_ccbq); + --lp->queuedccbs; + cp2->queued = 0; + } + else { + if (i != j) + np->squeue[j] = np->squeue[i]; + if ((j += 2) >= MAX_START*2) j = 0; + } + if ((i += 2) >= MAX_START*2) i = 0; + } + if (i != j) /* Copy back the idle task if needed */ + np->squeue[j] = np->squeue[i]; + np->squeueput = j; /* Update our current start queue pointer */ + + /* + ** Requeue the interrupted CCB in front of the + ** LUN CCB wait queue to preserve ordering. + */ + xpt_remque(&cp->link_ccbq); + xpt_insque_head(&cp->link_ccbq, &lp->wait_ccbq); + --lp->queuedccbs; + cp->queued = 0; + +next: + +#ifdef SCSI_NCR_IARB_SUPPORT + /* IARB hint may not be relevant any more. Forget it. */ + cp->host_flags &= ~HF_HINT_IARB; + if (np->last_cp) + np->last_cp = 0; +#endif + + /* + ** Now we can restart the SCRIPTS processor safely. + */ + OUTL_DSP (NCB_SCRIPT_PHYS (np, start)); + + switch(s_status) { + default: + case S_BUSY: + ncr_complete(np, cp); + break; + case S_QUEUE_FULL: + if (!lp || !lp->queuedccbs) { + ncr_complete(np, cp); + break; + } + if (bootverbose >= 1) { + PRINT_ADDR(cmd); + printk ("QUEUE FULL! %d busy, %d disconnected CCBs\n", + busyccbs, lp->queuedccbs); + } + /* + ** Decrease number of tags to the number of + ** disconnected commands. + */ + if (lp->queuedccbs < lp->numtags) { + lp->numtags = lp->queuedccbs; + lp->num_good = 0; + ncr_setup_tags (np, cp->target, cp->lun); + } + /* + ** Repair the offending CCB. + */ + cp->phys.header.savep = cp->startp; + cp->phys.header.lastp = cp->lastp0; + cp->host_status = HS_BUSY; + cp->scsi_status = S_ILLEGAL; + cp->xerr_status = 0; + cp->extra_bytes = 0; + cp->host_flags &= (HF_PM_TO_C|HF_DATA_IN); + + break; + + case S_TERMINATED: + case S_CHECK_COND: + /* + ** If we were requesting sense, give up. + */ + if (cp->host_flags & HF_AUTO_SENSE) { + ncr_complete(np, cp); + break; + } + + /* + ** Save SCSI status and extended error. + ** Compute the data residual now. + */ + cp->sv_scsi_status = cp->scsi_status; + cp->sv_xerr_status = cp->xerr_status; + cp->resid = ncr_compute_residual(np, cp); + + /* + ** Device returned CHECK CONDITION status. + ** Prepare all needed data strutures for getting + ** sense data. + */ + + /* + ** identify message + */ + cp->scsi_smsg2[0] = M_IDENTIFY | cp->lun; + msglen = 1; + + /* + ** If we are currently using anything different from + ** async. 8 bit data transfers with that target, + ** start a negotiation, since the device may want + ** to report us a UNIT ATTENTION condition due to + ** a cause we currently ignore, and we donnot want + ** to be stuck with WIDE and/or SYNC data transfer. + ** + ** cp->nego_status is filled by ncr_prepare_nego(). + ** + ** Do NOT negotiate if performing integrity check + ** or if integrity check has completed, all check + ** conditions will have been cleared. + */ + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if (DEBUG_FLAGS & DEBUG_IC) { + printk("%s: ncr_sir_to_redo: ic_done %2X, in_progress %2X\n", + ncr_name(np), tp->ic_done, cp->cmd->ic_in_progress); + } + + /* + ** If parity error during integrity check, + ** set the target width to narrow. Otherwise, + ** do not negotiate on a request sense. + */ + if ( np->check_integ_par && np->check_integrity + && cp->cmd->ic_in_progress ) { + cp->nego_status = 0; + msglen += + ncr_ic_nego (np, cp, cmd ,&cp->scsi_smsg2[msglen]); + } + + if (!np->check_integrity || + (np->check_integrity && + (!cp->cmd->ic_in_progress && !tp->ic_done)) ) { + ncr_negotiate(np, tp); + cp->nego_status = 0; + { + u_char sync_offset; + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + sync_offset = tp->sval & 0x3f; + else + sync_offset = tp->sval & 0x1f; + + if ((tp->wval & EWS) || sync_offset) + msglen += + ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]); + } + + } +#else + ncr_negotiate(np, tp); + cp->nego_status = 0; + if ((tp->wval & EWS) || (tp->sval & 0x1f)) + msglen += + ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]); +#endif /* SCSI_NCR_INTEGRITY_CHECKING */ + + /* + ** Message table indirect structure. + */ + cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg2)); + cp->phys.smsg.size = cpu_to_scr(msglen); + + /* + ** sense command + */ + cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, sensecmd)); + cp->phys.cmd.size = cpu_to_scr(6); + + /* + ** patch requested size into sense command + */ + cp->sensecmd[0] = 0x03; + cp->sensecmd[1] = cp->lun << 5; + cp->sensecmd[4] = sizeof(cp->sense_buf); + + /* + ** sense data + */ + bzero(cp->sense_buf, sizeof(cp->sense_buf)); + cp->phys.sense.addr = cpu_to_scr(CCB_PHYS(cp,sense_buf[0])); + cp->phys.sense.size = cpu_to_scr(sizeof(cp->sense_buf)); + + /* + ** requeue the command. + */ + startp = NCB_SCRIPTH_PHYS (np, sdata_in); + + cp->phys.header.savep = cpu_to_scr(startp); + cp->phys.header.goalp = cpu_to_scr(startp + 16); + cp->phys.header.lastp = cpu_to_scr(startp); + cp->phys.header.wgoalp = cpu_to_scr(startp + 16); + cp->phys.header.wlastp = cpu_to_scr(startp); + + cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; + cp->scsi_status = S_ILLEGAL; + cp->host_flags = (HF_AUTO_SENSE|HF_DATA_IN); + + cp->phys.header.go.start = + cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); + + /* + ** If lp not yet allocated, requeue the command. + */ + if (!lp) + ncr_put_start_queue(np, cp); + break; + } + + /* + ** requeue awaiting scsi commands for this lun. + */ + if (lp) + ncr_start_next_ccb(np, lp, 1); + + return; +} + +/*---------------------------------------------------------- +** +** After a device has accepted some management message +** as BUS DEVICE RESET, ABORT TASK, etc ..., or when +** a device signals a UNIT ATTENTION condition, some +** tasks are thrown away by the device. We are required +** to reflect that on our tasks list since the device +** will never complete these tasks. +** +** This function completes all disconnected CCBs for a +** given target that matches the following criteria: +** - lun=-1 means any logical UNIT otherwise a given one. +** - task=-1 means any task, otherwise a given one. +**---------------------------------------------------------- +*/ +static int ncr_clear_tasks(ncb_p np, u_char hsts, + int target, int lun, int task) +{ + int i = 0; + ccb_p cp; + + for (cp = np->ccbc; cp; cp = cp->link_ccb) { + if (cp->host_status != HS_DISCONNECT) + continue; + if (cp->target != target) + continue; + if (lun != -1 && cp->lun != lun) + continue; + if (task != -1 && cp->tag != NO_TAG && cp->scsi_smsg[2] != task) + continue; + cp->host_status = hsts; + cp->scsi_status = S_ILLEGAL; + ncr_complete(np, cp); + ++i; + } + return i; +} + +/*========================================================== +** +** ncr chip handler for TASKS recovery. +** +**========================================================== +** +** We cannot safely abort a command, while the SCRIPTS +** processor is running, since we just would be in race +** with it. +** +** As long as we have tasks to abort, we keep the SEM +** bit set in the ISTAT. When this bit is set, the +** SCRIPTS processor interrupts (SIR_SCRIPT_STOPPED) +** each time it enters the scheduler. +** +** If we have to reset a target, clear tasks of a unit, +** or to perform the abort of a disconnected job, we +** restart the SCRIPTS for selecting the target. Once +** selected, the SCRIPTS interrupts (SIR_TARGET_SELECTED). +** If it loses arbitration, the SCRIPTS will interrupt again +** the next time it will enter its scheduler, and so on ... +** +** On SIR_TARGET_SELECTED, we scan for the more +** appropriate thing to do: +** +** - If nothing, we just sent a M_ABORT message to the +** target to get rid of the useless SCSI bus ownership. +** According to the specs, no tasks shall be affected. +** - If the target is to be reset, we send it a M_RESET +** message. +** - If a logical UNIT is to be cleared , we send the +** IDENTIFY(lun) + M_ABORT. +** - If an untagged task is to be aborted, we send the +** IDENTIFY(lun) + M_ABORT. +** - If a tagged task is to be aborted, we send the +** IDENTIFY(lun) + task attributes + M_ABORT_TAG. +** +** Once our 'kiss of death' :) message has been accepted +** by the target, the SCRIPTS interrupts again +** (SIR_ABORT_SENT). On this interrupt, we complete +** all the CCBs that should have been aborted by the +** target according to our message. +** +**---------------------------------------------------------- +*/ +static void ncr_sir_task_recovery(ncb_p np, int num) +{ + ccb_p cp; + tcb_p tp; + int target=-1, lun=-1, task; + int i, k; + u_char *p; + + switch(num) { + /* + ** The SCRIPTS processor stopped before starting + ** the next command in order to allow us to perform + ** some task recovery. + */ + case SIR_SCRIPT_STOPPED: + + /* + ** Do we have any target to reset or unit to clear ? + */ + for (i = 0 ; i < MAX_TARGET ; i++) { + tp = &np->target[i]; + if (tp->to_reset || (tp->l0p && tp->l0p->to_clear)) { + target = i; + break; + } + if (!tp->lmp) + continue; + for (k = 1 ; k < MAX_LUN ; k++) { + if (tp->lmp[k] && tp->lmp[k]->to_clear) { + target = i; + break; + } + } + if (target != -1) + break; + } + + /* + ** If not, look at the CCB list for any + ** disconnected CCB to be aborted. + */ + if (target == -1) { + for (cp = np->ccbc; cp; cp = cp->link_ccb) { + if (cp->host_status != HS_DISCONNECT) + continue; + if (cp->to_abort) { + target = cp->target; + break; + } + } + } + + /* + ** If some target is to be selected, + ** prepare and start the selection. + */ + if (target != -1) { + tp = &np->target[target]; + np->abrt_sel.sel_id = target; + np->abrt_sel.sel_scntl3 = tp->wval; + np->abrt_sel.sel_sxfer = tp->sval; + np->abrt_sel.sel_scntl4 = tp->uval; + OUTL(nc_dsa, np->p_ncb); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, sel_for_abort)); + return; + } + + /* + ** Nothing is to be selected, so we donnot need + ** to synchronize with the SCRIPTS anymore. + ** Remove the SEM flag from the ISTAT. + */ + np->istat_sem = 0; + OUTB (nc_istat, SIGP); + + /* + ** Now look at CCBs to abort that haven't started yet. + ** Remove all those CCBs from the start queue and + ** complete them with appropriate status. + ** Btw, the SCRIPTS processor is still stopped, so + ** we are not in race. + */ + for (cp = np->ccbc; cp; cp = cp->link_ccb) { + if (cp->host_status != HS_BUSY && + cp->host_status != HS_NEGOTIATE) + continue; + if (!cp->to_abort) + continue; +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** If we are using IMMEDIATE ARBITRATION, we donnot + ** want to cancel the last queued CCB, since the + ** SCRIPTS may have anticipated the selection. + */ + if (cp == np->last_cp) { + cp->to_abort = 0; + continue; + } +#endif + /* + ** Compute index of next position in the start + ** queue the SCRIPTS will schedule. + */ + i = (INL (nc_scratcha) - np->p_squeue) / 4; + + /* + ** Remove the job from the start queue. + */ + k = -1; + while (1) { + if (i == np->squeueput) + break; + if (k == -1) { /* Not found yet */ + if (cp == ncr_ccb_from_dsa(np, + scr_to_cpu(np->squeue[i]))) + k = i; /* Found */ + } + else { + /* + ** Once found, we have to move + ** back all jobs by 1 position. + */ + np->squeue[k] = np->squeue[i]; + k += 2; + if (k >= MAX_START*2) + k = 0; + } + + i += 2; + if (i >= MAX_START*2) + i = 0; + } + /* + ** If job removed, repair the start queue. + */ + if (k != -1) { + np->squeue[k] = np->squeue[i]; /* Idle task */ + np->squeueput = k; /* Start queue pointer */ + } + cp->host_status = HS_ABORTED; + cp->scsi_status = S_ILLEGAL; + ncr_complete(np, cp); + } + break; + /* + ** The SCRIPTS processor has selected a target + ** we may have some manual recovery to perform for. + */ + case SIR_TARGET_SELECTED: + target = (INB (nc_sdid) & 0xf); + tp = &np->target[target]; + + np->abrt_tbl.addr = cpu_to_scr(vtobus(np->abrt_msg)); + + /* + ** If the target is to be reset, prepare a + ** M_RESET message and clear the to_reset flag + ** since we donnot expect this operation to fail. + */ + if (tp->to_reset) { + np->abrt_msg[0] = M_RESET; + np->abrt_tbl.size = 1; + tp->to_reset = 0; + break; + } + + /* + ** Otherwise, look for some logical unit to be cleared. + */ + if (tp->l0p && tp->l0p->to_clear) + lun = 0; + else if (tp->lmp) { + for (k = 1 ; k < MAX_LUN ; k++) { + if (tp->lmp[k] && tp->lmp[k]->to_clear) { + lun = k; + break; + } + } + } + + /* + ** If a logical unit is to be cleared, prepare + ** an IDENTIFY(lun) + ABORT MESSAGE. + */ + if (lun != -1) { + lcb_p lp = ncr_lp(np, tp, lun); + lp->to_clear = 0; /* We donnot expect to fail here */ + np->abrt_msg[0] = M_IDENTIFY | lun; + np->abrt_msg[1] = M_ABORT; + np->abrt_tbl.size = 2; + break; + } + + /* + ** Otherwise, look for some disconnected job to + ** abort for this target. + */ + for (cp = np->ccbc; cp; cp = cp->link_ccb) { + if (cp->host_status != HS_DISCONNECT) + continue; + if (cp->target != target) + continue; + if (cp->to_abort) + break; + } + + /* + ** If we have none, probably since the device has + ** completed the command before we won abitration, + ** send a M_ABORT message without IDENTIFY. + ** According to the specs, the device must just + ** disconnect the BUS and not abort any task. + */ + if (!cp) { + np->abrt_msg[0] = M_ABORT; + np->abrt_tbl.size = 1; + break; + } + + /* + ** We have some task to abort. + ** Set the IDENTIFY(lun) + */ + np->abrt_msg[0] = M_IDENTIFY | cp->lun; + + /* + ** If we want to abort an untagged command, we + ** will send a IDENTIFY + M_ABORT. + ** Otherwise (tagged command), we will send + ** a IDENTITFY + task attributes + ABORT TAG. + */ + if (cp->tag == NO_TAG) { + np->abrt_msg[1] = M_ABORT; + np->abrt_tbl.size = 2; + } + else { + np->abrt_msg[1] = cp->scsi_smsg[1]; + np->abrt_msg[2] = cp->scsi_smsg[2]; + np->abrt_msg[3] = M_ABORT_TAG; + np->abrt_tbl.size = 4; + } + cp->to_abort = 0; /* We donnot expect to fail here */ + break; + + /* + ** The target has accepted our message and switched + ** to BUS FREE phase as we expected. + */ + case SIR_ABORT_SENT: + target = (INB (nc_sdid) & 0xf); + tp = &np->target[target]; + + /* + ** If we didn't abort anything, leave here. + */ + if (np->abrt_msg[0] == M_ABORT) + break; + + /* + ** If we sent a M_RESET, then a hardware reset has + ** been performed by the target. + ** - Reset everything to async 8 bit + ** - Tell ourself to negotiate next time :-) + ** - Prepare to clear all disconnected CCBs for + ** this target from our task list (lun=task=-1) + */ + lun = -1; + task = -1; + if (np->abrt_msg[0] == M_RESET) { + tp->sval = 0; + tp->wval = np->rv_scntl3; + tp->uval = np->rv_scntl4; + ncr_set_sync_wide_status(np, target); + ncr_negotiate(np, tp); + } + + /* + ** Otherwise, check for the LUN and TASK(s) + ** concerned by the cancelation. + ** If it is not ABORT_TAG then it is CLEAR_QUEUE + ** or an ABORT message :-) + */ + else { + lun = np->abrt_msg[0] & 0x3f; + if (np->abrt_msg[1] == M_ABORT_TAG) + task = np->abrt_msg[2]; + } + + /* + ** Complete all the CCBs the device should have + ** aborted due to our 'kiss of death' message. + */ + (void) ncr_clear_tasks(np, HS_ABORTED, target, lun, task); + break; + + /* + ** We have performed a auto-sense that succeeded. + ** If the device reports a UNIT ATTENTION condition + ** due to a RESET condition, we must complete all + ** disconnect CCBs for this unit since the device + ** shall have thrown them away. + ** Since I haven't time to guess what the specs are + ** expecting for other UNIT ATTENTION conditions, I + ** decided to only care about RESET conditions. :) + */ + case SIR_AUTO_SENSE_DONE: + cp = ncr_ccb_from_dsa(np, INL (nc_dsa)); + if (!cp) + break; + memcpy(cp->cmd->sense_buffer, cp->sense_buf, + sizeof(cp->cmd->sense_buffer)); + p = &cp->cmd->sense_buffer[0]; + + if (p[0] != 0x70 || p[2] != 0x6 || p[12] != 0x29) + break; +#if 0 + (void) ncr_clear_tasks(np, HS_RESET, cp->target, cp->lun, -1); +#endif + break; + } + + /* + ** Print to the log the message we intend to send. + */ + if (num == SIR_TARGET_SELECTED) { + PRINT_TARGET(np, target); + ncr_printl_hex("control msgout:", np->abrt_msg, + np->abrt_tbl.size); + np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size); + } + + /* + ** Let the SCRIPTS processor continue. + */ + OUTONB_STD (); +} + + +/*========================================================== +** +** Gérard's alchemy:) that deals with with the data +** pointer for both MDP and the residual calculation. +** +**========================================================== +** +** I didn't want to bloat the code by more than 200 +** lignes for the handling of both MDP and the residual. +** This has been achieved by using a data pointer +** representation consisting in an index in the data +** array (dp_sg) and a negative offset (dp_ofs) that +** have the following meaning: +** +** - dp_sg = MAX_SCATTER +** we are at the end of the data script. +** - dp_sg < MAX_SCATTER +** dp_sg points to the next entry of the scatter array +** we want to transfer. +** - dp_ofs < 0 +** dp_ofs represents the residual of bytes of the +** previous entry scatter entry we will send first. +** - dp_ofs = 0 +** no residual to send first. +** +** The function ncr_evaluate_dp() accepts an arbitray +** offset (basically from the MDP message) and returns +** the corresponding values of dp_sg and dp_ofs. +** +**---------------------------------------------------------- +*/ + +static int ncr_evaluate_dp(ncb_p np, ccb_p cp, u_int32 scr, int *ofs) +{ + u_int32 dp_scr; + int dp_ofs, dp_sg, dp_sgmin; + int tmp; + struct pm_ctx *pm; + + /* + ** Compute the resulted data pointer in term of a script + ** address within some DATA script and a signed byte offset. + */ + dp_scr = scr; + dp_ofs = *ofs; + if (dp_scr == NCB_SCRIPT_PHYS (np, pm0_data)) + pm = &cp->phys.pm0; + else if (dp_scr == NCB_SCRIPT_PHYS (np, pm1_data)) + pm = &cp->phys.pm1; + else + pm = 0; + + if (pm) { + dp_scr = scr_to_cpu(pm->ret); + dp_ofs -= scr_to_cpu(pm->sg.size); + } + + /* + ** Deduce the index of the sg entry. + ** Keep track of the index of the first valid entry. + ** If result is dp_sg = MAX_SCATTER, then we are at the + ** end of the data and vice-versa. + */ + tmp = scr_to_cpu(cp->phys.header.goalp); + dp_sg = MAX_SCATTER; + if (dp_scr != tmp) + dp_sg -= (tmp - 8 - (int)dp_scr) / (SCR_SG_SIZE*4); + dp_sgmin = MAX_SCATTER - cp->segments; + + /* + ** Move to the sg entry the data pointer belongs to. + ** + ** If we are inside the data area, we expect result to be: + ** + ** Either, + ** dp_ofs = 0 and dp_sg is the index of the sg entry + ** the data pointer belongs to (or the end of the data) + ** Or, + ** dp_ofs < 0 and dp_sg is the index of the sg entry + ** the data pointer belongs to + 1. + */ + if (dp_ofs < 0) { + int n; + while (dp_sg > dp_sgmin) { + --dp_sg; + tmp = scr_to_cpu(cp->phys.data[dp_sg].size); + n = dp_ofs + (tmp & 0xffffff); + if (n > 0) { + ++dp_sg; + break; + } + dp_ofs = n; + } + } + else if (dp_ofs > 0) { + while (dp_sg < MAX_SCATTER) { + tmp = scr_to_cpu(cp->phys.data[dp_sg].size); + dp_ofs -= (tmp & 0xffffff); + ++dp_sg; + if (dp_ofs <= 0) + break; + } + } + + /* + ** Make sure the data pointer is inside the data area. + ** If not, return some error. + */ + if (dp_sg < dp_sgmin || (dp_sg == dp_sgmin && dp_ofs < 0)) + goto out_err; + else if (dp_sg > MAX_SCATTER || (dp_sg == MAX_SCATTER && dp_ofs > 0)) + goto out_err; + + /* + ** Save the extreme pointer if needed. + */ + if (dp_sg > cp->ext_sg || + (dp_sg == cp->ext_sg && dp_ofs > cp->ext_ofs)) { + cp->ext_sg = dp_sg; + cp->ext_ofs = dp_ofs; + } + + /* + ** Return data. + */ + *ofs = dp_ofs; + return dp_sg; + +out_err: + return -1; +} + +/*========================================================== +** +** ncr chip handler for MODIFY DATA POINTER MESSAGE +** +**========================================================== +** +** We also call this function on IGNORE WIDE RESIDUE +** messages that do not match a SWIDE full condition. +** Btw, we assume in that situation that such a message +** is equivalent to a MODIFY DATA POINTER (offset=-1). +** +**---------------------------------------------------------- +*/ + +static void ncr_modify_dp(ncb_p np, tcb_p tp, ccb_p cp, int ofs) +{ + int dp_ofs = ofs; + u_int32 dp_scr = INL (nc_temp); + u_int32 dp_ret; + u_int32 tmp; + u_char hflags; + int dp_sg; + struct pm_ctx *pm; + + /* + ** Not supported for auto_sense; + */ + if (cp->host_flags & HF_AUTO_SENSE) + goto out_reject; + + /* + ** Apply our alchemy:) (see comments in ncr_evaluate_dp()), + ** to the resulted data pointer. + */ + dp_sg = ncr_evaluate_dp(np, cp, dp_scr, &dp_ofs); + if (dp_sg < 0) + goto out_reject; + + /* + ** And our alchemy:) allows to easily calculate the data + ** script address we want to return for the next data phase. + */ + dp_ret = cpu_to_scr(cp->phys.header.goalp); + dp_ret = dp_ret - 8 - (MAX_SCATTER - dp_sg) * (SCR_SG_SIZE*4); + + /* + ** If offset / scatter entry is zero we donnot need + ** a context for the new current data pointer. + */ + if (dp_ofs == 0) { + dp_scr = dp_ret; + goto out_ok; + } + + /* + ** Get a context for the new current data pointer. + */ + hflags = INB (HF_PRT); + + if (hflags & HF_DP_SAVED) + hflags ^= HF_ACT_PM; + + if (!(hflags & HF_ACT_PM)) { + pm = &cp->phys.pm0; + dp_scr = NCB_SCRIPT_PHYS (np, pm0_data); + } + else { + pm = &cp->phys.pm1; + dp_scr = NCB_SCRIPT_PHYS (np, pm1_data); + } + + hflags &= ~(HF_DP_SAVED); + + OUTB (HF_PRT, hflags); + + /* + ** Set up the new current data pointer. + ** ofs < 0 there, and for the next data phase, we + ** want to transfer part of the data of the sg entry + ** corresponding to index dp_sg-1 prior to returning + ** to the main data script. + */ + pm->ret = cpu_to_scr(dp_ret); + tmp = scr_to_cpu(cp->phys.data[dp_sg-1].addr); + tmp += scr_to_cpu(cp->phys.data[dp_sg-1].size) + dp_ofs; + pm->sg.addr = cpu_to_scr(tmp); + pm->sg.size = cpu_to_scr(-dp_ofs); + +out_ok: + OUTL (nc_temp, dp_scr); + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); + return; + +out_reject: + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); +} + + +/*========================================================== +** +** ncr chip calculation of the data residual. +** +**========================================================== +** +** As I used to say, the requirement of data residual +** in SCSI is broken, useless and cannot be achieved +** without huge complexity. +** But most OSes and even the official CAM require it. +** When stupidity happens to be so widely spread inside +** a community, it gets hard to convince. +** +** Anyway, I don't care, since I am not going to use +** any software that considers this data residual as +** a relevant information. :) +** +**---------------------------------------------------------- +*/ + +static int ncr_compute_residual(ncb_p np, ccb_p cp) +{ + int dp_sg, dp_sgmin, tmp; + int resid=0; + int dp_ofs = 0; + + /* + * Check for some data lost or just thrown away. + * We are not required to be quite accurate in this + * situation. Btw, if we are odd for output and the + * device claims some more data, it may well happen + * than our residual be zero. :-) + */ + if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) { + if (cp->xerr_status & XE_EXTRA_DATA) + resid -= cp->extra_bytes; + if (cp->xerr_status & XE_SODL_UNRUN) + ++resid; + if (cp->xerr_status & XE_SWIDE_OVRUN) + --resid; + } + + + /* + ** If SCRIPTS reaches its goal point, then + ** there is no additionnal residual. + */ + if (cp->phys.header.lastp == cp->phys.header.goalp) + return resid; + + /* + ** If the last data pointer is data_io (direction + ** unknown), then no data transfer should have + ** taken place. + */ + if (cp->phys.header.lastp == NCB_SCRIPTH_PHYS (np, data_io)) + return cp->data_len; + + /* + ** If no data transfer occurs, or if the data + ** pointer is weird, return full residual. + */ + if (cp->startp == cp->phys.header.lastp || + ncr_evaluate_dp(np, cp, scr_to_cpu(cp->phys.header.lastp), + &dp_ofs) < 0) { + return cp->data_len; + } + + /* + ** We are now full comfortable in the computation + ** of the data residual (2's complement). + */ + dp_sgmin = MAX_SCATTER - cp->segments; + resid = -cp->ext_ofs; + for (dp_sg = cp->ext_sg; dp_sg < MAX_SCATTER; ++dp_sg) { + tmp = scr_to_cpu(cp->phys.data[dp_sg].size); + resid += (tmp & 0xffffff); + } + + /* + ** Hopefully, the result is not too wrong. + */ + return resid; +} + +/*========================================================== +** +** Print out the containt of a SCSI message. +** +**========================================================== +*/ + +static int ncr_show_msg (u_char * msg) +{ + u_char i; + printk ("%x",*msg); + if (*msg==M_EXTENDED) { + for (i=1;i<8;i++) { + if (i-1>msg[1]) break; + printk ("-%x",msg[i]); + }; + return (i+1); + } else if ((*msg & 0xf0) == 0x20) { + printk ("-%x",msg[1]); + return (2); + }; + return (1); +} + +static void ncr_print_msg (ccb_p cp, char *label, u_char *msg) +{ + if (cp) + PRINT_ADDR(cp->cmd); + if (label) + printk ("%s: ", label); + + (void) ncr_show_msg (msg); + printk (".\n"); +} + +/*=================================================================== +** +** Negotiation for WIDE and SYNCHRONOUS DATA TRANSFER. +** +**=================================================================== +** +** Was Sie schon immer ueber transfermode negotiation wissen wollten ... +** +** We try to negotiate sync and wide transfer only after +** a successful inquire command. We look at byte 7 of the +** inquire data to determine the capabilities of the target. +** +** When we try to negotiate, we append the negotiation message +** to the identify and (maybe) simple tag message. +** The host status field is set to HS_NEGOTIATE to mark this +** situation. +** +** If the target doesn't answer this message immediately +** (as required by the standard), the SIR_NEGO_FAILED interrupt +** will be raised eventually. +** The handler removes the HS_NEGOTIATE status, and sets the +** negotiated value to the default (async / nowide). +** +** If we receive a matching answer immediately, we check it +** for validity, and set the values. +** +** If we receive a Reject message immediately, we assume the +** negotiation has failed, and fall back to standard values. +** +** If we receive a negotiation message while not in HS_NEGOTIATE +** state, it's a target initiated negotiation. We prepare a +** (hopefully) valid answer, set our parameters, and send back +** this answer to the target. +** +** If the target doesn't fetch the answer (no message out phase), +** we assume the negotiation has failed, and fall back to default +** settings (SIR_NEGO_PROTO interrupt). +** +** When we set the values, we adjust them in all ccbs belonging +** to this target, in the controller's register, and in the "phys" +** field of the controller's struct ncb. +** +**--------------------------------------------------------------------- +*/ + +/*========================================================== +** +** ncr chip handler for SYNCHRONOUS DATA TRANSFER +** REQUEST (SDTR) message. +** +**========================================================== +** +** Read comments above. +** +**---------------------------------------------------------- +*/ +static void ncr_sync_nego(ncb_p np, tcb_p tp, ccb_p cp) +{ + u_char scntl3, scntl4; + u_char chg, ofs, per, fak; + + /* + ** Synchronous request message received. + */ + + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "sync msg in", np->msgin); + }; + + /* + ** get requested values. + */ + + chg = 0; + per = np->msgin[3]; + ofs = np->msgin[4]; + if (ofs==0) per=255; + + /* + ** if target sends SDTR message, + ** it CAN transfer synch. + */ + + if (ofs) + tp->inq_byte7 |= INQ7_SYNC; + + /* + ** check values against driver limits. + */ + + if (per < np->minsync) + {chg = 1; per = np->minsync;} + if (per < tp->minsync) + {chg = 1; per = tp->minsync;} + if (ofs > np->maxoffs_st) + {chg = 1; ofs = np->maxoffs_st;} + if (ofs > tp->maxoffs) + {chg = 1; ofs = tp->maxoffs;} + + /* + ** Check against controller limits. + */ + fak = 7; + scntl3 = 0; + scntl4 = 0; + if (ofs != 0) { + ncr_getsync(np, per, &fak, &scntl3); + if (fak > 7) { + chg = 1; + ofs = 0; + } + } + if (ofs == 0) { + fak = 7; + per = 0; + scntl3 = 0; + scntl4 = 0; + tp->minsync = 0; + } + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("sync: per=%d scntl3=0x%x scntl4=0x%x ofs=%d fak=%d chg=%d.\n", + per, scntl3, scntl4, ofs, fak, chg); + } + + if (INB (HS_PRT) == HS_NEGOTIATE) { + OUTB (HS_PRT, HS_BUSY); + switch (cp->nego_status) { + case NS_SYNC: + /* + ** This was an answer message + */ + if (chg) { + /* + ** Answer wasn't acceptable. + */ + ncr_setsync (np, cp, 0, 0xe0, 0); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); + } else { + /* + ** Answer is ok. + */ + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + ncr_setsync (np, cp, scntl3, (fak<<5)|ofs,0); + else + ncr_setsync (np, cp, scntl3, ofs, scntl4); + + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); + }; + return; + + case NS_WIDE: + ncr_setwide (np, cp, 0, 0); + break; + }; + }; + + /* + ** It was a request. Set value and + ** prepare an answer message + */ + + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + ncr_setsync (np, cp, scntl3, (fak<<5)|ofs,0); + else + ncr_setsync (np, cp, scntl3, ofs, scntl4); + + np->msgout[0] = M_EXTENDED; + np->msgout[1] = 3; + np->msgout[2] = M_X_SYNC_REQ; + np->msgout[3] = per; + np->msgout[4] = ofs; + + cp->nego_status = NS_SYNC; + + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "sync msgout", np->msgout); + } + + np->msgin [0] = M_NOOP; + + if (!ofs) + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); + else + OUTL_DSP (NCB_SCRIPTH_PHYS (np, sdtr_resp)); +} + +/*========================================================== +** +** ncr chip handler for WIDE DATA TRANSFER REQUEST +** (WDTR) message. +** +**========================================================== +** +** Read comments above. +** +**---------------------------------------------------------- +*/ +static void ncr_wide_nego(ncb_p np, tcb_p tp, ccb_p cp) +{ + u_char chg, wide; + + /* + ** Wide request message received. + */ + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "wide msgin", np->msgin); + }; + + /* + ** get requested values. + */ + + chg = 0; + wide = np->msgin[3]; + + /* + ** if target sends WDTR message, + ** it CAN transfer wide. + */ + + if (wide) + tp->inq_byte7 |= INQ7_WIDE16; + + /* + ** check values against driver limits. + */ + + if (wide > tp->usrwide) + {chg = 1; wide = tp->usrwide;} + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("wide: wide=%d chg=%d.\n", wide, chg); + } + + if (INB (HS_PRT) == HS_NEGOTIATE) { + OUTB (HS_PRT, HS_BUSY); + switch (cp->nego_status) { + case NS_WIDE: + /* + ** This was an answer message + */ + if (chg) { + /* + ** Answer wasn't acceptable. + */ + ncr_setwide (np, cp, 0, 1); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); + } else { + /* + ** Answer is ok. + */ + ncr_setwide (np, cp, wide, 1); + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); + }; + return; + + case NS_SYNC: + ncr_setsync (np, cp, 0, 0xe0, 0); + break; + }; + }; + + /* + ** It was a request, set value and + ** prepare an answer message + */ + + ncr_setwide (np, cp, wide, 1); + + np->msgout[0] = M_EXTENDED; + np->msgout[1] = 2; + np->msgout[2] = M_X_WIDE_REQ; + np->msgout[3] = wide; + + np->msgin [0] = M_NOOP; + + cp->nego_status = NS_WIDE; + + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "wide msgout", np->msgout); + } + + OUTL_DSP (NCB_SCRIPTH_PHYS (np, wdtr_resp)); +} +/*========================================================== +** +** ncr chip handler for PARALLEL PROTOCOL REQUEST +** (PPR) message. +** +**========================================================== +** +** Read comments above. +** +**---------------------------------------------------------- +*/ +static void ncr_ppr_nego(ncb_p np, tcb_p tp, ccb_p cp) +{ + u_char scntl3, scntl4; + u_char chg, ofs, per, fak, wth, dt; + + /* + ** PPR message received. + */ + + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "ppr msg in", np->msgin); + }; + + /* + ** get requested values. + */ + + chg = 0; + per = np->msgin[3]; + ofs = np->msgin[5]; + wth = np->msgin[6]; + dt = np->msgin[7]; + if (ofs==0) per=255; + + /* + ** if target sends sync (wide), + ** it CAN transfer synch (wide). + */ + + if (ofs) + tp->inq_byte7 |= INQ7_SYNC; + + if (wth) + tp->inq_byte7 |= INQ7_WIDE16; + + /* + ** check values against driver limits. + */ + + if (wth > tp->usrwide) + {chg = 1; wth = tp->usrwide;} + if (per < np->minsync) + {chg = 1; per = np->minsync;} + if (per < tp->minsync) + {chg = 1; per = tp->minsync;} + if (ofs > tp->maxoffs) + {chg = 1; ofs = tp->maxoffs;} + + /* + ** Check against controller limits. + */ + fak = 7; + scntl3 = 0; + scntl4 = 0; + if (ofs != 0) { + scntl4 = dt ? 0x80 : 0; + ncr_getsync(np, per, &fak, &scntl3); + if (fak > 7) { + chg = 1; + ofs = 0; + } + } + if (ofs == 0) { + fak = 7; + per = 0; + scntl3 = 0; + scntl4 = 0; + tp->minsync = 0; + } + + /* + ** If target responds with Ultra 3 speed + ** but narrow or not DT, reject. + ** If target responds with DT request + ** but not Ultra3 speeds, reject message, + ** reset min sync for target to 0x0A and + ** set flags to re-negotiate. + */ + + if ((per == 0x09) && ofs && (!wth || !dt)) + chg = 1; + else if (( (per > 0x09) && dt) ) + chg = 2; + + /* Not acceptable since beyond controller limit */ + if (!dt && ofs > np->maxoffs_st) + {chg = 2; ofs = np->maxoffs_st;} + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("ppr: wth=%d per=%d scntl3=0x%x scntl4=0x%x ofs=%d fak=%d chg=%d.\n", + wth, per, scntl3, scntl4, ofs, fak, chg); + } + + if (INB (HS_PRT) == HS_NEGOTIATE) { + OUTB (HS_PRT, HS_BUSY); + switch (cp->nego_status) { + case NS_PPR: + /* + ** This was an answer message + */ + if (chg) { + /* + ** Answer wasn't acceptable. + */ + if (chg == 2) { + /* Send message reject and reset flags for + ** host to re-negotiate with min period 0x0A. + */ + tp->minsync = 0x0A; + tp->period = 0; + tp->widedone = 0; + } + ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); + } else { + /* + ** Answer is ok. + */ + + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + ncr_setsyncwide (np, cp, scntl3, (fak<<5)|ofs,0, wth); + else + ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth); + + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); + + }; + return; + + case NS_SYNC: + ncr_setsync (np, cp, 0, 0xe0, 0); + break; + + case NS_WIDE: + ncr_setwide (np, cp, 0, 0); + break; + }; + }; + + /* + ** It was a request. Set value and + ** prepare an answer message + ** + ** If narrow or not DT and requesting Ultra3 + ** slow the bus down and force ST. If not + ** requesting Ultra3, force ST. + ** Max offset is 31=0x1f if ST mode. + */ + + if ((per == 0x09) && ofs && (!wth || !dt)) { + per = 0x0A; + dt = 0; + } + else if ( (per > 0x09) && dt) { + dt = 0; + } + if (!dt && ofs > np->maxoffs_st) + ofs = np->maxoffs_st; + + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + ncr_setsyncwide (np, cp, scntl3, (fak<<5)|ofs,0, wth); + else + ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth); + + np->msgout[0] = M_EXTENDED; + np->msgout[1] = 6; + np->msgout[2] = M_X_PPR_REQ; + np->msgout[3] = per; + np->msgout[4] = 0; + np->msgout[5] = ofs; + np->msgout[6] = wth; + np->msgout[7] = dt; + + cp->nego_status = NS_PPR; + + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "ppr msgout", np->msgout); + } + + np->msgin [0] = M_NOOP; + + if (!ofs) + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); + else + OUTL_DSP (NCB_SCRIPTH_PHYS (np, ppr_resp)); +} + + + +/* +** Reset SYNC or WIDE to default settings. +** Called when a negotiation does not succeed either +** on rejection or on protocol error. +*/ +static void ncr_nego_default(ncb_p np, tcb_p tp, ccb_p cp) +{ + /* + ** any error in negotiation: + ** fall back to default mode. + */ + switch (cp->nego_status) { + + case NS_SYNC: + ncr_setsync (np, cp, 0, 0xe0, 0); + break; + + case NS_WIDE: + ncr_setwide (np, cp, 0, 0); + break; + + case NS_PPR: + /* + * ppr_negotiation is set to 1 on the first ppr nego command. + * If ppr is successful, it is reset to 2. + * If unsuccessful it is reset to 0. + */ + if (DEBUG_FLAGS & DEBUG_NEGO) { + tcb_p tp=&np->target[cp->target]; + u_char factor, offset, width; + + ncr_get_xfer_info ( np, tp, &factor, &offset, &width); + + printk("Current factor %d offset %d width %d\n", + factor, offset, width); + } + if (tp->ppr_negotiation == 2) + ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0); + else if (tp->ppr_negotiation == 1) { + + /* First ppr command has received a M REJECT. + * Do not change the existing wide/sync parameter + * values (asyn/narrow if this as the first nego; + * may be different if target initiates nego.). + */ + tp->ppr_negotiation = 0; + } + else + { + tp->ppr_negotiation = 0; + ncr_setwide (np, cp, 0, 0); + } + break; + }; + np->msgin [0] = M_NOOP; + np->msgout[0] = M_NOOP; + cp->nego_status = 0; +} + +/*========================================================== +** +** ncr chip handler for MESSAGE REJECT received for +** a WIDE or SYNCHRONOUS negotiation. +** +** clear the PPR negotiation flag, all future nego. +** will be SDTR and WDTR +** +**========================================================== +** +** Read comments above. +** +**---------------------------------------------------------- +*/ +static void ncr_nego_rejected(ncb_p np, tcb_p tp, ccb_p cp) +{ + ncr_nego_default(np, tp, cp); + OUTB (HS_PRT, HS_BUSY); +} + + +/*========================================================== +** +** +** ncr chip exception handler for programmed interrupts. +** +** +**========================================================== +*/ + +void ncr_int_sir (ncb_p np) +{ + u_char num = INB (nc_dsps); + u_long dsa = INL (nc_dsa); + ccb_p cp = ncr_ccb_from_dsa(np, dsa); + u_char target = INB (nc_sdid) & 0x0f; + tcb_p tp = &np->target[target]; + int tmp; + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num); + + switch (num) { + /* + ** See comments in the SCRIPTS code. + */ +#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR + case SIR_DUMMY_INTERRUPT: + goto out; +#endif + + /* + ** The C code is currently trying to recover from something. + ** Typically, user want to abort some command. + */ + case SIR_SCRIPT_STOPPED: + case SIR_TARGET_SELECTED: + case SIR_ABORT_SENT: + case SIR_AUTO_SENSE_DONE: + ncr_sir_task_recovery(np, num); + return; + /* + ** The device didn't go to MSG OUT phase after having + ** been selected with ATN. We donnot want to handle + ** that. + */ + case SIR_SEL_ATN_NO_MSG_OUT: + printk ("%s:%d: No MSG OUT phase after selection with ATN.\n", + ncr_name (np), target); + goto out_stuck; + /* + ** The device didn't switch to MSG IN phase after + ** having reseleted the initiator. + */ + case SIR_RESEL_NO_MSG_IN: + /* + ** After reselection, the device sent a message that wasn't + ** an IDENTIFY. + */ + case SIR_RESEL_NO_IDENTIFY: + /* + ** If devices reselecting without sending an IDENTIFY + ** message still exist, this should help. + ** We just assume lun=0, 1 CCB, no tag. + */ + if (tp->l0p) { + OUTL (nc_dsa, scr_to_cpu(tp->l0p->tasktbl[0])); + OUTL_DSP (NCB_SCRIPT_PHYS (np, resel_go)); + return; + } + /* + ** The device reselected a LUN we donnot know of. + */ + case SIR_RESEL_BAD_LUN: + np->msgout[0] = M_RESET; + goto out; + /* + ** The device reselected for an untagged nexus and we + ** haven't any. + */ + case SIR_RESEL_BAD_I_T_L: + np->msgout[0] = M_ABORT; + goto out; + /* + ** The device reselected for a tagged nexus that we donnot + ** have. + */ + case SIR_RESEL_BAD_I_T_L_Q: + np->msgout[0] = M_ABORT_TAG; + goto out; + /* + ** The SCRIPTS let us know that the device has grabbed + ** our message and will abort the job. + */ + case SIR_RESEL_ABORTED: + np->lastmsg = np->msgout[0]; + np->msgout[0] = M_NOOP; + printk ("%s:%d: message %x sent on bad reselection.\n", + ncr_name (np), target, np->lastmsg); + goto out; + /* + ** The SCRIPTS let us know that a message has been + ** successfully sent to the device. + */ + case SIR_MSG_OUT_DONE: + np->lastmsg = np->msgout[0]; + np->msgout[0] = M_NOOP; + /* Should we really care of that */ + if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) { + if (cp) { + cp->xerr_status &= ~XE_PARITY_ERR; + if (!cp->xerr_status) + OUTOFFB (HF_PRT, HF_EXT_ERR); + } + } + goto out; + /* + ** The device didn't send a GOOD SCSI status. + ** We may have some work to do prior to allow + ** the SCRIPTS processor to continue. + */ + case SIR_BAD_STATUS: + if (!cp) + goto out; + ncr_sir_to_redo(np, num, cp); + return; + /* + ** We are asked by the SCRIPTS to prepare a + ** REJECT message. + */ + case SIR_REJECT_TO_SEND: + ncr_print_msg(cp, "M_REJECT to send for ", np->msgin); + np->msgout[0] = M_REJECT; + goto out; + /* + ** We have been ODD at the end of a DATA IN + ** transfer and the device didn't send a + ** IGNORE WIDE RESIDUE message. + ** It is a data overrun condition. + */ + case SIR_SWIDE_OVERRUN: + if (cp) { + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_SWIDE_OVRUN; + } + goto out; + /* + ** We have been ODD at the end of a DATA OUT + ** transfer. + ** It is a data underrun condition. + */ + case SIR_SODL_UNDERRUN: + if (cp) { + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_SODL_UNRUN; + } + goto out; + /* + ** The device wants us to tranfer more data than + ** expected or in the wrong direction. + ** The number of extra bytes is in scratcha. + ** It is a data overrun condition. + */ + case SIR_DATA_OVERRUN: + if (cp) { + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_EXTRA_DATA; + cp->extra_bytes += INL (nc_scratcha); + } + goto out; + /* + ** The device switched to an illegal phase (4/5). + */ + case SIR_BAD_PHASE: + if (cp) { + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_BAD_PHASE; + } + goto out; + /* + ** We received a message. + */ + case SIR_MSG_RECEIVED: + if (!cp) + goto out_stuck; + switch (np->msgin [0]) { + /* + ** We received an extended message. + ** We handle MODIFY DATA POINTER, SDTR, WDTR + ** and reject all other extended messages. + */ + case M_EXTENDED: + switch (np->msgin [2]) { + case M_X_MODIFY_DP: + if (DEBUG_FLAGS & DEBUG_POINTER) + ncr_print_msg(cp,"modify DP",np->msgin); + tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + + (np->msgin[5]<<8) + (np->msgin[6]); + ncr_modify_dp(np, tp, cp, tmp); + return; + case M_X_SYNC_REQ: + ncr_sync_nego(np, tp, cp); + return; + case M_X_WIDE_REQ: + ncr_wide_nego(np, tp, cp); + return; + case M_X_PPR_REQ: + ncr_ppr_nego(np, tp, cp); + return; + default: + goto out_reject; + } + break; + /* + ** We received a 1/2 byte message not handled from SCRIPTS. + ** We are only expecting MESSAGE REJECT and IGNORE WIDE + ** RESIDUE messages that haven't been anticipated by + ** SCRIPTS on SWIDE full condition. Unanticipated IGNORE + ** WIDE RESIDUE messages are aliased as MODIFY DP (-1). + */ + case M_IGN_RESIDUE: + if (DEBUG_FLAGS & DEBUG_POINTER) + ncr_print_msg(cp,"ign wide residue", np->msgin); + ncr_modify_dp(np, tp, cp, -1); + return; + case M_REJECT: + if (INB (HS_PRT) == HS_NEGOTIATE) + ncr_nego_rejected(np, tp, cp); + else { + PRINT_ADDR(cp->cmd); + printk ("M_REJECT received (%x:%x).\n", + scr_to_cpu(np->lastmsg), np->msgout[0]); + } + goto out_clrack; + break; + default: + goto out_reject; + } + break; + /* + ** We received an unknown message. + ** Ignore all MSG IN phases and reject it. + */ + case SIR_MSG_WEIRD: + ncr_print_msg(cp, "WEIRD message received", np->msgin); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_weird)); + return; + /* + ** Negotiation failed. + ** Target does not send us the reply. + ** Remove the HS_NEGOTIATE status. + */ + case SIR_NEGO_FAILED: + OUTB (HS_PRT, HS_BUSY); + /* + ** Negotiation failed. + ** Target does not want answer message. + */ + case SIR_NEGO_PROTO: + ncr_nego_default(np, tp, cp); + goto out; + }; + +out: + OUTONB_STD (); + return; +out_reject: + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); + return; +out_clrack: + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); + return; +out_stuck: + return; +} + + +/*========================================================== +** +** +** Acquire a control block +** +** +**========================================================== +*/ + +static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = ncr_lp(np, tp, ln); + u_short tag = NO_TAG; + XPT_QUEHEAD *qp; + ccb_p cp = (ccb_p) 0; + + /* + ** Allocate a new CCB if needed. + */ + if (xpt_que_empty(&np->free_ccbq)) + (void) ncr_alloc_ccb(np); + + /* + ** Look for a free CCB + */ + qp = xpt_remque_head(&np->free_ccbq); + if (!qp) + goto out; + cp = xpt_que_entry(qp, struct ccb, link_ccbq); + + /* + ** If the LCB is not yet available and we already + ** have queued a CCB for a LUN without LCB, + ** give up. Otherwise all is fine. :-) + */ + if (!lp) { + if (xpt_que_empty(&np->b0_ccbq)) + xpt_insque_head(&cp->link_ccbq, &np->b0_ccbq); + else + goto out_free; + } else { + /* + ** Tune tag mode if asked by user. + */ + if (lp->queuedepth != lp->numtags) { + ncr_setup_tags(np, tn, ln); + } + + /* + ** Get a tag for this nexus if required. + ** Keep from using more tags than we can handle. + */ + if (lp->usetags) { + if (lp->busyccbs < lp->maxnxs) { + tag = lp->cb_tags[lp->ia_tag]; + ++lp->ia_tag; + if (lp->ia_tag == MAX_TAGS) + lp->ia_tag = 0; + cp->tags_si = lp->tags_si; + ++lp->tags_sum[cp->tags_si]; + } + else + goto out_free; + } + + /* + ** Put the CCB in the LUN wait queue and + ** count it as busy. + */ + xpt_insque_tail(&cp->link_ccbq, &lp->wait_ccbq); + ++lp->busyccbs; + } + + /* + ** Remember all informations needed to free this CCB. + */ + cp->to_abort = 0; + cp->tag = tag; + cp->target = tn; + cp->lun = ln; + + if (DEBUG_FLAGS & DEBUG_TAGS) { + PRINT_LUN(np, tn, ln); + printk ("ccb @%p using tag %d.\n", cp, tag); + } + +out: + return cp; +out_free: + xpt_insque_head(&cp->link_ccbq, &np->free_ccbq); + return (ccb_p) 0; +} + +/*========================================================== +** +** +** Release one control block +** +** +**========================================================== +*/ + +static void ncr_free_ccb (ncb_p np, ccb_p cp) +{ + tcb_p tp = &np->target[cp->target]; + lcb_p lp = ncr_lp(np, tp, cp->lun); + + if (DEBUG_FLAGS & DEBUG_TAGS) { + PRINT_LUN(np, cp->target, cp->lun); + printk ("ccb @%p freeing tag %d.\n", cp, cp->tag); + } + + /* + ** If lun control block available, make available + ** the task slot and the tag if any. + ** Decrement counters. + */ + if (lp) { + if (cp->tag != NO_TAG) { + lp->cb_tags[lp->if_tag++] = cp->tag; + if (lp->if_tag == MAX_TAGS) + lp->if_tag = 0; + --lp->tags_sum[cp->tags_si]; + lp->tasktbl[cp->tag] = cpu_to_scr(np->p_bad_i_t_l_q); + } else { + lp->tasktbl[0] = cpu_to_scr(np->p_bad_i_t_l); + } + --lp->busyccbs; + if (cp->queued) { + --lp->queuedccbs; + } + } + + /* + ** Make this CCB available. + */ + xpt_remque(&cp->link_ccbq); + xpt_insque_head(&cp->link_ccbq, &np->free_ccbq); + cp -> host_status = HS_IDLE; + cp -> queued = 0; +} + +/*------------------------------------------------------------------------ +** Allocate a CCB and initialize its fixed part. +**------------------------------------------------------------------------ +**------------------------------------------------------------------------ +*/ +static ccb_p ncr_alloc_ccb(ncb_p np) +{ + ccb_p cp = 0; + int hcode; + + /* + ** Allocate memory for this CCB. + */ + cp = m_calloc_dma(sizeof(struct ccb), "CCB"); + if (!cp) + return 0; + + /* + ** Count it and initialyze it. + */ + np->actccbs++; + + /* + ** Remember virtual and bus address of this ccb. + */ + cp->p_ccb = vtobus(cp); + + /* + ** Insert this ccb into the hashed list. + */ + hcode = CCB_HASH_CODE(cp->p_ccb); + cp->link_ccbh = np->ccbh[hcode]; + np->ccbh[hcode] = cp; + + /* + ** Initialyze the start and restart actions. + */ + cp->phys.header.go.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + cp->phys.header.go.restart = cpu_to_scr(NCB_SCRIPTH_PHYS(np,bad_i_t_l)); + + /* + ** Initilialyze some other fields. + */ + cp->phys.smsg_ext.addr = cpu_to_scr(NCB_PHYS(np, msgin[2])); + + /* + ** Chain into wakeup list and free ccb queue. + */ + cp->link_ccb = np->ccbc; + np->ccbc = cp; + + xpt_insque_head(&cp->link_ccbq, &np->free_ccbq); + + return cp; +} + +/*------------------------------------------------------------------------ +** Look up a CCB from a DSA value. +**------------------------------------------------------------------------ +**------------------------------------------------------------------------ +*/ +static ccb_p ncr_ccb_from_dsa(ncb_p np, u_long dsa) +{ + int hcode; + ccb_p cp; + + hcode = CCB_HASH_CODE(dsa); + cp = np->ccbh[hcode]; + while (cp) { + if (cp->p_ccb == dsa) + break; + cp = cp->link_ccbh; + } + + return cp; +} + +/*========================================================== +** +** +** Allocation of resources for Targets/Luns/Tags. +** +** +**========================================================== +*/ + + +/*------------------------------------------------------------------------ +** Target control block initialisation. +**------------------------------------------------------------------------ +** This data structure is fully initialized after a SCSI command +** has been successfully completed for this target. +**------------------------------------------------------------------------ +*/ +static void ncr_init_tcb (ncb_p np, u_char tn) +{ + /* + ** Check some alignments required by the chip. + */ + assert (( (offsetof(struct ncr_reg, nc_sxfer) ^ + offsetof(struct tcb , sval )) &3) == 0); + assert (( (offsetof(struct ncr_reg, nc_scntl3) ^ + offsetof(struct tcb , wval )) &3) == 0); + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)){ + assert (( (offsetof(struct ncr_reg, nc_scntl4) ^ + offsetof(struct tcb , uval )) &3) == 0); + } +} + +/*------------------------------------------------------------------------ +** Lun control block allocation and initialization. +**------------------------------------------------------------------------ +** This data structure is allocated and initialized after a SCSI +** command has been successfully completed for this target/lun. +**------------------------------------------------------------------------ +*/ +static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = ncr_lp(np, tp, ln); + + /* + ** Already done, return. + */ + if (lp) + return lp; + + /* + ** Initialize the target control block if not yet. + */ + ncr_init_tcb(np, tn); + + /* + ** Allocate the lcb bus address array. + ** Compute the bus address of this table. + */ + if (ln && !tp->luntbl) { + int i; + + tp->luntbl = m_calloc_dma(256, "LUNTBL"); + if (!tp->luntbl) + goto fail; + for (i = 0 ; i < 64 ; i++) + tp->luntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun)); + tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl)); + } + + /* + ** Allocate the table of pointers for LUN(s) > 0, if needed. + */ + if (ln && !tp->lmp) { + tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP"); + if (!tp->lmp) + goto fail; + } + + /* + ** Allocate the lcb. + ** Make it available to the chip. + */ + lp = m_calloc_dma(sizeof(struct lcb), "LCB"); + if (!lp) + goto fail; + if (ln) { + tp->lmp[ln] = lp; + tp->luntbl[ln] = cpu_to_scr(vtobus(lp)); + } + else { + tp->l0p = lp; + tp->b_lun0 = cpu_to_scr(vtobus(lp)); + } + + /* + ** Initialize the CCB queue headers. + */ + xpt_que_init(&lp->busy_ccbq); + xpt_que_init(&lp->wait_ccbq); + + /* + ** Set max CCBs to 1 and use the default task array + ** by default. + */ + lp->maxnxs = 1; + lp->tasktbl = &lp->tasktbl_0; + lp->b_tasktbl = cpu_to_scr(vtobus(lp->tasktbl)); + lp->tasktbl[0] = cpu_to_scr(np->p_notask); + lp->resel_task = cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_notag)); + + /* + ** Initialize command queuing control. + */ + lp->busyccbs = 1; + lp->queuedccbs = 1; + lp->queuedepth = 1; +fail: + return lp; +} + + +/*------------------------------------------------------------------------ +** Lun control block setup on INQUIRY data received. +**------------------------------------------------------------------------ +** We only support WIDE, SYNC for targets and CMDQ for logical units. +** This setup is done on each INQUIRY since we are expecting user +** will play with CHANGE DEFINITION commands. :-) +**------------------------------------------------------------------------ +*/ +static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = ncr_lp(np, tp, ln); + u_char inq_byte7; + int i; + + /* + ** If no lcb, try to allocate it. + */ + if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln))) + goto fail; + +#if 0 /* No more used. Left here as provision */ + /* + ** Get device quirks. + */ + tp->quirks = 0; + if (tp->quirks && bootverbose) { + PRINT_LUN(np, tn, ln); + printk ("quirks=%x.\n", tp->quirks); + } +#endif + + /* + ** Evaluate trustable target/unit capabilities. + ** We only believe device version >= SCSI-2 that + ** use appropriate response data format (2). + ** But it seems that some CCS devices also + ** support SYNC and I donnot want to frustrate + ** anybody. ;-) + */ + inq_byte7 = 0; + if ((inq_data[2] & 0x7) >= 2 && (inq_data[3] & 0xf) == 2) + inq_byte7 = inq_data[7]; + else if ((inq_data[2] & 0x7) == 1 && (inq_data[3] & 0xf) == 1) + inq_byte7 = INQ7_SYNC; + + /* + ** Throw away announced LUN capabilities if we are told + ** that there is no real device supported by the logical unit. + */ + if ((inq_data[0] & 0xe0) > 0x20 || (inq_data[0] & 0x1f) == 0x1f) + inq_byte7 &= (INQ7_SYNC | INQ7_WIDE16); + + /* + ** If user is wanting SYNC, force this feature. + */ + if (driver_setup.force_sync_nego) + inq_byte7 |= INQ7_SYNC; + + /* + ** Prepare negotiation if SIP capabilities have changed. + */ + tp->inq_done = 1; + if ((inq_byte7 ^ tp->inq_byte7) & (INQ7_SYNC | INQ7_WIDE16)) { + tp->inq_byte7 = inq_byte7; + ncr_negotiate(np, tp); + } + + /* + ** If unit supports tagged commands, allocate and + ** initialyze the task table if not yet. + */ + if ((inq_byte7 & INQ7_QUEUE) && lp->tasktbl == &lp->tasktbl_0) { + lp->tasktbl = m_calloc_dma(MAX_TASKS*4, "TASKTBL"); + if (!lp->tasktbl) { + lp->tasktbl = &lp->tasktbl_0; + goto fail; + } + lp->b_tasktbl = cpu_to_scr(vtobus(lp->tasktbl)); + for (i = 0 ; i < MAX_TASKS ; i++) + lp->tasktbl[i] = cpu_to_scr(np->p_notask); + + lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS"); + if (!lp->cb_tags) + goto fail; + for (i = 0 ; i < MAX_TAGS ; i++) + lp->cb_tags[i] = i; + + lp->maxnxs = MAX_TAGS; + lp->tags_stime = ktime_get(3*HZ); + } + + /* + ** Adjust tagged queueing status if needed. + */ + if ((inq_byte7 ^ lp->inq_byte7) & INQ7_QUEUE) { + lp->inq_byte7 = inq_byte7; + lp->numtags = lp->maxtags; + ncr_setup_tags (np, tn, ln); + } + +fail: + return lp; +} + +/*========================================================== +** +** +** Build Scatter Gather Block +** +** +**========================================================== +** +** The transfer area may be scattered among +** several non adjacent physical pages. +** +** We may use MAX_SCATTER blocks. +** +**---------------------------------------------------------- +*/ + +/* +** We try to reduce the number of interrupts caused +** by unexpected phase changes due to disconnects. +** A typical harddisk may disconnect before ANY block. +** If we wanted to avoid unexpected phase changes at all +** we had to use a break point every 512 bytes. +** Of course the number of scatter/gather blocks is +** limited. +** Under Linux, the scatter/gatter blocks are provided by +** the generic driver. We just have to copy addresses and +** sizes to the data segment array. +*/ + +/* +** For 64 bit systems, we use the 8 upper bits of the size field +** to provide bus address bits 32-39 to the SCRIPTS processor. +** This allows the 895A and 896 to address up to 1 TB of memory. +** For 32 bit chips on 64 bit systems, we must be provided with +** memory addresses that fit into the first 32 bit bus address +** range and so, this does not matter and we expect an error from +** the chip if this ever happen. +** +** We use a separate function for the case Linux does not provide +** a scatter list in order to allow better code optimization +** for the case we have a scatter list (BTW, for now this just wastes +** about 40 bytes of code for x86, but my guess is that the scatter +** code will get more complex later). +*/ + +#define SCATTER_ONE(data, badd, len) \ + (data)->addr = cpu_to_scr(badd); \ + (data)->size = cpu_to_scr((((badd) >> 8) & 0xff000000) + len); + +#define CROSS_16MB(p, n) (((((u_long) p) + n - 1) ^ ((u_long) p)) & ~0xffffff) + +static int ncr_scatter_no_sglist(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) +{ + struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER-1]; + int segment; + + cp->data_len = cmd->request_bufflen; + + if (cmd->request_bufflen) { + dma_addr_t baddr = map_scsi_single_data(np, cmd); + + SCATTER_ONE(data, baddr, cmd->request_bufflen); + if (CROSS_16MB(baddr, cmd->request_bufflen)) { + cp->host_flags |= HF_PM_TO_C; +#ifdef DEBUG_896R1 +printk("He! we are crossing a 16 MB boundary (0x%lx, 0x%x)\n", + baddr, cmd->request_bufflen); +#endif + } + segment = 1; + } + else + segment = 0; + + return segment; +} + +/* +** DEL 472 - 53C896 Rev 1 - Part Number 609-0393055 - ITEM 5. +** +** We disable data phase mismatch handling from SCRIPTS for data +** transfers that contains scatter/gather entries that cross +** a 16 MB boundary. +** We use a different scatter function for 896 rev. 1 that needs +** such a work-around. Doing so, we do not affect performance for +** other chips. +** This problem should not be triggered for disk IOs under Linux, +** since such IOs are performed using pages and buffers that are +** nicely power-of-two sized and aligned. But, since this may change +** at any time, a work-around was required. +*/ +static int ncr_scatter_896R1(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) +{ + int segn; + int use_sg = (int) cmd->use_sg; + + cp->data_len = 0; + + if (!use_sg) + segn = ncr_scatter_no_sglist(np, cp, cmd); + else { + struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; + struct scr_tblmove *data; + + use_sg = map_scsi_sg_data(np, cmd); + if (use_sg > MAX_SCATTER) { + unmap_scsi_data(np, cmd); + return -1; + } + + data = &cp->phys.data[MAX_SCATTER - use_sg]; + + for (segn = 0; segn < use_sg; segn++) { + dma_addr_t baddr = scsi_sg_dma_address(&scatter[segn]); + unsigned int len = scsi_sg_dma_len(&scatter[segn]); + + SCATTER_ONE(&data[segn], + baddr, + len); + if (CROSS_16MB(baddr, scatter[segn].length)) { + cp->host_flags |= HF_PM_TO_C; +#ifdef DEBUG_896R1 +printk("He! we are crossing a 16 MB boundary (0x%lx, 0x%x)\n", + baddr, scatter[segn].length); +#endif + } + cp->data_len += len; + } + } + + return segn; +} + +static int ncr_scatter(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) +{ + int segment; + int use_sg = (int) cmd->use_sg; + + cp->data_len = 0; + + if (!use_sg) + segment = ncr_scatter_no_sglist(np, cp, cmd); + else { + struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; + struct scr_tblmove *data; + + use_sg = map_scsi_sg_data(np, cmd); + if (use_sg > MAX_SCATTER) { + unmap_scsi_data(np, cmd); + return -1; + } + data = &cp->phys.data[MAX_SCATTER - use_sg]; + + for (segment = 0; segment < use_sg; segment++) { + dma_addr_t baddr = scsi_sg_dma_address(&scatter[segment]); + unsigned int len = scsi_sg_dma_len(&scatter[segment]); + + SCATTER_ONE(&data[segment], + baddr, + len); + cp->data_len += len; + } + } + + return segment; +} + +/*========================================================== +** +** +** Test the pci bus snoop logic :-( +** +** Has to be called with interrupts disabled. +** +** +**========================================================== +*/ + +#ifndef SCSI_NCR_IOMAPPED +static int __init ncr_regtest (struct ncb* np) +{ + register volatile u_int32 data; + /* + ** ncr registers may NOT be cached. + ** write 0xffffffff to a read only register area, + ** and try to read it back. + */ + data = 0xffffffff; + OUTL_OFF(offsetof(struct ncr_reg, nc_dstat), data); + data = INL_OFF(offsetof(struct ncr_reg, nc_dstat)); +#if 1 + if (data == 0xffffffff) { +#else + if ((data & 0xe2f0fffd) != 0x02000080) { +#endif + printk ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", + (unsigned) data); + return (0x10); + }; + return (0); +} +#endif + +static int __init ncr_snooptest (struct ncb* np) +{ + u_int32 ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc; + u_char dstat; + int i, err=0; +#ifndef SCSI_NCR_IOMAPPED + if (np->reg) { + err |= ncr_regtest (np); + if (err) return (err); + } +#endif +restart_test: + /* + ** Enable Master Parity Checking as we intend + ** to enable it for normal operations. + */ + OUTB (nc_ctest4, (np->rv_ctest4 & MPEE)); + /* + ** init + */ + pc = NCB_SCRIPTH0_PHYS (np, snooptest); + host_wr = 1; + ncr_wr = 2; + /* + ** Set memory and register. + */ + np->ncr_cache = cpu_to_scr(host_wr); + OUTL (nc_temp, ncr_wr); + /* + ** Start script (exchange values) + */ + OUTL (nc_dsa, np->p_ncb); + OUTL_DSP (pc); + /* + ** Wait 'til done (with timeout) + */ + for (i=0; i=NCR_SNOOP_TIMEOUT) { + printk ("CACHE TEST FAILED: timeout.\n"); + return (0x20); + }; + /* + ** Check for fatal DMA errors. + */ + dstat = INB (nc_dstat); +#if 1 /* Band aiding for broken hardwares that fail PCI parity */ + if ((dstat & MDPE) && (np->rv_ctest4 & MPEE)) { + printk ("%s: PCI DATA PARITY ERROR DETECTED - " + "DISABLING MASTER DATA PARITY CHECKING.\n", + ncr_name(np)); + np->rv_ctest4 &= ~MPEE; + goto restart_test; + } +#endif + if (dstat & (MDPE|BF|IID)) { + printk ("CACHE TEST FAILED: DMA error (dstat=0x%02x).", dstat); + return (0x80); + } + /* + ** Save termination position. + */ + pc = INL (nc_dsp); + /* + ** Read memory and register. + */ + host_rd = scr_to_cpu(np->ncr_cache); + ncr_rd = INL (nc_scratcha); + ncr_bk = INL (nc_temp); + /* + ** Check termination position. + */ + if (pc != NCB_SCRIPTH0_PHYS (np, snoopend)+8) { + printk ("CACHE TEST FAILED: script execution failed.\n"); + printk ("start=%08lx, pc=%08lx, end=%08lx\n", + (u_long) NCB_SCRIPTH0_PHYS (np, snooptest), (u_long) pc, + (u_long) NCB_SCRIPTH0_PHYS (np, snoopend) +8); + return (0x40); + }; + /* + ** Show results. + */ + if (host_wr != ncr_rd) { + printk ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n", + (int) host_wr, (int) ncr_rd); + err |= 1; + }; + if (host_rd != ncr_wr) { + printk ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n", + (int) ncr_wr, (int) host_rd); + err |= 2; + }; + if (ncr_bk != ncr_wr) { + printk ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n", + (int) ncr_wr, (int) ncr_bk); + err |= 4; + }; + return (err); +} + +/*========================================================== +** +** Determine the ncr's clock frequency. +** This is essential for the negotiation +** of the synchronous transfer rate. +** +**========================================================== +** +** Note: we have to return the correct value. +** THERE IS NO SAFE DEFAULT VALUE. +** +** Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock. +** 53C860 and 53C875 rev. 1 support fast20 transfers but +** do not have a clock doubler and so are provided with a +** 80 MHz clock. All other fast20 boards incorporate a doubler +** and so should be delivered with a 40 MHz clock. +** The recent fast40 chips (895/896/895A) and the +** fast80 chip (C1010) use a 40 Mhz base clock +** and provide a clock quadrupler (160 Mhz). The code below +** tries to deal as cleverly as possible with all this stuff. +** +**---------------------------------------------------------- +*/ + +/* + * Select NCR SCSI clock frequency + */ +static void ncr_selectclock(ncb_p np, u_char scntl3) +{ + if (np->multiplier < 2) { + OUTB(nc_scntl3, scntl3); + return; + } + + if (bootverbose >= 2) + printk ("%s: enabling clock multiplier\n", ncr_name(np)); + + OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */ + + if ( (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && + (np->multiplier > 2)) { + int i = 20; /* Poll bit 5 of stest4 for quadrupler */ + while (!(INB(nc_stest4) & LCKFRQ) && --i > 0) + UDELAY (20); + if (!i) + printk("%s: the chip cannot lock the frequency\n", + ncr_name(np)); + + } else /* Wait 120 micro-seconds for multiplier*/ + UDELAY (120); + + OUTB(nc_stest3, HSC); /* Halt the scsi clock */ + OUTB(nc_scntl3, scntl3); + OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ + OUTB(nc_stest3, 0x00); /* Restart scsi clock */ +} + + +/* + * calculate NCR SCSI clock frequency (in KHz) + */ +static unsigned __init ncrgetfreq (ncb_p np, int gen) +{ + unsigned int ms = 0; + unsigned int f; + int count; + + /* + * Measure GEN timer delay in order + * to calculate SCSI clock frequency + * + * This code will never execute too + * many loop iterations (if DELAY is + * reasonably correct). It could get + * too low a delay (too high a freq.) + * if the CPU is slow executing the + * loop for some reason (an NMI, for + * example). For this reason we will + * if multiple measurements are to be + * performed trust the higher delay + * (lower frequency returned). + */ + OUTW (nc_sien , 0x0);/* mask all scsi interrupts */ + /* enable general purpose timer */ + (void) INW (nc_sist); /* clear pending scsi interrupt */ + OUTB (nc_dien , 0); /* mask all dma interrupts */ + (void) INW (nc_sist); /* another one, just to be sure :) */ + OUTB (nc_scntl3, 4); /* set pre-scaler to divide by 3 */ + OUTB (nc_stime1, 0); /* disable general purpose timer */ + OUTB (nc_stime1, gen); /* set to nominal delay of 1<= 2) + printk ("%s: Delay (GEN=%d): %u msec, %u KHz\n", + ncr_name(np), gen, ms, f); + + return f; +} + +static unsigned __init ncr_getfreq (ncb_p np) +{ + u_int f1, f2; + int gen = 11; + + (void) ncrgetfreq (np, gen); /* throw away first result */ + f1 = ncrgetfreq (np, gen); + f2 = ncrgetfreq (np, gen); + if (f1 > f2) f1 = f2; /* trust lower result */ + return f1; +} + +/* + * Get/probe NCR SCSI clock frequency + */ +static void __init ncr_getclock (ncb_p np, int mult) +{ + unsigned char scntl3 = np->sv_scntl3; + unsigned char stest1 = np->sv_stest1; + unsigned f1; + + np->multiplier = 1; + f1 = 40000; + + /* + ** True with 875/895/896/895A with clock multiplier selected + */ + if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) { + if (bootverbose >= 2) + printk ("%s: clock multiplier found\n", ncr_name(np)); + np->multiplier = mult; + } + + /* + ** If multiplier not found or scntl3 not 7,5,3, + ** reset chip and get frequency from general purpose timer. + ** Otherwise trust scntl3 BIOS setting. + */ + if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { + OUTB (nc_stest1, 0); /* make sure doubler is OFF */ + f1 = ncr_getfreq (np); + + if (bootverbose) + printk ("%s: NCR clock is %uKHz\n", ncr_name(np), f1); + + if (f1 < 55000) f1 = 40000; + else f1 = 80000; + + /* + ** Suggest to also check the PCI clock frequency + ** to make sure our frequency calculation algorithm + ** is not too biased. + */ + if (np->features & FE_66MHZ) { + np->pciclock_min = (66000*55+80-1)/80; + np->pciclock_max = (66000*55)/40; + } + else { + np->pciclock_min = (33000*55+80-1)/80; + np->pciclock_max = (33000*55)/40; + } + + if (f1 == 40000 && mult > 1) { + if (bootverbose >= 2) + printk ("%s: clock multiplier assumed\n", ncr_name(np)); + np->multiplier = mult; + } + } else { + if ((scntl3 & 7) == 3) f1 = 40000; + else if ((scntl3 & 7) == 5) f1 = 80000; + else f1 = 160000; + + f1 /= np->multiplier; + } + + /* + ** Compute controller synchronous parameters. + */ + f1 *= np->multiplier; + np->clock_khz = f1; +} + +/* + * Get/probe PCI clock frequency + */ +static u_int __init ncr_getpciclock (ncb_p np) +{ + static u_int f; + + OUTB (nc_stest1, SCLK); /* Use the PCI clock as SCSI clock */ + f = ncr_getfreq (np); + OUTB (nc_stest1, 0); + + return f; +} + +/*===================== LINUX ENTRY POINTS SECTION ==========================*/ + +#ifndef uchar +#define uchar unsigned char +#endif + +#ifndef ushort +#define ushort unsigned short +#endif + +#ifndef ulong +#define ulong unsigned long +#endif + +/* --------------------------------------------------------------------- +** +** Driver setup from the boot command line +** +** --------------------------------------------------------------------- +*/ + +#ifdef MODULE +#define ARG_SEP ' ' +#else +#define ARG_SEP ',' +#endif + +#define OPT_TAGS 1 +#define OPT_MASTER_PARITY 2 +#define OPT_SCSI_PARITY 3 +#define OPT_DISCONNECTION 4 +#define OPT_SPECIAL_FEATURES 5 +#define OPT_RESERVED_1 6 +#define OPT_FORCE_SYNC_NEGO 7 +#define OPT_REVERSE_PROBE 8 +#define OPT_DEFAULT_SYNC 9 +#define OPT_VERBOSE 10 +#define OPT_DEBUG 11 +#define OPT_BURST_MAX 12 +#define OPT_LED_PIN 13 +#define OPT_MAX_WIDE 14 +#define OPT_SETTLE_DELAY 15 +#define OPT_DIFF_SUPPORT 16 +#define OPT_IRQM 17 +#define OPT_PCI_FIX_UP 18 +#define OPT_BUS_CHECK 19 +#define OPT_OPTIMIZE 20 +#define OPT_RECOVERY 21 +#define OPT_SAFE_SETUP 22 +#define OPT_USE_NVRAM 23 +#define OPT_EXCLUDE 24 +#define OPT_HOST_ID 25 + +#ifdef SCSI_NCR_IARB_SUPPORT +#define OPT_IARB 26 +#endif + +static char setup_token[] __initdata = + "tags:" "mpar:" + "spar:" "disc:" + "specf:" "_rsvd1:" + "fsn:" "revprob:" + "sync:" "verb:" + "debug:" "burst:" + "led:" "wide:" + "settle:" "diff:" + "irqm:" "pcifix:" + "buschk:" "optim:" + "recovery:" + "safe:" "nvram:" + "excl:" "hostid:" +#ifdef SCSI_NCR_IARB_SUPPORT + "iarb:" +#endif + ; /* DONNOT REMOVE THIS ';' */ + +#ifdef MODULE +#define ARG_SEP ' ' +#else +#define ARG_SEP ',' +#endif + +static int __init get_setup_token(char *p) +{ + char *cur = setup_token; + char *pc; + int i = 0; + + while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { + ++pc; + ++i; + if (!strncmp(p, cur, pc - cur)) + return i; + cur = pc; + } + return 0; +} + + +int __init sym53c8xx_setup(char *str) +{ +#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT + char *cur = str; + char *pc, *pv; + unsigned long val; + int i, c; + int xi = 0; + + while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { + char *pe; + + val = 0; + pv = pc; + c = *++pv; + + if (c == 'n') + val = 0; + else if (c == 'y') + val = 1; + else + val = (int) simple_strtoul(pv, &pe, 0); + + switch (get_setup_token(cur)) { + case OPT_TAGS: + driver_setup.default_tags = val; + if (pe && *pe == '/') { + i = 0; + while (*pe && *pe != ARG_SEP && + i < sizeof(driver_setup.tag_ctrl)-1) { + driver_setup.tag_ctrl[i++] = *pe++; + } + driver_setup.tag_ctrl[i] = '\0'; + } + break; + case OPT_MASTER_PARITY: + driver_setup.master_parity = val; + break; + case OPT_SCSI_PARITY: + driver_setup.scsi_parity = val; + break; + case OPT_DISCONNECTION: + driver_setup.disconnection = val; + break; + case OPT_SPECIAL_FEATURES: + driver_setup.special_features = val; + break; + case OPT_FORCE_SYNC_NEGO: + driver_setup.force_sync_nego = val; + break; + case OPT_REVERSE_PROBE: + driver_setup.reverse_probe = val; + break; + case OPT_DEFAULT_SYNC: + driver_setup.default_sync = val; + break; + case OPT_VERBOSE: + driver_setup.verbose = val; + break; + case OPT_DEBUG: + driver_setup.debug = val; + break; + case OPT_BURST_MAX: + driver_setup.burst_max = val; + break; + case OPT_LED_PIN: + driver_setup.led_pin = val; + break; + case OPT_MAX_WIDE: + driver_setup.max_wide = val? 1:0; + break; + case OPT_SETTLE_DELAY: + driver_setup.settle_delay = val; + break; + case OPT_DIFF_SUPPORT: + driver_setup.diff_support = val; + break; + case OPT_IRQM: + driver_setup.irqm = val; + break; + case OPT_PCI_FIX_UP: + driver_setup.pci_fix_up = val; + break; + case OPT_BUS_CHECK: + driver_setup.bus_check = val; + break; + case OPT_OPTIMIZE: + driver_setup.optimize = val; + break; + case OPT_RECOVERY: + driver_setup.recovery = val; + break; + case OPT_USE_NVRAM: + driver_setup.use_nvram = val; + break; + case OPT_SAFE_SETUP: + memcpy(&driver_setup, &driver_safe_setup, + sizeof(driver_setup)); + break; + case OPT_EXCLUDE: + if (xi < SCSI_NCR_MAX_EXCLUDES) + driver_setup.excludes[xi++] = val; + break; + case OPT_HOST_ID: + driver_setup.host_id = val; + break; +#ifdef SCSI_NCR_IARB_SUPPORT + case OPT_IARB: + driver_setup.iarb = val; + break; +#endif + default: + printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur); + break; + } + + if ((cur = strchr(cur, ARG_SEP)) != NULL) + ++cur; + } +#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */ + return 1; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) +#ifndef MODULE +__setup("sym53c8xx=", sym53c8xx_setup); +#endif +#endif + +static int +sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device); + +/* +** Linux entry point for SYM53C8XX devices detection routine. +** +** Called by the middle-level scsi drivers at initialization time, +** or at module installation. +** +** Read the PCI configuration and try to attach each +** detected NCR board. +** +** If NVRAM is present, try to attach boards according to +** the used defined boot order. +** +** Returns the number of boards successfully attached. +*/ + +static void __init ncr_print_driver_setup(void) +{ +#define YesNo(y) y ? 'y' : 'n' + printk (NAME53C8XX ": setup=disc:%c,specf:%d,tags:%d,sync:%d," + "burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n", + YesNo(driver_setup.disconnection), + driver_setup.special_features, + driver_setup.default_tags, + driver_setup.default_sync, + driver_setup.burst_max, + YesNo(driver_setup.max_wide), + driver_setup.diff_support, + YesNo(driver_setup.reverse_probe), + driver_setup.bus_check); + + printk (NAME53C8XX ": setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x," + "led:%c,settle:%d,irqm:0x%x,nvram:0x%x,pcifix:0x%x\n", + YesNo(driver_setup.master_parity), + YesNo(driver_setup.scsi_parity), + YesNo(driver_setup.force_sync_nego), + driver_setup.verbose, + driver_setup.debug, + YesNo(driver_setup.led_pin), + driver_setup.settle_delay, + driver_setup.irqm, + driver_setup.use_nvram, + driver_setup.pci_fix_up); +#undef YesNo +} + +/*=================================================================== +** SYM53C8XX devices description table and chip ids list. +**=================================================================== +*/ + +static ncr_chip ncr_chip_table[] __initdata = SCSI_NCR_CHIP_TABLE; +static ushort ncr_chip_ids[] __initdata = SCSI_NCR_CHIP_IDS; + +#ifdef SCSI_NCR_PQS_PDS_SUPPORT +/*=================================================================== +** Detect all NCR PQS/PDS boards and keep track of their bus nr. +** +** The NCR PQS or PDS card is constructed as a DEC bridge +** behind which sit a proprietary NCR memory controller and +** four or two 53c875s as separate devices. In its usual mode +** of operation, the 875s are slaved to the memory controller +** for all transfers. We can tell if an 875 is part of a +** PQS/PDS or not since if it is, it will be on the same bus +** as the memory controller. To operate with the Linux +** driver, the memory controller is disabled and the 875s +** freed to function independently. The only wrinkle is that +** the preset SCSI ID (which may be zero) must be read in from +** a special configuration space register of the 875 +**=================================================================== +*/ +#define SCSI_NCR_MAX_PQS_BUS 16 +static int pqs_bus[SCSI_NCR_MAX_PQS_BUS] __initdata = { 0 }; + +static void __init ncr_detect_pqs_pds(void) +{ + short index; + pcidev_t dev = PCIDEV_NULL; + + for(index=0; index < SCSI_NCR_MAX_PQS_BUS; index++) { + u_char tmp; + + dev = pci_find_device(0x101a, 0x0009, dev); + if (dev == PCIDEV_NULL) { + pqs_bus[index] = -1; + break; + } + printk(KERN_INFO NAME53C8XX ": NCR PQS/PDS memory controller detected on bus %d\n", PciBusNumber(dev)); + pci_read_config_byte(dev, 0x44, &tmp); + /* bit 1: allow individual 875 configuration */ + tmp |= 0x2; + pci_write_config_byte(dev, 0x44, tmp); + pci_read_config_byte(dev, 0x45, &tmp); + /* bit 2: drive individual 875 interrupts to the bus */ + tmp |= 0x4; + pci_write_config_byte(dev, 0x45, tmp); + + pqs_bus[index] = PciBusNumber(dev); + } +} +#endif /* SCSI_NCR_PQS_PDS_SUPPORT */ + +/*=================================================================== +** Detect all 53c8xx hosts and then attach them. +** +** If we are using NVRAM, once all hosts are detected, we need to +** check any NVRAM for boot order in case detect and boot order +** differ and attach them using the order in the NVRAM. +** +** If no NVRAM is found or data appears invalid attach boards in +** the order they are detected. +**=================================================================== +*/ +int __init sym53c8xx_detect(Scsi_Host_Template *tpnt) +{ + pcidev_t pcidev; + int i, j, chips, hosts, count; + int attach_count = 0; + ncr_device *devtbl, *devp; +#ifdef SCSI_NCR_NVRAM_SUPPORT + ncr_nvram nvram0, nvram, *nvp; +#endif + + /* + ** PCI is required. + */ + if (!pci_present()) + return 0; + + /* + ** Initialize driver general stuff. + */ +#ifdef SCSI_NCR_PROC_INFO_SUPPORT +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,27) + tpnt->proc_dir = &proc_scsi_sym53c8xx; +#else + tpnt->proc_name = NAME53C8XX; +#endif + tpnt->proc_info = sym53c8xx_proc_info; +#endif + +#if defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE) +if (sym53c8xx) + sym53c8xx_setup(sym53c8xx); +#endif +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT + ncr_debug = driver_setup.debug; +#endif + + if (initverbose >= 2) + ncr_print_driver_setup(); + + /* + ** Allocate the device table since we donnot want to + ** overflow the kernel stack. + ** 1 x 4K PAGE is enough for more than 40 devices for i386. + */ + devtbl = m_calloc(PAGE_SIZE, "devtbl"); + if (!devtbl) + return 0; + + /* + ** Detect all NCR PQS/PDS memory controllers. + */ +#ifdef SCSI_NCR_PQS_PDS_SUPPORT + ncr_detect_pqs_pds(); +#endif + + /* + ** Detect all 53c8xx hosts. + ** Save the first Symbios NVRAM content if any + ** for the boot order. + */ + chips = sizeof(ncr_chip_ids) / sizeof(ncr_chip_ids[0]); + hosts = PAGE_SIZE / sizeof(*devtbl); +#ifdef SCSI_NCR_NVRAM_SUPPORT + nvp = (driver_setup.use_nvram & 0x1) ? &nvram0 : 0; +#endif + j = 0; + count = 0; + pcidev = PCIDEV_NULL; + while (1) { + char *msg = ""; + if (count >= hosts) + break; + if (j >= chips) + break; + i = driver_setup.reverse_probe ? chips - 1 - j : j; + pcidev = pci_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i], + pcidev); + if (pcidev == PCIDEV_NULL) { + ++j; + continue; + } + if (pci_enable_device(pcidev)) /* @!*!$&*!%-*#;! */ + continue; + /* Some HW as the HP LH4 may report twice PCI devices */ + for (i = 0; i < count ; i++) { + if (devtbl[i].slot.bus == PciBusNumber(pcidev) && + devtbl[i].slot.device_fn == PciDeviceFn(pcidev)) + break; + } + if (i != count) /* Ignore this device if we already have it */ + continue; + pci_set_master(pcidev); + devp = &devtbl[count]; + devp->host_id = driver_setup.host_id; + devp->attach_done = 0; + if (sym53c8xx_pci_init(tpnt, pcidev, devp)) { + continue; + } + ++count; +#ifdef SCSI_NCR_NVRAM_SUPPORT + if (nvp) { + ncr_get_nvram(devp, nvp); + switch(nvp->type) { + case SCSI_NCR_SYMBIOS_NVRAM: + /* + * Switch to the other nvram buffer, so that + * nvram0 will contain the first Symbios + * format NVRAM content with boot order. + */ + nvp = &nvram; + msg = "with Symbios NVRAM"; + break; + case SCSI_NCR_TEKRAM_NVRAM: + msg = "with Tekram NVRAM"; + break; + } + } +#endif +#ifdef SCSI_NCR_PQS_PDS_SUPPORT + if (devp->pqs_pds) + msg = "(NCR PQS/PDS)"; +#endif + printk(KERN_INFO NAME53C8XX ": 53c%s detected %s\n", + devp->chip.name, msg); + } + + /* + ** If we have found a SYMBIOS NVRAM, use first the NVRAM boot + ** sequence as device boot order. + ** check devices in the boot record against devices detected. + ** attach devices if we find a match. boot table records that + ** do not match any detected devices will be ignored. + ** devices that do not match any boot table will not be attached + ** here but will attempt to be attached during the device table + ** rescan. + */ +#ifdef SCSI_NCR_NVRAM_SUPPORT + if (!nvp || nvram0.type != SCSI_NCR_SYMBIOS_NVRAM) + goto next; + for (i = 0; i < 4; i++) { + Symbios_host *h = &nvram0.data.Symbios.host[i]; + for (j = 0 ; j < count ; j++) { + devp = &devtbl[j]; + if (h->device_fn != devp->slot.device_fn || + h->bus_nr != devp->slot.bus || + h->device_id != devp->chip.device_id) + continue; + if (devp->attach_done) + continue; + if (h->flags & SYMBIOS_INIT_SCAN_AT_BOOT) { + ncr_get_nvram(devp, nvp); + if (!ncr_attach (tpnt, attach_count, devp)) + attach_count++; + } + else if (!(driver_setup.use_nvram & 0x80)) + printk(KERN_INFO NAME53C8XX + ": 53c%s state OFF thus not attached\n", + devp->chip.name); + else + continue; + + devp->attach_done = 1; + break; + } + } +next: +#endif + + /* + ** Rescan device list to make sure all boards attached. + ** Devices without boot records will not be attached yet + ** so try to attach them here. + */ + for (i= 0; i < count; i++) { + devp = &devtbl[i]; + if (!devp->attach_done) { +#ifdef SCSI_NCR_NVRAM_SUPPORT + ncr_get_nvram(devp, nvp); +#endif + if (!ncr_attach (tpnt, attach_count, devp)) + attach_count++; + } + } + + m_free(devtbl, PAGE_SIZE, "devtbl"); + + return attach_count; +} + +/*=================================================================== +** Read and check the PCI configuration for any detected NCR +** boards and save data for attaching after all boards have +** been detected. +**=================================================================== +*/ +static int __init +sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device) +{ + u_short vendor_id, device_id, command, status_reg; + u_char cache_line_size, latency_timer; + u_char suggested_cache_line_size = 0; + u_char pci_fix_up = driver_setup.pci_fix_up; + u_char revision; + u_int irq; + u_long base, base_c, base_2, base_2_c, io_port; + int i; + ncr_chip *chip; + + printk(KERN_INFO NAME53C8XX ": at PCI bus %d, device %d, function %d\n", + PciBusNumber(pdev), + (int) (PciDeviceFn(pdev) & 0xf8) >> 3, + (int) (PciDeviceFn(pdev) & 7)); + + /* + ** Read info from the PCI config space. + ** pci_read_config_xxx() functions are assumed to be used for + ** successfully detected PCI devices. + */ + vendor_id = PciVendorId(pdev); + device_id = PciDeviceId(pdev); + irq = PciIrqLine(pdev); + + i = pci_get_base_address(pdev, 0, &io_port); + io_port = pci_get_base_cookie(pdev, 0); + + base_c = pci_get_base_cookie(pdev, i); + i = pci_get_base_address(pdev, i, &base); + + base_2_c = pci_get_base_cookie(pdev, i); + (void) pci_get_base_address(pdev, i, &base_2); + + pci_read_config_word(pdev, PCI_COMMAND, &command); + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer); + pci_read_config_word(pdev, PCI_STATUS, &status_reg); + +#ifdef SCSI_NCR_PQS_PDS_SUPPORT + /* + ** Match the BUS number for PQS/PDS devices. + ** Read the SCSI ID from a special register mapped + ** into the configuration space of the individual + ** 875s. This register is set up by the PQS bios + */ + for(i = 0; i < SCSI_NCR_MAX_PQS_BUS && pqs_bus[i] != -1; i++) { + u_char tmp; + if (pqs_bus[i] == PciBusNumber(pdev)) { + pci_read_config_byte(pdev, 0x84, &tmp); + device->pqs_pds = 1; + device->host_id = tmp; + break; + } + } +#endif /* SCSI_NCR_PQS_PDS_SUPPORT */ + + /* + ** If user excludes this chip, donnot initialize it. + */ + for (i = 0 ; i < SCSI_NCR_MAX_EXCLUDES ; i++) { + if (driver_setup.excludes[i] == + (io_port & PCI_BASE_ADDRESS_IO_MASK)) + return -1; + } + /* + ** Check if the chip is supported + */ + chip = 0; + for (i = 0; i < sizeof(ncr_chip_table)/sizeof(ncr_chip_table[0]); i++) { + if (device_id != ncr_chip_table[i].device_id) + continue; + if (revision > ncr_chip_table[i].revision_id) + continue; + if (!(ncr_chip_table[i].features & FE_LDSTR)) + break; + chip = &device->chip; + memcpy(chip, &ncr_chip_table[i], sizeof(*chip)); + chip->revision_id = revision; + break; + } + +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + /* Configure DMA attributes. For DAC capable boards, we can encode + ** 32+8 bits for SCSI DMA data addresses with the extra bits used + ** in the size field. We use normal 32-bit PCI addresses for + ** descriptors. + */ + if (chip && (chip->features & FE_DAC)) { + if (pci_set_dma_mask(pdev, (u64) 0xffffffffff)) + chip->features &= ~FE_DAC_IN_USE; + else + chip->features |= FE_DAC_IN_USE; + } + + if (chip && !(chip->features & FE_DAC_IN_USE)) { + if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) { + printk(KERN_WARNING NAME53C8XX + "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); + return -1; + } + } +#endif + + /* + ** Ignore Symbios chips controlled by SISL RAID controller. + ** This controller sets value 0x52414944 at RAM end - 16. + */ +#if defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED) + if (chip && (base_2_c & PCI_BASE_ADDRESS_MEM_MASK)) { + unsigned int ram_size, ram_val; + u_long ram_ptr; + + if (chip->features & FE_RAM8K) + ram_size = 8192; + else + ram_size = 4096; + + ram_ptr = remap_pci_mem(base_2_c & PCI_BASE_ADDRESS_MEM_MASK, + ram_size); + if (ram_ptr) { + ram_val = readl_raw(ram_ptr + ram_size - 16); + unmap_pci_mem(ram_ptr, ram_size); + if (ram_val == 0x52414944) { + printk(NAME53C8XX": not initializing, " + "driven by SISL RAID controller.\n"); + return -1; + } + } + } +#endif /* i386 and PCI MEMORY accessible */ + + if (!chip) { + printk(NAME53C8XX ": not initializing, device not supported\n"); + return -1; + } + +#if defined(__powerpc__) || defined(__hppa__) + /* + ** Fix-up for power/pc and hppa. + ** Should not be performed by the driver. + */ + if ((command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) + != (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { + printk(NAME53C8XX ": setting%s%s...\n", + (command & PCI_COMMAND_IO) ? "" : " PCI_COMMAND_IO", + (command & PCI_COMMAND_MEMORY) ? "" : " PCI_COMMAND_MEMORY"); + command |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(pdev, PCI_COMMAND, command); + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) + if ( is_prep ) { + if (io_port >= 0x10000000) { + printk(NAME53C8XX ": reallocating io_port (Wacky IBM)"); + io_port = (io_port & 0x00FFFFFF) | 0x01000000; + pci_write_config_dword(pdev, + PCI_BASE_ADDRESS_0, io_port); + } + if (base >= 0x10000000) { + printk(NAME53C8XX ": reallocating base (Wacky IBM)"); + base = (base & 0x00FFFFFF) | 0x01000000; + pci_write_config_dword(pdev, + PCI_BASE_ADDRESS_1, base); + } + if (base_2 >= 0x10000000) { + printk(NAME53C8XX ": reallocating base2 (Wacky IBM)"); + base_2 = (base_2 & 0x00FFFFFF) | 0x01000000; + pci_write_config_dword(pdev, + PCI_BASE_ADDRESS_2, base_2); + } + } +#endif +#endif /* __powerpc__ */ + +#if defined(__i386__) && !defined(MODULE) + if (!cache_line_size) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,75) + extern char x86; + switch(x86) { +#else + switch(boot_cpu_data.x86) { +#endif + case 4: suggested_cache_line_size = 4; break; + case 6: + case 5: suggested_cache_line_size = 8; break; + } + } +#endif /* __i386__ */ + + /* + ** Check availability of IO space, memory space. + ** Enable master capability if not yet. + ** + ** We shouldn't have to care about the IO region when + ** we are using MMIO. But calling check_region() from + ** both the ncr53c8xx and the sym53c8xx drivers prevents + ** from attaching devices from the both drivers. + ** If you have a better idea, let me know. + */ +/* #ifdef SCSI_NCR_IOMAPPED */ +#if 1 + if (!(command & PCI_COMMAND_IO)) { + printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n", + (long) io_port); + io_port = 0; + } +#endif + if (!(command & PCI_COMMAND_MEMORY)) { + printk(NAME53C8XX ": PCI_COMMAND_MEMORY not set.\n"); + base = 0; + base_2 = 0; + } + io_port &= PCI_BASE_ADDRESS_IO_MASK; + base &= PCI_BASE_ADDRESS_MEM_MASK; + base_2 &= PCI_BASE_ADDRESS_MEM_MASK; + +/* #ifdef SCSI_NCR_IOMAPPED */ +#if 1 + if (io_port && check_region (io_port, 128)) { + printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n", + (long) io_port); + io_port = 0; + } + if (!io_port) + return -1; +#endif +#ifndef SCSI_NCR_IOMAPPED + if (!base) { + printk(NAME53C8XX ": MMIO base address disabled.\n"); + return -1; + } +#endif + + /* + ** Set MASTER capable and PARITY bit, if not yet. + */ + if ((command & (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY)) + != (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY)) { + printk(NAME53C8XX ": setting%s%s...(fix-up)\n", + (command & PCI_COMMAND_MASTER) ? "" : " PCI_COMMAND_MASTER", + (command & PCI_COMMAND_PARITY) ? "" : " PCI_COMMAND_PARITY"); + command |= (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY); + pci_write_config_word(pdev, PCI_COMMAND, command); + } + + /* + ** Fix some features according to driver setup. + */ + if (!(driver_setup.special_features & 1)) + chip->features &= ~FE_SPECIAL_SET; + else { + if (driver_setup.special_features & 2) + chip->features &= ~FE_WRIE; + if (driver_setup.special_features & 4) + chip->features &= ~FE_NOPM; + } + + /* + ** Work around for errant bit in 895A. The 66Mhz + ** capable bit is set erroneously. Clear this bit. + ** (Item 1 DEL 533) + ** + ** Make sure Config space and Features agree. + ** + ** Recall: writes are not normal to status register - + ** write a 1 to clear and a 0 to leave unchanged. + ** Can only reset bits. + */ + if (chip->features & FE_66MHZ) { + if (!(status_reg & PCI_STATUS_66MHZ)) + chip->features &= ~FE_66MHZ; + } + else { + if (status_reg & PCI_STATUS_66MHZ) { + status_reg = PCI_STATUS_66MHZ; + pci_write_config_word(pdev, PCI_STATUS, status_reg); + pci_read_config_word(pdev, PCI_STATUS, &status_reg); + } + } + + /* + ** Some features are required to be enabled in order to + ** work around some chip problems. :) ;) + ** (ITEM 12 of a DEL about the 896 I haven't yet). + ** We must ensure the chip will use WRITE AND INVALIDATE. + ** The revision number limit is for now arbitrary. + */ + if (device_id == PCI_DEVICE_ID_NCR_53C896 && revision <= 0x10) { + chip->features |= (FE_WRIE | FE_CLSE); + pci_fix_up |= 3; /* Force appropriate PCI fix-up */ + } + +#ifdef SCSI_NCR_PCI_FIX_UP_SUPPORT + /* + ** Try to fix up PCI config according to wished features. + */ + if ((pci_fix_up & 1) && (chip->features & FE_CLSE) && + !cache_line_size && suggested_cache_line_size) { + cache_line_size = suggested_cache_line_size; + pci_write_config_byte(pdev, + PCI_CACHE_LINE_SIZE, cache_line_size); + printk(NAME53C8XX ": PCI_CACHE_LINE_SIZE set to %d (fix-up).\n", + cache_line_size); + } + + if ((pci_fix_up & 2) && cache_line_size && + (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) { + printk(NAME53C8XX": setting PCI_COMMAND_INVALIDATE (fix-up)\n"); + command |= PCI_COMMAND_INVALIDATE; + pci_write_config_word(pdev, PCI_COMMAND, command); + } + + /* + ** Tune PCI LATENCY TIMER according to burst max length transfer. + ** (latency timer >= burst length + 6, we add 10 to be quite sure) + */ + + if (chip->burst_max && (latency_timer == 0 || (pci_fix_up & 4))) { + uchar lt = (1 << chip->burst_max) + 6 + 10; + if (latency_timer < lt) { + printk(NAME53C8XX + ": changing PCI_LATENCY_TIMER from %d to %d.\n", + (int) latency_timer, (int) lt); + latency_timer = lt; + pci_write_config_byte(pdev, + PCI_LATENCY_TIMER, latency_timer); + } + } + +#endif /* SCSI_NCR_PCI_FIX_UP_SUPPORT */ + + /* + ** Initialise ncr_device structure with items required by ncr_attach. + */ + device->pdev = pdev; + device->slot.bus = PciBusNumber(pdev); + device->slot.device_fn = PciDeviceFn(pdev); + device->slot.base = base; + device->slot.base_2 = base_2; + device->slot.base_c = base_c; + device->slot.base_2_c = base_2_c; + device->slot.io_port = io_port; + device->slot.irq = irq; + device->attach_done = 0; + + return 0; +} + + +/*=================================================================== +** Detect and try to read SYMBIOS and TEKRAM NVRAM. +** +** Data can be used to order booting of boards. +** +** Data is saved in ncr_device structure if NVRAM found. This +** is then used to find drive boot order for ncr_attach(). +** +** NVRAM data is passed to Scsi_Host_Template later during +** ncr_attach() for any device set up. +*=================================================================== +*/ +#ifdef SCSI_NCR_NVRAM_SUPPORT +static void __init ncr_get_nvram(ncr_device *devp, ncr_nvram *nvp) +{ + devp->nvram = nvp; + if (!nvp) + return; + /* + ** Get access to chip IO registers + */ +#ifdef SCSI_NCR_IOMAPPED + request_region(devp->slot.io_port, 128, NAME53C8XX); + devp->slot.base_io = devp->slot.io_port; +#else + devp->slot.reg = + (struct ncr_reg *) remap_pci_mem(devp->slot.base_c, 128); + if (!devp->slot.reg) + return; +#endif + + /* + ** Try to read SYMBIOS nvram. + ** Try to read TEKRAM nvram if Symbios nvram not found. + */ + if (!sym_read_Symbios_nvram(&devp->slot, &nvp->data.Symbios)) + nvp->type = SCSI_NCR_SYMBIOS_NVRAM; + else if (!sym_read_Tekram_nvram(&devp->slot, devp->chip.device_id, + &nvp->data.Tekram)) + nvp->type = SCSI_NCR_TEKRAM_NVRAM; + else { + nvp->type = 0; + devp->nvram = 0; + } + + /* + ** Release access to chip IO registers + */ +#ifdef SCSI_NCR_IOMAPPED + release_region(devp->slot.base_io, 128); +#else + unmap_pci_mem((u_long) devp->slot.reg, 128ul); +#endif + +} +#endif /* SCSI_NCR_NVRAM_SUPPORT */ + +/* +** Linux select queue depths function +*/ + +#define DEF_DEPTH (driver_setup.default_tags) +#define ALL_TARGETS -2 +#define NO_TARGET -1 +#define ALL_LUNS -2 +#define NO_LUN -1 + +static int device_queue_depth(ncb_p np, int target, int lun) +{ + int c, h, t, u, v; + char *p = driver_setup.tag_ctrl; + char *ep; + + h = -1; + t = NO_TARGET; + u = NO_LUN; + while ((c = *p++) != 0) { + v = simple_strtoul(p, &ep, 0); + switch(c) { + case '/': + ++h; + t = ALL_TARGETS; + u = ALL_LUNS; + break; + case 't': + if (t != target) + t = (target == v) ? v : NO_TARGET; + u = ALL_LUNS; + break; + case 'u': + if (u != lun) + u = (lun == v) ? v : NO_LUN; + break; + case 'q': + if (h == np->unit && + (t == ALL_TARGETS || t == target) && + (u == ALL_LUNS || u == lun)) + return v; + break; + case '-': + t = ALL_TARGETS; + u = ALL_LUNS; + break; + default: + break; + } + p = ep; + } + return DEF_DEPTH; +} + +int sym53c8xx_slave_configure(Scsi_Device *device) +{ + struct Scsi_Host *host = device->host; + ncb_p np; + tcb_p tp; + lcb_p lp; + int numtags, depth_to_use; + + np = ((struct host_data *) host->hostdata)->ncb; + tp = &np->target[device->id]; + lp = ncr_lp(np, tp, device->lun); + + /* + ** Select queue depth from driver setup. + ** Donnot use more than configured by user. + ** Use at least 2. + ** Donnot use more than our maximum. + */ + numtags = device_queue_depth(np, device->id, device->lun); + if (numtags > tp->usrtags) + numtags = tp->usrtags; + if (!device->tagged_supported) + numtags = 1; + depth_to_use = numtags; + if (depth_to_use < 2) + depth_to_use = 2; + if (depth_to_use > MAX_TAGS) + depth_to_use = MAX_TAGS; + + scsi_adjust_queue_depth(device, + (device->tagged_supported ? + MSG_SIMPLE_TAG : 0), + depth_to_use); + + /* + ** Since the queue depth is not tunable under Linux, + ** we need to know this value in order not to + ** announce stupid things to user. + */ + if (lp) { + lp->numtags = lp->maxtags = numtags; + lp->scdev_depth = depth_to_use; + } + ncr_setup_tags (np, device->id, device->lun); + +#ifdef DEBUG_SYM53C8XX + printk("sym53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n", + np->unit, device->id, device->lun, depth_to_use); +#endif + + return 0; +} + +/* +** Linux entry point for info() function +*/ +const char *sym53c8xx_info (struct Scsi_Host *host) +{ + return SCSI_NCR_DRIVER_NAME; +} + +/* +** Linux entry point of queuecommand() function +*/ + +int sym53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) +{ + ncb_p np = ((struct host_data *) cmd->device->host->hostdata)->ncb; + unsigned long flags; + int sts; + +#ifdef DEBUG_SYM53C8XX +printk("sym53c8xx_queue_command\n"); +#endif + + cmd->scsi_done = done; + cmd->host_scribble = NULL; + cmd->SCp.ptr = NULL; + cmd->SCp.buffer = NULL; +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + __data_mapped(cmd) = 0; + __data_mapping(cmd) = 0; +#endif + + NCR_LOCK_NCB(np, flags); + + if ((sts = ncr_queue_command(np, cmd)) != DID_OK) { + SetScsiResult(cmd, sts, 0); +#ifdef DEBUG_SYM53C8XX +printk("sym53c8xx : command not queued - result=%d\n", sts); +#endif + } +#ifdef DEBUG_SYM53C8XX + else +printk("sym53c8xx : command successfully queued\n"); +#endif + + NCR_UNLOCK_NCB(np, flags); + + if (sts != DID_OK) { + unmap_scsi_data(np, cmd); + done(cmd); + } + + return sts; +} + +/* +** Linux entry point of the interrupt handler. +** Since linux versions > 1.3.70, we trust the kernel for +** passing the internal host descriptor as 'dev_id'. +** Otherwise, we scan the host list and call the interrupt +** routine for each host that uses this IRQ. +*/ + +static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) +{ + unsigned long flags; + ncb_p np = (ncb_p) dev_id; + Scsi_Cmnd *done_list; + +#ifdef DEBUG_SYM53C8XX + printk("sym53c8xx : interrupt received\n"); +#endif + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("["); + + NCR_LOCK_NCB(np, flags); + ncr_exception(np); + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("]\n"); + + if (done_list) { + NCR_LOCK_SCSI_DONE(done_list->device->host, flags); + ncr_flush_done_cmds(done_list); + NCR_UNLOCK_SCSI_DONE(done_list->device->host, flags); + } +} + +/* +** Linux entry point of the timer handler +*/ + +static void sym53c8xx_timeout(unsigned long npref) +{ + ncb_p np = (ncb_p) npref; + unsigned long flags; + Scsi_Cmnd *done_list; + + NCR_LOCK_NCB(np, flags); + ncr_timeout((ncb_p) np); + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + if (done_list) { + NCR_LOCK_SCSI_DONE(done_list->device->host, flags); + ncr_flush_done_cmds(done_list); + NCR_UNLOCK_SCSI_DONE(done_list->device->host, flags); + } +} + +/* +** Linux entry point of reset() function +*/ + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS +int sym53c8xx_reset(Scsi_Cmnd *cmd, unsigned int reset_flags) +#else +int sym53c8xx_reset(Scsi_Cmnd *cmd) +#endif +{ + ncb_p np = ((struct host_data *) cmd->device->host->hostdata)->ncb; + int sts; + unsigned long flags; + Scsi_Cmnd *done_list; + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + printk("sym53c8xx_reset: pid=%lu reset_flags=%x serial_number=%ld serial_number_at_timeout=%ld\n", + cmd->pid, reset_flags, cmd->serial_number, cmd->serial_number_at_timeout); +#else + printk("sym53c8xx_reset: command pid %lu\n", cmd->pid); +#endif + + NCR_LOCK_NCB(np, flags); + + /* + * We have to just ignore reset requests in some situations. + */ +#if defined SCSI_RESET_NOT_RUNNING + if (cmd->serial_number != cmd->serial_number_at_timeout) { + sts = SCSI_RESET_NOT_RUNNING; + goto out; + } +#endif + /* + * If the mid-level driver told us reset is synchronous, it seems + * that we must call the done() callback for the involved command, + * even if this command was not queued to the low-level driver, + * before returning SCSI_RESET_SUCCESS. + */ + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + sts = ncr_reset_bus(np, cmd, + (reset_flags & (SCSI_RESET_SYNCHRONOUS | SCSI_RESET_ASYNCHRONOUS)) == SCSI_RESET_SYNCHRONOUS); +#else + sts = ncr_reset_bus(np, cmd, 0); +#endif + + /* + * Since we always reset the controller, when we return success, + * we add this information to the return code. + */ +#if defined SCSI_RESET_HOST_RESET + if (sts == SCSI_RESET_SUCCESS) + sts |= SCSI_RESET_HOST_RESET; +#endif + +out: + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + ncr_flush_done_cmds(done_list); + + return sts; +} + +/* +** Linux entry point of abort() function +*/ + +int sym53c8xx_abort(Scsi_Cmnd *cmd) +{ + ncb_p np = ((struct host_data *) cmd->device->host->hostdata)->ncb; + int sts; + unsigned long flags; + Scsi_Cmnd *done_list; + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + printk("sym53c8xx_abort: pid=%lu serial_number=%ld serial_number_at_timeout=%ld\n", + cmd->pid, cmd->serial_number, cmd->serial_number_at_timeout); +#else + printk("sym53c8xx_abort: command pid %lu\n", cmd->pid); +#endif + + NCR_LOCK_NCB(np, flags); + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + /* + * We have to just ignore abort requests in some situations. + */ + if (cmd->serial_number != cmd->serial_number_at_timeout) { + sts = SCSI_ABORT_NOT_RUNNING; + goto out; + } +#endif + + sts = ncr_abort_command(np, cmd); +out: + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + ncr_flush_done_cmds(done_list); + + return sts; +} + + +int sym53c8xx_release(struct Scsi_Host *host) +{ +#ifdef DEBUG_SYM53C8XX +printk("sym53c8xx : release\n"); +#endif + ncr_detach(((struct host_data *) host->hostdata)->ncb); + + return 1; +} + + +/* +** Scsi command waiting list management. +** +** It may happen that we cannot insert a scsi command into the start queue, +** in the following circumstances. +** Too few preallocated ccb(s), +** maxtags < cmd_per_lun of the Linux host control block, +** etc... +** Such scsi commands are inserted into a waiting list. +** When a scsi command complete, we try to requeue the commands of the +** waiting list. +*/ + +#define next_wcmd host_scribble + +static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd) +{ + Scsi_Cmnd *wcmd; + +#ifdef DEBUG_WAITING_LIST + printk("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd); +#endif + cmd->next_wcmd = 0; + if (!(wcmd = np->waiting_list)) np->waiting_list = cmd; + else { + while ((wcmd->next_wcmd) != 0) + wcmd = (Scsi_Cmnd *) wcmd->next_wcmd; + wcmd->next_wcmd = (char *) cmd; + } +} + +static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd) +{ + Scsi_Cmnd **pcmd = &np->waiting_list; + + while (*pcmd) { + if (cmd == *pcmd) { + if (to_remove) { + *pcmd = (Scsi_Cmnd *) cmd->next_wcmd; + cmd->next_wcmd = 0; + } +#ifdef DEBUG_WAITING_LIST + printk("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd); +#endif + return cmd; + } + pcmd = (Scsi_Cmnd **) &(*pcmd)->next_wcmd; + } + return 0; +} + +static void process_waiting_list(ncb_p np, int sts) +{ + Scsi_Cmnd *waiting_list, *wcmd; + + waiting_list = np->waiting_list; + np->waiting_list = 0; + +#ifdef DEBUG_WAITING_LIST + if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts); +#endif + while ((wcmd = waiting_list) != 0) { + waiting_list = (Scsi_Cmnd *) wcmd->next_wcmd; + wcmd->next_wcmd = 0; + if (sts == DID_OK) { +#ifdef DEBUG_WAITING_LIST + printk("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd); +#endif + sts = ncr_queue_command(np, wcmd); + } + if (sts != DID_OK) { +#ifdef DEBUG_WAITING_LIST + printk("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts); +#endif + SetScsiResult(wcmd, sts, 0); + ncr_queue_done_cmd(np, wcmd); + } + } +} + +#undef next_wcmd + +#ifdef SCSI_NCR_PROC_INFO_SUPPORT + +/*========================================================================= +** Proc file system stuff +** +** A read operation returns adapter information. +** A write operation is a control command. +** The string is parsed in the driver code and the command is passed +** to the ncr_usercmd() function. +**========================================================================= +*/ + +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT + +#define is_digit(c) ((c) >= '0' && (c) <= '9') +#define digit_to_bin(c) ((c) - '0') +#define is_space(c) ((c) == ' ' || (c) == '\t') + +static int skip_spaces(char *ptr, int len) +{ + int cnt, c; + + for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt--); + + return (len - cnt); +} + +static int get_int_arg(char *ptr, int len, u_long *pv) +{ + int cnt, c; + u_long v; + + for (v = 0, cnt = len; cnt > 0 && (c = *ptr++) && is_digit(c); cnt--) { + v = (v * 10) + digit_to_bin(c); + } + + if (pv) + *pv = v; + + return (len - cnt); +} + +static int is_keyword(char *ptr, int len, char *verb) +{ + int verb_len = strlen(verb); + + if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len)) + return verb_len; + else + return 0; + +} + +#define SKIP_SPACES(min_spaces) \ + if ((arg_len = skip_spaces(ptr, len)) < (min_spaces)) \ + return -EINVAL; \ + ptr += arg_len; len -= arg_len; + +#define GET_INT_ARG(v) \ + if (!(arg_len = get_int_arg(ptr, len, &(v)))) \ + return -EINVAL; \ + ptr += arg_len; len -= arg_len; + + +/* +** Parse a control command +*/ + +static int ncr_user_command(ncb_p np, char *buffer, int length) +{ + char *ptr = buffer; + int len = length; + struct usrcmd *uc = &np->user; + int arg_len; + u_long target; + + bzero(uc, sizeof(*uc)); + + if (len > 0 && ptr[len-1] == '\n') + --len; + + if ((arg_len = is_keyword(ptr, len, "setsync")) != 0) + uc->cmd = UC_SETSYNC; + else if ((arg_len = is_keyword(ptr, len, "settags")) != 0) + uc->cmd = UC_SETTAGS; + else if ((arg_len = is_keyword(ptr, len, "setorder")) != 0) + uc->cmd = UC_SETORDER; + else if ((arg_len = is_keyword(ptr, len, "setverbose")) != 0) + uc->cmd = UC_SETVERBOSE; + else if ((arg_len = is_keyword(ptr, len, "setwide")) != 0) + uc->cmd = UC_SETWIDE; + else if ((arg_len = is_keyword(ptr, len, "setdebug")) != 0) + uc->cmd = UC_SETDEBUG; + else if ((arg_len = is_keyword(ptr, len, "setflag")) != 0) + uc->cmd = UC_SETFLAG; + else if ((arg_len = is_keyword(ptr, len, "resetdev")) != 0) + uc->cmd = UC_RESETDEV; + else if ((arg_len = is_keyword(ptr, len, "cleardev")) != 0) + uc->cmd = UC_CLEARDEV; + else + arg_len = 0; + +#ifdef DEBUG_PROC_INFO +printk("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd); +#endif + + if (!arg_len) + return -EINVAL; + ptr += arg_len; len -= arg_len; + + switch(uc->cmd) { + case UC_SETSYNC: + case UC_SETTAGS: + case UC_SETWIDE: + case UC_SETFLAG: + case UC_RESETDEV: + case UC_CLEARDEV: + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "all")) != 0) { + ptr += arg_len; len -= arg_len; + uc->target = ~0; + } else { + GET_INT_ARG(target); + uc->target = (1<cmd) { + case UC_SETVERBOSE: + case UC_SETSYNC: + case UC_SETTAGS: + case UC_SETWIDE: + SKIP_SPACES(1); + GET_INT_ARG(uc->data); +#ifdef DEBUG_PROC_INFO +printk("ncr_user_command: data=%ld\n", uc->data); +#endif + break; + case UC_SETORDER: + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "simple"))) + uc->data = M_SIMPLE_TAG; + else if ((arg_len = is_keyword(ptr, len, "ordered"))) + uc->data = M_ORDERED_TAG; + else if ((arg_len = is_keyword(ptr, len, "default"))) + uc->data = 0; + else + return -EINVAL; + break; + case UC_SETDEBUG: + while (len > 0) { + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "alloc"))) + uc->data |= DEBUG_ALLOC; + else if ((arg_len = is_keyword(ptr, len, "phase"))) + uc->data |= DEBUG_PHASE; + else if ((arg_len = is_keyword(ptr, len, "queue"))) + uc->data |= DEBUG_QUEUE; + else if ((arg_len = is_keyword(ptr, len, "result"))) + uc->data |= DEBUG_RESULT; + else if ((arg_len = is_keyword(ptr, len, "pointer"))) + uc->data |= DEBUG_POINTER; + else if ((arg_len = is_keyword(ptr, len, "script"))) + uc->data |= DEBUG_SCRIPT; + else if ((arg_len = is_keyword(ptr, len, "tiny"))) + uc->data |= DEBUG_TINY; + else if ((arg_len = is_keyword(ptr, len, "timing"))) + uc->data |= DEBUG_TIMING; + else if ((arg_len = is_keyword(ptr, len, "nego"))) + uc->data |= DEBUG_NEGO; + else if ((arg_len = is_keyword(ptr, len, "tags"))) + uc->data |= DEBUG_TAGS; + else + return -EINVAL; + ptr += arg_len; len -= arg_len; + } +#ifdef DEBUG_PROC_INFO +printk("ncr_user_command: data=%ld\n", uc->data); +#endif + break; + case UC_SETFLAG: + while (len > 0) { + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "trace"))) + uc->data |= UF_TRACE; + else if ((arg_len = is_keyword(ptr, len, "no_disc"))) + uc->data |= UF_NODISC; + else + return -EINVAL; + ptr += arg_len; len -= arg_len; + } + break; + default: + break; + } + + if (len) + return -EINVAL; + else { + unsigned long flags; + + NCR_LOCK_NCB(np, flags); + ncr_usercmd (np); + NCR_UNLOCK_NCB(np, flags); + } + return length; +} + +#endif /* SCSI_NCR_USER_COMMAND_SUPPORT */ + +#ifdef SCSI_NCR_USER_INFO_SUPPORT + +struct info_str +{ + char *buffer; + int length; + int offset; + int pos; +}; + +static void copy_mem_info(struct info_str *info, char *data, int len) +{ + if (info->pos + len > info->length) + len = info->length - info->pos; + + if (info->pos + len < info->offset) { + info->pos += len; + return; + } + if (info->pos < info->offset) { + data += (info->offset - info->pos); + len -= (info->offset - info->pos); + } + + if (len > 0) { + memcpy(info->buffer + info->pos, data, len); + info->pos += len; + } +} + +static int copy_info(struct info_str *info, char *fmt, ...) +{ + va_list args; + char buf[81]; + int len; + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + copy_mem_info(info, buf, len); + return len; +} + +/* +** Copy formatted information into the input buffer. +*/ + +static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) +{ + struct info_str info; + + info.buffer = ptr; + info.length = len; + info.offset = offset; + info.pos = 0; + + copy_info(&info, "General information:\n"); + copy_info(&info, " Chip " NAME53C "%s, device id 0x%x, " + "revision id 0x%x\n", + np->chip_name, np->device_id, np->revision_id); + copy_info(&info, " On PCI bus %d, device %d, function %d, " +#ifdef __sparc__ + "IRQ %s\n", +#else + "IRQ %d\n", +#endif + np->bus, (np->device_fn & 0xf8) >> 3, np->device_fn & 7, +#ifdef __sparc__ + __irq_itoa(np->irq)); +#else + (int) np->irq); +#endif + copy_info(&info, " Synchronous period factor %d, " + "max commands per lun %d\n", + (int) np->minsync, MAX_TAGS); + + if (driver_setup.debug || driver_setup.verbose > 1) { + copy_info(&info, " Debug flags 0x%x, verbosity level %d\n", + driver_setup.debug, driver_setup.verbose); + } + + return info.pos > info.offset? info.pos - info.offset : 0; +} + +#endif /* SCSI_NCR_USER_INFO_SUPPORT */ + +/* +** Entry point of the scsi proc fs of the driver. +** - func = 0 means read (returns adapter infos) +** - func = 1 means write (parse user control command) +*/ + +static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int func) +{ + struct Scsi_Host *host; + struct host_data *host_data; + ncb_p ncb = 0; + int retv; + +#ifdef DEBUG_PROC_INFO +printk("sym53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func); +#endif + + host = scsi_host_hn_get(hostno); + if (!host) + return -EINVAL; + + host_data = (struct host_data *) host->hostdata; + ncb = host_data->ncb; + retv = -EINVAL; + if (!ncb) + goto out; + + if (func) { +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT + retv = ncr_user_command(ncb, buffer, length); +#endif + } else { + if (start) + *start = buffer; +#ifdef SCSI_NCR_USER_INFO_SUPPORT + retv = ncr_host_info(ncb, buffer, offset, length); +#endif + } + +out: + scsi_host_put(host); + return retv; +} + + +/*========================================================================= +** End of proc file system stuff +**========================================================================= +*/ +#endif + + +#ifdef SCSI_NCR_NVRAM_SUPPORT + +/* + * 24C16 EEPROM reading. + * + * GPOI0 - data in/data out + * GPIO1 - clock + * Symbios NVRAM wiring now also used by Tekram. + */ + +#define SET_BIT 0 +#define CLR_BIT 1 +#define SET_CLK 2 +#define CLR_CLK 3 + +/* + * Set/clear data/clock bit in GPIO0 + */ +static void __init +S24C16_set_bit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode) +{ + UDELAY (5); + switch (bit_mode){ + case SET_BIT: + *gpreg |= write_bit; + break; + case CLR_BIT: + *gpreg &= 0xfe; + break; + case SET_CLK: + *gpreg |= 0x02; + break; + case CLR_CLK: + *gpreg &= 0xfd; + break; + + } + OUTB (nc_gpreg, *gpreg); + UDELAY (5); +} + +/* + * Send START condition to NVRAM to wake it up. + */ +static void __init S24C16_start(ncr_slot *np, u_char *gpreg) +{ + S24C16_set_bit(np, 1, gpreg, SET_BIT); + S24C16_set_bit(np, 0, gpreg, SET_CLK); + S24C16_set_bit(np, 0, gpreg, CLR_BIT); + S24C16_set_bit(np, 0, gpreg, CLR_CLK); +} + +/* + * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!! + */ +static void __init S24C16_stop(ncr_slot *np, u_char *gpreg) +{ + S24C16_set_bit(np, 0, gpreg, SET_CLK); + S24C16_set_bit(np, 1, gpreg, SET_BIT); +} + +/* + * Read or write a bit to the NVRAM, + * read if GPIO0 input else write if GPIO0 output + */ +static void __init +S24C16_do_bit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg) +{ + S24C16_set_bit(np, write_bit, gpreg, SET_BIT); + S24C16_set_bit(np, 0, gpreg, SET_CLK); + if (read_bit) + *read_bit = INB (nc_gpreg); + S24C16_set_bit(np, 0, gpreg, CLR_CLK); + S24C16_set_bit(np, 0, gpreg, CLR_BIT); +} + +/* + * Output an ACK to the NVRAM after reading, + * change GPIO0 to output and when done back to an input + */ +static void __init +S24C16_write_ack(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl) +{ + OUTB (nc_gpcntl, *gpcntl & 0xfe); + S24C16_do_bit(np, 0, write_bit, gpreg); + OUTB (nc_gpcntl, *gpcntl); +} + +/* + * Input an ACK from NVRAM after writing, + * change GPIO0 to input and when done back to an output + */ +static void __init +S24C16_read_ack(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl) +{ + OUTB (nc_gpcntl, *gpcntl | 0x01); + S24C16_do_bit(np, read_bit, 1, gpreg); + OUTB (nc_gpcntl, *gpcntl); +} + +/* + * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK, + * GPIO0 must already be set as an output + */ +static void __init +S24C16_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, + u_char *gpreg, u_char *gpcntl) +{ + int x; + + for (x = 0; x < 8; x++) + S24C16_do_bit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg); + + S24C16_read_ack(np, ack_data, gpreg, gpcntl); +} + +/* + * READ a byte from the NVRAM and then send an ACK to say we have got it, + * GPIO0 must already be set as an input + */ +static void __init +S24C16_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, + u_char *gpreg, u_char *gpcntl) +{ + int x; + u_char read_bit; + + *read_data = 0; + for (x = 0; x < 8; x++) { + S24C16_do_bit(np, &read_bit, 1, gpreg); + *read_data |= ((read_bit & 0x01) << (7 - x)); + } + + S24C16_write_ack(np, ack_data, gpreg, gpcntl); +} + +/* + * Read 'len' bytes starting at 'offset'. + */ +static int __init +sym_read_S24C16_nvram (ncr_slot *np, int offset, u_char *data, int len) +{ + u_char gpcntl, gpreg; + u_char old_gpcntl, old_gpreg; + u_char ack_data; + int retv = 1; + int x; + + /* save current state of GPCNTL and GPREG */ + old_gpreg = INB (nc_gpreg); + old_gpcntl = INB (nc_gpcntl); + gpcntl = old_gpcntl & 0x1c; + + /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ + OUTB (nc_gpreg, old_gpreg); + OUTB (nc_gpcntl, gpcntl); + + /* this is to set NVRAM into a known state with GPIO0/1 both low */ + gpreg = old_gpreg; + S24C16_set_bit(np, 0, &gpreg, CLR_CLK); + S24C16_set_bit(np, 0, &gpreg, CLR_BIT); + + /* now set NVRAM inactive with GPIO0/1 both high */ + S24C16_stop(np, &gpreg); + + /* activate NVRAM */ + S24C16_start(np, &gpreg); + + /* write device code and random address MSB */ + S24C16_write_byte(np, &ack_data, + 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); + if (ack_data & 0x01) + goto out; + + /* write random address LSB */ + S24C16_write_byte(np, &ack_data, + offset & 0xff, &gpreg, &gpcntl); + if (ack_data & 0x01) + goto out; + + /* regenerate START state to set up for reading */ + S24C16_start(np, &gpreg); + + /* rewrite device code and address MSB with read bit set (lsb = 0x01) */ + S24C16_write_byte(np, &ack_data, + 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); + if (ack_data & 0x01) + goto out; + + /* now set up GPIO0 for inputting data */ + gpcntl |= 0x01; + OUTB (nc_gpcntl, gpcntl); + + /* input all requested data - only part of total NVRAM */ + for (x = 0; x < len; x++) + S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl); + + /* finally put NVRAM back in inactive mode */ + gpcntl &= 0xfe; + OUTB (nc_gpcntl, gpcntl); + S24C16_stop(np, &gpreg); + retv = 0; +out: + /* return GPIO0/1 to original states after having accessed NVRAM */ + OUTB (nc_gpcntl, old_gpcntl); + OUTB (nc_gpreg, old_gpreg); + + return retv; +} + +#undef SET_BIT +#undef CLR_BIT +#undef SET_CLK +#undef CLR_CLK + +/* + * Try reading Symbios NVRAM. + * Return 0 if OK. + */ +static int __init sym_read_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram) +{ + static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0}; + u_char *data = (u_char *) nvram; + int len = sizeof(*nvram); + u_short csum; + int x; + + /* probe the 24c16 and read the SYMBIOS 24c16 area */ + if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len)) + return 1; + + /* check valid NVRAM signature, verify byte count and checksum */ + if (nvram->type != 0 || + memcmp(nvram->trailer, Symbios_trailer, 6) || + nvram->byte_count != len - 12) + return 1; + + /* verify checksum */ + for (x = 6, csum = 0; x < len - 6; x++) + csum += data[x]; + if (csum != nvram->checksum) + return 1; + + return 0; +} + +/* + * 93C46 EEPROM reading. + * + * GPOI0 - data in + * GPIO1 - data out + * GPIO2 - clock + * GPIO4 - chip select + * + * Used by Tekram. + */ + +/* + * Pulse clock bit in GPIO0 + */ +static void __init T93C46_Clk(ncr_slot *np, u_char *gpreg) +{ + OUTB (nc_gpreg, *gpreg | 0x04); + UDELAY (2); + OUTB (nc_gpreg, *gpreg); +} + +/* + * Read bit from NVRAM + */ +static void __init T93C46_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg) +{ + UDELAY (2); + T93C46_Clk(np, gpreg); + *read_bit = INB (nc_gpreg); +} + +/* + * Write bit to GPIO0 + */ +static void __init T93C46_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg) +{ + if (write_bit & 0x01) + *gpreg |= 0x02; + else + *gpreg &= 0xfd; + + *gpreg |= 0x10; + + OUTB (nc_gpreg, *gpreg); + UDELAY (2); + + T93C46_Clk(np, gpreg); +} + +/* + * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!! + */ +static void __init T93C46_Stop(ncr_slot *np, u_char *gpreg) +{ + *gpreg &= 0xef; + OUTB (nc_gpreg, *gpreg); + UDELAY (2); + + T93C46_Clk(np, gpreg); +} + +/* + * Send read command and address to NVRAM + */ +static void __init +T93C46_Send_Command(ncr_slot *np, u_short write_data, + u_char *read_bit, u_char *gpreg) +{ + int x; + + /* send 9 bits, start bit (1), command (2), address (6) */ + for (x = 0; x < 9; x++) + T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg); + + *read_bit = INB (nc_gpreg); +} + +/* + * READ 2 bytes from the NVRAM + */ +static void __init +T93C46_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg) +{ + int x; + u_char read_bit; + + *nvram_data = 0; + for (x = 0; x < 16; x++) { + T93C46_Read_Bit(np, &read_bit, gpreg); + + if (read_bit & 0x01) + *nvram_data |= (0x01 << (15 - x)); + else + *nvram_data &= ~(0x01 << (15 - x)); + } +} + +/* + * Read Tekram NvRAM data. + */ +static int __init +T93C46_Read_Data(ncr_slot *np, u_short *data,int len,u_char *gpreg) +{ + u_char read_bit; + int x; + + for (x = 0; x < len; x++) { + + /* output read command and address */ + T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg); + if (read_bit & 0x01) + return 1; /* Bad */ + T93C46_Read_Word(np, &data[x], gpreg); + T93C46_Stop(np, gpreg); + } + + return 0; +} + +/* + * Try reading 93C46 Tekram NVRAM. + */ +static int __init +sym_read_T93C46_nvram (ncr_slot *np, Tekram_nvram *nvram) +{ + u_char gpcntl, gpreg; + u_char old_gpcntl, old_gpreg; + int retv = 1; + + /* save current state of GPCNTL and GPREG */ + old_gpreg = INB (nc_gpreg); + old_gpcntl = INB (nc_gpcntl); + + /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in, + 1/2/4 out */ + gpreg = old_gpreg & 0xe9; + OUTB (nc_gpreg, gpreg); + gpcntl = (old_gpcntl & 0xe9) | 0x09; + OUTB (nc_gpcntl, gpcntl); + + /* input all of NVRAM, 64 words */ + retv = T93C46_Read_Data(np, (u_short *) nvram, + sizeof(*nvram) / sizeof(short), &gpreg); + + /* return GPIO0/1/2/4 to original states after having accessed NVRAM */ + OUTB (nc_gpcntl, old_gpcntl); + OUTB (nc_gpreg, old_gpreg); + + return retv; +} + +/* + * Try reading Tekram NVRAM. + * Return 0 if OK. + */ +static int __init +sym_read_Tekram_nvram (ncr_slot *np, u_short device_id, Tekram_nvram *nvram) +{ + u_char *data = (u_char *) nvram; + int len = sizeof(*nvram); + u_short csum; + int x; + + switch (device_id) { + case PCI_DEVICE_ID_NCR_53C885: + case PCI_DEVICE_ID_NCR_53C895: + case PCI_DEVICE_ID_NCR_53C896: + x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, + data, len); + break; + case PCI_DEVICE_ID_NCR_53C875: + x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, + data, len); + if (!x) + break; + default: + x = sym_read_T93C46_nvram(np, nvram); + break; + } + if (x) + return 1; + + /* verify checksum */ + for (x = 0, csum = 0; x < len - 1; x += 2) + csum += data[x] + (data[x+1] << 8); + if (csum != 0x1234) + return 1; + + return 0; +} + +#endif /* SCSI_NCR_NVRAM_SUPPORT */ + +/* +** Module stuff +*/ + +MODULE_LICENSE("GPL"); + +static Scsi_Host_Template driver_template = { + .name = "sym53c8xx", + .detect = sym53c8xx_detect, + .release = sym53c8xx_release, + .info = sym53c8xx_info, + .queuecommand = sym53c8xx_queue_command, + .slave_configure = sym53c8xx_slave_configure, + .abort = sym53c8xx_abort, + .reset = sym53c8xx_reset, + .can_queue = SCSI_NCR_CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SCSI_NCR_SG_TABLESIZE, + .cmd_per_lun = SCSI_NCR_CMD_PER_LUN, + .max_sectors = MAX_HW_SEGMENTS*8, + .use_clustering = DISABLE_CLUSTERING, + .highmem_io = 1 +}; +#include "scsi_module.c" diff --git a/demos/demo_rule9/sym53c8xx.res b/demos/demo_rule9/sym53c8xx.res new file mode 100644 index 0000000..2dfcc9b --- /dev/null +++ b/demos/demo_rule9/sym53c8xx.res @@ -0,0 +1,14732 @@ +/****************************************************************************** +** High Performance device driver for the Symbios 53C896 controller. +** +** Copyright (C) 1998-2001 Gerard Roudier +** +** This driver also supports all the Symbios 53C8XX controller family, +** except 53C810 revisions < 16, 53C825 revisions < 16 and all +** revisions of 53C815 controllers. +** +** This driver is based on the Linux port of the FreeBSD ncr driver. +** +** Copyright (C) 1994 Wolfgang Stanglmeier +** +**----------------------------------------------------------------------------- +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- +** +** The Linux port of the FreeBSD ncr driver has been achieved in +** november 1995 by: +** +** Gerard Roudier +** +** Being given that this driver originates from the FreeBSD version, and +** in order to keep synergy on both, any suggested enhancements and corrections +** received on Linux are automatically a potential candidate for the FreeBSD +** version. +** +** The original driver has been written for 386bsd and FreeBSD by +** Wolfgang Stanglmeier +** Stefan Esser +** +**----------------------------------------------------------------------------- +** +** Major contributions: +** -------------------- +** +** NVRAM detection and reading. +** Copyright (C) 1997 Richard Waltham +** +******************************************************************************* +*/ + +/* +** Supported SCSI features: +** Synchronous data transfers +** Wide16 SCSI BUS +** Disconnection/Reselection +** Tagged command queuing +** SCSI Parity checking +** +** Supported NCR/SYMBIOS chips: +** 53C810A (8 bits, Fast 10, no rom BIOS) +** 53C825A (Wide, Fast 10, on-board rom BIOS) +** 53C860 (8 bits, Fast 20, no rom BIOS) +** 53C875 (Wide, Fast 20, on-board rom BIOS) +** 53C876 (Wide, Fast 20 Dual, on-board rom BIOS) +** 53C895 (Wide, Fast 40, on-board rom BIOS) +** 53C895A (Wide, Fast 40, on-board rom BIOS) +** 53C896 (Wide, Fast 40 Dual, on-board rom BIOS) +** 53C897 (Wide, Fast 40 Dual, on-board rom BIOS) +** 53C1510D (Wide, Fast 40 Dual, on-board rom BIOS) +** 53C1010 (Wide, Fast 80 Dual, on-board rom BIOS) +** 53C1010_66(Wide, Fast 80 Dual, on-board rom BIOS, 33/66MHz PCI) +** +** Other features: +** Memory mapped IO +** Module +** Shared IRQ +*/ + +/* +** Name and version of the driver +*/ +#define SCSI_NCR_DRIVER_NAME "sym53c8xx-1.7.3c-20010512" + +#define SCSI_NCR_DEBUG_FLAGS (0) + +#define NAME53C "sym53c" +#define NAME53C8XX "sym53c8xx" + +/*========================================================== +** +** Include files +** +**========================================================== +*/ + +#include + +#include + +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,17) +#include +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,35) +#include +#endif + +#ifndef __init +#define __init +#endif +#ifndef __initdata +#define __initdata +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92) +#include +#endif + +#include "scsi.h" +#include "hosts.h" + +#include + +/* +** Define BITS_PER_LONG for earlier linux versions. +*/ +#ifndef BITS_PER_LONG +#if (~0UL) == 0xffffffffUL +#define BITS_PER_LONG 32 +#else +#define BITS_PER_LONG 64 +#endif +#endif + +/* +** Define the BSD style u_int32 and u_int64 type. +** Are in fact u_int32_t and u_int64_t :-) +*/ +typedef u32 u_int32; +typedef u64 u_int64; + +#include "sym53c8xx.h" + +/* +** Donnot compile integrity checking code for Linux-2.3.0 +** and above since SCSI data structures are not ready yet. +*/ +/* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) */ +#if 0 +#define SCSI_NCR_INTEGRITY_CHECKING +#endif + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +/* +** Hmmm... What complex some PCI-HOST bridges actually are, +** despite the fact that the PCI specifications are looking +** so smart and simple! ;-) +*/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,47) +#define SCSI_NCR_DYNAMIC_DMA_MAPPING +#endif + +/*========================================================== +** +** A la VMS/CAM-3 queue management. +** Implemented from linux list management. +** +**========================================================== +*/ + +typedef struct xpt_quehead { + struct xpt_quehead *flink; /* Forward pointer */ + struct xpt_quehead *blink; /* Backward pointer */ +} XPT_QUEHEAD; + +#define xpt_que_init(ptr) do { \ + (ptr)->flink = (ptr); (ptr)->blink = (ptr); \ +} while (0) + +static inline void __xpt_que_add(struct xpt_quehead * new, + struct xpt_quehead * blink, + struct xpt_quehead * flink) +{ + flink->blink = new; + new->flink = flink; + new->blink = blink; + blink->flink = new; +} + +static inline void __xpt_que_del(struct xpt_quehead * blink, + struct xpt_quehead * flink) +{ + flink->blink = blink; + blink->flink = flink; +} + +static inline int xpt_que_empty(struct xpt_quehead *head) +{ + return head->flink == head; +} + +static inline void xpt_que_splice(struct xpt_quehead *list, + struct xpt_quehead *head) +{ + struct xpt_quehead *first = list->flink; + + if (first != list) { + struct xpt_quehead *last = list->blink; + struct xpt_quehead *at = head->flink; + + first->blink = head; + head->flink = first; + + last->flink = at; + at->blink = last; + } +} + +#define xpt_que_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + + +#define xpt_insque(new, pos) __xpt_que_add(new, pos, (pos)->flink) + +#define xpt_remque(el) __xpt_que_del((el)->blink, (el)->flink) + +#define xpt_insque_head(new, head) __xpt_que_add(new, head, (head)->flink) + +static inline struct xpt_quehead *xpt_remque_head(struct xpt_quehead *head) +{ + struct xpt_quehead *elem = head->flink; + + if (elem != head) + __xpt_que_del(head, elem->flink); + else + elem = 0; + return elem; +} + +#define xpt_insque_tail(new, head) __xpt_que_add(new, (head)->blink, head) + +static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head) +{ + struct xpt_quehead *elem = head->blink; + + if (elem != head) + __xpt_que_del(elem->blink, head); + else + elem = 0; + return elem; +} + +/*========================================================== +** +** Configuration and Debugging +** +**========================================================== +*/ + +/* +** SCSI address of this device. +** The boot routines should have set it. +** If not, use this. +*/ + +#ifndef SCSI_NCR_MYADDR +#define SCSI_NCR_MYADDR (7) +#endif + +/* +** The maximum number of tags per logic unit. +** Used only for devices that support tags. +*/ + +#ifndef SCSI_NCR_MAX_TAGS +#define SCSI_NCR_MAX_TAGS (8) +#endif + +/* +** TAGS are actually unlimited (256 tags/lun). +** But Linux only supports 255. :) +*/ +#if SCSI_NCR_MAX_TAGS > 255 +#define MAX_TAGS 255 +#else +#define MAX_TAGS SCSI_NCR_MAX_TAGS +#endif + +/* +** Since the ncr chips only have a 8 bit ALU, we try to be clever +** about offset calculation in the TASK TABLE per LUN that is an +** array of DWORDS = 4 bytes. +*/ +#if MAX_TAGS > (512/4) +#define MAX_TASKS (1024/4) +#elif MAX_TAGS > (256/4) +#define MAX_TASKS (512/4) +#else +#define MAX_TASKS (256/4) +#endif + +/* +** This one means 'NO TAG for this job' +*/ +#define NO_TAG (256) + +/* +** Number of targets supported by the driver. +** n permits target numbers 0..n-1. +** Default is 16, meaning targets #0..#15. +** #7 .. is myself. +*/ + +#ifdef SCSI_NCR_MAX_TARGET +#define MAX_TARGET (SCSI_NCR_MAX_TARGET) +#else +#define MAX_TARGET (16) +#endif + +/* +** Number of logic units supported by the driver. +** n enables logic unit numbers 0..n-1. +** The common SCSI devices require only +** one lun, so take 1 as the default. +*/ + +#ifdef SCSI_NCR_MAX_LUN +#define MAX_LUN 64 +#else +#define MAX_LUN (1) +#endif + +/* +** Asynchronous pre-scaler (ns). Shall be 40 for +** the SCSI timings to be compliant. +*/ + +#ifndef SCSI_NCR_MIN_ASYNC +#define SCSI_NCR_MIN_ASYNC (40) +#endif + +/* +** The maximum number of jobs scheduled for starting. +** We allocate 4 entries more than the value we announce +** to the SCSI upper layer. Guess why ! :-) +*/ + +#ifdef SCSI_NCR_CAN_QUEUE +#define MAX_START (SCSI_NCR_CAN_QUEUE + 4) +#else +#define MAX_START (MAX_TARGET + 7 * MAX_TAGS) +#endif + +/* +** We donnot want to allocate more than 1 PAGE for the +** the start queue and the done queue. We hard-code entry +** size to 8 in order to let cpp do the checking. +** Allows 512-4=508 pending IOs for i386 but Linux seems for +** now not able to provide the driver with this amount of IOs. +*/ +#if MAX_START > PAGE_SIZE/8 +#undef MAX_START +#define MAX_START (PAGE_SIZE/8) +#endif + +/* +** The maximum number of segments a transfer is split into. +** We support up to 127 segments for both read and write. +*/ + +#define MAX_SCATTER (SCSI_NCR_MAX_SCATTER) +#define SCR_SG_SIZE (2) + +/* +** other +*/ + +#define NCR_SNOOP_TIMEOUT (1000000) + +/*========================================================== +** +** Miscallaneous BSDish defines. +** +**========================================================== +*/ + +#define u_char unsigned char +#define u_short unsigned short +#define u_int unsigned int +#define u_long unsigned long + +#ifndef bcopy +#define bcopy(s, d, n) memcpy((d), (s), (n)) +#endif + +#ifndef bzero +#define bzero(d, n) memset((d), 0, (n)) +#endif + +#ifndef offsetof +#define offsetof(t, m) ((size_t) (&((t *)0)->m)) +#endif + +/* +** Simple Wrapper to kernel PCI bus interface. +** +** This wrapper allows to get rid of old kernel PCI interface +** and still allows to preserve linux-2.0 compatibilty. +** In fact, it is mostly an incomplete emulation of the new +** PCI code for pre-2.2 kernels. When kernel-2.0 support +** will be dropped, we will just have to remove most of this +** code. +*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) + +typedef struct pci_dev *pcidev_t; +#define PCIDEV_NULL (0) +#define PciBusNumber(d) (d)->bus->number +#define PciDeviceFn(d) (d)->devfn +#define PciVendorId(d) (d)->vendor +#define PciDeviceId(d) (d)->device +#define PciIrqLine(d) (d)->irq + +static u_long __init +pci_get_base_cookie(struct pci_dev *pdev, int index) +{ + u_long base; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,12) + base = pdev->resource[index].start; +#else + base = pdev->base_address[index]; +#if BITS_PER_LONG > 32 + if ((base & 0x7) == 0x4) + *base |= (((u_long)pdev->base_address[++index]) << 32); +#endif +#endif + return (base & ~0x7ul); +} + +static int __init +pci_get_base_address(struct pci_dev *pdev, int index, u_long *base) +{ + u32 tmp; +#define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2)) + + pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp); + *base = tmp; + ++index; + if ((tmp & 0x7) == 0x4) { +#if BITS_PER_LONG > 32 + pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp); + *base |= (((u_long)tmp) << 32); +#endif + ++index; + } + return index; +#undef PCI_BAR_OFFSET +} + +#else /* Incomplete emulation of current PCI code for pre-2.2 kernels */ + +typedef unsigned int pcidev_t; +#define PCIDEV_NULL (~0u) +#define PciBusNumber(d) ((d)>>8) +#define PciDeviceFn(d) ((d)&0xff) +#define __PciDev(busn, devfn) (((busn)<<8)+(devfn)) + +#define pci_present pcibios_present + +#define pci_read_config_byte(d, w, v) \ + pcibios_read_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v) +#define pci_read_config_word(d, w, v) \ + pcibios_read_config_word(PciBusNumber(d), PciDeviceFn(d), w, v) +#define pci_read_config_dword(d, w, v) \ + pcibios_read_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v) + +#define pci_write_config_byte(d, w, v) \ + pcibios_write_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v) +#define pci_write_config_word(d, w, v) \ + pcibios_write_config_word(PciBusNumber(d), PciDeviceFn(d), w, v) +#define pci_write_config_dword(d, w, v) \ + pcibios_write_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v) + +static pcidev_t __init +pci_find_device(unsigned int vendor, unsigned int device, pcidev_t prev) +{ + static unsigned short pci_index; + int retv; + unsigned char bus_number, device_fn; + + if (prev == PCIDEV_NULL) + pci_index = 0; + else + ++pci_index; + retv = pcibios_find_device (vendor, device, pci_index, + &bus_number, &device_fn); + return retv ? PCIDEV_NULL : __PciDev(bus_number, device_fn); +} + +static u_short __init PciVendorId(pcidev_t dev) +{ + u_short vendor_id; + pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); + return vendor_id; +} + +static u_short __init PciDeviceId(pcidev_t dev) +{ + u_short device_id; + pci_read_config_word(dev, PCI_DEVICE_ID, &device_id); + return device_id; +} + +static u_int __init PciIrqLine(pcidev_t dev) +{ + u_char irq; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + return irq; +} + +static int __init +pci_get_base_address(pcidev_t dev, int offset, u_long *base) +{ + u_int32 tmp; + + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp); + *base = tmp; + offset += sizeof(u_int32); + if ((tmp & 0x7) == 0x4) { +#if BITS_PER_LONG > 32 + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp); + *base |= (((u_long)tmp) << 32); +#endif + offset += sizeof(u_int32); + } + return offset; +} +static u_long __init +pci_get_base_cookie(struct pci_dev *pdev, int offset) +{ + u_long base; + + (void) pci_get_base_address(dev, offset, &base); + + return base; +} + +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) */ + +/* Does not make sense in earlier kernels */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +#define pci_enable_device(pdev) (0) +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) +#define scsi_set_pci_device(inst, pdev) (0) +#endif + +/*========================================================== +** +** Debugging tags +** +**========================================================== +*/ + +#define DEBUG_ALLOC (0x0001) +#define DEBUG_PHASE (0x0002) +#define DEBUG_QUEUE (0x0008) +#define DEBUG_RESULT (0x0010) +#define DEBUG_POINTER (0x0020) +#define DEBUG_SCRIPT (0x0040) +#define DEBUG_TINY (0x0080) +#define DEBUG_TIMING (0x0100) +#define DEBUG_NEGO (0x0200) +#define DEBUG_TAGS (0x0400) +#define DEBUG_IC (0x0800) + +/* +** Enable/Disable debug messages. +** Can be changed at runtime too. +*/ + +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT +static int ncr_debug = SCSI_NCR_DEBUG_FLAGS; + #define DEBUG_FLAGS ncr_debug +#else + #define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS +#endif + +/* +** SMP threading. +** +** Assuming that SMP systems are generally high end systems and may +** use several SCSI adapters, we are using one lock per controller +** instead of some global one. For the moment (linux-2.1.95), driver's +** entry points are called with the 'io_request_lock' lock held, so: +** - We are uselessly loosing a couple of micro-seconds to lock the +** controller data structure. +** - But the driver is not broken by design for SMP and so can be +** more resistant to bugs or bad changes in the IO sub-system code. +** - A small advantage could be that the interrupt code is grained as +** wished (e.g.: threaded by controller). +*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) + +spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED; +#define NCR_LOCK_DRIVER(flags) spin_lock_irqsave(&sym53c8xx_lock, flags) +#define NCR_UNLOCK_DRIVER(flags) spin_unlock_irqrestore(&sym53c8xx_lock,flags) + +#define NCR_INIT_LOCK_NCB(np) spin_lock_init(&np->smp_lock); +#define NCR_LOCK_NCB(np, flags) spin_lock_irqsave(&np->smp_lock, flags) +#define NCR_UNLOCK_NCB(np, flags) spin_unlock_irqrestore(&np->smp_lock, flags) + +#define NCR_LOCK_SCSI_DONE(host, flags) \ + spin_lock_irqsave(((host)->host_lock), flags) +#define NCR_UNLOCK_SCSI_DONE(host, flags) \ + spin_unlock_irqrestore(((host)->host_lock), flags) + +#else + +#define NCR_LOCK_DRIVER(flags) do { save_flags(flags); cli(); } while (0) +#define NCR_UNLOCK_DRIVER(flags) do { restore_flags(flags); } while (0) + +#define NCR_INIT_LOCK_NCB(np) do { } while (0) +#define NCR_LOCK_NCB(np, flags) do { save_flags(flags); cli(); } while (0) +#define NCR_UNLOCK_NCB(np, flags) do { restore_flags(flags); } while (0) + +#define NCR_LOCK_SCSI_DONE(host, flags) do {;} while (0) +#define NCR_UNLOCK_SCSI_DONE(host, flags) do {;} while (0) + +#endif + +/* +** Memory mapped IO +** +** Since linux-2.1, we must use ioremap() to map the io memory space. +** iounmap() to unmap it. That allows portability. +** Linux 1.3.X and 2.0.X allow to remap physical pages addresses greater +** than the highest physical memory address to kernel virtual pages with +** vremap() / vfree(). That was not portable but worked with i386 +** architecture. +*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +#define ioremap vremap +#define iounmap vfree +#endif + +#ifdef __sparc__ +# include +# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) +#elif defined(__alpha__) +# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) +#else /* others */ +# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) +#endif + +#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED +static u_long __init remap_pci_mem(u_long base, u_long size) +{ + u_long page_base = ((u_long) base) & PAGE_MASK; + u_long page_offs = ((u_long) base) - page_base; + u_long page_remapped = (u_long) ioremap(page_base, page_offs+size); + + return page_remapped? (page_remapped + page_offs) : 0UL; +} + +static void __init unmap_pci_mem(u_long vaddr, u_long size) +{ + if (vaddr) + iounmap((void *) (vaddr & PAGE_MASK)); +} + +#endif /* not def SCSI_NCR_PCI_MEM_NOT_SUPPORTED */ + +/* +** Insert a delay in micro-seconds and milli-seconds. +** ------------------------------------------------- +** Under Linux, udelay() is restricted to delay < 1 milli-second. +** In fact, it generally works for up to 1 second delay. +** Since 2.1.105, the mdelay() function is provided for delays +** in milli-seconds. +** Under 2.0 kernels, udelay() is an inline function that is very +** inaccurate on Pentium processors. +*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,105) +#define UDELAY udelay +#define MDELAY mdelay +#else +static void UDELAY(long us) { udelay(us); } +static void MDELAY(long ms) { while (ms--) UDELAY(1000); } +#endif + +/* +** Simple power of two buddy-like allocator +** ---------------------------------------- +** This simple code is not intended to be fast, but to provide +** power of 2 aligned memory allocations. +** Since the SCRIPTS processor only supplies 8 bit arithmetic, +** this allocator allows simple and fast address calculations +** from the SCRIPTS code. In addition, cache line alignment +** is guaranteed for power of 2 cache line size. +** Enhanced in linux-2.3.44 to provide a memory pool per pcidev +** to support dynamic dma mapping. (I would have preferred a +** real bus astraction, btw). +*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) +#define __GetFreePages(flags, order) __get_free_pages(flags, order) +#else +#define __GetFreePages(flags, order) __get_free_pages(flags, order, 0) +#endif + +#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ +#if PAGE_SIZE >= 8192 +#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum */ +#else +#define MEMO_PAGE_ORDER 1 /* 2 PAGES maximum */ +#endif +#define MEMO_FREE_UNUSED /* Free unused pages immediately */ +#define MEMO_WARN 1 +#define MEMO_GFP_FLAGS GFP_ATOMIC +#define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER) +#define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT) +#define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1) + +typedef u_long m_addr_t; /* Enough bits to bit-hack addresses */ +typedef pcidev_t m_bush_t; /* Something that addresses DMAable */ + +typedef struct m_link { /* Link between free memory chunks */ + struct m_link *next; +} m_link_s; + +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING +typedef struct m_vtob { /* Virtual to Bus address translation */ + struct m_vtob *next; + m_addr_t vaddr; + m_addr_t baddr; +} m_vtob_s; +#define VTOB_HASH_SHIFT 5 +#define VTOB_HASH_SIZE (1UL << VTOB_HASH_SHIFT) +#define VTOB_HASH_MASK (VTOB_HASH_SIZE-1) +#define VTOB_HASH_CODE(m) \ + ((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK) +#endif + +typedef struct m_pool { /* Memory pool of a given kind */ +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + m_bush_t bush; + m_addr_t (*getp)(struct m_pool *); + void (*freep)(struct m_pool *, m_addr_t); +#define M_GETP() mp->getp(mp) +#define M_FREEP(p) mp->freep(mp, p) +#define GetPages() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER) +#define FreePages(p) free_pages(p, MEMO_PAGE_ORDER) + int nump; + m_vtob_s *(vtob[VTOB_HASH_SIZE]); + struct m_pool *next; +#else +#define M_GETP() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER) +#define M_FREEP(p) free_pages(p, MEMO_PAGE_ORDER) +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1]; +} m_pool_s; + +static void *___m_alloc(m_pool_s *mp, int size) +{ + int i = 0; + int s = (1 << MEMO_SHIFT); + int j; + m_addr_t a; + m_link_s *h = mp->h; + + if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) + return 0; + + while (size > s) { + s <<= 1; + ++i; + } + + j = i; + while (!h[j].next) { + if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { + h[j].next = (m_link_s *) M_GETP(); + if (h[j].next) + h[j].next->next = 0; + break; + } + ++j; + s <<= 1; + } + a = (m_addr_t) h[j].next; + if (a) { + h[j].next = h[j].next->next; + while (j > i) { + j -= 1; + s >>= 1; + h[j].next = (m_link_s *) (a+s); + h[j].next->next = 0; + } + } +#ifdef DEBUG + printk("___m_alloc(%d) = %p\n", size, (void *) a); +#endif + return (void *) a; +} + +static void ___m_free(m_pool_s *mp, void *ptr, int size) +{ + int i = 0; + int s = (1 << MEMO_SHIFT); + m_link_s *q; + m_addr_t a, b; + m_link_s *h = mp->h; + +#ifdef DEBUG + printk("___m_free(%p, %d)\n", ptr, size); +#endif + + if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) + return; + + while (size > s) { + s <<= 1; + ++i; + } + + a = (m_addr_t) ptr; + + while (1) { +#ifdef MEMO_FREE_UNUSED + if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { + M_FREEP(a); + break; + } +#endif + b = a ^ s; + q = &h[i]; + while (q->next && q->next != (m_link_s *) b) { + q = q->next; + } + if (!q->next) { + ((m_link_s *) a)->next = h[i].next; + h[i].next = (m_link_s *) a; + break; + } + q->next = q->next->next; + a = a & b; + s <<= 1; + ++i; + } +} + +static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags) +{ + void *p; + + p = ___m_alloc(mp, size); + + if (DEBUG_FLAGS & DEBUG_ALLOC) + printk ("new %-10s[%4d] @%p.\n", name, size, p); + + if (p) + bzero(p, size); + else if (uflags & MEMO_WARN) + printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size); + + return p; +} + +#define __m_calloc(mp, s, n) __m_calloc2(mp, s, n, MEMO_WARN) + +static void __m_free(m_pool_s *mp, void *ptr, int size, char *name) +{ + if (DEBUG_FLAGS & DEBUG_ALLOC) + printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr); + + ___m_free(mp, ptr, size); + +} + +/* + * With pci bus iommu support, we use a default pool of unmapped memory + * for memory we donnot need to DMA from/to and one pool per pcidev for + * memory accessed by the PCI chip. `mp0' is the default not DMAable pool. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +static m_pool_s mp0; + +#else + +static m_addr_t ___mp0_getp(m_pool_s *mp) +{ + m_addr_t m = GetPages(); + if (m) + ++mp->nump; + return m; +} + +static void ___mp0_freep(m_pool_s *mp, m_addr_t m) +{ + FreePages(m); + --mp->nump; +} + +static m_pool_s mp0 = {0, ___mp0_getp, ___mp0_freep}; + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +static void *m_calloc(int size, char *name) +{ + u_long flags; + void *m; + NCR_LOCK_DRIVER(flags); + m = __m_calloc(&mp0, size, name); + NCR_UNLOCK_DRIVER(flags); + return m; +} + +static void m_free(void *ptr, int size, char *name) +{ + u_long flags; + NCR_LOCK_DRIVER(flags); + __m_free(&mp0, ptr, size, name); + NCR_UNLOCK_DRIVER(flags); +} + +/* + * DMAable pools. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +/* Without pci bus iommu support, all the memory is assumed DMAable */ + +#define __m_calloc_dma(b, s, n) m_calloc(s, n) +#define __m_free_dma(b, p, s, n) m_free(p, s, n) +#define __vtobus(b, p) virt_to_bus(p) + +#else + +/* + * With pci bus iommu support, we maintain one pool per pcidev and a + * hashed reverse table for virtual to bus physical address translations. + */ +static m_addr_t ___dma_getp(m_pool_s *mp) +{ + m_addr_t vp; + m_vtob_s *vbp; + + vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB"); + if (vbp) { + dma_addr_t daddr; + vp = (m_addr_t) pci_alloc_consistent(mp->bush, + PAGE_SIZE<vaddr = vp; + vbp->baddr = daddr; + vbp->next = mp->vtob[hc]; + mp->vtob[hc] = vbp; + ++mp->nump; + return vp; + } + else + __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); + } + return 0; +} + +static void ___dma_freep(m_pool_s *mp, m_addr_t m) +{ + m_vtob_s **vbpp, *vbp; + int hc = VTOB_HASH_CODE(m); + + vbpp = &mp->vtob[hc]; + while (*vbpp && (*vbpp)->vaddr != m) + vbpp = &(*vbpp)->next; + if (*vbpp) { + vbp = *vbpp; + *vbpp = (*vbpp)->next; + pci_free_consistent(mp->bush, PAGE_SIZE<vaddr, (dma_addr_t)vbp->baddr); + __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); + --mp->nump; + } +} + +static inline m_pool_s *___get_dma_pool(m_bush_t bush) +{ + m_pool_s *mp; + for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next); + return mp; +} + +static m_pool_s *___cre_dma_pool(m_bush_t bush) +{ + m_pool_s *mp; + mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL"); + if (mp) { + bzero(mp, sizeof(*mp)); + mp->bush = bush; + mp->getp = ___dma_getp; + mp->freep = ___dma_freep; + mp->next = mp0.next; + mp0.next = mp; + } + return mp; +} + +static void ___del_dma_pool(m_pool_s *p) +{ + struct m_pool **pp = &mp0.next; + + while (*pp && *pp != p) + pp = &(*pp)->next; + if (*pp) { + *pp = (*pp)->next; + __m_free(&mp0, p, sizeof(*p), "MPOOL"); + } +} + +static void *__m_calloc_dma(m_bush_t bush, int size, char *name) +{ + u_long flags; + struct m_pool *mp; + void *m = 0; + + NCR_LOCK_DRIVER(flags); + mp = ___get_dma_pool(bush); + if (!mp) + mp = ___cre_dma_pool(bush); + if (mp) + m = __m_calloc(mp, size, name); + if (mp && !mp->nump) + ___del_dma_pool(mp); + NCR_UNLOCK_DRIVER(flags); + + return m; +} + +static void __m_free_dma(m_bush_t bush, void *m, int size, char *name) +{ + u_long flags; + struct m_pool *mp; + + NCR_LOCK_DRIVER(flags); + mp = ___get_dma_pool(bush); + if (mp) + __m_free(mp, m, size, name); + if (mp && !mp->nump) + ___del_dma_pool(mp); + NCR_UNLOCK_DRIVER(flags); +} + +static m_addr_t __vtobus(m_bush_t bush, void *m) +{ + u_long flags; + m_pool_s *mp; + int hc = VTOB_HASH_CODE(m); + m_vtob_s *vp = 0; + m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK; + + NCR_LOCK_DRIVER(flags); + mp = ___get_dma_pool(bush); + if (mp) { + vp = mp->vtob[hc]; + while (vp && (m_addr_t) vp->vaddr != a) + vp = vp->next; + } + NCR_UNLOCK_DRIVER(flags); + return vp ? vp->baddr + (((m_addr_t) m) - a) : 0; +} + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +#define _m_calloc_dma(np, s, n) __m_calloc_dma(np->pdev, s, n) +#define _m_free_dma(np, p, s, n) __m_free_dma(np->pdev, p, s, n) +#define m_calloc_dma(s, n) _m_calloc_dma(np, s, n) +#define m_free_dma(p, s, n) _m_free_dma(np, p, s, n) +#define _vtobus(np, p) __vtobus(np->pdev, p) +#define vtobus(p) _vtobus(np, p) + +/* + * Deal with DMA mapping/unmapping. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +/* Linux versions prior to pci bus iommu kernel interface */ + +#define __unmap_scsi_data(pdev, cmd) do {; } while (0) +#define __map_scsi_single_data(pdev, cmd) (__vtobus(pdev,(cmd)->request_buffer)) +#define __map_scsi_sg_data(pdev, cmd) ((cmd)->use_sg) +#define __sync_scsi_data(pdev, cmd) do {; } while (0) + +#define scsi_sg_dma_address(sc) vtobus((sc)->address) +#define scsi_sg_dma_len(sc) ((sc)->length) + +#else + +/* Linux version with pci bus iommu kernel interface */ + +/* To keep track of the dma mapping (sg/single) that has been set */ +#define __data_mapped(cmd) (cmd)->SCp.phase +#define __data_mapping(cmd) (cmd)->SCp.dma_handle + +static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(__data_mapped(cmd)) { + case 2: + pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + pci_unmap_page(pdev, __data_mapping(cmd), + cmd->request_bufflen, dma_dir); + break; + } + __data_mapped(cmd) = 0; +} + +static dma_addr_t __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + dma_addr_t mapping; + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + if (cmd->request_bufflen == 0) + return 0; + + mapping = pci_map_page(pdev, + virt_to_page(cmd->request_buffer), + ((unsigned long)cmd->request_buffer & + ~PAGE_MASK), + cmd->request_bufflen, dma_dir); + __data_mapped(cmd) = 1; + __data_mapping(cmd) = mapping; + + return mapping; +} + +static int __map_scsi_sg_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int use_sg; + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + if (cmd->use_sg == 0) + return 0; + + use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + __data_mapped(cmd) = 2; + __data_mapping(cmd) = use_sg; + + return use_sg; +} + +static void __sync_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(__data_mapped(cmd)) { + case 2: + pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + pci_dma_sync_single(pdev, __data_mapping(cmd), + cmd->request_bufflen, dma_dir); + break; + } +} + +#define scsi_sg_dma_address(sc) sg_dma_address(sc) +#define scsi_sg_dma_len(sc) sg_dma_len(sc) + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->pdev, cmd) +#define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->pdev, cmd) +#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->pdev, cmd) +#define sync_scsi_data(np, cmd) __sync_scsi_data(np->pdev, cmd) + + +/* + * Print out some buffer. + */ +static void ncr_print_hex(u_char *p, int n) +{ + while (n-- > 0) + printk (" %x", *p++); +} + +static void ncr_printl_hex(char *label, u_char *p, int n) +{ + printk("%s", label); + ncr_print_hex(p, n); + printk (".\n"); +} + +/* +** Transfer direction +** +** Until some linux kernel version near 2.3.40, low-level scsi +** drivers were not told about data transfer direction. +** We check the existence of this feature that has been expected +** for a _long_ time by all SCSI driver developers by just +** testing against the definition of SCSI_DATA_UNKNOWN. Indeed +** this is a hack, but testing against a kernel version would +** have been a shame. ;-) +*/ +#ifdef SCSI_DATA_UNKNOWN + +#define scsi_data_direction(cmd) (cmd->sc_data_direction) + +#else + +#define SCSI_DATA_UNKNOWN 0 +#define SCSI_DATA_WRITE 1 +#define SCSI_DATA_READ 2 +#define SCSI_DATA_NONE 3 + +static __inline__ int scsi_data_direction(Scsi_Cmnd *cmd) +{ + int direction; + + switch((int) cmd->cmnd[0]) { + case 0x08: /* READ(6) 08 */ + case 0x28: /* READ(10) 28 */ + case 0xA8: /* READ(12) A8 */ + direction = SCSI_DATA_READ; + break; + case 0x0A: /* WRITE(6) 0A */ + case 0x2A: /* WRITE(10) 2A */ + case 0xAA: /* WRITE(12) AA */ + direction = SCSI_DATA_WRITE; + break; + default: + direction = SCSI_DATA_UNKNOWN; + break; + } + + return direction; +} + +#endif /* SCSI_DATA_UNKNOWN */ + + +/* +** /proc directory entry and proc_info function +*/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,27) +static struct proc_dir_entry proc_scsi_sym53c8xx = { + PROC_SCSI_SYM53C8XX, 9, NAME53C8XX, + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +#endif +#ifdef SCSI_NCR_PROC_INFO_SUPPORT +static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int func); +#endif + +/* +** Driver setup. +** +** This structure is initialized from linux config options. +** It can be overridden at boot-up by the boot command line. +*/ +static struct ncr_driver_setup + driver_setup = SCSI_NCR_DRIVER_SETUP; + +#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT +static struct ncr_driver_setup + driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP; +# ifdef MODULE +char *sym53c8xx = 0; /* command line passed by insmod */ +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) +MODULE_PARM(sym53c8xx, "s"); +# endif +# endif +#endif + +/* +** Other Linux definitions +*/ +#define SetScsiResult(cmd, h_sts, s_sts) \ + cmd->result = (((h_sts) << 16) + ((s_sts) & 0x7f)) + +/* We may have to remind our amnesiac SCSI layer of the reason of the abort */ +#if 0 +#define SetScsiAbortResult(cmd) \ + SetScsiResult( \ + cmd, \ + (cmd)->abort_reason == DID_TIME_OUT ? DID_TIME_OUT : DID_ABORT, \ + 0xff) +#else +#define SetScsiAbortResult(cmd) SetScsiResult(cmd, DID_ABORT, 0xff) +#endif + +static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs); +static void sym53c8xx_timeout(unsigned long np); + +#define initverbose (driver_setup.verbose) +#define bootverbose (np->verbose) + +#ifdef SCSI_NCR_NVRAM_SUPPORT +static u_char Tekram_sync[16] __initdata = + {25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10}; +#endif /* SCSI_NCR_NVRAM_SUPPORT */ + +/* +** Structures used by sym53c8xx_detect/sym53c8xx_pci_init to +** transmit device configuration to the ncr_attach() function. +*/ +typedef struct { + int bus; + u_char device_fn; + u_long base; + u_long base_2; + u_long io_port; + u_long base_c; + u_long base_2_c; + int irq; +/* port and reg fields to use INB, OUTB macros */ + u_long base_io; + volatile struct ncr_reg *reg; +} ncr_slot; + +typedef struct { + int type; +#define SCSI_NCR_SYMBIOS_NVRAM (1) +#define SCSI_NCR_TEKRAM_NVRAM (2) +#ifdef SCSI_NCR_NVRAM_SUPPORT + union { + Symbios_nvram Symbios; + Tekram_nvram Tekram; + } data; +#endif +} ncr_nvram; + +/* +** Structure used by sym53c8xx_detect/sym53c8xx_pci_init +** to save data on each detected board for ncr_attach(). +*/ +typedef struct { + pcidev_t pdev; + ncr_slot slot; + ncr_chip chip; + ncr_nvram *nvram; + u_char host_id; +#ifdef SCSI_NCR_PQS_PDS_SUPPORT + u_char pqs_pds; +#endif + int attach_done; +} ncr_device; + +/*========================================================== +** +** assert () +** +**========================================================== +** +** modified copy from 386bsd:/usr/include/sys/assert.h +** +**---------------------------------------------------------- +*/ + +#define assert(expression) { \ + if (!(expression)) { \ + (void)panic( \ + "assertion \"%s\" failed: file \"%s\", line %d\n", \ + #expression, \ + __FILE__, __LINE__); \ + } \ +} + +/*========================================================== +** +** Command control block states. +** +**========================================================== +*/ + +#define HS_IDLE (0) +#define HS_BUSY (1) +#define HS_NEGOTIATE (2) /* sync/wide data transfer*/ +#define HS_DISCONNECT (3) /* Disconnected by target */ + +#define HS_DONEMASK (0x80) +#define HS_COMPLETE (4|HS_DONEMASK) +#define HS_SEL_TIMEOUT (5|HS_DONEMASK) /* Selection timeout */ +#define HS_RESET (6|HS_DONEMASK) /* SCSI reset */ +#define HS_ABORTED (7|HS_DONEMASK) /* Transfer aborted */ +#define HS_TIMEOUT (8|HS_DONEMASK) /* Software timeout */ +#define HS_FAIL (9|HS_DONEMASK) /* SCSI or PCI bus errors */ +#define HS_UNEXPECTED (10|HS_DONEMASK)/* Unexpected disconnect */ + +#define DSA_INVALID 0xffffffff + +/*========================================================== +** +** Software Interrupt Codes +** +**========================================================== +*/ + +#define SIR_BAD_STATUS (1) +#define SIR_SEL_ATN_NO_MSG_OUT (2) +#define SIR_MSG_RECEIVED (3) +#define SIR_MSG_WEIRD (4) +#define SIR_NEGO_FAILED (5) +#define SIR_NEGO_PROTO (6) +#define SIR_SCRIPT_STOPPED (7) +#define SIR_REJECT_TO_SEND (8) +#define SIR_SWIDE_OVERRUN (9) +#define SIR_SODL_UNDERRUN (10) +#define SIR_RESEL_NO_MSG_IN (11) +#define SIR_RESEL_NO_IDENTIFY (12) +#define SIR_RESEL_BAD_LUN (13) +#define SIR_TARGET_SELECTED (14) +#define SIR_RESEL_BAD_I_T_L (15) +#define SIR_RESEL_BAD_I_T_L_Q (16) +#define SIR_ABORT_SENT (17) +#define SIR_RESEL_ABORTED (18) +#define SIR_MSG_OUT_DONE (19) +#define SIR_AUTO_SENSE_DONE (20) +#define SIR_DUMMY_INTERRUPT (21) +#define SIR_DATA_OVERRUN (22) +#define SIR_BAD_PHASE (23) +#define SIR_MAX (23) + +/*========================================================== +** +** Extended error bits. +** xerr_status field of struct ccb. +** +**========================================================== +*/ + +#define XE_EXTRA_DATA (1) /* unexpected data phase */ +#define XE_BAD_PHASE (2) /* illegal phase (4/5) */ +#define XE_PARITY_ERR (4) /* unrecovered SCSI parity error */ +#define XE_SODL_UNRUN (1<<3) +#define XE_SWIDE_OVRUN (1<<4) + +/*========================================================== +** +** Negotiation status. +** nego_status field of struct ccb. +** +**========================================================== +*/ + +#define NS_NOCHANGE (0) +#define NS_SYNC (1) +#define NS_WIDE (2) +#define NS_PPR (4) + +/*========================================================== +** +** "Special features" of targets. +** quirks field of struct tcb. +** actualquirks field of struct ccb. +** +**========================================================== +*/ + +#define QUIRK_AUTOSAVE (0x01) + +/*========================================================== +** +** Capability bits in Inquire response byte 7. +** +**========================================================== +*/ + +#define INQ7_QUEUE (0x02) +#define INQ7_SYNC (0x10) +#define INQ7_WIDE16 (0x20) + +/*========================================================== +** +** A CCB hashed table is used to retrieve CCB address +** from DSA value. +** +**========================================================== +*/ + +#define CCB_HASH_SHIFT 8 +#define CCB_HASH_SIZE (1UL << CCB_HASH_SHIFT) +#define CCB_HASH_MASK (CCB_HASH_SIZE-1) +#define CCB_HASH_CODE(dsa) (((dsa) >> 11) & CCB_HASH_MASK) + +/*========================================================== +** +** Declaration of structs. +** +**========================================================== +*/ + +struct tcb; +struct lcb; +struct ccb; +struct ncb; +struct script; + +typedef struct ncb * ncb_p; +typedef struct tcb * tcb_p; +typedef struct lcb * lcb_p; +typedef struct ccb * ccb_p; + +struct link { + ncrcmd l_cmd; + ncrcmd l_paddr; +}; + +struct usrcmd { + u_long target; + u_long lun; + u_long data; + u_long cmd; +}; + +#define UC_SETSYNC 10 +#define UC_SETTAGS 11 +#define UC_SETDEBUG 12 +#define UC_SETORDER 13 +#define UC_SETWIDE 14 +#define UC_SETFLAG 15 +#define UC_SETVERBOSE 17 +#define UC_RESETDEV 18 +#define UC_CLEARDEV 19 + +#define UF_TRACE (0x01) +#define UF_NODISC (0x02) +#define UF_NOSCAN (0x04) + +/*======================================================================== +** +** Declaration of structs: target control block +** +**======================================================================== +*/ +struct tcb { + /*---------------------------------------------------------------- + ** LUN tables. + ** An array of bus addresses is used on reselection by + ** the SCRIPT. + **---------------------------------------------------------------- + */ + u_int32 *luntbl; /* lcbs bus address table */ + u_int32 b_luntbl; /* bus address of this table */ + u_int32 b_lun0; /* bus address of lun0 */ + lcb_p l0p; /* lcb of LUN #0 (normal case) */ +#if MAX_LUN > 1 + lcb_p *lmp; /* Other lcb's [1..MAX_LUN] */ +#endif + /*---------------------------------------------------------------- + ** Target capabilities. + **---------------------------------------------------------------- + */ + u_char inq_done; /* Target capabilities received */ + u_char inq_byte7; /* Contains these capabilities */ + + /*---------------------------------------------------------------- + ** Some flags. + **---------------------------------------------------------------- + */ + u_char to_reset; /* This target is to be reset */ + + /*---------------------------------------------------------------- + ** Pointer to the ccb used for negotiation. + ** Prevent from starting a negotiation for all queued commands + ** when tagged command queuing is enabled. + **---------------------------------------------------------------- + */ + ccb_p nego_cp; + + /*---------------------------------------------------------------- + ** negotiation of wide and synch transfer and device quirks. + ** sval, wval and uval are read from SCRIPTS and so have alignment + ** constraints. + **---------------------------------------------------------------- + */ +/*0*/ u_char uval; +/*1*/ u_char sval; +/*2*/ u_char filler2; +/*3*/ u_char wval; + u_short period; + u_char minsync; + u_char maxoffs; + u_char quirks; + u_char widedone; + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + u_char ic_min_sync; + u_char ic_max_width; + u_char ic_done; +#endif + u_char ic_maximums_set; + u_char ppr_negotiation; + + /*---------------------------------------------------------------- + ** User settable limits and options. + ** These limits are read from the NVRAM if present. + **---------------------------------------------------------------- + */ + u_char usrsync; + u_char usrwide; + u_short usrtags; + u_char usrflag; +}; + +/*======================================================================== +** +** Declaration of structs: lun control block +** +**======================================================================== +*/ +struct lcb { + /*---------------------------------------------------------------- + ** On reselection, SCRIPTS use this value as a JUMP address + ** after the IDENTIFY has been successfully received. + ** This field is set to 'resel_tag' if TCQ is enabled and + ** to 'resel_notag' if TCQ is disabled. + ** (Must be at zero due to bad lun handling on reselection) + **---------------------------------------------------------------- + */ +/*0*/ u_int32 resel_task; + + /*---------------------------------------------------------------- + ** Task table used by the script processor to retrieve the + ** task corresponding to a reselected nexus. The TAG is used + ** as offset to determine the corresponding entry. + ** Each entry contains the associated CCB bus address. + **---------------------------------------------------------------- + */ + u_int32 tasktbl_0; /* Used if TCQ not enabled */ + u_int32 *tasktbl; + u_int32 b_tasktbl; + + /*---------------------------------------------------------------- + ** CCB queue management. + **---------------------------------------------------------------- + */ + XPT_QUEHEAD busy_ccbq; /* Queue of busy CCBs */ + XPT_QUEHEAD wait_ccbq; /* Queue of waiting for IO CCBs */ + u_short busyccbs; /* CCBs busy for this lun */ + u_short queuedccbs; /* CCBs queued to the controller*/ + u_short queuedepth; /* Queue depth for this lun */ + u_short scdev_depth; /* SCSI device queue depth */ + u_short maxnxs; /* Max possible nexuses */ + + /*---------------------------------------------------------------- + ** Control of tagged command queuing. + ** Tags allocation is performed using a circular buffer. + ** This avoids using a loop for tag allocation. + **---------------------------------------------------------------- + */ + u_short ia_tag; /* Tag allocation index */ + u_short if_tag; /* Tag release index */ + u_char *cb_tags; /* Circular tags buffer */ + u_char inq_byte7; /* Store unit CmdQ capability */ + u_char usetags; /* Command queuing is active */ + u_char to_clear; /* User wants to clear all tasks*/ + u_short maxtags; /* Max NR of tags asked by user */ + u_short numtags; /* Current number of tags */ + + /*---------------------------------------------------------------- + ** QUEUE FULL and ORDERED tag control. + **---------------------------------------------------------------- + */ + u_short num_good; /* Nr of GOOD since QUEUE FULL */ + u_short tags_sum[2]; /* Tags sum counters */ + u_char tags_si; /* Current index to tags sum */ + u_long tags_stime; /* Last time we switch tags_sum */ +}; + +/*======================================================================== +** +** Declaration of structs: actions for a task. +** +**======================================================================== +** +** It is part of the CCB and is called by the scripts processor to +** start or restart the data structure (nexus). +** +**------------------------------------------------------------------------ +*/ +struct action { + u_int32 start; + u_int32 restart; +}; + +/*======================================================================== +** +** Declaration of structs: Phase mismatch context. +** +**======================================================================== +** +** It is part of the CCB and is used as parameters for the DATA +** pointer. We need two contexts to handle correctly the SAVED +** DATA POINTER. +** +**------------------------------------------------------------------------ +*/ +struct pm_ctx { + struct scr_tblmove sg; /* Updated interrupted SG block */ + u_int32 ret; /* SCRIPT return address */ +}; + +/*======================================================================== +** +** Declaration of structs: global HEADER. +** +**======================================================================== +** +** In earlier driver versions, this substructure was copied from the +** ccb to a global address after selection (or reselection) and copied +** back before disconnect. Since we are now using LOAD/STORE DSA +** RELATIVE instructions, the script is able to access directly these +** fields, and so, this header is no more copied. +** +**------------------------------------------------------------------------ +*/ + +struct head { + /*---------------------------------------------------------------- + ** Start and restart SCRIPTS addresses (must be at 0). + **---------------------------------------------------------------- + */ + struct action go; + + /*---------------------------------------------------------------- + ** Saved data pointer. + ** Points to the position in the script responsible for the + ** actual transfer of data. + ** It's written after reception of a SAVE_DATA_POINTER message. + ** The goalpointer points after the last transfer command. + **---------------------------------------------------------------- + */ + u_int32 savep; + u_int32 lastp; + u_int32 goalp; + + /*---------------------------------------------------------------- + ** Alternate data pointer. + ** They are copied back to savep/lastp/goalp by the SCRIPTS + ** when the direction is unknown and the device claims data out. + **---------------------------------------------------------------- + */ + u_int32 wlastp; + u_int32 wgoalp; + + /*---------------------------------------------------------------- + ** Status fields. + **---------------------------------------------------------------- + */ + u_char status[4]; /* host status */ +}; + +/* +** LUN control block lookup. +** We use a direct pointer for LUN #0, and a table of pointers +** which is only allocated for devices that support LUN(s) > 0. +*/ +#if MAX_LUN <= 1 +#define ncr_lp(np, tp, lun) (!lun) ? (tp)->l0p : 0 +#else +#define ncr_lp(np, tp, lun) \ + (!lun) ? (tp)->l0p : (tp)->lmp ? (tp)->lmp[(lun)] : 0 +#endif + +/* +** The status bytes are used by the host and the script processor. +** +** The four bytes (status[4]) are copied to the scratchb register +** (declared as scr0..scr3 in ncr_reg.h) just after the select/reselect, +** and copied back just after disconnecting. +** Inside the script the XX_REG are used. +*/ + +/* +** Last four bytes (script) +*/ +#define QU_REG scr0 +#define HS_REG scr1 +#define HS_PRT nc_scr1 +#define SS_REG scr2 +#define SS_PRT nc_scr2 +#define HF_REG scr3 +#define HF_PRT nc_scr3 + +/* +** Last four bytes (host) +*/ +#define actualquirks phys.header.status[0] +#define host_status phys.header.status[1] +#define scsi_status phys.header.status[2] +#define host_flags phys.header.status[3] + +/* +** Host flags +*/ +#define HF_IN_PM0 1u +#define HF_IN_PM1 (1u<<1) +#define HF_ACT_PM (1u<<2) +#define HF_DP_SAVED (1u<<3) +#define HF_AUTO_SENSE (1u<<4) +#define HF_DATA_IN (1u<<5) +#define HF_PM_TO_C (1u<<6) +#define HF_EXT_ERR (1u<<7) + +#ifdef SCSI_NCR_IARB_SUPPORT +#define HF_HINT_IARB (1u<<7) +#endif + +/* +** This one is stolen from QU_REG.:) +*/ +#define HF_DATA_ST (1u<<7) + +/*========================================================== +** +** Declaration of structs: Data structure block +** +**========================================================== +** +** During execution of a ccb by the script processor, +** the DSA (data structure address) register points +** to this substructure of the ccb. +** This substructure contains the header with +** the script-processor-changable data and +** data blocks for the indirect move commands. +** +**---------------------------------------------------------- +*/ + +struct dsb { + + /* + ** Header. + */ + + struct head header; + + /* + ** Table data for Script + */ + + struct scr_tblsel select; + struct scr_tblmove smsg ; + struct scr_tblmove smsg_ext ; + struct scr_tblmove cmd ; + struct scr_tblmove sense ; + struct scr_tblmove wresid; + struct scr_tblmove data [MAX_SCATTER]; + + /* + ** Phase mismatch contexts. + ** We need two to handle correctly the + ** SAVED DATA POINTER. + */ + + struct pm_ctx pm0; + struct pm_ctx pm1; +}; + + +/*======================================================================== +** +** Declaration of structs: Command control block. +** +**======================================================================== +*/ +struct ccb { + /*---------------------------------------------------------------- + ** This is the data structure which is pointed by the DSA + ** register when it is executed by the script processor. + ** It must be the first entry. + **---------------------------------------------------------------- + */ + struct dsb phys; + + /*---------------------------------------------------------------- + ** The general SCSI driver provides a + ** pointer to a control block. + **---------------------------------------------------------------- + */ + Scsi_Cmnd *cmd; /* SCSI command */ + u_char cdb_buf[16]; /* Copy of CDB */ + u_char sense_buf[64]; + int data_len; /* Total data length */ + int segments; /* Number of SG segments */ + + /*---------------------------------------------------------------- + ** Message areas. + ** We prepare a message to be sent after selection. + ** We may use a second one if the command is rescheduled + ** due to CHECK_CONDITION or QUEUE FULL status. + ** Contents are IDENTIFY and SIMPLE_TAG. + ** While negotiating sync or wide transfer, + ** a SDTR or WDTR message is appended. + **---------------------------------------------------------------- + */ + u_char scsi_smsg [12]; + u_char scsi_smsg2[12]; + + /*---------------------------------------------------------------- + ** Miscellaneous status'. + **---------------------------------------------------------------- + */ + u_char nego_status; /* Negotiation status */ + u_char xerr_status; /* Extended error flags */ + u_int32 extra_bytes; /* Extraneous bytes transferred */ + + /*---------------------------------------------------------------- + ** Saved info for auto-sense + **---------------------------------------------------------------- + */ + u_char sv_scsi_status; + u_char sv_xerr_status; + + /*---------------------------------------------------------------- + ** Other fields. + **---------------------------------------------------------------- + */ + u_long p_ccb; /* BUS address of this CCB */ + u_char sensecmd[6]; /* Sense command */ + u_char to_abort; /* This CCB is to be aborted */ + u_short tag; /* Tag for this transfer */ + /* NO_TAG means no tag */ + u_char tags_si; /* Lun tags sum index (0,1) */ + + u_char target; + u_char lun; + u_short queued; + ccb_p link_ccb; /* Host adapter CCB chain */ + ccb_p link_ccbh; /* Host adapter CCB hash chain */ + XPT_QUEHEAD link_ccbq; /* Link to unit CCB queue */ + u_int32 startp; /* Initial data pointer */ + u_int32 lastp0; /* Initial 'lastp' */ + int ext_sg; /* Extreme data pointer, used */ + int ext_ofs; /* to calculate the residual. */ + int resid; +}; + +#define CCB_PHYS(cp,lbl) (cp->p_ccb + offsetof(struct ccb, lbl)) + + +/*======================================================================== +** +** Declaration of structs: NCR device descriptor +** +**======================================================================== +*/ +struct ncb { + /*---------------------------------------------------------------- + ** Idle task and invalid task actions and their bus + ** addresses. + **---------------------------------------------------------------- + */ + struct action idletask; + struct action notask; + struct action bad_i_t_l; + struct action bad_i_t_l_q; + u_long p_idletask; + u_long p_notask; + u_long p_bad_i_t_l; + u_long p_bad_i_t_l_q; + + /*---------------------------------------------------------------- + ** Dummy lun table to protect us against target returning bad + ** lun number on reselection. + **---------------------------------------------------------------- + */ + u_int32 *badluntbl; /* Table physical address */ + u_int32 resel_badlun; /* SCRIPT handler BUS address */ + + /*---------------------------------------------------------------- + ** Bit 32-63 of the on-chip RAM bus address in LE format. + ** The START_RAM64 script loads the MMRS and MMWS from this + ** field. + **---------------------------------------------------------------- + */ + u_int32 scr_ram_seg; + + /*---------------------------------------------------------------- + ** CCBs management queues. + **---------------------------------------------------------------- + */ + Scsi_Cmnd *waiting_list; /* Commands waiting for a CCB */ + /* when lcb is not allocated. */ + Scsi_Cmnd *done_list; /* Commands waiting for done() */ + /* callback to be invoked. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) + spinlock_t smp_lock; /* Lock for SMP threading */ +#endif + + /*---------------------------------------------------------------- + ** Chip and controller indentification. + **---------------------------------------------------------------- + */ + int unit; /* Unit number */ + char chip_name[8]; /* Chip name */ + char inst_name[16]; /* ncb instance name */ + + /*---------------------------------------------------------------- + ** Initial value of some IO register bits. + ** These values are assumed to have been set by BIOS, and may + ** be used for probing adapter implementation differences. + **---------------------------------------------------------------- + */ + u_char sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4, + sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_stest1, sv_scntl4; + + /*---------------------------------------------------------------- + ** Actual initial value of IO register bits used by the + ** driver. They are loaded at initialisation according to + ** features that are to be enabled. + **---------------------------------------------------------------- + */ + u_char rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4, + rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1, rv_scntl4; + + /*---------------------------------------------------------------- + ** Target data. + ** Target control block bus address array used by the SCRIPT + ** on reselection. + **---------------------------------------------------------------- + */ + struct tcb target[MAX_TARGET]; + u_int32 *targtbl; + + /*---------------------------------------------------------------- + ** Virtual and physical bus addresses of the chip. + **---------------------------------------------------------------- + */ +#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + u_long base_va; /* MMIO base virtual address */ + u_long base2_va; /* On-chip RAM virtual address */ +#endif + u_long base_ba; /* MMIO base bus address */ + u_long base_io; /* IO space base address */ + u_long base_ws; /* (MM)IO window size */ + u_long base2_ba; /* On-chip RAM bus address */ + u_long base2_ws; /* On-chip RAM window size */ + u_int irq; /* IRQ number */ + volatile /* Pointer to volatile for */ + struct ncr_reg *reg; /* memory mapped IO. */ + + /*---------------------------------------------------------------- + ** SCRIPTS virtual and physical bus addresses. + ** 'script' is loaded in the on-chip RAM if present. + ** 'scripth' stays in main memory for all chips except the + ** 53C895A and 53C896 that provide 8K on-chip RAM. + **---------------------------------------------------------------- + */ + struct script *script0; /* Copies of script and scripth */ + struct scripth *scripth0; /* relocated for this ncb. */ + u_long p_script; /* Actual script and scripth */ + u_long p_scripth; /* bus addresses. */ + u_long p_scripth0; + + /*---------------------------------------------------------------- + ** General controller parameters and configuration. + **---------------------------------------------------------------- + */ + pcidev_t pdev; + u_short device_id; /* PCI device id */ + u_char revision_id; /* PCI device revision id */ + u_char bus; /* PCI BUS number */ + u_char device_fn; /* PCI BUS device and function */ + u_char myaddr; /* SCSI id of the adapter */ + u_char maxburst; /* log base 2 of dwords burst */ + u_char maxwide; /* Maximum transfer width */ + u_char minsync; /* Minimum sync period factor */ + u_char maxsync; /* Maximum sync period factor */ + u_char maxoffs; /* Max scsi offset */ + u_char maxoffs_st; /* Max scsi offset in ST mode */ + u_char multiplier; /* Clock multiplier (1,2,4) */ + u_char clock_divn; /* Number of clock divisors */ + u_long clock_khz; /* SCSI clock frequency in KHz */ + u_int features; /* Chip features map */ + + /*---------------------------------------------------------------- + ** Range for the PCI clock frequency measurement result + ** that ensures the algorithm used by the driver can be + ** trusted for the SCSI clock frequency measurement. + ** (Assuming a PCI clock frequency of 33 MHz). + **---------------------------------------------------------------- + */ + u_int pciclock_min; + u_int pciclock_max; + + /*---------------------------------------------------------------- + ** Start queue management. + ** It is filled up by the host processor and accessed by the + ** SCRIPTS processor in order to start SCSI commands. + **---------------------------------------------------------------- + */ + u_long p_squeue; /* Start queue BUS address */ + u_int32 *squeue; /* Start queue virtual address */ + u_short squeueput; /* Next free slot of the queue */ + u_short actccbs; /* Number of allocated CCBs */ + u_short queuedepth; /* Start queue depth */ + + /*---------------------------------------------------------------- + ** Command completion queue. + ** It is the same size as the start queue to avoid overflow. + **---------------------------------------------------------------- + */ + u_short dqueueget; /* Next position to scan */ + u_int32 *dqueue; /* Completion (done) queue */ + + /*---------------------------------------------------------------- + ** Timeout handler. + **---------------------------------------------------------------- + */ + struct timer_list timer; /* Timer handler link header */ + u_long lasttime; + u_long settle_time; /* Resetting the SCSI BUS */ + + /*---------------------------------------------------------------- + ** Debugging and profiling. + **---------------------------------------------------------------- + */ + struct ncr_reg regdump; /* Register dump */ + u_long regtime; /* Time it has been done */ + + /*---------------------------------------------------------------- + ** Miscellaneous buffers accessed by the scripts-processor. + ** They shall be DWORD aligned, because they may be read or + ** written with a script command. + **---------------------------------------------------------------- + */ + u_char msgout[12]; /* Buffer for MESSAGE OUT */ + u_char msgin [12]; /* Buffer for MESSAGE IN */ + u_int32 lastmsg; /* Last SCSI message sent */ + u_char scratch; /* Scratch for SCSI receive */ + + /*---------------------------------------------------------------- + ** Miscellaneous configuration and status parameters. + **---------------------------------------------------------------- + */ + u_char scsi_mode; /* Current SCSI BUS mode */ + u_char order; /* Tag order to use */ + u_char verbose; /* Verbosity for this controller*/ + u_int32 ncr_cache; /* Used for cache test at init. */ + u_long p_ncb; /* BUS address of this NCB */ + + /*---------------------------------------------------------------- + ** CCB lists and queue. + **---------------------------------------------------------------- + */ + ccb_p ccbh[CCB_HASH_SIZE]; /* CCB hashed by DSA value */ + struct ccb *ccbc; /* CCB chain */ + XPT_QUEHEAD free_ccbq; /* Queue of available CCBs */ + + /*---------------------------------------------------------------- + ** IMMEDIATE ARBITRATION (IARB) control. + ** We keep track in 'last_cp' of the last CCB that has been + ** queued to the SCRIPTS processor and clear 'last_cp' when + ** this CCB completes. If last_cp is not zero at the moment + ** we queue a new CCB, we set a flag in 'last_cp' that is + ** used by the SCRIPTS as a hint for setting IARB. + ** We donnot set more than 'iarb_max' consecutive hints for + ** IARB in order to leave devices a chance to reselect. + ** By the way, any non zero value of 'iarb_max' is unfair. :) + **---------------------------------------------------------------- + */ +#ifdef SCSI_NCR_IARB_SUPPORT + struct ccb *last_cp; /* Last queud CCB used for IARB */ + u_short iarb_max; /* Max. # consecutive IARB hints*/ + u_short iarb_count; /* Actual # of these hints */ +#endif + + /*---------------------------------------------------------------- + ** We need the LCB in order to handle disconnections and + ** to count active CCBs for task management. So, we use + ** a unique CCB for LUNs we donnot have the LCB yet. + ** This queue normally should have at most 1 element. + **---------------------------------------------------------------- + */ + XPT_QUEHEAD b0_ccbq; + + /*---------------------------------------------------------------- + ** We use a different scatter function for 896 rev 1. + **---------------------------------------------------------------- + */ + int (*scatter) (ncb_p, ccb_p, Scsi_Cmnd *); + + /*---------------------------------------------------------------- + ** Command abort handling. + ** We need to synchronize tightly with the SCRIPTS + ** processor in order to handle things correctly. + **---------------------------------------------------------------- + */ + u_char abrt_msg[4]; /* Message to send buffer */ + struct scr_tblmove abrt_tbl; /* Table for the MOV of it */ + struct scr_tblsel abrt_sel; /* Sync params for selection */ + u_char istat_sem; /* Tells the chip to stop (SEM) */ + + /*---------------------------------------------------------------- + ** Fields that should be removed or changed. + **---------------------------------------------------------------- + */ + struct usrcmd user; /* Command from user */ + volatile u_char release_stage; /* Synchronisation stage on release */ + + /*---------------------------------------------------------------- + ** Fields that are used (primarily) for integrity check + **---------------------------------------------------------------- + */ + unsigned char check_integrity; /* Enable midlayer integ. check on + * bus scan. */ +#ifdef SCSI_NCR_INTEGRITY_CHECKING + unsigned char check_integ_par; /* Set if par or Init. Det. error + * used only during integ check */ +#endif +}; + +#define NCB_PHYS(np, lbl) (np->p_ncb + offsetof(struct ncb, lbl)) +#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl)) +#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl)) +#define NCB_SCRIPTH0_PHYS(np,lbl) (np->p_scripth0+offsetof (struct scripth,lbl)) + +/*========================================================== +** +** +** Script for NCR-Processor. +** +** Use ncr_script_fill() to create the variable parts. +** Use ncr_script_copy_and_bind() to make a copy and +** bind to physical addresses. +** +** +**========================================================== +** +** We have to know the offsets of all labels before +** we reach them (for forward jumps). +** Therefore we declare a struct here. +** If you make changes inside the script, +** DONT FORGET TO CHANGE THE LENGTHS HERE! +** +**---------------------------------------------------------- +*/ + +/* +** Script fragments which are loaded into the on-chip RAM +** of 825A, 875, 876, 895, 895A and 896 chips. +*/ +struct script { + ncrcmd start [ 14]; + ncrcmd getjob_begin [ 4]; + ncrcmd getjob_end [ 4]; + ncrcmd select [ 8]; + ncrcmd wf_sel_done [ 2]; + ncrcmd send_ident [ 2]; +#ifdef SCSI_NCR_IARB_SUPPORT + ncrcmd select2 [ 8]; +#else + ncrcmd select2 [ 2]; +#endif + ncrcmd command [ 2]; + ncrcmd dispatch [ 28]; + ncrcmd sel_no_cmd [ 10]; + ncrcmd init [ 6]; + ncrcmd clrack [ 4]; + ncrcmd disp_status [ 4]; + ncrcmd datai_done [ 26]; + ncrcmd datao_done [ 12]; + ncrcmd ign_i_w_r_msg [ 4]; + ncrcmd datai_phase [ 2]; + ncrcmd datao_phase [ 4]; + ncrcmd msg_in [ 2]; + ncrcmd msg_in2 [ 10]; +#ifdef SCSI_NCR_IARB_SUPPORT + ncrcmd status [ 14]; +#else + ncrcmd status [ 10]; +#endif + ncrcmd complete [ 8]; +#ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES + ncrcmd complete2 [ 12]; +#else + ncrcmd complete2 [ 10]; +#endif +#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR + ncrcmd done [ 18]; +#else + ncrcmd done [ 14]; +#endif + ncrcmd done_end [ 2]; + ncrcmd save_dp [ 8]; + ncrcmd restore_dp [ 4]; + ncrcmd disconnect [ 20]; +#ifdef SCSI_NCR_IARB_SUPPORT + ncrcmd idle [ 4]; +#else + ncrcmd idle [ 2]; +#endif +#ifdef SCSI_NCR_IARB_SUPPORT + ncrcmd ungetjob [ 6]; +#else + ncrcmd ungetjob [ 4]; +#endif + ncrcmd reselect [ 4]; + ncrcmd reselected [ 20]; + ncrcmd resel_scntl4 [ 30]; +#if MAX_TASKS*4 > 512 + ncrcmd resel_tag [ 18]; +#elif MAX_TASKS*4 > 256 + ncrcmd resel_tag [ 12]; +#else + ncrcmd resel_tag [ 8]; +#endif + ncrcmd resel_go [ 6]; + ncrcmd resel_notag [ 2]; + ncrcmd resel_dsa [ 8]; + ncrcmd data_in [MAX_SCATTER * SCR_SG_SIZE]; + ncrcmd data_in2 [ 4]; + ncrcmd data_out [MAX_SCATTER * SCR_SG_SIZE]; + ncrcmd data_out2 [ 4]; + ncrcmd pm0_data [ 12]; + ncrcmd pm0_data_out [ 6]; + ncrcmd pm0_data_end [ 6]; + ncrcmd pm1_data [ 12]; + ncrcmd pm1_data_out [ 6]; + ncrcmd pm1_data_end [ 6]; +}; + +/* +** Script fragments which stay in main memory for all chips +** except for the 895A and 896 that support 8K on-chip RAM. +*/ +struct scripth { + ncrcmd start64 [ 2]; + ncrcmd no_data [ 2]; + ncrcmd sel_for_abort [ 18]; + ncrcmd sel_for_abort_1 [ 2]; + ncrcmd select_no_atn [ 8]; + ncrcmd wf_sel_done_no_atn [ 4]; + + ncrcmd msg_in_etc [ 14]; + ncrcmd msg_received [ 4]; + ncrcmd msg_weird_seen [ 4]; + ncrcmd msg_extended [ 20]; + ncrcmd msg_bad [ 6]; + ncrcmd msg_weird [ 4]; + ncrcmd msg_weird1 [ 8]; + + ncrcmd wdtr_resp [ 6]; + ncrcmd send_wdtr [ 4]; + ncrcmd sdtr_resp [ 6]; + ncrcmd send_sdtr [ 4]; + ncrcmd ppr_resp [ 6]; + ncrcmd send_ppr [ 4]; + ncrcmd nego_bad_phase [ 4]; + ncrcmd msg_out [ 4]; + ncrcmd msg_out_done [ 4]; + ncrcmd data_ovrun [ 2]; + ncrcmd data_ovrun1 [ 22]; + ncrcmd data_ovrun2 [ 8]; + ncrcmd abort_resel [ 16]; + ncrcmd resend_ident [ 4]; + ncrcmd ident_break [ 4]; + ncrcmd ident_break_atn [ 4]; + ncrcmd sdata_in [ 6]; + ncrcmd data_io [ 2]; + ncrcmd data_io_com [ 8]; + ncrcmd data_io_out [ 12]; + ncrcmd resel_bad_lun [ 4]; + ncrcmd bad_i_t_l [ 4]; + ncrcmd bad_i_t_l_q [ 4]; + ncrcmd bad_status [ 6]; + ncrcmd tweak_pmj [ 12]; + ncrcmd pm_handle [ 20]; + ncrcmd pm_handle1 [ 4]; + ncrcmd pm_save [ 4]; + ncrcmd pm0_save [ 14]; + ncrcmd pm1_save [ 14]; + + /* WSR handling */ +#ifdef SYM_DEBUG_PM_WITH_WSR + ncrcmd pm_wsr_handle [ 44]; +#else + ncrcmd pm_wsr_handle [ 42]; +#endif + ncrcmd wsr_ma_helper [ 4]; + + /* Data area */ + ncrcmd zero [ 1]; + ncrcmd scratch [ 1]; + ncrcmd scratch1 [ 1]; + ncrcmd pm0_data_addr [ 1]; + ncrcmd pm1_data_addr [ 1]; + ncrcmd saved_dsa [ 1]; + ncrcmd saved_drs [ 1]; + ncrcmd done_pos [ 1]; + ncrcmd startpos [ 1]; + ncrcmd targtbl [ 1]; + /* End of data area */ + +#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + ncrcmd start_ram [ 1]; + ncrcmd script0_ba [ 4]; + ncrcmd start_ram64 [ 3]; + ncrcmd script0_ba64 [ 3]; + ncrcmd scripth0_ba64 [ 6]; + ncrcmd ram_seg64 [ 1]; +#endif + ncrcmd snooptest [ 6]; + ncrcmd snoopend [ 2]; +}; + +/*========================================================== +** +** +** Function headers. +** +** +**========================================================== +*/ + +static ccb_p ncr_alloc_ccb (ncb_p np); +static void ncr_complete (ncb_p np, ccb_p cp); +static void ncr_exception (ncb_p np); +static void ncr_free_ccb (ncb_p np, ccb_p cp); +static ccb_p ncr_ccb_from_dsa(ncb_p np, u_long dsa); +static void ncr_init_tcb (ncb_p np, u_char tn); +static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln); +static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, + u_char *inq_data); +static void ncr_getclock (ncb_p np, int mult); +static u_int ncr_getpciclock (ncb_p np); +static void ncr_selectclock (ncb_p np, u_char scntl3); +static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln); +static void ncr_init (ncb_p np, int reset, char * msg, u_long code); +static void ncr_int_sbmc (ncb_p np); +static void ncr_int_par (ncb_p np, u_short sist); +static void ncr_int_ma (ncb_p np); +static void ncr_int_sir (ncb_p np); +static void ncr_int_sto (ncb_p np); +static void ncr_int_udc (ncb_p np); +static void ncr_negotiate (ncb_p np, tcb_p tp); +static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr); +#ifdef SCSI_NCR_INTEGRITY_CHECKING +static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr); +#endif +static void ncr_script_copy_and_bind + (ncb_p np, ncrcmd *src, ncrcmd *dst, int len); +static void ncr_script_fill (struct script * scr, struct scripth * scripth); +static int ncr_scatter_896R1 (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd); +static int ncr_scatter (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd); +static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p); +static void ncr_get_xfer_info(ncb_p np, tcb_p tp, u_char *factor, u_char *offset, u_char *width); +static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, u_char scntl4); +static void ncr_set_sync_wide_status (ncb_p np, u_char target); +static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln); +static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack); +static void ncr_setsyncwide (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, u_char scntl4, u_char wide); +static int ncr_show_msg (u_char * msg); +static void ncr_print_msg (ccb_p cp, char *label, u_char * msg); +static int ncr_snooptest (ncb_p np); +static void ncr_timeout (ncb_p np); +static void ncr_wakeup (ncb_p np, u_long code); +static int ncr_wakeup_done (ncb_p np); +static void ncr_start_next_ccb (ncb_p np, lcb_p lp, int maxn); +static void ncr_put_start_queue(ncb_p np, ccb_p cp); +static void ncr_chip_reset (ncb_p np); +static void ncr_soft_reset (ncb_p np); +static void ncr_start_reset (ncb_p np); +static int ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay); +static int ncr_compute_residual (ncb_p np, ccb_p cp); + +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT +static void ncr_usercmd (ncb_p np); +#endif + +static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device); +static void ncr_free_resources(ncb_p np); + +static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd); +static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd); +static void process_waiting_list(ncb_p np, int sts); + +#define remove_from_waiting_list(np, cmd) \ + retrieve_from_waiting_list(1, (np), (cmd)) +#define requeue_waiting_list(np) process_waiting_list((np), DID_OK) +#define reset_waiting_list(np) process_waiting_list((np), DID_RESET) + +#ifdef SCSI_NCR_NVRAM_SUPPORT +static void ncr_get_nvram (ncr_device *devp, ncr_nvram *nvp); +static int sym_read_Tekram_nvram (ncr_slot *np, u_short device_id, + Tekram_nvram *nvram); +static int sym_read_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram); +#endif + +/*========================================================== +** +** +** Global static data. +** +** +**========================================================== +*/ + +static inline char *ncr_name (ncb_p np) +{ + return np->inst_name; +} + + +/*========================================================== +** +** +** Scripts for NCR-Processor. +** +** Use ncr_script_bind for binding to physical addresses. +** +** +**========================================================== +** +** NADDR generates a reference to a field of the controller data. +** PADDR generates a reference to another part of the script. +** RADDR generates a reference to a script processor register. +** FADDR generates a reference to a script processor register +** with offset. +** +**---------------------------------------------------------- +*/ + +#define RELOC_SOFTC 0x40000000 +#define RELOC_LABEL 0x50000000 +#define RELOC_REGISTER 0x60000000 +#if 0 +#define RELOC_KVAR 0x70000000 +#endif +#define RELOC_LABELH 0x80000000 +#define RELOC_MASK 0xf0000000 + +#define NADDR(label) (RELOC_SOFTC | offsetof(struct ncb, label)) +#define PADDR(label) (RELOC_LABEL | offsetof(struct script, label)) +#define PADDRH(label) (RELOC_LABELH | offsetof(struct scripth, label)) +#define RADDR(label) (RELOC_REGISTER | REG(label)) +#define FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs))) +#define KVAR(which) (RELOC_KVAR | (which)) + +#define SCR_DATA_ZERO 0xf00ff00f + +#ifdef RELOC_KVAR +#define SCRIPT_KVAR_JIFFIES (0) +#define SCRIPT_KVAR_FIRST SCRIPT_KVAR_JIFFIES +#define SCRIPT_KVAR_LAST SCRIPT_KVAR_JIFFIES +/* + * Kernel variables referenced in the scripts. + * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY. + */ +static void *script_kvars[] __initdata = + { (void *)&jiffies }; +#endif + +static struct script script0 __initdata = { +/*--------------------------< START >-----------------------*/ { + /* + ** This NOP will be patched with LED ON + ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) + */ + SCR_NO_OP, + 0, + /* + ** Clear SIGP. + */ + SCR_FROM_REG (ctest2), + 0, + + /* + ** Stop here if the C code wants to perform + ** some error recovery procedure manually. + ** (Indicate this by setting SEM in ISTAT) + */ + SCR_FROM_REG (istat), + 0, + /* + ** Report to the C code the next position in + ** the start queue the SCRIPTS will schedule. + ** The C code must not change SCRATCHA. + */ + SCR_LOAD_ABS (scratcha, 4), + PADDRH (startpos), + SCR_INT ^ IFTRUE (MASK (SEM, SEM)), + SIR_SCRIPT_STOPPED, + + /* + ** Start the next job. + ** + ** @DSA = start point for this job. + ** SCRATCHA = address of this job in the start queue. + ** + ** We will restore startpos with SCRATCHA if we fails the + ** arbitration or if it is the idle job. + ** + ** The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS + ** is a critical path. If it is partially executed, it then + ** may happen that the job address is not yet in the DSA + ** and the next queue position points to the next JOB. + */ + SCR_LOAD_ABS (dsa, 4), + PADDRH (startpos), + SCR_LOAD_REL (temp, 4), + 4, +}/*-------------------------< GETJOB_BEGIN >------------------*/,{ + SCR_STORE_ABS (temp, 4), + PADDRH (startpos), + SCR_LOAD_REL (dsa, 4), + 0, +}/*-------------------------< GETJOB_END >--------------------*/,{ + SCR_LOAD_REL (temp, 4), + 0, + SCR_RETURN, + 0, + +}/*-------------------------< SELECT >----------------------*/,{ + /* + ** DSA contains the address of a scheduled + ** data structure. + ** + ** SCRATCHA contains the address of the start queue + ** entry which points to the next job. + ** + ** Set Initiator mode. + ** + ** (Target mode is left as an exercise for the reader) + */ + + SCR_CLR (SCR_TRG), + 0, + /* + ** And try to select this target. + */ + SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select), + PADDR (ungetjob), + /* + ** Now there are 4 possibilities: + ** + ** (1) The ncr loses arbitration. + ** This is ok, because it will try again, + ** when the bus becomes idle. + ** (But beware of the timeout function!) + ** + ** (2) The ncr is reselected. + ** Then the script processor takes the jump + ** to the RESELECT label. + ** + ** (3) The ncr wins arbitration. + ** Then it will execute SCRIPTS instruction until + ** the next instruction that checks SCSI phase. + ** Then will stop and wait for selection to be + ** complete or selection time-out to occur. + ** + ** After having won arbitration, the ncr SCRIPTS + ** processor is able to execute instructions while + ** the SCSI core is performing SCSI selection. But + ** some script instruction that is not waiting for + ** a valid phase (or selection timeout) to occur + ** breaks the selection procedure, by probably + ** affecting timing requirements. + ** So we have to wait immediately for the next phase + ** or the selection to complete or time-out. + */ + + /* + ** load the savep (saved pointer) into + ** the actual data pointer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + /* + ** Initialize the status registers + */ + SCR_LOAD_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + +}/*-------------------------< WF_SEL_DONE >----------------------*/,{ + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), + SIR_SEL_ATN_NO_MSG_OUT, +}/*-------------------------< SEND_IDENT >----------------------*/,{ + /* + ** Selection complete. + ** Send the IDENTIFY and SIMPLE_TAG messages + ** (and the M_X_SYNC_REQ / M_X_WIDE_REQ message) + */ + SCR_MOVE_TBL ^ SCR_MSG_OUT, + offsetof (struct dsb, smsg), +}/*-------------------------< SELECT2 >----------------------*/,{ +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** Set IMMEDIATE ARBITRATION if we have been given + ** a hint to do so. (Some job to do after this one). + */ + SCR_FROM_REG (HF_REG), + 0, + SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)), + 8, + SCR_REG_REG (scntl1, SCR_OR, IARB), + 0, +#endif + /* + ** Anticipate the COMMAND phase. + ** This is the PHASE we expect at this point. + */ + SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)), + PADDR (sel_no_cmd), + +}/*-------------------------< COMMAND >--------------------*/,{ + /* + ** ... and send the command + */ + SCR_MOVE_TBL ^ SCR_COMMAND, + offsetof (struct dsb, cmd), + +}/*-----------------------< DISPATCH >----------------------*/,{ + /* + ** MSG_IN is the only phase that shall be + ** entered at least once for each (re)selection. + ** So we test it first. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), + PADDR (msg_in), + SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)), + PADDR (datao_phase), + SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)), + PADDR (datai_phase), + SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)), + PADDR (status), + SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)), + PADDR (command), + SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)), + PADDRH (msg_out), + /* + * Discard as many illegal phases as + * required and tell the C code about. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)), + 16, + SCR_MOVE_ABS (1) ^ SCR_ILG_OUT, + NADDR (scratch), + SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)), + -16, + SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)), + 16, + SCR_MOVE_ABS (1) ^ SCR_ILG_IN, + NADDR (scratch), + SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)), + -16, + SCR_INT, + SIR_BAD_PHASE, + SCR_JUMP, + PADDR (dispatch), +}/*---------------------< SEL_NO_CMD >----------------------*/,{ + /* + ** The target does not switch to command + ** phase after IDENTIFY has been sent. + ** + ** If it stays in MSG OUT phase send it + ** the IDENTIFY again. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), + PADDRH (resend_ident), + /* + ** If target does not switch to MSG IN phase + ** and we sent a negotiation, assert the + ** failure immediately. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + SCR_FROM_REG (HS_REG), + 0, + SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), + SIR_NEGO_FAILED, + /* + ** Jump to dispatcher. + */ + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< INIT >------------------------*/,{ + /* + ** Wait for the SCSI RESET signal to be + ** inactive before restarting operations, + ** since the chip may hang on SEL_ATN + ** if SCSI RESET is active. + */ + SCR_FROM_REG (sstat0), + 0, + SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)), + -16, + SCR_JUMP, + PADDR (start), +}/*-------------------------< CLRACK >----------------------*/,{ + /* + ** Terminate possible pending message phase. + */ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< DISP_STATUS >----------------------*/,{ + /* + ** Anticipate STATUS phase. + ** + ** Does spare 3 SCRIPTS instructions when we have + ** completed the INPUT of the data. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)), + PADDR (status), + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< DATAI_DONE >-------------------*/,{ + /* + * If the device wants us to send more data, + * we must count the extra bytes. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_IN)), + PADDRH (data_ovrun), + /* + ** If the SWIDE is not full, jump to dispatcher. + ** We anticipate a STATUS phase. + ** If we get later an IGNORE WIDE RESIDUE, we + ** will alias it as a MODIFY DP (-1). + */ + SCR_FROM_REG (scntl2), + 0, + SCR_JUMP ^ IFFALSE (MASK (WSR, WSR)), + PADDR (disp_status), + /* + ** The SWIDE is full. + ** Clear this condition. + */ + SCR_REG_REG (scntl2, SCR_OR, WSR), + 0, + /* + * We are expecting an IGNORE RESIDUE message + * from the device, otherwise we are in data + * overrun condition. Check against MSG_IN phase. + */ + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), + SIR_SWIDE_OVERRUN, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (disp_status), + /* + * We are in MSG_IN phase, + * Read the first byte of the message. + * If it is not an IGNORE RESIDUE message, + * signal overrun and jump to message + * processing. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[0]), + SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)), + SIR_SWIDE_OVERRUN, + SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)), + PADDR (msg_in2), + + /* + * We got the message we expected. + * Read the 2nd byte, and jump to dispatcher. + */ + SCR_CLR (SCR_ACK), + 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[1]), + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP, + PADDR (disp_status), + +}/*-------------------------< DATAO_DONE >-------------------*/,{ + /* + * If the device wants us to send more data, + * we must count the extra bytes. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)), + PADDRH (data_ovrun), + /* + ** If the SODL is not full jump to dispatcher. + ** We anticipate a MSG IN phase or a STATUS phase. + */ + SCR_FROM_REG (scntl2), + 0, + SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)), + PADDR (disp_status), + /* + ** The SODL is full, clear this condition. + */ + SCR_REG_REG (scntl2, SCR_OR, WSS), + 0, + /* + ** And signal a DATA UNDERRUN condition + ** to the C code. + */ + SCR_INT, + SIR_SODL_UNDERRUN, + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< IGN_I_W_R_MSG >--------------*/,{ + /* + ** We jump here from the phase mismatch interrupt, + ** When we have a SWIDE and the device has presented + ** a IGNORE WIDE RESIDUE message on the BUS. + ** We just have to throw away this message and then + ** to jump to dispatcher. + */ + SCR_MOVE_ABS (2) ^ SCR_MSG_IN, + NADDR (scratch), + /* + ** Clear ACK and jump to dispatcher. + */ + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< DATAI_PHASE >------------------*/,{ + SCR_RETURN, + 0, +}/*-------------------------< DATAO_PHASE >------------------*/,{ + /* + ** Patch for 53c1010_66 only - to allow A0 part + ** to operate properly in a 33MHz PCI bus. + ** + ** SCR_REG_REG(scntl4, SCR_OR, 0x0c), + ** 0, + */ + SCR_NO_OP, + 0, + SCR_RETURN, + 0, +}/*-------------------------< MSG_IN >--------------------*/,{ + /* + ** Get the first byte of the message. + ** + ** The script processor doesn't negate the + ** ACK signal after this transfer. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[0]), +}/*-------------------------< MSG_IN2 >--------------------*/,{ + /* + ** Check first against 1 byte messages + ** that we handle from SCRIPTS. + */ + SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)), + PADDR (complete), + SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)), + PADDR (disconnect), + SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)), + PADDR (save_dp), + SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)), + PADDR (restore_dp), + /* + ** We handle all other messages from the + ** C code, so no need to waste on-chip RAM + ** for those ones. + */ + SCR_JUMP, + PADDRH (msg_in_etc), + +}/*-------------------------< STATUS >--------------------*/,{ + /* + ** get the status + */ + SCR_MOVE_ABS (1) ^ SCR_STATUS, + NADDR (scratch), +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** If STATUS is not GOOD, clear IMMEDIATE ARBITRATION, + ** since we may have to tamper the start queue from + ** the C code. + */ + SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)), + 8, + SCR_REG_REG (scntl1, SCR_AND, ~IARB), + 0, +#endif + /* + ** save status to scsi_status. + ** mark as complete. + */ + SCR_TO_REG (SS_REG), + 0, + SCR_LOAD_REG (HS_REG, HS_COMPLETE), + 0, + /* + ** Anticipate the MESSAGE PHASE for + ** the TASK COMPLETE message. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), + PADDR (msg_in), + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< COMPLETE >-----------------*/,{ + /* + ** Complete message. + ** + ** Copy the data pointer to LASTP in header. + */ + SCR_STORE_REL (temp, 4), + offsetof (struct ccb, phys.header.lastp), + /* + ** When we terminate the cycle by clearing ACK, + ** the target may disconnect immediately. + ** + ** We don't want to be told of an + ** "unexpected disconnect", + ** so we disable this feature. + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + /* + ** Terminate cycle ... + */ + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + /* + ** ... and wait for the disconnect. + */ + SCR_WAIT_DISC, + 0, +}/*-------------------------< COMPLETE2 >-----------------*/,{ + /* + ** Save host status to header. + */ + SCR_STORE_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + +#ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES + /* + ** Some bridges may reorder DMA writes to memory. + ** We donnot want the CPU to deal with completions + ** without all the posted write having been flushed + ** to memory. This DUMMY READ should flush posted + ** buffers prior to the CPU having to deal with + ** completions. + */ + SCR_LOAD_REL (scr0, 4), /* DUMMY READ */ + offsetof (struct ccb, phys.header.status), +#endif + /* + ** If command resulted in not GOOD status, + ** call the C code if needed. + */ + SCR_FROM_REG (SS_REG), + 0, + SCR_CALL ^ IFFALSE (DATA (S_GOOD)), + PADDRH (bad_status), + + /* + ** If we performed an auto-sense, call + ** the C code to synchronyze task aborts + ** with UNIT ATTENTION conditions. + */ + SCR_FROM_REG (HF_REG), + 0, + SCR_INT ^ IFTRUE (MASK (HF_AUTO_SENSE, HF_AUTO_SENSE)), + SIR_AUTO_SENSE_DONE, + +}/*------------------------< DONE >-----------------*/,{ +#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR + /* + ** It seems that some bridges flush everything + ** when the INTR line is raised. For these ones, + ** we can just ensure that the INTR line will be + ** raised before each completion. So, if it happens + ** that we have been faster that the CPU, we just + ** have to synchronize with it. A dummy programmed + ** interrupt will do the trick. + ** Note that we overlap at most 1 IO with the CPU + ** in this situation and that the IRQ line must not + ** be shared. + */ + SCR_FROM_REG (istat), + 0, + SCR_INT ^ IFTRUE (MASK (INTF, INTF)), + SIR_DUMMY_INTERRUPT, +#endif + /* + ** Copy the DSA to the DONE QUEUE and + ** signal completion to the host. + ** If we are interrupted between DONE + ** and DONE_END, we must reset, otherwise + ** the completed CCB will be lost. + */ + SCR_STORE_ABS (dsa, 4), + PADDRH (saved_dsa), + SCR_LOAD_ABS (dsa, 4), + PADDRH (done_pos), + SCR_LOAD_ABS (scratcha, 4), + PADDRH (saved_dsa), + SCR_STORE_REL (scratcha, 4), + 0, + /* + ** The instruction below reads the DONE QUEUE next + ** free position from memory. + ** In addition it ensures that all PCI posted writes + ** are flushed and so the DSA value of the done + ** CCB is visible by the CPU before INTFLY is raised. + */ + SCR_LOAD_REL (temp, 4), + 4, + SCR_INT_FLY, + 0, + SCR_STORE_ABS (temp, 4), + PADDRH (done_pos), +}/*------------------------< DONE_END >-----------------*/,{ + SCR_JUMP, + PADDR (start), + +}/*-------------------------< SAVE_DP >------------------*/,{ + /* + ** Clear ACK immediately. + ** No need to delay it. + */ + SCR_CLR (SCR_ACK), + 0, + /* + ** Keep track we received a SAVE DP, so + ** we will switch to the other PM context + ** on the next PM since the DP may point + ** to the current PM context. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED), + 0, + /* + ** SAVE_DP message: + ** Copy the data pointer to SAVEP in header. + */ + SCR_STORE_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + SCR_JUMP, + PADDR (dispatch), +}/*-------------------------< RESTORE_DP >---------------*/,{ + /* + ** RESTORE_DP message: + ** Copy SAVEP in header to actual data pointer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< DISCONNECT >---------------*/,{ + /* + ** DISCONNECTing ... + ** + ** disable the "unexpected disconnect" feature, + ** and remove the ACK signal. + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + /* + ** Wait for the disconnect. + */ + SCR_WAIT_DISC, + 0, + /* + ** Status is: DISCONNECTED. + */ + SCR_LOAD_REG (HS_REG, HS_DISCONNECT), + 0, + /* + ** Save host status to header. + */ + SCR_STORE_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + /* + ** If QUIRK_AUTOSAVE is set, + ** do an "save pointer" operation. + */ + SCR_FROM_REG (QU_REG), + 0, + SCR_JUMP ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)), + PADDR (start), + /* + ** like SAVE_DP message: + ** Remember we saved the data pointer. + ** Copy data pointer to SAVEP in header. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED), + 0, + SCR_STORE_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + SCR_JUMP, + PADDR (start), + +}/*-------------------------< IDLE >------------------------*/,{ + /* + ** Nothing to do? + ** Wait for reselect. + ** This NOP will be patched with LED OFF + ** SCR_REG_REG (gpreg, SCR_OR, 0x01) + */ + SCR_NO_OP, + 0, +#ifdef SCSI_NCR_IARB_SUPPORT + SCR_JUMPR, + 8, +#endif +}/*-------------------------< UNGETJOB >-----------------*/,{ +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** Set IMMEDIATE ARBITRATION, for the next time. + ** This will give us better chance to win arbitration + ** for the job we just wanted to do. + */ + SCR_REG_REG (scntl1, SCR_OR, IARB), + 0, +#endif + /* + ** We are not able to restart the SCRIPTS if we are + ** interrupted and these instruction haven't been + ** all executed. BTW, this is very unlikely to + ** happen, but we check that from the C code. + */ + SCR_LOAD_REG (dsa, 0xff), + 0, + SCR_STORE_ABS (scratcha, 4), + PADDRH (startpos), +}/*-------------------------< RESELECT >--------------------*/,{ + /* + ** make the host status invalid. + */ + SCR_CLR (SCR_TRG), + 0, + /* + ** Sleep waiting for a reselection. + ** If SIGP is set, special treatment. + ** + ** Zu allem bereit .. + */ + SCR_WAIT_RESEL, + PADDR(start), +}/*-------------------------< RESELECTED >------------------*/,{ + /* + ** This NOP will be patched with LED ON + ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) + */ + SCR_NO_OP, + 0, + /* + ** load the target id into the sdid + */ + SCR_REG_SFBR (ssid, SCR_AND, 0x8F), + 0, + SCR_TO_REG (sdid), + 0, + /* + ** load the target control block address + */ + SCR_LOAD_ABS (dsa, 4), + PADDRH (targtbl), + SCR_SFBR_REG (dsa, SCR_SHL, 0), + 0, + SCR_REG_REG (dsa, SCR_SHL, 0), + 0, + SCR_REG_REG (dsa, SCR_AND, 0x3c), + 0, + SCR_LOAD_REL (dsa, 4), + 0, + /* + ** Load the synchronous transfer registers. + */ + SCR_LOAD_REL (scntl3, 1), + offsetof(struct tcb, wval), + SCR_LOAD_REL (sxfer, 1), + offsetof(struct tcb, sval), +}/*-------------------------< RESEL_SCNTL4 >------------------*/,{ + /* + ** Write with uval value. Patch if device + ** does not support Ultra3. + ** + ** SCR_LOAD_REL (scntl4, 1), + ** offsetof(struct tcb, uval), + */ + + SCR_NO_OP, + 0, + /* + * We expect MESSAGE IN phase. + * If not, get help from the C code. + */ + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), + SIR_RESEL_NO_MSG_IN, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin), + + /* + * If IDENTIFY LUN #0, use a faster path + * to find the LCB structure. + */ + SCR_JUMPR ^ IFTRUE (MASK (0x80, 0xbf)), + 56, + /* + * If message isn't an IDENTIFY, + * tell the C code about. + */ + SCR_INT ^ IFFALSE (MASK (0x80, 0x80)), + SIR_RESEL_NO_IDENTIFY, + /* + * It is an IDENTIFY message, + * Load the LUN control block address. + */ + SCR_LOAD_REL (dsa, 4), + offsetof(struct tcb, b_luntbl), + SCR_SFBR_REG (dsa, SCR_SHL, 0), + 0, + SCR_REG_REG (dsa, SCR_SHL, 0), + 0, + SCR_REG_REG (dsa, SCR_AND, 0xfc), + 0, + SCR_LOAD_REL (dsa, 4), + 0, + SCR_JUMPR, + 8, + /* + ** LUN 0 special case (but usual one :)) + */ + SCR_LOAD_REL (dsa, 4), + offsetof(struct tcb, b_lun0), + + /* + ** Load the reselect task action for this LUN. + ** Load the tasks DSA array for this LUN. + ** Call the action. + */ + SCR_LOAD_REL (temp, 4), + offsetof(struct lcb, resel_task), + SCR_LOAD_REL (dsa, 4), + offsetof(struct lcb, b_tasktbl), + SCR_RETURN, + 0, +}/*-------------------------< RESEL_TAG >-------------------*/,{ + /* + ** ACK the IDENTIFY or TAG previously received + */ + + SCR_CLR (SCR_ACK), + 0, + /* + ** Read IDENTIFY + SIMPLE + TAG using a single MOVE. + ** Agressive optimization, is'nt it? + ** No need to test the SIMPLE TAG message, since the + ** driver only supports conformant devices for tags. ;-) + */ + SCR_MOVE_ABS (2) ^ SCR_MSG_IN, + NADDR (msgin), + /* + ** Read the TAG from the SIDL. + ** Still an aggressive optimization. ;-) + ** Compute the CCB indirect jump address which + ** is (#TAG*2 & 0xfc) due to tag numbering using + ** 1,3,5..MAXTAGS*2+1 actual values. + */ + SCR_REG_SFBR (sidl, SCR_SHL, 0), + 0, +#if MAX_TASKS*4 > 512 + SCR_JUMPR ^ IFFALSE (CARRYSET), + 8, + SCR_REG_REG (dsa1, SCR_OR, 2), + 0, + SCR_REG_REG (sfbr, SCR_SHL, 0), + 0, + SCR_JUMPR ^ IFFALSE (CARRYSET), + 8, + SCR_REG_REG (dsa1, SCR_OR, 1), + 0, +#elif MAX_TASKS*4 > 256 + SCR_JUMPR ^ IFFALSE (CARRYSET), + 8, + SCR_REG_REG (dsa1, SCR_OR, 1), + 0, +#endif + /* + ** Retrieve the DSA of this task. + ** JUMP indirectly to the restart point of the CCB. + */ + SCR_SFBR_REG (dsa, SCR_AND, 0xfc), + 0, +}/*-------------------------< RESEL_GO >-------------------*/,{ + SCR_LOAD_REL (dsa, 4), + 0, + SCR_LOAD_REL (temp, 4), + offsetof(struct ccb, phys.header.go.restart), + SCR_RETURN, + 0, + /* In normal situations we branch to RESEL_DSA */ +}/*-------------------------< RESEL_NOTAG >-------------------*/,{ + /* + ** JUMP indirectly to the restart point of the CCB. + */ + SCR_JUMP, + PADDR (resel_go), + +}/*-------------------------< RESEL_DSA >-------------------*/,{ + /* + ** Ack the IDENTIFY or TAG previously received. + */ + SCR_CLR (SCR_ACK), + 0, + /* + ** load the savep (saved pointer) into + ** the actual data pointer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + /* + ** Initialize the status registers + */ + SCR_LOAD_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + /* + ** Jump to dispatcher. + */ + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< DATA_IN >--------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTER parameter, +** it is filled in at runtime. +** +** ##===========< i=0; i========= +** || SCR_CHMOV_TBL ^ SCR_DATA_IN, +** || offsetof (struct dsb, data[ i]), +** ##========================================== +** +**--------------------------------------------------------- +*/ +0 +}/*-------------------------< DATA_IN2 >-------------------*/,{ + SCR_CALL, + PADDR (datai_done), + SCR_JUMP, + PADDRH (data_ovrun), +}/*-------------------------< DATA_OUT >--------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTER parameter, +** it is filled in at runtime. +** +** ##===========< i=0; i========= +** || SCR_CHMOV_TBL ^ SCR_DATA_OUT, +** || offsetof (struct dsb, data[ i]), +** ##========================================== +** +**--------------------------------------------------------- +*/ +0 +}/*-------------------------< DATA_OUT2 >-------------------*/,{ + SCR_CALL, + PADDR (datao_done), + SCR_JUMP, + PADDRH (data_ovrun), + +}/*-------------------------< PM0_DATA >--------------------*/,{ + /* + ** Read our host flags to SFBR, so we will be able + ** to check against the data direction we expect. + */ + SCR_FROM_REG (HF_REG), + 0, + /* + ** Check against actual DATA PHASE. + */ + SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), + PADDR (pm0_data_out), + /* + ** Actual phase is DATA IN. + ** Check against expected direction. + */ + SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)), + PADDRH (data_ovrun), + /* + ** Keep track we are moving data from the + ** PM0 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0), + 0, + /* + ** Move the data to memory. + */ + SCR_CHMOV_TBL ^ SCR_DATA_IN, + offsetof (struct ccb, phys.pm0.sg), + SCR_JUMP, + PADDR (pm0_data_end), +}/*-------------------------< PM0_DATA_OUT >----------------*/,{ + /* + ** Actual phase is DATA OUT. + ** Check against expected direction. + */ + SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)), + PADDRH (data_ovrun), + /* + ** Keep track we are moving data from the + ** PM0 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0), + 0, + /* + ** Move the data from memory. + */ + SCR_CHMOV_TBL ^ SCR_DATA_OUT, + offsetof (struct ccb, phys.pm0.sg), +}/*-------------------------< PM0_DATA_END >----------------*/,{ + /* + ** Clear the flag that told we were moving + ** data from the PM0 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)), + 0, + /* + ** Return to the previous DATA script which + ** is guaranteed by design (if no bug) to be + ** the main DATA script for this transfer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.pm0.ret), + SCR_RETURN, + 0, +}/*-------------------------< PM1_DATA >--------------------*/,{ + /* + ** Read our host flags to SFBR, so we will be able + ** to check against the data direction we expect. + */ + SCR_FROM_REG (HF_REG), + 0, + /* + ** Check against actual DATA PHASE. + */ + SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), + PADDR (pm1_data_out), + /* + ** Actual phase is DATA IN. + ** Check against expected direction. + */ + SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)), + PADDRH (data_ovrun), + /* + ** Keep track we are moving data from the + ** PM1 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1), + 0, + /* + ** Move the data to memory. + */ + SCR_CHMOV_TBL ^ SCR_DATA_IN, + offsetof (struct ccb, phys.pm1.sg), + SCR_JUMP, + PADDR (pm1_data_end), +}/*-------------------------< PM1_DATA_OUT >----------------*/,{ + /* + ** Actual phase is DATA OUT. + ** Check against expected direction. + */ + SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)), + PADDRH (data_ovrun), + /* + ** Keep track we are moving data from the + ** PM1 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1), + 0, + /* + ** Move the data from memory. + */ + SCR_CHMOV_TBL ^ SCR_DATA_OUT, + offsetof (struct ccb, phys.pm1.sg), +}/*-------------------------< PM1_DATA_END >----------------*/,{ + /* + ** Clear the flag that told we were moving + ** data from the PM1 DATA mini-script. + */ + SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)), + 0, + /* + ** Return to the previous DATA script which + ** is guaranteed by design (if no bug) to be + ** the main DATA script for this transfer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.pm1.ret), + SCR_RETURN, + 0, +}/*---------------------------------------------------------*/ +}; + + +static struct scripth scripth0 __initdata = { +/*------------------------< START64 >-----------------------*/{ + /* + ** SCRIPT entry point for the 895A and the 896. + ** For now, there is no specific stuff for that + ** chip at this point, but this may come. + */ + SCR_JUMP, + PADDR (init), +}/*-------------------------< NO_DATA >-------------------*/,{ + SCR_JUMP, + PADDRH (data_ovrun), +}/*-----------------------< SEL_FOR_ABORT >------------------*/,{ + /* + ** We are jumped here by the C code, if we have + ** some target to reset or some disconnected + ** job to abort. Since error recovery is a serious + ** busyness, we will really reset the SCSI BUS, if + ** case of a SCSI interrupt occurring in this path. + */ + + /* + ** Set initiator mode. + */ + SCR_CLR (SCR_TRG), + 0, + /* + ** And try to select this target. + */ + SCR_SEL_TBL_ATN ^ offsetof (struct ncb, abrt_sel), + PADDR (reselect), + + /* + ** Wait for the selection to complete or + ** the selection to time out. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)), + -8, + /* + ** Call the C code. + */ + SCR_INT, + SIR_TARGET_SELECTED, + /* + ** The C code should let us continue here. + ** Send the 'kiss of death' message. + ** We expect an immediate disconnect once + ** the target has eaten the message. + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_MOVE_TBL ^ SCR_MSG_OUT, + offsetof (struct ncb, abrt_tbl), + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + SCR_WAIT_DISC, + 0, + /* + ** Tell the C code that we are done. + */ + SCR_INT, + SIR_ABORT_SENT, +}/*-----------------------< SEL_FOR_ABORT_1 >--------------*/,{ + /* + ** Jump at scheduler. + */ + SCR_JUMP, + PADDR (start), + +}/*------------------------< SELECT_NO_ATN >-----------------*/,{ + /* + ** Set Initiator mode. + ** And try to select this target without ATN. + */ + + SCR_CLR (SCR_TRG), + 0, + SCR_SEL_TBL ^ offsetof (struct dsb, select), + PADDR (ungetjob), + /* + ** load the savep (saved pointer) into + ** the actual data pointer. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + /* + ** Initialize the status registers + */ + SCR_LOAD_REL (scr0, 4), + offsetof (struct ccb, phys.header.status), + +}/*------------------------< WF_SEL_DONE_NO_ATN >-----------------*/,{ + /* + ** Wait immediately for the next phase or + ** the selection to complete or time-out. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)), + 0, + SCR_JUMP, + PADDR (select2), + +}/*-------------------------< MSG_IN_ETC >--------------------*/,{ + /* + ** If it is an EXTENDED (variable size message) + ** Handle it. + */ + SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)), + PADDRH (msg_extended), + /* + ** Let the C code handle any other + ** 1 byte message. + */ + SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)), + PADDRH (msg_received), + SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)), + PADDRH (msg_received), + /* + ** We donnot handle 2 bytes messages from SCRIPTS. + ** So, let the C code deal with these ones too. + */ + SCR_JUMP ^ IFFALSE (MASK (0x20, 0xf0)), + PADDRH (msg_weird_seen), + SCR_CLR (SCR_ACK), + 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[1]), + SCR_JUMP, + PADDRH (msg_received), + +}/*-------------------------< MSG_RECEIVED >--------------------*/,{ + SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */ + 0, + SCR_INT, + SIR_MSG_RECEIVED, + +}/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{ + SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */ + 0, + SCR_INT, + SIR_MSG_WEIRD, + +}/*-------------------------< MSG_EXTENDED >--------------------*/,{ + /* + ** Clear ACK and get the next byte + ** assumed to be the message length. + */ + SCR_CLR (SCR_ACK), + 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[1]), + /* + ** Try to catch some unlikely situations as 0 length + ** or too large the length. + */ + SCR_JUMP ^ IFTRUE (DATA (0)), + PADDRH (msg_weird_seen), + SCR_TO_REG (scratcha), + 0, + SCR_REG_REG (sfbr, SCR_ADD, (256-8)), + 0, + SCR_JUMP ^ IFTRUE (CARRYSET), + PADDRH (msg_weird_seen), + /* + ** We donnot handle extended messages from SCRIPTS. + ** Read the amount of data correponding to the + ** message length and call the C code. + */ + SCR_STORE_REL (scratcha, 1), + offsetof (struct dsb, smsg_ext.size), + SCR_CLR (SCR_ACK), + 0, + SCR_MOVE_TBL ^ SCR_MSG_IN, + offsetof (struct dsb, smsg_ext), + SCR_JUMP, + PADDRH (msg_received), + +}/*-------------------------< MSG_BAD >------------------*/,{ + /* + ** unimplemented message - reject it. + */ + SCR_INT, + SIR_REJECT_TO_SEND, + SCR_SET (SCR_ATN), + 0, + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< MSG_WEIRD >--------------------*/,{ + /* + ** weird message received + ** ignore all MSG IN phases and reject it. + */ + SCR_INT, + SIR_REJECT_TO_SEND, + SCR_SET (SCR_ATN), + 0, +}/*-------------------------< MSG_WEIRD1 >--------------------*/,{ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (scratch), + SCR_JUMP, + PADDRH (msg_weird1), +}/*-------------------------< WDTR_RESP >----------------*/,{ + /* + ** let the target fetch our answer. + */ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), + PADDRH (nego_bad_phase), + +}/*-------------------------< SEND_WDTR >----------------*/,{ + /* + ** Send the M_X_WIDE_REQ + */ + SCR_MOVE_ABS (4) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_JUMP, + PADDRH (msg_out_done), + +}/*-------------------------< SDTR_RESP >-------------*/,{ + /* + ** let the target fetch our answer. + */ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), + PADDRH (nego_bad_phase), + +}/*-------------------------< SEND_SDTR >-------------*/,{ + /* + ** Send the M_X_SYNC_REQ + */ + SCR_MOVE_ABS (5) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_JUMP, + PADDRH (msg_out_done), + +}/*-------------------------< PPR_RESP >-------------*/,{ + /* + ** let the target fetch our answer. + */ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), + PADDRH (nego_bad_phase), + +}/*-------------------------< SEND_PPR >-------------*/,{ + /* + ** Send the M_X_PPR_REQ + */ + SCR_MOVE_ABS (8) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_JUMP, + PADDRH (msg_out_done), + +}/*-------------------------< NEGO_BAD_PHASE >------------*/,{ + SCR_INT, + SIR_NEGO_PROTO, + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< MSG_OUT >-------------------*/,{ + /* + ** The target requests a message. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, + NADDR (msgout), + /* + ** ... wait for the next phase + ** if it's a message out, send it again, ... + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), + PADDRH (msg_out), +}/*-------------------------< MSG_OUT_DONE >--------------*/,{ + /* + ** ... else clear the message ... + */ + SCR_INT, + SIR_MSG_OUT_DONE, + /* + ** ... and process the next phase + */ + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< DATA_OVRUN >-----------------------*/,{ + /* + * Use scratcha to count the extra bytes. + */ + SCR_LOAD_ABS (scratcha, 4), + PADDRH (zero), +}/*-------------------------< DATA_OVRUN1 >----------------------*/,{ + /* + * The target may want to transfer too much data. + * + * If phase is DATA OUT write 1 byte and count it. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)), + 16, + SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT, + NADDR (scratch), + SCR_JUMP, + PADDRH (data_ovrun2), + /* + * If WSR is set, clear this condition, and + * count this byte. + */ + SCR_FROM_REG (scntl2), + 0, + SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)), + 16, + SCR_REG_REG (scntl2, SCR_OR, WSR), + 0, + SCR_JUMP, + PADDRH (data_ovrun2), + /* + * Finally check against DATA IN phase. + * Signal data overrun to the C code + * and jump to dispatcher if not so. + * Read 1 byte otherwise and count it. + */ + SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)), + 16, + SCR_INT, + SIR_DATA_OVERRUN, + SCR_JUMP, + PADDR (dispatch), + SCR_CHMOV_ABS (1) ^ SCR_DATA_IN, + NADDR (scratch), +}/*-------------------------< DATA_OVRUN2 >----------------------*/,{ + /* + * Count this byte. + * This will allow to return a negative + * residual to user. + */ + SCR_REG_REG (scratcha, SCR_ADD, 0x01), + 0, + SCR_REG_REG (scratcha1, SCR_ADDC, 0), + 0, + SCR_REG_REG (scratcha2, SCR_ADDC, 0), + 0, + /* + * .. and repeat as required. + */ + SCR_JUMP, + PADDRH (data_ovrun1), + +}/*-------------------------< ABORT_RESEL >----------------*/,{ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + /* + ** send the abort/abortag/reset message + ** we expect an immediate disconnect + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + SCR_WAIT_DISC, + 0, + SCR_INT, + SIR_RESEL_ABORTED, + SCR_JUMP, + PADDR (start), +}/*-------------------------< RESEND_IDENT >-------------------*/,{ + /* + ** The target stays in MSG OUT phase after having acked + ** Identify [+ Tag [+ Extended message ]]. Targets shall + ** behave this way on parity error. + ** We must send it again all the messages. + */ + SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the */ + 0, /* 1rst ACK = 90 ns. Hope the NCR is'nt too fast */ + SCR_JUMP, + PADDR (send_ident), +}/*-------------------------< IDENT_BREAK >-------------------*/,{ + SCR_CLR (SCR_ATN), + 0, + SCR_JUMP, + PADDR (select2), +}/*-------------------------< IDENT_BREAK_ATN >----------------*/,{ + SCR_SET (SCR_ATN), + 0, + SCR_JUMP, + PADDR (select2), +}/*-------------------------< SDATA_IN >-------------------*/,{ + SCR_CHMOV_TBL ^ SCR_DATA_IN, + offsetof (struct dsb, sense), + SCR_CALL, + PADDR (datai_done), + SCR_JUMP, + PADDRH (data_ovrun), +}/*-------------------------< DATA_IO >--------------------*/,{ + /* + ** We jump here if the data direction was unknown at the + ** time we had to queue the command to the scripts processor. + ** Pointers had been set as follow in this situation: + ** savep --> DATA_IO + ** lastp --> start pointer when DATA_IN + ** goalp --> goal pointer when DATA_IN + ** wlastp --> start pointer when DATA_OUT + ** wgoalp --> goal pointer when DATA_OUT + ** This script sets savep/lastp/goalp according to the + ** direction chosen by the target. + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)), + PADDRH(data_io_out), +}/*-------------------------< DATA_IO_COM >-----------------*/,{ + /* + ** Direction is DATA IN. + ** Warning: we jump here, even when phase is DATA OUT. + */ + SCR_LOAD_REL (scratcha, 4), + offsetof (struct ccb, phys.header.lastp), + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.header.savep), + + /* + ** Jump to the SCRIPTS according to actual direction. + */ + SCR_LOAD_REL (temp, 4), + offsetof (struct ccb, phys.header.savep), + SCR_RETURN, + 0, +}/*-------------------------< DATA_IO_OUT >-----------------*/,{ + /* + ** Direction is DATA OUT. + */ + SCR_REG_REG (HF_REG, SCR_AND, (~HF_DATA_IN)), + 0, + SCR_LOAD_REL (scratcha, 4), + offsetof (struct ccb, phys.header.wlastp), + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.header.lastp), + SCR_LOAD_REL (scratcha, 4), + offsetof (struct ccb, phys.header.wgoalp), + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.header.goalp), + SCR_JUMP, + PADDRH(data_io_com), + +}/*-------------------------< RESEL_BAD_LUN >---------------*/,{ + /* + ** Message is an IDENTIFY, but lun is unknown. + ** Signal problem to C code for logging the event. + ** Send a M_ABORT to clear all pending tasks. + */ + SCR_INT, + SIR_RESEL_BAD_LUN, + SCR_JUMP, + PADDRH (abort_resel), +}/*-------------------------< BAD_I_T_L >------------------*/,{ + /* + ** We donnot have a task for that I_T_L. + ** Signal problem to C code for logging the event. + ** Send a M_ABORT message. + */ + SCR_INT, + SIR_RESEL_BAD_I_T_L, + SCR_JUMP, + PADDRH (abort_resel), +}/*-------------------------< BAD_I_T_L_Q >----------------*/,{ + /* + ** We donnot have a task that matches the tag. + ** Signal problem to C code for logging the event. + ** Send a M_ABORTTAG message. + */ + SCR_INT, + SIR_RESEL_BAD_I_T_L_Q, + SCR_JUMP, + PADDRH (abort_resel), +}/*-------------------------< BAD_STATUS >-----------------*/,{ + /* + ** Anything different from INTERMEDIATE + ** CONDITION MET should be a bad SCSI status, + ** given that GOOD status has already been tested. + ** Call the C code. + */ + SCR_LOAD_ABS (scratcha, 4), + PADDRH (startpos), + SCR_INT ^ IFFALSE (DATA (S_COND_MET)), + SIR_BAD_STATUS, + SCR_RETURN, + 0, + +}/*-------------------------< TWEAK_PMJ >------------------*/,{ + /* + ** Disable PM handling from SCRIPTS for the data phase + ** and so force PM to be handled from C code if HF_PM_TO_C + ** flag is set. + */ + SCR_FROM_REG(HF_REG), + 0, + SCR_JUMPR ^ IFTRUE (MASK (HF_PM_TO_C, HF_PM_TO_C)), + 16, + SCR_REG_REG (ccntl0, SCR_OR, ENPMJ), + 0, + SCR_RETURN, + 0, + SCR_REG_REG (ccntl0, SCR_AND, (~ENPMJ)), + 0, + SCR_RETURN, + 0, + +}/*-------------------------< PM_HANDLE >------------------*/,{ + /* + ** Phase mismatch handling. + ** + ** Since we have to deal with 2 SCSI data pointers + ** (current and saved), we need at least 2 contexts. + ** Each context (pm0 and pm1) has a saved area, a + ** SAVE mini-script and a DATA phase mini-script. + */ + /* + ** Get the PM handling flags. + */ + SCR_FROM_REG (HF_REG), + 0, + /* + ** If no flags (1rst PM for example), avoid + ** all the below heavy flags testing. + ** This makes the normal case a bit faster. + */ + SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED))), + PADDRH (pm_handle1), + /* + ** If we received a SAVE DP, switch to the + ** other PM context since the savep may point + ** to the current PM context. + */ + SCR_JUMPR ^ IFFALSE (MASK (HF_DP_SAVED, HF_DP_SAVED)), + 8, + SCR_REG_REG (sfbr, SCR_XOR, HF_ACT_PM), + 0, + /* + ** If we have been interrupt in a PM DATA mini-script, + ** we take the return address from the corresponding + ** saved area. + ** This ensure the return address always points to the + ** main DATA script for this transfer. + */ + SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1))), + PADDRH (pm_handle1), + SCR_JUMPR ^ IFFALSE (MASK (HF_IN_PM0, HF_IN_PM0)), + 16, + SCR_LOAD_REL (ia, 4), + offsetof(struct ccb, phys.pm0.ret), + SCR_JUMP, + PADDRH (pm_save), + SCR_LOAD_REL (ia, 4), + offsetof(struct ccb, phys.pm1.ret), + SCR_JUMP, + PADDRH (pm_save), +}/*-------------------------< PM_HANDLE1 >-----------------*/,{ + /* + ** Normal case. + ** Update the return address so that it + ** will point after the interrupted MOVE. + */ + SCR_REG_REG (ia, SCR_ADD, 8), + 0, + SCR_REG_REG (ia1, SCR_ADDC, 0), + 0, +}/*-------------------------< PM_SAVE >--------------------*/,{ + /* + ** Clear all the flags that told us if we were + ** interrupted in a PM DATA mini-script and/or + ** we received a SAVE DP. + */ + SCR_SFBR_REG (HF_REG, SCR_AND, (~(HF_IN_PM0|HF_IN_PM1|HF_DP_SAVED))), + 0, + /* + ** Choose the current PM context. + */ + SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)), + PADDRH (pm1_save), +}/*-------------------------< PM0_SAVE >-------------------*/,{ + SCR_STORE_REL (ia, 4), + offsetof(struct ccb, phys.pm0.ret), + /* + ** If WSR bit is set, either UA and RBC may + ** have to be changed whatever the device wants + ** to ignore this residue ot not. + */ + SCR_FROM_REG (scntl2), + 0, + SCR_CALL ^ IFTRUE (MASK (WSR, WSR)), + PADDRH (pm_wsr_handle), + /* + ** Save the remaining byte count, the updated + ** address and the return address. + */ + SCR_STORE_REL (rbc, 4), + offsetof(struct ccb, phys.pm0.sg.size), + SCR_STORE_REL (ua, 4), + offsetof(struct ccb, phys.pm0.sg.addr), + /* + ** Set the current pointer at the PM0 DATA mini-script. + */ + SCR_LOAD_ABS (temp, 4), + PADDRH (pm0_data_addr), + SCR_JUMP, + PADDR (dispatch), +}/*-------------------------< PM1_SAVE >-------------------*/,{ + SCR_STORE_REL (ia, 4), + offsetof(struct ccb, phys.pm1.ret), + /* + ** If WSR bit is set, either UA and RBC may + ** have been changed whatever the device wants + ** to ignore this residue or not. + */ + SCR_FROM_REG (scntl2), + 0, + SCR_CALL ^ IFTRUE (MASK (WSR, WSR)), + PADDRH (pm_wsr_handle), + /* + ** Save the remaining byte count, the updated + ** address and the return address. + */ + SCR_STORE_REL (rbc, 4), + offsetof(struct ccb, phys.pm1.sg.size), + SCR_STORE_REL (ua, 4), + offsetof(struct ccb, phys.pm1.sg.addr), + /* + ** Set the current pointer at the PM1 DATA mini-script. + */ + SCR_LOAD_ABS (temp, 4), + PADDRH (pm1_data_addr), + SCR_JUMP, + PADDR (dispatch), +}/*--------------------------< PM_WSR_HANDLE >-----------------------*/,{ + /* + * Phase mismatch handling from SCRIPT with WSR set. + * Such a condition can occur if the chip wants to + * execute a CHMOV(size > 1) when the WSR bit is + * set and the target changes PHASE. + */ +#ifdef SYM_DEBUG_PM_WITH_WSR + /* + * Some debugging may still be needed.:) + */ + SCR_INT, + SIR_PM_WITH_WSR, +#endif + /* + * We must move the residual byte to memory. + * + * UA contains bit 0..31 of the address to + * move the residual byte. + * Move it to the table indirect. + */ + SCR_STORE_REL (ua, 4), + offsetof (struct ccb, phys.wresid.addr), + /* + * Increment UA (move address to next position). + */ + SCR_REG_REG (ua, SCR_ADD, 1), + 0, + SCR_REG_REG (ua1, SCR_ADDC, 0), + 0, + SCR_REG_REG (ua2, SCR_ADDC, 0), + 0, + SCR_REG_REG (ua3, SCR_ADDC, 0), + 0, + /* + * Compute SCRATCHA as: + * - size to transfer = 1 byte. + * - bit 24..31 = high address bit [32...39]. + */ + SCR_LOAD_ABS (scratcha, 4), + PADDRH (zero), + SCR_REG_REG (scratcha, SCR_OR, 1), + 0, + SCR_FROM_REG (rbc3), + 0, + SCR_TO_REG (scratcha3), + 0, + /* + * Move this value to the table indirect. + */ + SCR_STORE_REL (scratcha, 4), + offsetof (struct ccb, phys.wresid.size), + /* + * Wait for a valid phase. + * While testing with bogus QUANTUM drives, the C1010 + * sometimes raised a spurious phase mismatch with + * WSR and the CHMOV(1) triggered another PM. + * Waiting explicitely for the PHASE seemed to avoid + * the nested phase mismatch. Btw, this didn't happen + * using my IBM drives. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)), + 0, + /* + * Perform the move of the residual byte. + */ + SCR_CHMOV_TBL ^ SCR_DATA_IN, + offsetof (struct ccb, phys.wresid), + /* + * We can now handle the phase mismatch with UA fixed. + * RBC[0..23]=0 is a special case that does not require + * a PM context. The C code also checks against this. + */ + SCR_FROM_REG (rbc), + 0, + SCR_RETURN ^ IFFALSE (DATA (0)), + 0, + SCR_FROM_REG (rbc1), + 0, + SCR_RETURN ^ IFFALSE (DATA (0)), + 0, + SCR_FROM_REG (rbc2), + 0, + SCR_RETURN ^ IFFALSE (DATA (0)), + 0, + /* + * RBC[0..23]=0. + * Not only we donnot need a PM context, but this would + * lead to a bogus CHMOV(0). This condition means that + * the residual was the last byte to move from this CHMOV. + * So, we just have to move the current data script pointer + * (i.e. TEMP) to the SCRIPTS address following the + * interrupted CHMOV and jump to dispatcher. + */ + SCR_STORE_ABS (ia, 4), + PADDRH (scratch), + SCR_LOAD_ABS (temp, 4), + PADDRH (scratch), + SCR_JUMP, + PADDR (dispatch), +}/*--------------------------< WSR_MA_HELPER >-----------------------*/,{ + /* + * Helper for the C code when WSR bit is set. + * Perform the move of the residual byte. + */ + SCR_CHMOV_TBL ^ SCR_DATA_IN, + offsetof (struct ccb, phys.wresid), + SCR_JUMP, + PADDR (dispatch), +}/*-------------------------< ZERO >------------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< SCRATCH >---------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< SCRATCH1 >--------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< PM0_DATA_ADDR >---------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< PM1_DATA_ADDR >---------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< SAVED_DSA >-------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< SAVED_DRS >-------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< DONE_POS >--------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< STARTPOS >--------------------*/,{ + SCR_DATA_ZERO, +}/*-------------------------< TARGTBL >---------------------*/,{ + SCR_DATA_ZERO, + + +/* +** We may use MEMORY MOVE instructions to load the on chip-RAM, +** if it happens that mapping PCI memory is not possible. +** But writing the RAM from the CPU is the preferred method, +** since PCI 2.2 seems to disallow PCI self-mastering. +*/ + +#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + +}/*-------------------------< START_RAM >-------------------*/,{ + /* + ** Load the script into on-chip RAM, + ** and jump to start point. + */ + SCR_COPY (sizeof (struct script)), +}/*-------------------------< SCRIPT0_BA >--------------------*/,{ + 0, + PADDR (start), + SCR_JUMP, + PADDR (init), + +}/*-------------------------< START_RAM64 >--------------------*/,{ + /* + ** Load the RAM and start for 64 bit PCI (895A,896). + ** Both scripts (script and scripth) are loaded into + ** the RAM which is 8K (4K for 825A/875/895). + ** We also need to load some 32-63 bit segments + ** address of the SCRIPTS processor. + ** LOAD/STORE ABSOLUTE always refers to on-chip RAM + ** in our implementation. The main memory is + ** accessed using LOAD/STORE DSA RELATIVE. + */ + SCR_LOAD_REL (mmws, 4), + offsetof (struct ncb, scr_ram_seg), + SCR_COPY (sizeof(struct script)), +}/*-------------------------< SCRIPT0_BA64 >--------------------*/,{ + 0, + PADDR (start), + SCR_COPY (sizeof(struct scripth)), +}/*-------------------------< SCRIPTH0_BA64 >--------------------*/,{ + 0, + PADDRH (start64), + SCR_LOAD_REL (mmrs, 4), + offsetof (struct ncb, scr_ram_seg), + SCR_JUMP64, + PADDRH (start64), +}/*-------------------------< RAM_SEG64 >--------------------*/,{ + 0, + +#endif /* SCSI_NCR_PCI_MEM_NOT_SUPPORTED */ + +}/*-------------------------< SNOOPTEST >-------------------*/,{ + /* + ** Read the variable. + */ + SCR_LOAD_REL (scratcha, 4), + offsetof(struct ncb, ncr_cache), + SCR_STORE_REL (temp, 4), + offsetof(struct ncb, ncr_cache), + SCR_LOAD_REL (temp, 4), + offsetof(struct ncb, ncr_cache), +}/*-------------------------< SNOOPEND >-------------------*/,{ + /* + ** And stop. + */ + SCR_INT, + 99, +}/*--------------------------------------------------------*/ +}; + +/*========================================================== +** +** +** Fill in #define dependent parts of the script +** +** +**========================================================== +*/ + +void __init ncr_script_fill (struct script * scr, struct scripth * scrh) +{ + int i; + ncrcmd *p; + + p = scr->data_in; + for (i=0; idata_in + sizeof (scr->data_in)); + + p = scr->data_out; + + for (i=0; idata_out + sizeof (scr->data_out)); +} + +/*========================================================== +** +** +** Copy and rebind a script. +** +** +**========================================================== +*/ + +static void __init +ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len) +{ + ncrcmd opcode, new, old, tmp1, tmp2; + ncrcmd *start, *end; + int relocs; + int opchanged = 0; + + start = src; + end = src + len/4; + + while (src < end) { + + opcode = *src++; + *dst++ = cpu_to_scr(opcode); + + /* + ** If we forget to change the length + ** in struct script, a field will be + ** padded with 0. This is an illegal + ** command. + */ + + if (opcode == 0) { + printk (KERN_INFO "%s: ERROR0 IN SCRIPT at %d.\n", + ncr_name(np), (int) (src-start-1)); + MDELAY (10000); + continue; + }; + + /* + ** We use the bogus value 0xf00ff00f ;-) + ** to reserve data area in SCRIPTS. + */ + if (opcode == SCR_DATA_ZERO) { + dst[-1] = 0; + continue; + } + + if (DEBUG_FLAGS & DEBUG_SCRIPT) + printk (KERN_INFO "%p: <%x>\n", + (src-1), (unsigned)opcode); + + /* + ** We don't have to decode ALL commands + */ + switch (opcode >> 28) { + + case 0xf: + /* + ** LOAD / STORE DSA relative, don't relocate. + */ + relocs = 0; + break; + case 0xe: + /* + ** LOAD / STORE absolute. + */ + relocs = 1; + break; + case 0xc: + /* + ** COPY has TWO arguments. + */ + relocs = 2; + tmp1 = src[0]; + tmp2 = src[1]; +#ifdef RELOC_KVAR + if ((tmp1 & RELOC_MASK) == RELOC_KVAR) + tmp1 = 0; + if ((tmp2 & RELOC_MASK) == RELOC_KVAR) + tmp2 = 0; +#endif + if ((tmp1 ^ tmp2) & 3) { + printk (KERN_ERR"%s: ERROR1 IN SCRIPT at %d.\n", + ncr_name(np), (int) (src-start-1)); + MDELAY (1000); + } + /* + ** If PREFETCH feature not enabled, remove + ** the NO FLUSH bit if present. + */ + if ((opcode & SCR_NO_FLUSH) && + !(np->features & FE_PFEN)) { + dst[-1] = cpu_to_scr(opcode & ~SCR_NO_FLUSH); + ++opchanged; + } + break; + + case 0x0: + /* + ** MOVE/CHMOV (absolute address) + */ + if (!(np->features & FE_WIDE)) + dst[-1] = cpu_to_scr(opcode | OPC_MOVE); + relocs = 1; + break; + + case 0x1: + /* + ** MOVE/CHMOV (table indirect) + */ + if (!(np->features & FE_WIDE)) + dst[-1] = cpu_to_scr(opcode | OPC_MOVE); + relocs = 0; + break; + + case 0x8: + /* + ** JUMP / CALL + ** don't relocate if relative :-) + */ + if (opcode & 0x00800000) + relocs = 0; + else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/ + relocs = 2; + else + relocs = 1; + break; + + case 0x4: + case 0x5: + case 0x6: + case 0x7: + relocs = 1; + break; + + default: + relocs = 0; + break; + }; + + if (!relocs) { + *dst++ = cpu_to_scr(*src++); + continue; + } + while (relocs--) { + old = *src++; + + switch (old & RELOC_MASK) { + case RELOC_REGISTER: + new = (old & ~RELOC_MASK) + np->base_ba; + break; + case RELOC_LABEL: + new = (old & ~RELOC_MASK) + np->p_script; + break; + case RELOC_LABELH: + new = (old & ~RELOC_MASK) + np->p_scripth; + break; + case RELOC_SOFTC: + new = (old & ~RELOC_MASK) + np->p_ncb; + break; +#ifdef RELOC_KVAR + case RELOC_KVAR: + new=0; + if (((old & ~RELOC_MASK) < SCRIPT_KVAR_FIRST) || + ((old & ~RELOC_MASK) > SCRIPT_KVAR_LAST)) + panic("ncr KVAR out of range"); + new = vtobus(script_kvars[old & ~RELOC_MASK]); +#endif + break; + case 0: + /* Don't relocate a 0 address. */ + if (old == 0) { + new = old; + break; + } + /* fall through */ + default: + new = 0; /* For 'cc' not to complain */ + panic("ncr_script_copy_and_bind: " + "weird relocation %x\n", old); + break; + } + + *dst++ = cpu_to_scr(new); + } + }; +} + +/*========================================================== +** +** +** Auto configuration: attach and init a host adapter. +** +** +**========================================================== +*/ + +/* +** Linux host data structure. +*/ + +struct host_data { + struct ncb *ncb; +}; + +/* +** Print something which allows to retrieve the controler type, unit, +** target, lun concerned by a kernel message. +*/ + +static void PRINT_TARGET(ncb_p np, int target) +{ + printk(KERN_INFO "%s-<%d,*>: ", ncr_name(np), target); +} + +static void PRINT_LUN(ncb_p np, int target, int lun) +{ + printk(KERN_INFO "%s-<%d,%d>: ", ncr_name(np), target, lun); +} + +static void PRINT_ADDR(Scsi_Cmnd *cmd) +{ + struct host_data *host_data = (struct host_data *) cmd->device->host->hostdata; + PRINT_LUN(host_data->ncb, cmd->device->id, cmd->device->lun); +} + +/*========================================================== +** +** NCR chip clock divisor table. +** Divisors are multiplied by 10,000,000 in order to make +** calculations more simple. +** +**========================================================== +*/ + +#define _5M 5000000 +static u_long div_10M[] = + {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; + + +/*=============================================================== +** +** Prepare io register values used by ncr_init() according +** to selected and supported features. +** +** NCR/SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64, +** 128 transfers. All chips support at least 16 transfers bursts. +** The 825A, 875 and 895 chips support bursts of up to 128 +** transfers and the 895A and 896 support bursts of up to 64 +** transfers. All other chips support up to 16 transfers bursts. +** +** For PCI 32 bit data transfers each transfer is a DWORD (4 bytes). +** It is a QUADWORD (8 bytes) for PCI 64 bit data transfers. +** Only the 896 is able to perform 64 bit data transfers. +** +** We use log base 2 (burst length) as internal code, with +** value 0 meaning "burst disabled". +** +**=============================================================== +*/ + +/* + * Burst length from burst code. + */ +#define burst_length(bc) (!(bc))? 0 : 1 << (bc) + +/* + * Burst code from io register bits. + */ +#define burst_code(dmode, ctest4, ctest5) \ + (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1 + +/* + * Set initial io register bits from burst code. + */ +static inline void ncr_init_burst(ncb_p np, u_char bc) +{ + np->rv_ctest4 &= ~0x80; + np->rv_dmode &= ~(0x3 << 6); + np->rv_ctest5 &= ~0x4; + + if (!bc) { + np->rv_ctest4 |= 0x80; + } + else { + --bc; + np->rv_dmode |= ((bc & 0x3) << 6); + np->rv_ctest5 |= (bc & 0x4); + } +} + +#ifdef SCSI_NCR_NVRAM_SUPPORT + +/* +** Get target set-up from Symbios format NVRAM. +*/ + +static void __init +ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram) +{ + tcb_p tp = &np->target[target]; + Symbios_target *tn = &nvram->target[target]; + + tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255; + tp->usrwide = tn->bus_width == 0x10 ? 1 : 0; + tp->usrtags = + (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? MAX_TAGS : 0; + + if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE)) + tp->usrflag |= UF_NODISC; + if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)) + tp->usrflag |= UF_NOSCAN; +} + +/* +** Get target set-up from Tekram format NVRAM. +*/ + +static void __init +ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram) +{ + tcb_p tp = &np->target[target]; + struct Tekram_target *tn = &nvram->target[target]; + int i; + + if (tn->flags & TEKRAM_SYNC_NEGO) { + i = tn->sync_index & 0xf; + tp->usrsync = Tekram_sync[i]; + } + + tp->usrwide = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0; + + if (tn->flags & TEKRAM_TAGGED_COMMANDS) { + tp->usrtags = 2 << nvram->max_tags_index; + } + + if (!(tn->flags & TEKRAM_DISCONNECT_ENABLE)) + tp->usrflag = UF_NODISC; + + /* If any device does not support parity, we will not use this option */ + if (!(tn->flags & TEKRAM_PARITY_CHECK)) + np->rv_scntl0 &= ~0x0a; /* SCSI parity checking disabled */ +} +#endif /* SCSI_NCR_NVRAM_SUPPORT */ + +/* +** Save initial settings of some IO registers. +** Assumed to have been set by BIOS. +*/ +static void __init ncr_save_initial_setting(ncb_p np) +{ + np->sv_scntl0 = INB(nc_scntl0) & 0x0a; + np->sv_dmode = INB(nc_dmode) & 0xce; + np->sv_dcntl = INB(nc_dcntl) & 0xa8; + np->sv_ctest3 = INB(nc_ctest3) & 0x01; + np->sv_ctest4 = INB(nc_ctest4) & 0x80; + np->sv_gpcntl = INB(nc_gpcntl); + np->sv_stest2 = INB(nc_stest2) & 0x20; + np->sv_stest4 = INB(nc_stest4); + np->sv_stest1 = INB(nc_stest1); + + np->sv_scntl3 = INB(nc_scntl3) & 0x07; + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66) ){ + /* + ** C1010 always uses large fifo, bit 5 rsvd + ** scntl4 used ONLY with C1010 + */ + np->sv_ctest5 = INB(nc_ctest5) & 0x04 ; + np->sv_scntl4 = INB(nc_scntl4); + } + else { + np->sv_ctest5 = INB(nc_ctest5) & 0x24 ; + np->sv_scntl4 = 0; + } +} + +/* +** Prepare io register values used by ncr_init() +** according to selected and supported features. +*/ +static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram) +{ + u_char burst_max; + u_long period; + int i; + +#ifdef CONFIG_PARISC + char scsi_mode = -1; + struct hardware_path hwpath; +#endif + + /* + ** Wide ? + */ + + np->maxwide = (np->features & FE_WIDE)? 1 : 0; + + /* + * Guess the frequency of the chip's clock. + */ + if (np->features & (FE_ULTRA3 | FE_ULTRA2)) + np->clock_khz = 160000; + else if (np->features & FE_ULTRA) + np->clock_khz = 80000; + else + np->clock_khz = 40000; + + /* + * Get the clock multiplier factor. + */ + if (np->features & FE_QUAD) + np->multiplier = 4; + else if (np->features & FE_DBLR) + np->multiplier = 2; + else + np->multiplier = 1; + + /* + * Measure SCSI clock frequency for chips + * it may vary from assumed one. + */ + if (np->features & FE_VARCLK) + ncr_getclock(np, np->multiplier); + + /* + * Divisor to be used for async (timer pre-scaler). + * + * Note: For C1010 the async divisor is 2(8) if he + * quadrupler is disabled (enabled). + */ + + if ( (np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + + np->rv_scntl3 = 0; + } + else + { + i = np->clock_divn - 1; + while (--i >= 0) { + if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz + > div_10M[i]) { + ++i; + break; + } + } + np->rv_scntl3 = i+1; + } + + + /* + * Save the ultra3 register for the C1010/C1010_66 + */ + + np->rv_scntl4 = np->sv_scntl4; + + /* + * Minimum synchronous period factor supported by the chip. + * Btw, 'period' is in tenths of nanoseconds. + */ + + period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz; + +#ifdef CONFIG_PARISC + /* Host firmware (PDC) keeps a table for crippling SCSI capabilities. + * Many newer machines export one channel of 53c896 chip + * as SE, 50-pin HD. Also used for Multi-initiator SCSI clusters + * to set the SCSI Initiator ID. + */ + get_pci_node_path(np->pdev, &hwpath); + if (pdc_get_initiator(&hwpath, &np->myaddr, &period, &np->maxwide, &scsi_mode)) + { + if (np->maxwide) + np->features |= FE_WIDE; + if (scsi_mode >= 0) { + /* C3000 PDC reports period/mode */ + driver_setup.diff_support = 0; + switch(scsi_mode) { + case 0: np->scsi_mode = SMODE_SE; break; + case 1: np->scsi_mode = SMODE_HVD; break; + case 2: np->scsi_mode = SMODE_LVD; break; + default: break; + } + } + } +#endif + + if (period <= 250) np->minsync = 10; + else if (period <= 303) np->minsync = 11; + else if (period <= 500) np->minsync = 12; + else np->minsync = (period + 40 - 1) / 40; + + /* + * Fix up. If sync. factor is 10 (160000Khz clock) and chip + * supports ultra3, then min. sync. period 12.5ns and the factor is 9 + * Also keep track of the maximum offset in ST mode which may differ + * from the maximum offset in DT mode. For now hardcoded to 31. + */ + + if (np->features & FE_ULTRA3) { + if (np->minsync == 10) + np->minsync = 9; + np->maxoffs_st = 31; + } + else + np->maxoffs_st = np->maxoffs; + + /* + * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2). + * + * Transfer period minimums: SCSI-1 200 (50); Fast 100 (25) + * Ultra 50 (12); Ultra2 (6); Ultra3 (3) + */ + + if (np->minsync < 25 && !(np->features & (FE_ULTRA|FE_ULTRA2|FE_ULTRA3))) + np->minsync = 25; + else if (np->minsync < 12 && (np->features & FE_ULTRA)) + np->minsync = 12; + else if (np->minsync < 10 && (np->features & FE_ULTRA2)) + np->minsync = 10; + else if (np->minsync < 9 && (np->features & FE_ULTRA3)) + np->minsync = 9; + + /* + * Maximum synchronous period factor supported by the chip. + */ + + period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz); + np->maxsync = period > 2540 ? 254 : period / 10; + + /* + ** 64 bit (53C895A or 53C896) ? + */ + if (np->features & FE_DAC) { + if (np->features & FE_DAC_IN_USE) + np->rv_ccntl1 |= (XTIMOD | EXTIBMV); + else + np->rv_ccntl1 |= (DDAC); + } + + /* + ** Phase mismatch handled by SCRIPTS (53C895A, 53C896 or C1010) ? + */ + if (np->features & FE_NOPM) + np->rv_ccntl0 |= (ENPMJ); + + /* + ** Prepare initial value of other IO registers + */ +#if defined SCSI_NCR_TRUST_BIOS_SETTING + np->rv_scntl0 = np->sv_scntl0; + np->rv_dmode = np->sv_dmode; + np->rv_dcntl = np->sv_dcntl; + np->rv_ctest3 = np->sv_ctest3; + np->rv_ctest4 = np->sv_ctest4; + np->rv_ctest5 = np->sv_ctest5; + burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5); +#else + + /* + ** Select burst length (dwords) + */ + burst_max = driver_setup.burst_max; + if (burst_max == 255) + burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5); + if (burst_max > 7) + burst_max = 7; + if (burst_max > np->maxburst) + burst_max = np->maxburst; + + /* + ** DEL 352 - 53C810 Rev x11 - Part Number 609-0392140 - ITEM 2. + ** This chip and the 860 Rev 1 may wrongly use PCI cache line + ** based transactions on LOAD/STORE instructions. So we have + ** to prevent these chips from using such PCI transactions in + ** this driver. The generic sym53c8xx driver that does not use + ** LOAD/STORE instructions does not need this work-around. + */ + if ((np->device_id == PCI_DEVICE_ID_NCR_53C810 && + np->revision_id >= 0x10 && np->revision_id <= 0x11) || + (np->device_id == PCI_DEVICE_ID_NCR_53C860 && + np->revision_id <= 0x1)) + np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP); + + /* + ** DEL ? - 53C1010 Rev 1 - Part Number 609-0393638 + ** 64-bit Slave Cycles must be disabled. + */ + if ( ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) && (np->revision_id < 0x02) ) + || (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 ) ) + np->rv_ccntl1 |= 0x10; + + /* + ** Select all supported special features. + ** If we are using on-board RAM for scripts, prefetch (PFEN) + ** does not help, but burst op fetch (BOF) does. + ** Disabling PFEN makes sure BOF will be used. + */ + if (np->features & FE_ERL) + np->rv_dmode |= ERL; /* Enable Read Line */ + if (np->features & FE_BOF) + np->rv_dmode |= BOF; /* Burst Opcode Fetch */ + if (np->features & FE_ERMP) + np->rv_dmode |= ERMP; /* Enable Read Multiple */ +#if 1 + if ((np->features & FE_PFEN) && !np->base2_ba) +#else + if (np->features & FE_PFEN) +#endif + np->rv_dcntl |= PFEN; /* Prefetch Enable */ + if (np->features & FE_CLSE) + np->rv_dcntl |= CLSE; /* Cache Line Size Enable */ + if (np->features & FE_WRIE) + np->rv_ctest3 |= WRIE; /* Write and Invalidate */ + + + if ( (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && + (np->features & FE_DFS)) + np->rv_ctest5 |= DFS; /* Dma Fifo Size */ + /* C1010/C1010_66 always large fifo */ + + /* + ** Select some other + */ + if (driver_setup.master_parity) + np->rv_ctest4 |= MPEE; /* Master parity checking */ + if (driver_setup.scsi_parity) + np->rv_scntl0 |= 0x0a; /* full arb., ena parity, par->ATN */ + +#ifdef SCSI_NCR_NVRAM_SUPPORT + /* + ** Get parity checking, host ID and verbose mode from NVRAM + **/ + if (nvram) { + switch(nvram->type) { + case SCSI_NCR_TEKRAM_NVRAM: + np->myaddr = nvram->data.Tekram.host_id & 0x0f; + break; + case SCSI_NCR_SYMBIOS_NVRAM: + if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE)) + np->rv_scntl0 &= ~0x0a; + np->myaddr = nvram->data.Symbios.host_id & 0x0f; + if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS) + np->verbose += 1; + break; + } + } +#endif + /* + ** Get SCSI addr of host adapter (set by bios?). + */ + if (np->myaddr == 255) { + np->myaddr = INB(nc_scid) & 0x07; + if (!np->myaddr) + np->myaddr = SCSI_NCR_MYADDR; + } + +#endif /* SCSI_NCR_TRUST_BIOS_SETTING */ + + /* + * Prepare initial io register bits for burst length + */ + ncr_init_burst(np, burst_max); + + /* + ** Set SCSI BUS mode. + ** + ** - ULTRA2 chips (895/895A/896) + ** and ULTRA 3 chips (1010) report the current + ** BUS mode through the STEST4 IO register. + ** - For previous generation chips (825/825A/875), + ** user has to tell us how to check against HVD, + ** since a 100% safe algorithm is not possible. + */ + np->scsi_mode = SMODE_SE; + if (np->features & (FE_ULTRA2 | FE_ULTRA3)) + np->scsi_mode = (np->sv_stest4 & SMODE); + else if (np->features & FE_DIFF) { + switch(driver_setup.diff_support) { + case 4: /* Trust previous settings if present, then GPIO3 */ + if (np->sv_scntl3) { + if (np->sv_stest2 & 0x20) + np->scsi_mode = SMODE_HVD; + break; + } + case 3: /* SYMBIOS controllers report HVD through GPIO3 */ + if (nvram && nvram->type != SCSI_NCR_SYMBIOS_NVRAM) + break; + if (INB(nc_gpreg) & 0x08) + break; + case 2: /* Set HVD unconditionally */ + np->scsi_mode = SMODE_HVD; + case 1: /* Trust previous settings for HVD */ + if (np->sv_stest2 & 0x20) + np->scsi_mode = SMODE_HVD; + break; + default:/* Don't care about HVD */ + break; + } + } + if (np->scsi_mode == SMODE_HVD) + np->rv_stest2 |= 0x20; + + /* + ** Set LED support from SCRIPTS. + ** Ignore this feature for boards known to use a + ** specific GPIO wiring and for the 895A or 896 + ** that drive the LED directly. + ** Also probe initial setting of GPIO0 as output. + */ + if ((driver_setup.led_pin || + (nvram && nvram->type == SCSI_NCR_SYMBIOS_NVRAM)) && + !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01)) + np->features |= FE_LED0; + + /* + ** Set irq mode. + */ + switch(driver_setup.irqm & 3) { + case 2: + np->rv_dcntl |= IRQM; + break; + case 1: + np->rv_dcntl |= (np->sv_dcntl & IRQM); + break; + default: + break; + } + + /* + ** Configure targets according to driver setup. + ** If NVRAM present get targets setup from NVRAM. + ** Allow to override sync, wide and NOSCAN from + ** boot command line. + */ + for (i = 0 ; i < MAX_TARGET ; i++) { + tcb_p tp = &np->target[i]; + + tp->usrsync = 255; +#ifdef SCSI_NCR_NVRAM_SUPPORT + if (nvram) { + switch(nvram->type) { + case SCSI_NCR_TEKRAM_NVRAM: + ncr_Tekram_setup_target(np, i, &nvram->data.Tekram); + break; + case SCSI_NCR_SYMBIOS_NVRAM: + ncr_Symbios_setup_target(np, i, &nvram->data.Symbios); + break; + } + if (driver_setup.use_nvram & 0x2) + tp->usrsync = driver_setup.default_sync; + if (driver_setup.use_nvram & 0x4) + tp->usrwide = driver_setup.max_wide; + if (driver_setup.use_nvram & 0x8) + tp->usrflag &= ~UF_NOSCAN; + } + else { +#else + if (1) { +#endif + tp->usrsync = driver_setup.default_sync; + tp->usrwide = driver_setup.max_wide; + tp->usrtags = MAX_TAGS; + if (!driver_setup.disconnection) + np->target[i].usrflag = UF_NODISC; + } + } + + /* + ** Announce all that stuff to user. + */ + + i = nvram ? nvram->type : 0; + printk(KERN_INFO "%s: %sID %d, Fast-%d%s%s\n", ncr_name(np), + i == SCSI_NCR_SYMBIOS_NVRAM ? "Symbios format NVRAM, " : + (i == SCSI_NCR_TEKRAM_NVRAM ? "Tekram format NVRAM, " : ""), + np->myaddr, + np->minsync < 10 ? 80 : + (np->minsync < 12 ? 40 : (np->minsync < 25 ? 20 : 10) ), + (np->rv_scntl0 & 0xa) ? ", Parity Checking" : ", NO Parity", + (np->rv_stest2 & 0x20) ? ", Differential" : ""); + + if (bootverbose > 1) { + printk (KERN_INFO "%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " + "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", + ncr_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl, + np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); + + printk (KERN_INFO "%s: final SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " + "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", + ncr_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl, + np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); + } + + if (bootverbose && np->base2_ba) + printk (KERN_INFO "%s: on-chip RAM at 0x%lx\n", + ncr_name(np), np->base2_ba); + + return 0; +} + + +#ifdef SCSI_NCR_DEBUG_NVRAM + +void __init ncr_display_Symbios_nvram(ncb_p np, Symbios_nvram *nvram) +{ + int i; + + /* display Symbios nvram host data */ + printk(KERN_DEBUG "%s: HOST ID=%d%s%s%s%s%s\n", + ncr_name(np), nvram->host_id & 0x0f, + (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", + (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"", + (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"", + (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"", + (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :""); + + /* display Symbios nvram drive data */ + for (i = 0 ; i < 15 ; i++) { + struct Symbios_target *tn = &nvram->target[i]; + printk(KERN_DEBUG "%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n", + ncr_name(np), i, + (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "", + (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "", + (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "", + (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "", + tn->bus_width, + tn->sync_period / 4, + tn->timeout); + } +} + +static u_char Tekram_boot_delay[7] __initdata = {3, 5, 10, 20, 30, 60, 120}; + +void __init ncr_display_Tekram_nvram(ncb_p np, Tekram_nvram *nvram) +{ + int i, tags, boot_delay; + char *rem; + + /* display Tekram nvram host data */ + tags = 2 << nvram->max_tags_index; + boot_delay = 0; + if (nvram->boot_delay_index < 6) + boot_delay = Tekram_boot_delay[nvram->boot_delay_index]; + switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) { + default: + case 0: rem = ""; break; + case 1: rem = " REMOVABLE=boot device"; break; + case 2: rem = " REMOVABLE=all"; break; + } + + printk(KERN_DEBUG + "%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n", + ncr_name(np), nvram->host_id & 0x0f, + (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", + (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES" :"", + (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"", + (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"", + (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"", + (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"", + (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"", + (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"", + rem, boot_delay, tags); + + /* display Tekram nvram drive data */ + for (i = 0; i <= 15; i++) { + int sync, j; + struct Tekram_target *tn = &nvram->target[i]; + j = tn->sync_index & 0xf; + sync = Tekram_sync[j]; + printk(KERN_DEBUG "%s-%d:%s%s%s%s%s%s PERIOD=%d\n", + ncr_name(np), i, + (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "", + (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "", + (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "", + (tn->flags & TEKRAM_START_CMD) ? " START" : "", + (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "", + (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "", + sync); + } +} +#endif /* SCSI_NCR_DEBUG_NVRAM */ + +/* +** Host attach and initialisations. +** +** Allocate host data and ncb structure. +** Request IO region and remap MMIO region. +** Do chip initialization. +** If all is OK, install interrupt handling and +** start the timer daemon. +*/ + +static int __init +ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device) +{ + struct host_data *host_data; + ncb_p np = 0; + struct Scsi_Host *instance = 0; + u_long flags = 0; + ncr_nvram *nvram = device->nvram; + int i; + + printk(KERN_INFO NAME53C "%s-%d: rev 0x%x on pci bus %d device %d function %d " +#ifdef __sparc__ + "irq %s\n", +#else + "irq %d\n", +#endif + device->chip.name, unit, device->chip.revision_id, + device->slot.bus, (device->slot.device_fn & 0xf8) >> 3, + device->slot.device_fn & 7, +#ifdef __sparc__ + __irq_itoa(device->slot.irq)); +#else + device->slot.irq); +#endif + + /* + ** Allocate host_data structure + */ + if (!(instance = scsi_register(tpnt, sizeof(*host_data)))) + goto attach_error; + host_data = (struct host_data *) instance->hostdata; + + /* + ** Allocate the host control block. + */ + np = __m_calloc_dma(device->pdev, sizeof(struct ncb), "NCB"); + if (!np) + goto attach_error; + NCR_INIT_LOCK_NCB(np); + np->pdev = device->pdev; + np->p_ncb = vtobus(np); + host_data->ncb = np; + + /* + ** Store input informations in the host data structure. + */ + strncpy(np->chip_name, device->chip.name, sizeof(np->chip_name) - 1); + np->unit = unit; + np->verbose = driver_setup.verbose; + sprintf(np->inst_name, NAME53C "%s-%d", np->chip_name, np->unit); + np->device_id = device->chip.device_id; + np->revision_id = device->chip.revision_id; + np->bus = device->slot.bus; + np->device_fn = device->slot.device_fn; + np->features = device->chip.features; + np->clock_divn = device->chip.nr_divisor; + np->maxoffs = device->chip.offset_max; + np->maxburst = device->chip.burst_max; + np->myaddr = device->host_id; + + /* + ** Allocate the start queue. + */ + np->squeue = (ncrcmd *) + m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); + if (!np->squeue) + goto attach_error; + np->p_squeue = vtobus(np->squeue); + + /* + ** Allocate the done queue. + */ + np->dqueue = (ncrcmd *) + m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE"); + if (!np->dqueue) + goto attach_error; + + /* + ** Allocate the target bus address array. + */ + np->targtbl = (u_int32 *) m_calloc_dma(256, "TARGTBL"); + if (!np->targtbl) + goto attach_error; + + /* + ** Allocate SCRIPTS areas + */ + np->script0 = (struct script *) + m_calloc_dma(sizeof(struct script), "SCRIPT"); + if (!np->script0) + goto attach_error; + np->scripth0 = (struct scripth *) + m_calloc_dma(sizeof(struct scripth), "SCRIPTH"); + if (!np->scripth0) + goto attach_error; + + /* + ** Initialyze the CCB free queue and, + ** allocate some CCB. We need at least ONE. + */ + xpt_que_init(&np->free_ccbq); + xpt_que_init(&np->b0_ccbq); + if (!ncr_alloc_ccb(np)) + goto attach_error; + + /* + ** Initialize timer structure + ** + */ + init_timer(&np->timer); + np->timer.data = (unsigned long) np; + np->timer.function = sym53c8xx_timeout; + + /* + ** Try to map the controller chip to + ** virtual and physical memory. + */ + + np->base_ba = device->slot.base; + np->base_ws = (np->features & FE_IO256)? 256 : 128; + np->base2_ba = (np->features & FE_RAM)? device->slot.base_2 : 0; + +#ifndef SCSI_NCR_IOMAPPED + np->base_va = remap_pci_mem(device->slot.base_c, np->base_ws); + if (!np->base_va) { + printk(KERN_ERR "%s: can't map PCI MMIO region\n",ncr_name(np)); + goto attach_error; + } + else if (bootverbose > 1) + printk(KERN_INFO "%s: using memory mapped IO\n", ncr_name(np)); + + /* + ** Make the controller's registers available. + ** Now the INB INW INL OUTB OUTW OUTL macros + ** can be used safely. + */ + + np->reg = (struct ncr_reg *) np->base_va; + +#endif /* !defined SCSI_NCR_IOMAPPED */ + + /* + ** If on-chip RAM is used, make sure SCRIPTS isn't too large. + */ + if (np->base2_ba && sizeof(struct script) > 4096) { + printk(KERN_ERR "%s: script too large.\n", ncr_name(np)); + goto attach_error; + } + + /* + ** Try to map the controller chip into iospace. + */ + + if (device->slot.io_port) { + request_region(device->slot.io_port, np->base_ws, NAME53C8XX); + np->base_io = device->slot.io_port; + } + +#ifdef SCSI_NCR_NVRAM_SUPPORT + if (nvram) { + switch(nvram->type) { + case SCSI_NCR_SYMBIOS_NVRAM: +#ifdef SCSI_NCR_DEBUG_NVRAM + ncr_display_Symbios_nvram(np, &nvram->data.Symbios); +#endif + break; + case SCSI_NCR_TEKRAM_NVRAM: +#ifdef SCSI_NCR_DEBUG_NVRAM + ncr_display_Tekram_nvram(np, &nvram->data.Tekram); +#endif + break; + default: + nvram = 0; +#ifdef SCSI_NCR_DEBUG_NVRAM + printk(KERN_DEBUG "%s: NVRAM: None or invalid data.\n", ncr_name(np)); +#endif + } + } +#endif + + /* + ** Save setting of some IO registers, so we will + ** be able to probe specific implementations. + */ + ncr_save_initial_setting (np); + + /* + ** Reset the chip now, since it has been reported + ** that SCSI clock calibration may not work properly + ** if the chip is currently active. + */ + ncr_chip_reset (np); + + /* + ** Do chip dependent initialization. + */ + (void) ncr_prepare_setting(np, nvram); + + /* + ** Check the PCI clock frequency if needed. + ** + ** Must be done after ncr_prepare_setting since it destroys + ** STEST1 that is used to probe for the clock multiplier. + ** + ** The range is currently [22688 - 45375 Khz], given + ** the values used by ncr_getclock(). + ** This calibration of the frequecy measurement + ** algorithm against the PCI clock frequency is only + ** performed if the driver has had to measure the SCSI + ** clock due to other heuristics not having been enough + ** to deduce the SCSI clock frequency. + ** + ** When the chip has been initialized correctly by the + ** SCSI BIOS, the driver deduces the presence of the + ** clock multiplier and the value of the SCSI clock from + ** initial values of IO registers, and therefore no + ** clock measurement is performed. + ** Normally the driver should never have to measure any + ** clock, unless the controller may use a 80 MHz clock + ** or has a clock multiplier and any of the following + ** condition is met: + ** + ** - No SCSI BIOS is present. + ** - SCSI BIOS did'nt enable the multiplier for some reason. + ** - User has disabled the controller from the SCSI BIOS. + ** - User booted the O/S from another O/S that did'nt enable + ** the multiplier for some reason. + ** + ** As a result, the driver may only have to measure some + ** frequency in very unusual situations. + ** + ** For this reality test against the PCI clock to really + ** protect against flaws in the udelay() calibration or + ** driver problem that affect the clock measurement + ** algorithm, the actual PCI clock frequency must be 33 MHz. + */ + i = np->pciclock_max ? ncr_getpciclock(np) : 0; + if (i && (i < np->pciclock_min || i > np->pciclock_max)) { + printk(KERN_ERR "%s: PCI clock (%u KHz) is out of range " + "[%u KHz - %u KHz].\n", + ncr_name(np), i, np->pciclock_min, np->pciclock_max); + goto attach_error; + } + + /* + ** Patch script to physical addresses + */ + ncr_script_fill (&script0, &scripth0); + + np->p_script = vtobus(np->script0); + np->p_scripth = vtobus(np->scripth0); + np->p_scripth0 = np->p_scripth; + + if (np->base2_ba) { + np->p_script = np->base2_ba; + if (np->features & FE_RAM8K) { + np->base2_ws = 8192; + np->p_scripth = np->p_script + 4096; +#if BITS_PER_LONG > 32 + np->scr_ram_seg = cpu_to_scr(np->base2_ba >> 32); +#endif + } + else + np->base2_ws = 4096; +#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + np->base2_va = + remap_pci_mem(device->slot.base_2_c, np->base2_ws); + if (!np->base2_va) { + printk(KERN_ERR "%s: can't map PCI MEMORY region\n", + ncr_name(np)); + goto attach_error; + } +#endif + } + + ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script)); + ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth)); + + /* + ** Patch some variables in SCRIPTS + */ + np->scripth0->pm0_data_addr[0] = + cpu_to_scr(NCB_SCRIPT_PHYS(np, pm0_data)); + np->scripth0->pm1_data_addr[0] = + cpu_to_scr(NCB_SCRIPT_PHYS(np, pm1_data)); + + /* + ** Patch if not Ultra 3 - Do not write to scntl4 + */ + if (np->features & FE_ULTRA3) { + np->script0->resel_scntl4[0] = cpu_to_scr(SCR_LOAD_REL (scntl4, 1)); + np->script0->resel_scntl4[1] = cpu_to_scr(offsetof(struct tcb, uval)); + } + + +#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + np->scripth0->script0_ba[0] = cpu_to_scr(vtobus(np->script0)); + np->scripth0->script0_ba64[0] = cpu_to_scr(vtobus(np->script0)); + np->scripth0->scripth0_ba64[0] = cpu_to_scr(vtobus(np->scripth0)); + np->scripth0->ram_seg64[0] = np->scr_ram_seg; +#endif + /* + ** Prepare the idle and invalid task actions. + */ + np->idletask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->idletask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); + np->p_idletask = NCB_PHYS(np, idletask); + + np->notask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->notask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); + np->p_notask = NCB_PHYS(np, notask); + + np->bad_i_t_l.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->bad_i_t_l.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); + np->p_bad_i_t_l = NCB_PHYS(np, bad_i_t_l); + + np->bad_i_t_l_q.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->bad_i_t_l_q.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np,bad_i_t_l_q)); + np->p_bad_i_t_l_q = NCB_PHYS(np, bad_i_t_l_q); + + /* + ** Allocate and prepare the bad lun table. + */ + np->badluntbl = m_calloc_dma(256, "BADLUNTBL"); + if (!np->badluntbl) + goto attach_error; + + assert (offsetof(struct lcb, resel_task) == 0); + np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, resel_bad_lun)); + + for (i = 0 ; i < 64 ; i++) + np->badluntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun)); + + /* + ** Prepare the target bus address array. + */ + np->scripth0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl)); + for (i = 0 ; i < MAX_TARGET ; i++) { + np->targtbl[i] = cpu_to_scr(NCB_PHYS(np, target[i])); + np->target[i].b_luntbl = cpu_to_scr(vtobus(np->badluntbl)); + np->target[i].b_lun0 = cpu_to_scr(NCB_PHYS(np, resel_badlun)); + } + + /* + ** Patch the script for LED support. + */ + + if (np->features & FE_LED0) { + np->script0->idle[0] = + cpu_to_scr(SCR_REG_REG(gpreg, SCR_OR, 0x01)); + np->script0->reselected[0] = + cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe)); + np->script0->start[0] = + cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe)); + } + + /* + ** Patch the script to provide an extra clock cycle on + ** data out phase - 53C1010_66MHz part only. + ** (Fixed in rev. 1 of the chip) + */ + if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 && + np->revision_id < 1){ + np->script0->datao_phase[0] = + cpu_to_scr(SCR_REG_REG(scntl4, SCR_OR, 0x0c)); + } + +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** If user does not want to use IMMEDIATE ARBITRATION + ** when we are reselected while attempting to arbitrate, + ** patch the SCRIPTS accordingly with a SCRIPT NO_OP. + */ + if (!(driver_setup.iarb & 1)) + np->script0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); + /* + ** If user wants IARB to be set when we win arbitration + ** and have other jobs, compute the max number of consecutive + ** settings of IARB hint before we leave devices a chance to + ** arbitrate for reselection. + */ + np->iarb_max = (driver_setup.iarb >> 4); +#endif + + /* + ** DEL 472 - 53C896 Rev 1 - Part Number 609-0393055 - ITEM 5. + */ + if (np->device_id == PCI_DEVICE_ID_NCR_53C896 && + np->revision_id <= 0x1 && (np->features & FE_NOPM)) { + np->scatter = ncr_scatter_896R1; + np->script0->datai_phase[0] = cpu_to_scr(SCR_JUMP); + np->script0->datai_phase[1] = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj)); + np->script0->datao_phase[0] = cpu_to_scr(SCR_JUMP); + np->script0->datao_phase[1] = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj)); + } + else +#ifdef DEBUG_896R1 + np->scatter = ncr_scatter_896R1; +#else + np->scatter = ncr_scatter; +#endif + + /* + ** Reset chip. + ** We should use ncr_soft_reset(), but we donnot want to do + ** so, since we may not be safe if ABRT interrupt occurs due + ** to the BIOS or previous O/S having enable this interrupt. + ** + ** For C1010 need to set ABRT bit prior to SRST if SCRIPTs + ** are running. Not true in this case. + */ + ncr_chip_reset(np); + + /* + ** Now check the cache handling of the pci chipset. + */ + + if (ncr_snooptest (np)) { + printk (KERN_ERR "CACHE INCORRECTLY CONFIGURED.\n"); + goto attach_error; + }; + + /* + ** Install the interrupt handler. + ** If we synchonize the C code with SCRIPTS on interrupt, + ** we donnot want to share the INTR line at all. + */ + if (request_irq(device->slot.irq, sym53c8xx_intr, +#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR + ((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT), +#else + ((driver_setup.irqm & 0x10) ? 0 : SA_SHIRQ) | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) + ((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT), +#else + 0, +#endif +#endif + NAME53C8XX, np)) { + printk(KERN_ERR "%s: request irq %d failure\n", + ncr_name(np), device->slot.irq); + goto attach_error; + } + np->irq = device->slot.irq; + + /* + ** After SCSI devices have been opened, we cannot + ** reset the bus safely, so we do it here. + ** Interrupt handler does the real work. + ** Process the reset exception, + ** if interrupts are not enabled yet. + ** Then enable disconnects. + */ + NCR_LOCK_NCB(np, flags); + if (ncr_reset_scsi_bus(np, 0, driver_setup.settle_delay) != 0) { + printk(KERN_ERR "%s: FATAL ERROR: CHECK SCSI BUS - CABLES, TERMINATION, DEVICE POWER etc.!\n", ncr_name(np)); + + NCR_UNLOCK_NCB(np, flags); + goto attach_error; + } + ncr_exception (np); + + /* + ** The middle-level SCSI driver does not + ** wait for devices to settle. + ** Wait synchronously if more than 2 seconds. + */ + if (driver_setup.settle_delay > 2) { + printk(KERN_INFO "%s: waiting %d seconds for scsi devices to settle...\n", + ncr_name(np), driver_setup.settle_delay); + MDELAY (1000 * driver_setup.settle_delay); + } + + /* + ** start the timeout daemon + */ + np->lasttime=0; + ncr_timeout (np); + + /* + ** use SIMPLE TAG messages by default + */ +#ifdef SCSI_NCR_ALWAYS_SIMPLE_TAG + np->order = M_SIMPLE_TAG; +#endif + + /* + ** Done. + ** Fill Linux host instance structure + ** and return success. + */ + instance->max_channel = 0; + instance->this_id = np->myaddr; + instance->max_id = np->maxwide ? 16 : 8; + instance->max_lun = MAX_LUN; +#ifndef SCSI_NCR_IOMAPPED +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29) + instance->base = (unsigned long) np->reg; +#else + instance->base = (char *) np->reg; +#endif +#endif + instance->irq = np->irq; + instance->unique_id = np->base_io; + instance->io_port = np->base_io; + instance->n_io_port = np->base_ws; + instance->dma_channel = 0; + instance->cmd_per_lun = MAX_TAGS; + instance->can_queue = (MAX_START-4); + scsi_set_device(instance, &device->pdev->dev); + + np->check_integrity = 0; + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + instance->check_integrity = 0; + +#ifdef SCSI_NCR_ENABLE_INTEGRITY_CHECK + if ( !(driver_setup.bus_check & 0x04) ) { + np->check_integrity = 1; + instance->check_integrity = 1; + } +#endif +#endif + + NCR_UNLOCK_NCB(np, flags); + + /* + ** Now let the generic SCSI driver + ** look for the SCSI devices on the bus .. + */ + return 0; + +attach_error: + if (!instance) return -1; + printk(KERN_INFO "%s: giving up ...\n", ncr_name(np)); + if (np) + ncr_free_resources(np); + scsi_unregister(instance); + + return -1; + } + + +/* +** Free controller resources. +*/ +static void ncr_free_resources(ncb_p np) +{ + ccb_p cp; + tcb_p tp; + lcb_p lp; + int target, lun; + + if (np->irq) + free_irq(np->irq, np); + if (np->base_io) + release_region(np->base_io, np->base_ws); +#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + if (np->base_va) + unmap_pci_mem(np->base_va, np->base_ws); + if (np->base2_va) + unmap_pci_mem(np->base2_va, np->base2_ws); +#endif + if (np->scripth0) + m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH"); + if (np->script0) + m_free_dma(np->script0, sizeof(struct script), "SCRIPT"); + if (np->squeue) + m_free_dma(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); + if (np->dqueue) + m_free_dma(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE"); + + while ((cp = np->ccbc) != NULL) { + np->ccbc = cp->link_ccb; + m_free_dma(cp, sizeof(*cp), "CCB"); + } + + if (np->badluntbl) + m_free_dma(np->badluntbl, 256,"BADLUNTBL"); + + for (target = 0; target < MAX_TARGET ; target++) { + tp = &np->target[target]; + for (lun = 0 ; lun < MAX_LUN ; lun++) { + lp = ncr_lp(np, tp, lun); + if (!lp) + continue; + if (lp->tasktbl != &lp->tasktbl_0) + m_free_dma(lp->tasktbl, MAX_TASKS*4, "TASKTBL"); + if (lp->cb_tags) + m_free(lp->cb_tags, MAX_TAGS, "CB_TAGS"); + m_free_dma(lp, sizeof(*lp), "LCB"); + } +#if MAX_LUN > 1 + if (tp->lmp) + m_free(tp->lmp, MAX_LUN * sizeof(lcb_p), "LMP"); + if (tp->luntbl) + m_free_dma(tp->luntbl, 256, "LUNTBL"); +#endif + } + + if (np->targtbl) + m_free_dma(np->targtbl, 256, "TARGTBL"); + + m_free_dma(np, sizeof(*np), "NCB"); +} + + +/*========================================================== +** +** +** Done SCSI commands list management. +** +** We donnot enter the scsi_done() callback immediately +** after a command has been seen as completed but we +** insert it into a list which is flushed outside any kind +** of driver critical section. +** This allows to do minimal stuff under interrupt and +** inside critical sections and to also avoid locking up +** on recursive calls to driver entry points under SMP. +** In fact, the only kernel point which is entered by the +** driver with a driver lock set is get_free_pages(GFP_ATOMIC...) +** that shall not reenter the driver under any circumstance. +** +**========================================================== +*/ +static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd) +{ + unmap_scsi_data(np, cmd); + cmd->host_scribble = (char *) np->done_list; + np->done_list = cmd; +} + +static inline void ncr_flush_done_cmds(Scsi_Cmnd *lcmd) +{ + Scsi_Cmnd *cmd; + + while (lcmd) { + cmd = lcmd; + lcmd = (Scsi_Cmnd *) cmd->host_scribble; + cmd->scsi_done(cmd); + } +} + +/*========================================================== +** +** +** Prepare the next negotiation message for integrity check, +** if needed. +** +** Fill in the part of message buffer that contains the +** negotiation and the nego_status field of the CCB. +** Returns the size of the message in bytes. +** +** If tp->ppr_negotiation is 1 and a M_REJECT occurs, then +** we disable ppr_negotiation. If the first ppr_negotiation is +** successful, set this flag to 2. +** +**========================================================== +*/ +#ifdef SCSI_NCR_INTEGRITY_CHECKING +static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr) +{ + tcb_p tp = &np->target[cp->target]; + int msglen = 0; + int nego = 0; + u_char new_width, new_offset, new_period; + u_char no_increase; + + if (tp->ppr_negotiation == 1) /* PPR message successful */ + tp->ppr_negotiation = 2; + + if (tp->inq_done) { + + if (!tp->ic_maximums_set) { + tp->ic_maximums_set = 1; + + /* + * Check against target, host and user limits + */ + if ( (tp->inq_byte7 & INQ7_WIDE16) && + np->maxwide && tp->usrwide) + tp->ic_max_width = 1; + else + tp->ic_max_width = 0; + + + if ((tp->inq_byte7 & INQ7_SYNC) && tp->maxoffs) + tp->ic_min_sync = (tp->minsync < np->minsync) ? + np->minsync : tp->minsync; + else + tp->ic_min_sync = 255; + + tp->period = 1; + tp->widedone = 1; + + /* + * Enable PPR negotiation - only if Ultra3 support + * is accessible. + */ + +#if 0 + if (tp->ic_max_width && (tp->ic_min_sync != 255 )) + tp->ppr_negotiation = 1; +#endif + tp->ppr_negotiation = 0; + if (np->features & FE_ULTRA3) { + if (tp->ic_max_width && (tp->ic_min_sync == 0x09)) + tp->ppr_negotiation = 1; + } + + if (!tp->ppr_negotiation) + cmd->ic_nego &= ~NS_PPR; + } + + if (DEBUG_FLAGS & DEBUG_IC) { + printk("%s: cmd->ic_nego %d, 1st byte 0x%2X\n", + ncr_name(np), cmd->ic_nego, cmd->cmnd[0]); + } + + /* Previous command recorded a parity or an initiator + * detected error condition. Force bus to narrow for this + * target. Clear flag. Negotation on request sense. + * Note: kernel forces 2 bus resets :o( but clears itself out. + * Minor bug? in scsi_obsolete.c (ugly) + */ + if (np->check_integ_par) { + printk("%s: Parity Error. Target set to narrow.\n", + ncr_name(np)); + tp->ic_max_width = 0; + tp->widedone = tp->period = 0; + } + + /* Initializing: + * If ic_nego == NS_PPR, we are in the initial test for + * PPR messaging support. If driver flag is clear, then + * either we don't support PPR nego (narrow or async device) + * or this is the second TUR and we have had a M. REJECT + * or unexpected disconnect on the first PPR negotiation. + * Do not negotiate, reset nego flags (in case a reset has + * occurred), clear ic_nego and return. + * General case: Kernel will clear flag on a fallback. + * Do only SDTR or WDTR in the future. + */ + if (!tp->ppr_negotiation && (cmd->ic_nego == NS_PPR )) { + tp->ppr_negotiation = 0; + cmd->ic_nego &= ~NS_PPR; + tp->widedone = tp->period = 1; + return msglen; + } + else if (( tp->ppr_negotiation && !(cmd->ic_nego & NS_PPR )) || + (!tp->ppr_negotiation && (cmd->ic_nego & NS_PPR )) ) { + tp->ppr_negotiation = 0; + cmd->ic_nego &= ~NS_PPR; + } + + /* + * Always check the PPR nego. flag bit if ppr_negotiation + * is set. If the ic_nego PPR bit is clear, + * there must have been a fallback. Do only + * WDTR / SDTR in the future. + */ + if ((tp->ppr_negotiation) && (!(cmd->ic_nego & NS_PPR))) + tp->ppr_negotiation = 0; + + /* In case of a bus reset, ncr_negotiate will reset + * the flags tp->widedone and tp->period to 0, forcing + * a new negotiation. Do WDTR then SDTR. If PPR, do both. + * Do NOT increase the period. It is possible for the Scsi_Cmnd + * flags to be set to increase the period when a bus reset + * occurs - we don't want to change anything. + */ + + no_increase = 0; + + if (tp->ppr_negotiation && (!tp->widedone) && (!tp->period) ) { + cmd->ic_nego = NS_PPR; + tp->widedone = tp->period = 1; + no_increase = 1; + } + else if (!tp->widedone) { + cmd->ic_nego = NS_WIDE; + tp->widedone = 1; + no_increase = 1; + } + else if (!tp->period) { + cmd->ic_nego = NS_SYNC; + tp->period = 1; + no_increase = 1; + } + + new_width = cmd->ic_nego_width & tp->ic_max_width; + + switch (cmd->ic_nego_sync) { + case 2: /* increase the period */ + if (!no_increase) { + if (tp->ic_min_sync <= 0x09) + tp->ic_min_sync = 0x0A; + else if (tp->ic_min_sync <= 0x0A) + tp->ic_min_sync = 0x0C; + else if (tp->ic_min_sync <= 0x0C) + tp->ic_min_sync = 0x19; + else if (tp->ic_min_sync <= 0x19) + tp->ic_min_sync *= 2; + else { + tp->ic_min_sync = 255; + cmd->ic_nego_sync = 0; + tp->maxoffs = 0; + } + } + new_period = tp->maxoffs?tp->ic_min_sync:0; + new_offset = tp->maxoffs; + break; + + case 1: /* nego. to maximum */ + new_period = tp->maxoffs?tp->ic_min_sync:0; + new_offset = tp->maxoffs; + break; + + case 0: /* nego to async */ + default: + new_period = 0; + new_offset = 0; + break; + }; + + + nego = NS_NOCHANGE; + if (tp->ppr_negotiation) { + u_char options_byte = 0; + + /* + ** Must make sure data is consistent. + ** If period is 9 and sync, must be wide and DT bit set. + ** else period must be larger. If the width is 0, + ** reset bus to wide but increase the period to 0x0A. + ** Note: The strange else clause is due to the integrity check. + ** If fails at 0x09, wide, the I.C. code will redo at the same + ** speed but a narrow bus. The driver must take care of slowing + ** the bus speed down. + ** + ** The maximum offset in ST mode is 31, in DT mode 62 (1010/1010_66 only) + */ + if ( (new_period==0x09) && new_offset) { + if (new_width) + options_byte = 0x02; + else { + tp->ic_min_sync = 0x0A; + new_period = 0x0A; + cmd->ic_nego_width = 1; + new_width = 1; + } + } + if (!options_byte && new_offset > np->maxoffs_st) + new_offset = np->maxoffs_st; + + nego = NS_PPR; + + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 6; + msgptr[msglen++] = M_X_PPR_REQ; + msgptr[msglen++] = new_period; + msgptr[msglen++] = 0; + msgptr[msglen++] = new_offset; + msgptr[msglen++] = new_width; + msgptr[msglen++] = options_byte; + + } + else { + switch (cmd->ic_nego & ~NS_PPR) { + case NS_WIDE: + /* + ** WDTR negotiation on if device supports + ** wide or if wide device forced narrow + ** due to a parity error. + */ + + cmd->ic_nego_width &= tp->ic_max_width; + + if (tp->ic_max_width | np->check_integ_par) { + nego = NS_WIDE; + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 2; + msgptr[msglen++] = M_X_WIDE_REQ; + msgptr[msglen++] = new_width; + } + break; + + case NS_SYNC: + /* + ** negotiate synchronous transfers + ** Target must support sync transfers. + ** Min. period = 0x0A, maximum offset of 31=0x1f. + */ + + if (tp->inq_byte7 & INQ7_SYNC) { + + if (new_offset && (new_period < 0x0A)) { + tp->ic_min_sync = 0x0A; + new_period = 0x0A; + } + if (new_offset > np->maxoffs_st) + new_offset = np->maxoffs_st; + nego = NS_SYNC; + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 3; + msgptr[msglen++] = M_X_SYNC_REQ; + msgptr[msglen++] = new_period; + msgptr[msglen++] = new_offset; + } + else + cmd->ic_nego_sync = 0; + break; + + case NS_NOCHANGE: + break; + } + } + + }; + + cp->nego_status = nego; + np->check_integ_par = 0; + + if (nego) { + tp->nego_cp = cp; + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, nego == NS_WIDE ? + "wide/narrow msgout": + (nego == NS_SYNC ? "sync/async msgout" : "ppr msgout"), + msgptr); + }; + }; + + return msglen; +} +#endif /* SCSI_NCR_INTEGRITY_CHECKING */ + +/*========================================================== +** +** +** Prepare the next negotiation message if needed. +** +** Fill in the part of message buffer that contains the +** negotiation and the nego_status field of the CCB. +** Returns the size of the message in bytes. +** +** +**========================================================== +*/ + + +static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr) +{ + tcb_p tp = &np->target[cp->target]; + int msglen = 0; + int nego = 0; + u_char width, offset, factor, last_byte; + + if (!np->check_integrity) { + /* If integrity checking disabled, enable PPR messaging + * if device supports wide, sync and ultra 3 + */ + if (tp->ppr_negotiation == 1) /* PPR message successful */ + tp->ppr_negotiation = 2; + + if ((tp->inq_done) && (!tp->ic_maximums_set)) { + tp->ic_maximums_set = 1; + + /* + * Issue PPR only if board is capable + * and set-up for Ultra3 transfers. + */ + tp->ppr_negotiation = 0; + if ( (np->features & FE_ULTRA3) && + (tp->usrwide) && (tp->maxoffs) && + (tp->minsync == 0x09) ) + tp->ppr_negotiation = 1; + } + } + + if (tp->inq_done) { + /* + * Get the current width, offset and period + */ + ncr_get_xfer_info( np, tp, &factor, + &offset, &width); + + /* + ** negotiate wide transfers ? + */ + + if (!tp->widedone) { + if (tp->inq_byte7 & INQ7_WIDE16) { + if (tp->ppr_negotiation) + nego = NS_PPR; + else + nego = NS_WIDE; + + width = tp->usrwide; +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if (tp->ic_done) + width &= tp->ic_max_width; +#endif + } else + tp->widedone=1; + + }; + + /* + ** negotiate synchronous transfers? + */ + + if ((nego != NS_WIDE) && !tp->period) { + if (tp->inq_byte7 & INQ7_SYNC) { + if (tp->ppr_negotiation) + nego = NS_PPR; + else + nego = NS_SYNC; + + /* Check for async flag */ + if (tp->maxoffs == 0) { + offset = 0; + factor = 0; + } + else { + offset = tp->maxoffs; + factor = tp->minsync; +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if ((tp->ic_done) && + (factor < tp->ic_min_sync)) + factor = tp->ic_min_sync; +#endif + } + + } else { + offset = 0; + factor = 0; + tp->period =0xffff; + PRINT_TARGET(np, cp->target); + printk ("target did not report SYNC.\n"); + }; + }; + }; + + switch (nego) { + case NS_PPR: + /* + ** Must make sure data is consistent. + ** If period is 9 and sync, must be wide and DT bit set + ** else period must be larger. + ** Maximum offset is 31=0x1f is ST mode, 62 if DT mode + */ + last_byte = 0; + if ( (factor==9) && offset) { + if (!width) { + factor = 0x0A; + } + else + last_byte = 0x02; + } + if (!last_byte && offset > np->maxoffs_st) + offset = np->maxoffs_st; + + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 6; + msgptr[msglen++] = M_X_PPR_REQ; + msgptr[msglen++] = factor; + msgptr[msglen++] = 0; + msgptr[msglen++] = offset; + msgptr[msglen++] = width; + msgptr[msglen++] = last_byte; + break; + case NS_SYNC: + /* + ** Never negotiate faster than Ultra 2 (25ns periods) + */ + if (offset && (factor < 0x0A)) { + factor = 0x0A; + tp->minsync = 0x0A; + } + if (offset > np->maxoffs_st) + offset = np->maxoffs_st; + + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 3; + msgptr[msglen++] = M_X_SYNC_REQ; + msgptr[msglen++] = factor; + msgptr[msglen++] = offset; + break; + case NS_WIDE: + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 2; + msgptr[msglen++] = M_X_WIDE_REQ; + msgptr[msglen++] = width; + break; + }; + + cp->nego_status = nego; + + if (nego) { + tp->nego_cp = cp; + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, nego == NS_WIDE ? + "wide msgout": + (nego == NS_SYNC ? "sync msgout" : "ppr msgout"), + msgptr); + }; + }; + + return msglen; +} + +/*========================================================== +** +** +** Start execution of a SCSI command. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) +{ +/* Scsi_Device *device = cmd->device; */ + tcb_p tp = &np->target[cmd->device->id]; + lcb_p lp = ncr_lp(np, tp, cmd->device->lun); + ccb_p cp; + + u_char idmsg, *msgptr; + u_int msglen; + int direction; + u_int32 lastp, goalp; + + /*--------------------------------------------- + ** + ** Some shortcuts ... + ** + **--------------------------------------------- + */ + if ((cmd->device->id == np->myaddr ) || + (cmd->device->id >= MAX_TARGET) || + (cmd->device->lun >= MAX_LUN )) { + return(DID_BAD_TARGET); + } + + /*--------------------------------------------- + ** + ** Complete the 1st TEST UNIT READY command + ** with error condition if the device is + ** flagged NOSCAN, in order to speed up + ** the boot. + ** + **--------------------------------------------- + */ + if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12) && + (tp->usrflag & UF_NOSCAN)) { + tp->usrflag &= ~UF_NOSCAN; + return DID_BAD_TARGET; + } + + if (DEBUG_FLAGS & DEBUG_TINY) { + PRINT_ADDR(cmd); + printk ("CMD=%x ", cmd->cmnd[0]); + } + + /*--------------------------------------------------- + ** + ** Assign a ccb / bind cmd. + ** If resetting, shorten settle_time if necessary + ** in order to avoid spurious timeouts. + ** If resetting or no free ccb, + ** insert cmd into the waiting list. + ** + **---------------------------------------------------- + */ + if (np->settle_time && cmd->timeout_per_command >= HZ) { + u_long tlimit = ktime_get(cmd->timeout_per_command - HZ); + if (ktime_dif(np->settle_time, tlimit) > 0) + np->settle_time = tlimit; + } + + if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->device->id, cmd->device->lun))) { + insert_into_waiting_list(np, cmd); + return(DID_OK); + } + cp->cmd = cmd; + + /*--------------------------------------------------- + ** + ** Enable tagged queue if asked by scsi ioctl + ** + **---------------------------------------------------- + */ +#if 0 /* This stuff was only useful for linux-1.2.13 */ + if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) { + lp->numtags = tp->usrtags; + ncr_setup_tags (np, cp->target, cp->lun); + } +#endif + + /*---------------------------------------------------- + ** + ** Build the identify / tag / sdtr message + ** + **---------------------------------------------------- + */ + + idmsg = M_IDENTIFY | cp->lun; + + if (cp ->tag != NO_TAG || (lp && !(tp->usrflag & UF_NODISC))) + idmsg |= 0x40; + + msgptr = cp->scsi_smsg; + msglen = 0; + msgptr[msglen++] = idmsg; + + if (cp->tag != NO_TAG) { + char order = np->order; + + /* + ** Force ordered tag if necessary to avoid timeouts + ** and to preserve interactivity. + */ + if (lp && ktime_exp(lp->tags_stime)) { + lp->tags_si = !(lp->tags_si); + if (lp->tags_sum[lp->tags_si]) { + order = M_ORDERED_TAG; + if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>0){ + PRINT_ADDR(cmd); + printk("ordered tag forced.\n"); + } + } + lp->tags_stime = ktime_get(3*HZ); + } + + if (order == 0) { + /* + ** Ordered write ops, unordered read ops. + */ + switch (cmd->cmnd[0]) { + case 0x08: /* READ_SMALL (6) */ + case 0x28: /* READ_BIG (10) */ + case 0xa8: /* READ_HUGE (12) */ + order = M_SIMPLE_TAG; + break; + default: + order = M_ORDERED_TAG; + } + } + msgptr[msglen++] = order; + /* + ** For less than 128 tags, actual tags are numbered + ** 1,3,5,..2*MAXTAGS+1,since we may have to deal + ** with devices that have problems with #TAG 0 or too + ** great #TAG numbers. For more tags (up to 256), + ** we use directly our tag number. + */ +#if MAX_TASKS > (512/4) + msgptr[msglen++] = cp->tag; +#else + msgptr[msglen++] = (cp->tag << 1) + 1; +#endif + } + + cp->host_flags = 0; + + /*---------------------------------------------------- + ** + ** Build the data descriptors + ** + **---------------------------------------------------- + */ + + direction = scsi_data_direction(cmd); + if (direction != SCSI_DATA_NONE) { + cp->segments = np->scatter (np, cp, cp->cmd); + if (cp->segments < 0) { + ncr_free_ccb(np, cp); + return(DID_ERROR); + } + } + else { + cp->data_len = 0; + cp->segments = 0; + } + + /*--------------------------------------------------- + ** + ** negotiation required? + ** + ** (nego_status is filled by ncr_prepare_nego()) + ** + **--------------------------------------------------- + */ + + cp->nego_status = 0; + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if ((np->check_integrity && tp->ic_done) || !np->check_integrity) { + if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) { + msglen += ncr_prepare_nego (np, cp, msgptr + msglen); + } + } + else if (np->check_integrity && (cmd->ic_in_progress)) { + msglen += ncr_ic_nego (np, cp, cmd, msgptr + msglen); + } + else if (np->check_integrity && cmd->ic_complete) { + u_long current_period; + u_char current_offset, current_width, current_factor; + + ncr_get_xfer_info (np, tp, ¤t_factor, + ¤t_offset, ¤t_width); + + tp->ic_max_width = current_width; + tp->ic_min_sync = current_factor; + + if (current_factor == 9) current_period = 125; + else if (current_factor == 10) current_period = 250; + else if (current_factor == 11) current_period = 303; + else if (current_factor == 12) current_period = 500; + else current_period = current_factor * 40; + + /* + * Negotiation for this target is complete. Update flags. + */ + tp->period = current_period; + tp->widedone = 1; + tp->ic_done = 1; + + printk("%s: Integrity Check Complete: \n", ncr_name(np)); + + printk("%s: %s %s SCSI", ncr_name(np), + current_offset?"SYNC":"ASYNC", + tp->ic_max_width?"WIDE":"NARROW"); + if (current_offset) { + u_long mbs = 10000 * (tp->ic_max_width + 1); + + printk(" %d.%d MB/s", + (int) (mbs / current_period), (int) (mbs % current_period)); + + printk(" (%d ns, %d offset)\n", + (int) current_period/10, current_offset); + } + else + printk(" %d MB/s. \n ", (tp->ic_max_width+1)*5); + } +#else + if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) { + msglen += ncr_prepare_nego (np, cp, msgptr + msglen); + } +#endif /* SCSI_NCR_INTEGRITY_CHECKING */ + + + /*---------------------------------------------------- + ** + ** Determine xfer direction. + ** + **---------------------------------------------------- + */ + if (!cp->data_len) + direction = SCSI_DATA_NONE; + + /* + ** If data direction is UNKNOWN, speculate DATA_READ + ** but prepare alternate pointers for WRITE in case + ** of our speculation will be just wrong. + ** SCRIPTS will swap values if needed. + */ + switch(direction) { + case SCSI_DATA_UNKNOWN: + case SCSI_DATA_WRITE: + goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8; + lastp = goalp - 8 - (cp->segments * (SCR_SG_SIZE*4)); + if (direction != SCSI_DATA_UNKNOWN) + break; + cp->phys.header.wgoalp = cpu_to_scr(goalp); + cp->phys.header.wlastp = cpu_to_scr(lastp); + /* fall through */ + case SCSI_DATA_READ: + cp->host_flags |= HF_DATA_IN; + goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8; + lastp = goalp - 8 - (cp->segments * (SCR_SG_SIZE*4)); + break; + default: + case SCSI_DATA_NONE: + lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data); + break; + } + + /* + ** Set all pointers values needed by SCRIPTS. + ** If direction is unknown, start at data_io. + */ + cp->phys.header.lastp = cpu_to_scr(lastp); + cp->phys.header.goalp = cpu_to_scr(goalp); + + if (direction == SCSI_DATA_UNKNOWN) + cp->phys.header.savep = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io)); + else + cp->phys.header.savep= cpu_to_scr(lastp); + + /* + ** Save the initial data pointer in order to be able + ** to redo the command. + ** We also have to save the initial lastp, since it + ** will be changed to DATA_IO if we don't know the data + ** direction and the device completes the command with + ** QUEUE FULL status (without entering the data phase). + */ + cp->startp = cp->phys.header.savep; + cp->lastp0 = cp->phys.header.lastp; + + /*---------------------------------------------------- + ** + ** fill in ccb + ** + **---------------------------------------------------- + ** + ** + ** physical -> virtual backlink + ** Generic SCSI command + */ + + /* + ** Startqueue + */ + cp->phys.header.go.start = cpu_to_scr(NCB_SCRIPT_PHYS (np,select)); + cp->phys.header.go.restart = cpu_to_scr(NCB_SCRIPT_PHYS (np,resel_dsa)); + /* + ** select + */ + cp->phys.select.sel_id = cp->target; + cp->phys.select.sel_scntl3 = tp->wval; + cp->phys.select.sel_sxfer = tp->sval; + cp->phys.select.sel_scntl4 = tp->uval; + /* + ** message + */ + cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg)); + cp->phys.smsg.size = cpu_to_scr(msglen); + + /* + ** command + */ + memcpy(cp->cdb_buf, cmd->cmnd, MIN(cmd->cmd_len, sizeof(cp->cdb_buf))); + cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, cdb_buf[0])); + cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len); + + /* + ** status + */ + cp->actualquirks = tp->quirks; + cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; + cp->scsi_status = S_ILLEGAL; + cp->xerr_status = 0; + cp->extra_bytes = 0; + + /* + ** extreme data pointer. + ** shall be positive, so -1 is lower than lowest.:) + */ + cp->ext_sg = -1; + cp->ext_ofs = 0; + + /*---------------------------------------------------- + ** + ** Critical region: start this job. + ** + **---------------------------------------------------- + */ + + /* + ** activate this job. + */ + + /* + ** insert next CCBs into start queue. + ** 2 max at a time is enough to flush the CCB wait queue. + */ + if (lp) + ncr_start_next_ccb(np, lp, 2); + else + ncr_put_start_queue(np, cp); + + /* + ** Command is successfully queued. + */ + + return(DID_OK); +} + + +/*========================================================== +** +** +** Insert a CCB into the start queue and wake up the +** SCRIPTS processor. +** +** +**========================================================== +*/ + +static void ncr_start_next_ccb(ncb_p np, lcb_p lp, int maxn) +{ + XPT_QUEHEAD *qp; + ccb_p cp; + + while (maxn-- && lp->queuedccbs < lp->queuedepth) { + qp = xpt_remque_head(&lp->wait_ccbq); + if (!qp) + break; + ++lp->queuedccbs; + cp = xpt_que_entry(qp, struct ccb, link_ccbq); + xpt_insque_tail(qp, &lp->busy_ccbq); + lp->tasktbl[cp->tag == NO_TAG ? 0 : cp->tag] = + cpu_to_scr(cp->p_ccb); + ncr_put_start_queue(np, cp); + } +} + +static void ncr_put_start_queue(ncb_p np, ccb_p cp) +{ + u_short qidx; + +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** If the previously queued CCB is not yet done, + ** set the IARB hint. The SCRIPTS will go with IARB + ** for this job when starting the previous one. + ** We leave devices a chance to win arbitration by + ** not using more than 'iarb_max' consecutive + ** immediate arbitrations. + */ + if (np->last_cp && np->iarb_count < np->iarb_max) { + np->last_cp->host_flags |= HF_HINT_IARB; + ++np->iarb_count; + } + else + np->iarb_count = 0; + np->last_cp = cp; +#endif + + /* + ** insert into start queue. + */ + qidx = np->squeueput + 2; + if (qidx >= MAX_START*2) qidx = 0; + + np->squeue [qidx] = cpu_to_scr(np->p_idletask); + MEMORY_BARRIER(); + np->squeue [np->squeueput] = cpu_to_scr(cp->p_ccb); + + np->squeueput = qidx; + cp->queued = 1; + + if (DEBUG_FLAGS & DEBUG_QUEUE) + printk ("%s: queuepos=%d.\n", ncr_name (np), np->squeueput); + + /* + ** Script processor may be waiting for reselect. + ** Wake it up. + */ + MEMORY_BARRIER(); + OUTB (nc_istat, SIGP|np->istat_sem); +} + + +/*========================================================== +** +** Soft reset the chip. +** +** Some 896 and 876 chip revisions may hang-up if we set +** the SRST (soft reset) bit at the wrong time when SCRIPTS +** are running. +** So, we need to abort the current operation prior to +** soft resetting the chip. +** +**========================================================== +*/ + +static void ncr_chip_reset (ncb_p np) +{ + OUTB (nc_istat, SRST); + UDELAY (10); + OUTB (nc_istat, 0); +} + +static void ncr_soft_reset(ncb_p np) +{ + u_char istat; + int i; + + if (!(np->features & FE_ISTAT1) || !(INB (nc_istat1) & SRUN)) + goto do_chip_reset; + + OUTB (nc_istat, CABRT); + for (i = 100000 ; i ; --i) { + istat = INB (nc_istat); + if (istat & SIP) { + INW (nc_sist); + } + else if (istat & DIP) { + if (INB (nc_dstat) & ABRT) + break; + } + UDELAY(5); + } + OUTB (nc_istat, 0); + if (!i) + printk("%s: unable to abort current chip operation, " + "ISTAT=0x%02x.\n", ncr_name(np), istat); +do_chip_reset: + ncr_chip_reset(np); +} + +/*========================================================== +** +** +** Start reset process. +** The interrupt handler will reinitialize the chip. +** The timeout handler will wait for settle_time before +** clearing it and so resuming command processing. +** +** +**========================================================== +*/ +static void ncr_start_reset(ncb_p np) +{ + (void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay); +} + +static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay) +{ + u_int32 term; + int retv = 0; + + np->settle_time = ktime_get(settle_delay * HZ); + + if (bootverbose > 1) + printk("%s: resetting, " + "command processing suspended for %d seconds\n", + ncr_name(np), settle_delay); + + ncr_soft_reset(np); /* Soft reset the chip */ + UDELAY (2000); /* The 895/6 need time for the bus mode to settle */ + if (enab_int) + OUTW (nc_sien, RST); + /* + ** Enable Tolerant, reset IRQD if present and + ** properly set IRQ mode, prior to resetting the bus. + */ + OUTB (nc_stest3, TE); + OUTB (nc_dcntl, (np->rv_dcntl & IRQM)); + OUTB (nc_scntl1, CRST); + UDELAY (200); + + if (!driver_setup.bus_check) + goto out; + /* + ** Check for no terminators or SCSI bus shorts to ground. + ** Read SCSI data bus, data parity bits and control signals. + ** We are expecting RESET to be TRUE and other signals to be + ** FALSE. + */ + term = INB(nc_sstat0); + term = ((term & 2) << 7) + ((term & 1) << 17); /* rst sdp0 */ + term |= ((INB(nc_sstat2) & 0x01) << 26) | /* sdp1 */ + ((INW(nc_sbdl) & 0xff) << 9) | /* d7-0 */ + ((INW(nc_sbdl) & 0xff00) << 10) | /* d15-8 */ + INB(nc_sbcl); /* req ack bsy sel atn msg cd io */ + + if (!(np->features & FE_WIDE)) + term &= 0x3ffff; + + if (term != (2<<7)) { + printk("%s: suspicious SCSI data while resetting the BUS.\n", + ncr_name(np)); + printk("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = " + "0x%lx, expecting 0x%lx\n", + ncr_name(np), + (np->features & FE_WIDE) ? "dp1,d15-8," : "", + (u_long)term, (u_long)(2<<7)); + if (driver_setup.bus_check == 1) + retv = 1; + } +out: + OUTB (nc_scntl1, 0); + return retv; +} + +/*========================================================== +** +** +** Reset the SCSI BUS. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +static int ncr_reset_bus (ncb_p np, Scsi_Cmnd *cmd, int sync_reset) +{ +/* Scsi_Device *device = cmd->device; */ + ccb_p cp; + int found; + +/* + * Return immediately if reset is in progress. + */ + if (np->settle_time) { + return SCSI_RESET_PUNT; + } +/* + * Start the reset process. + * The script processor is then assumed to be stopped. + * Commands will now be queued in the waiting list until a settle + * delay of 2 seconds will be completed. + */ + ncr_start_reset(np); +/* + * First, look in the wakeup list + */ + for (found=0, cp=np->ccbc; cp; cp=cp->link_ccb) { + /* + ** look for the ccb of this command. + */ + if (cp->host_status == HS_IDLE) continue; + if (cp->cmd == cmd) { + found = 1; + break; + } + } +/* + * Then, look in the waiting list + */ + if (!found && retrieve_from_waiting_list(0, np, cmd)) + found = 1; +/* + * Wake-up all awaiting commands with DID_RESET. + */ + reset_waiting_list(np); +/* + * Wake-up all pending commands with HS_RESET -> DID_RESET. + */ + ncr_wakeup(np, HS_RESET); +/* + * If the involved command was not in a driver queue, and the + * scsi driver told us reset is synchronous, and the command is not + * currently in the waiting list, complete it with DID_RESET status, + * in order to keep it alive. + */ + if (!found && sync_reset && !retrieve_from_waiting_list(0, np, cmd)) { + SetScsiResult(cmd, DID_RESET, 0); + ncr_queue_done_cmd(np, cmd); + } + + return SCSI_RESET_SUCCESS; +} + +/*========================================================== +** +** +** Abort an SCSI command. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +static int ncr_abort_command (ncb_p np, Scsi_Cmnd *cmd) +{ +/* Scsi_Device *device = cmd->device; */ + ccb_p cp; + +/* + * First, look for the scsi command in the waiting list + */ + if (remove_from_waiting_list(np, cmd)) { + SetScsiAbortResult(cmd); + ncr_queue_done_cmd(np, cmd); + return SCSI_ABORT_SUCCESS; + } + +/* + * Then, look in the wakeup list + */ + for (cp=np->ccbc; cp; cp=cp->link_ccb) { + /* + ** look for the ccb of this command. + */ + if (cp->host_status == HS_IDLE) continue; + if (cp->cmd == cmd) + break; + } + + if (!cp) { + return SCSI_ABORT_NOT_RUNNING; + } + + /* + ** Keep track we have to abort this job. + */ + cp->to_abort = 1; + + /* + ** Tell the SCRIPTS processor to stop + ** and synchronize with us. + */ + np->istat_sem = SEM; + + /* + ** If there are no requests, the script + ** processor will sleep on SEL_WAIT_RESEL. + ** Let's wake it up, since it may have to work. + */ + OUTB (nc_istat, SIGP|SEM); + + /* + ** Tell user we are working for him. + */ + return SCSI_ABORT_PENDING; +} + +/*========================================================== +** +** Linux release module stuff. +** +** Called before unloading the module +** Detach the host. +** We have to free resources and halt the NCR chip +** +**========================================================== +*/ + +static int ncr_detach(ncb_p np) +{ + int i; + + printk("%s: detaching ...\n", ncr_name(np)); + +/* +** Stop the ncr_timeout process +** Set release_stage to 1 and wait that ncr_timeout() set it to 2. +*/ + np->release_stage = 1; + for (i = 50 ; i && np->release_stage != 2 ; i--) MDELAY (100); + if (np->release_stage != 2) + printk("%s: the timer seems to be already stopped\n", + ncr_name(np)); + else np->release_stage = 2; + +/* +** Reset NCR chip. +** We should use ncr_soft_reset(), but we donnot want to do +** so, since we may not be safe if interrupts occur. +*/ + + printk("%s: resetting chip\n", ncr_name(np)); + ncr_chip_reset(np); + +/* +** Restore bios setting for automatic clock detection. +*/ + OUTB(nc_dmode, np->sv_dmode); + OUTB(nc_dcntl, np->sv_dcntl); + OUTB(nc_ctest3, np->sv_ctest3); + OUTB(nc_ctest4, np->sv_ctest4); + OUTB(nc_ctest5, np->sv_ctest5); + OUTB(nc_gpcntl, np->sv_gpcntl); + OUTB(nc_stest2, np->sv_stest2); + + ncr_selectclock(np, np->sv_scntl3); +/* +** Free host resources +*/ + ncr_free_resources(np); + + return 1; +} + +/*========================================================== +** +** +** Complete execution of a SCSI command. +** Signal completion to the generic SCSI driver. +** +** +**========================================================== +*/ + +void ncr_complete (ncb_p np, ccb_p cp) +{ + Scsi_Cmnd *cmd; + tcb_p tp; + lcb_p lp; + + /* + ** Sanity check + */ + if (!cp || !cp->cmd) + return; + + /* + ** Print some debugging info. + */ + + if (DEBUG_FLAGS & DEBUG_TINY) + printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp, + cp->host_status,cp->scsi_status); + + /* + ** Get command, target and lun pointers. + */ + + cmd = cp->cmd; + cp->cmd = NULL; + tp = &np->target[cp->target]; + lp = ncr_lp(np, tp, cp->lun); + + /* + ** We donnot queue more than 1 ccb per target + ** with negotiation at any time. If this ccb was + ** used for negotiation, clear this info in the tcb. + */ + + if (cp == tp->nego_cp) + tp->nego_cp = 0; + +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** We just complete the last queued CCB. + ** Clear this info that is no more relevant. + */ + if (cp == np->last_cp) + np->last_cp = 0; +#endif + + /* + ** If auto-sense performed, change scsi status, + ** Otherwise, compute the residual. + */ + if (cp->host_flags & HF_AUTO_SENSE) { + cp->scsi_status = cp->sv_scsi_status; + cp->xerr_status = cp->sv_xerr_status; + } + else { + cp->resid = 0; + if (cp->xerr_status || + cp->phys.header.lastp != cp->phys.header.goalp) + cp->resid = ncr_compute_residual(np, cp); + } + + /* + ** Check for extended errors. + */ + + if (cp->xerr_status) { + if (cp->xerr_status & XE_PARITY_ERR) { + PRINT_ADDR(cmd); + printk ("unrecovered SCSI parity error.\n"); + } + if (cp->xerr_status & XE_EXTRA_DATA) { + PRINT_ADDR(cmd); + printk ("extraneous data discarded.\n"); + } + if (cp->xerr_status & XE_BAD_PHASE) { + PRINT_ADDR(cmd); + printk ("illegal scsi phase (4/5).\n"); + } + if (cp->xerr_status & XE_SODL_UNRUN) { + PRINT_ADDR(cmd); + printk ("ODD transfer in DATA OUT phase.\n"); + } + if (cp->xerr_status & XE_SWIDE_OVRUN){ + PRINT_ADDR(cmd); + printk ("ODD transfer in DATA IN phase.\n"); + } + + if (cp->host_status==HS_COMPLETE) + cp->host_status = HS_FAIL; + } + + /* + ** Print out any error for debugging purpose. + */ + if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { + if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD || + cp->resid) { + PRINT_ADDR(cmd); + printk ("ERROR: cmd=%x host_status=%x scsi_status=%x " + "data_len=%d residual=%d\n", + cmd->cmnd[0], cp->host_status, cp->scsi_status, + cp->data_len, cp->resid); + } + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,99) + /* + ** Move residual byte count to user structure. + */ + cmd->resid = cp->resid; +#endif + /* + ** Check the status. + */ + if ( (cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_GOOD || + cp->scsi_status == S_COND_MET)) { + /* + ** All went well (GOOD status). + ** CONDITION MET status is returned on + ** `Pre-Fetch' or `Search data' success. + */ + SetScsiResult(cmd, DID_OK, cp->scsi_status); + + /* + ** Allocate the lcb if not yet. + */ + if (!lp) + ncr_alloc_lcb (np, cp->target, cp->lun); + + /* + ** On standard INQUIRY response (EVPD and CmDt + ** not set), setup logical unit according to + ** announced capabilities (we need the 1rst 8 bytes). + */ + if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) && + cmd->request_bufflen - cp->resid > 7 && !cmd->use_sg) { + sync_scsi_data(np, cmd); /* SYNC the data */ + ncr_setup_lcb (np, cp->target, cp->lun, + (char *) cmd->request_buffer); + } + + /* + ** If tags was reduced due to queue full, + ** increase tags if 1000 good status received. + */ + if (lp && lp->usetags && lp->numtags < lp->maxtags) { + ++lp->num_good; + if (lp->num_good >= 1000) { + lp->num_good = 0; + ++lp->numtags; + ncr_setup_tags (np, cp->target, cp->lun); + } + } + } else if ((cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_CHECK_COND)) { + /* + ** Check condition code + */ + SetScsiResult(cmd, DID_OK, S_CHECK_COND); + + if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { + PRINT_ADDR(cmd); + ncr_printl_hex("sense data:", cmd->sense_buffer, 14); + } + } else if ((cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_CONFLICT)) { + /* + ** Reservation Conflict condition code + */ + SetScsiResult(cmd, DID_OK, S_CONFLICT); + + } else if ((cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_BUSY || + cp->scsi_status == S_QUEUE_FULL)) { + + /* + ** Target is busy. + */ + SetScsiResult(cmd, DID_OK, cp->scsi_status); + + } else if ((cp->host_status == HS_SEL_TIMEOUT) + || (cp->host_status == HS_TIMEOUT)) { + + /* + ** No response + */ + SetScsiResult(cmd, DID_TIME_OUT, cp->scsi_status); + + } else if (cp->host_status == HS_RESET) { + + /* + ** SCSI bus reset + */ + SetScsiResult(cmd, DID_RESET, cp->scsi_status); + + } else if (cp->host_status == HS_ABORTED) { + + /* + ** Transfer aborted + */ + SetScsiAbortResult(cmd); + + } else { + int did_status; + + /* + ** Other protocol messes + */ + PRINT_ADDR(cmd); + printk ("COMMAND FAILED (%x %x) @%p.\n", + cp->host_status, cp->scsi_status, cp); + + did_status = DID_ERROR; + if (cp->xerr_status & XE_PARITY_ERR) + did_status = DID_PARITY; + + SetScsiResult(cmd, did_status, cp->scsi_status); + } + + /* + ** trace output + */ + + if (tp->usrflag & UF_TRACE) { + PRINT_ADDR(cmd); + printk (" CMD:"); + ncr_print_hex(cmd->cmnd, cmd->cmd_len); + + if (cp->host_status==HS_COMPLETE) { + switch (cp->scsi_status) { + case S_GOOD: + printk (" GOOD"); + break; + case S_CHECK_COND: + printk (" SENSE:"); + ncr_print_hex(cmd->sense_buffer, 14); + break; + default: + printk (" STAT: %x\n", cp->scsi_status); + break; + } + } else printk (" HOSTERROR: %x", cp->host_status); + printk ("\n"); + } + + /* + ** Free this ccb + */ + ncr_free_ccb (np, cp); + + /* + ** requeue awaiting scsi commands for this lun. + */ + if (lp && lp->queuedccbs < lp->queuedepth && + !xpt_que_empty(&lp->wait_ccbq)) + ncr_start_next_ccb(np, lp, 2); + + /* + ** requeue awaiting scsi commands for this controller. + */ + if (np->waiting_list) + requeue_waiting_list(np); + + /* + ** signal completion to generic driver. + */ + ncr_queue_done_cmd(np, cmd); +} + +/*========================================================== +** +** +** Signal all (or one) control block done. +** +** +**========================================================== +*/ + +/* +** The NCR has completed CCBs. +** Look at the DONE QUEUE. +** +** On architectures that may reorder LOAD/STORE operations, +** a memory barrier may be needed after the reading of the +** so-called `flag' and prior to dealing with the data. +*/ +int ncr_wakeup_done (ncb_p np) +{ + ccb_p cp; + int i, n; + u_long dsa; + + n = 0; + i = np->dqueueget; + while (1) { + dsa = scr_to_cpu(np->dqueue[i]); + if (!dsa) + break; + np->dqueue[i] = 0; + if ((i = i+2) >= MAX_START*2) + i = 0; + + cp = ncr_ccb_from_dsa(np, dsa); + if (cp) { + MEMORY_BARRIER(); + ncr_complete (np, cp); + ++n; + } + else + printk (KERN_ERR "%s: bad DSA (%lx) in done queue.\n", + ncr_name(np), dsa); + } + np->dqueueget = i; + + return n; +} + +/* +** Complete all active CCBs. +*/ +void ncr_wakeup (ncb_p np, u_long code) +{ + ccb_p cp = np->ccbc; + + while (cp) { + if (cp->host_status != HS_IDLE) { + cp->host_status = code; + ncr_complete (np, cp); + } + cp = cp->link_ccb; + } +} + +/*========================================================== +** +** +** Start NCR chip. +** +** +**========================================================== +*/ + +void ncr_init (ncb_p np, int reset, char * msg, u_long code) +{ + int i; + u_long phys; + + /* + ** Reset chip if asked, otherwise just clear fifos. + */ + + if (reset) + ncr_soft_reset(np); + else { + OUTB (nc_stest3, TE|CSF); + OUTONB (nc_ctest3, CLF); + } + + /* + ** Message. + */ + + if (msg) printk (KERN_INFO "%s: restart (%s).\n", ncr_name (np), msg); + + /* + ** Clear Start Queue + */ + phys = np->p_squeue; + np->queuedepth = MAX_START - 1; /* 1 entry needed as end marker */ + for (i = 0; i < MAX_START*2; i += 2) { + np->squeue[i] = cpu_to_scr(np->p_idletask); + np->squeue[i+1] = cpu_to_scr(phys + (i+2)*4); + } + np->squeue[MAX_START*2-1] = cpu_to_scr(phys); + + + /* + ** Start at first entry. + */ + np->squeueput = 0; + np->scripth0->startpos[0] = cpu_to_scr(phys); + + /* + ** Clear Done Queue + */ + phys = vtobus(np->dqueue); + for (i = 0; i < MAX_START*2; i += 2) { + np->dqueue[i] = 0; + np->dqueue[i+1] = cpu_to_scr(phys + (i+2)*4); + } + np->dqueue[MAX_START*2-1] = cpu_to_scr(phys); + + /* + ** Start at first entry. + */ + np->scripth0->done_pos[0] = cpu_to_scr(phys); + np->dqueueget = 0; + + /* + ** Wakeup all pending jobs. + */ + ncr_wakeup (np, code); + + /* + ** Init chip. + */ + + OUTB (nc_istat, 0x00 ); /* Remove Reset, abort */ + UDELAY (2000); /* The 895 needs time for the bus mode to settle */ + + OUTB (nc_scntl0, np->rv_scntl0 | 0xc0); + /* full arb., ena parity, par->ATN */ + OUTB (nc_scntl1, 0x00); /* odd parity, and remove CRST!! */ + + ncr_selectclock(np, np->rv_scntl3); /* Select SCSI clock */ + + OUTB (nc_scid , RRE|np->myaddr); /* Adapter SCSI address */ + OUTW (nc_respid, 1ul<myaddr); /* Id to respond to */ + OUTB (nc_istat , SIGP ); /* Signal Process */ + OUTB (nc_dmode , np->rv_dmode); /* Burst length, dma mode */ + OUTB (nc_ctest5, np->rv_ctest5); /* Large fifo + large burst */ + + OUTB (nc_dcntl , NOCOM|np->rv_dcntl); /* Protect SFBR */ + OUTB (nc_ctest3, np->rv_ctest3); /* Write and invalidate */ + OUTB (nc_ctest4, np->rv_ctest4); /* Master parity checking */ + + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)){ + OUTB (nc_stest2, EXT|np->rv_stest2); + /* Extended Sreq/Sack filtering, not supported in C1010/C1010_66 */ + } + OUTB (nc_stest3, TE); /* TolerANT enable */ + OUTB (nc_stime0, 0x0c); /* HTH disabled STO 0.25 sec */ + + /* + ** DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2. + ** Disable overlapped arbitration for all dual-function + ** devices, regardless revision id. + ** We may consider it is a post-chip-design feature. ;-) + ** + ** Errata applies to all 896 and 1010 parts. + */ + if (np->device_id == PCI_DEVICE_ID_NCR_53C875) + OUTB (nc_ctest0, (1<<5)); + else if (np->device_id == PCI_DEVICE_ID_NCR_53C896 || + np->device_id == PCI_DEVICE_ID_LSI_53C1010 || + np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 ) + np->rv_ccntl0 |= DPR; + + /* + ** C1010_66MHz rev 0 part requies AIPCNTL1 bit 3 to be set. + */ + if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66) + OUTB(nc_aipcntl1, (1<<3)); + + /* + ** Write CCNTL0/CCNTL1 for chips capable of 64 bit addressing + ** and/or hardware phase mismatch, since only such chips + ** seem to support those IO registers. + */ + if (np->features & (FE_DAC | FE_NOPM)) { + OUTB (nc_ccntl0, np->rv_ccntl0); + OUTB (nc_ccntl1, np->rv_ccntl1); + } + + /* + ** If phase mismatch handled by scripts (53C895A or 53C896 + ** or 53C1010 or 53C1010_66), set PM jump addresses. + */ + + if (np->features & FE_NOPM) { + printk(KERN_INFO "%s: handling phase mismatch from SCRIPTS.\n", + ncr_name(np)); + OUTL (nc_pmjad1, NCB_SCRIPTH_PHYS (np, pm_handle)); + OUTL (nc_pmjad2, NCB_SCRIPTH_PHYS (np, pm_handle)); + } + + /* + ** Enable GPIO0 pin for writing if LED support from SCRIPTS. + ** Also set GPIO5 and clear GPIO6 if hardware LED control. + */ + + if (np->features & FE_LED0) + OUTB(nc_gpcntl, INB(nc_gpcntl) & ~0x01); + else if (np->features & FE_LEDC) + OUTB(nc_gpcntl, (INB(nc_gpcntl) & ~0x41) | 0x20); + + + /* + ** enable ints + */ + + OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR); + OUTB (nc_dien , MDPE|BF|SSI|SIR|IID); + + /* + ** For 895/895A/896/c1010 + ** Enable SBMC interrupt and save current SCSI bus mode. + */ + if ( (np->features & FE_ULTRA2) || (np->features & FE_ULTRA3) ) { + OUTONW (nc_sien, SBMC); + np->scsi_mode = INB (nc_stest4) & SMODE; + } + + /* + ** Fill in target structure. + ** Reinitialize usrsync. + ** Reinitialize usrwide. + ** Prepare sync negotiation according to actual SCSI bus mode. + */ + + for (i=0;itarget[i]; + + tp->to_reset = 0; + + tp->sval = 0; + tp->wval = np->rv_scntl3; + tp->uval = np->rv_scntl4; + + if (tp->usrsync != 255) { + if (tp->usrsync <= np->maxsync) { + if (tp->usrsync < np->minsync) { + tp->usrsync = np->minsync; + } + } + else + tp->usrsync = 255; + }; + + if (tp->usrwide > np->maxwide) + tp->usrwide = np->maxwide; + + ncr_negotiate (np, tp); + } + + /* + ** Download SCSI SCRIPTS to on-chip RAM if present, + ** and start script processor. + ** We do the download preferently from the CPU. + ** For platforms that may not support PCI memory mapping, + ** we use a simple SCRIPTS that performs MEMORY MOVEs. + */ + if (np->base2_ba) { + if (bootverbose) + printk ("%s: Downloading SCSI SCRIPTS.\n", + ncr_name(np)); +#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED + if (np->base2_ws == 8192) + phys = NCB_SCRIPTH0_PHYS (np, start_ram64); + else + phys = NCB_SCRIPTH_PHYS (np, start_ram); +#else + if (np->base2_ws == 8192) { + memcpy_to_pci(np->base2_va + 4096, + np->scripth0, sizeof(struct scripth)); + OUTL (nc_mmws, np->scr_ram_seg); + OUTL (nc_mmrs, np->scr_ram_seg); + OUTL (nc_sfs, np->scr_ram_seg); + phys = NCB_SCRIPTH_PHYS (np, start64); + } + else + phys = NCB_SCRIPT_PHYS (np, init); + memcpy_to_pci(np->base2_va, np->script0, sizeof(struct script)); +#endif /* SCSI_NCR_PCI_MEM_NOT_SUPPORTED */ + } + else + phys = NCB_SCRIPT_PHYS (np, init); + + np->istat_sem = 0; + + OUTL (nc_dsa, np->p_ncb); + OUTL_DSP (phys); +} + +/*========================================================== +** +** Prepare the negotiation values for wide and +** synchronous transfers. +** +**========================================================== +*/ + +static void ncr_negotiate (struct ncb* np, struct tcb* tp) +{ + /* + ** minsync unit is 4ns ! + */ + + u_long minsync = tp->usrsync; + + /* + ** SCSI bus mode limit + */ + + if (np->scsi_mode && np->scsi_mode == SMODE_SE) { + if (minsync < 12) minsync = 12; + } + + /* + ** our limit .. + */ + + if (minsync < np->minsync) + minsync = np->minsync; + + /* + ** divider limit + */ + + if (minsync > np->maxsync) + minsync = 255; + + tp->minsync = minsync; + tp->maxoffs = (minsync<255 ? np->maxoffs : 0); + + /* + ** period=0: has to negotiate sync transfer + */ + + tp->period=0; + + /* + ** widedone=0: has to negotiate wide transfer + */ + tp->widedone=0; +} + +/*========================================================== +** +** Get clock factor and sync divisor for a given +** synchronous factor period. +** Returns the clock factor (in sxfer) and scntl3 +** synchronous divisor field. +** +**========================================================== +*/ + +static void ncr_getsync(ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p) +{ + u_long clk = np->clock_khz; /* SCSI clock frequency in kHz */ + int div = np->clock_divn; /* Number of divisors supported */ + u_long fak; /* Sync factor in sxfer */ + u_long per; /* Period in tenths of ns */ + u_long kpc; /* (per * clk) */ + + /* + ** Compute the synchronous period in tenths of nano-seconds + ** from sfac. + ** + ** Note, if sfac == 9, DT is being used. Double the period of 125 + ** to 250. + */ + if (sfac <= 10) per = 250; + else if (sfac == 11) per = 303; + else if (sfac == 12) per = 500; + else per = 40 * sfac; + + /* + ** Look for the greatest clock divisor that allows an + ** input speed faster than the period. + */ + kpc = per * clk; + while (--div >= 0) + if (kpc >= (div_10M[div] << 2)) break; + + /* + ** Calculate the lowest clock factor that allows an output + ** speed not faster than the period. + */ + fak = (kpc - 1) / div_10M[div] + 1; + +#if 0 /* This optimization does not seem very useful */ + + per = (fak * div_10M[div]) / clk; + + /* + ** Why not to try the immediate lower divisor and to choose + ** the one that allows the fastest output speed ? + ** We don't want input speed too much greater than output speed. + */ + if (div >= 1 && fak < 8) { + u_long fak2, per2; + fak2 = (kpc - 1) / div_10M[div-1] + 1; + per2 = (fak2 * div_10M[div-1]) / clk; + if (per2 < per && fak2 <= 8) { + fak = fak2; + per = per2; + --div; + } + } +#endif + + if (fak < 4) fak = 4; /* Should never happen, too bad ... */ + + /* + ** Compute and return sync parameters for the ncr + */ + *fakp = fak - 4; + + /* + ** If sfac < 25, and 8xx parts, desire that the chip operate at + ** least at Ultra speeds. Must set bit 7 of scntl3. + ** For C1010, do not set this bit. If operating at Ultra3 speeds, + ** set the U3EN bit instead. + */ + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + *scntl3p = (div+1) << 4; + *fakp = 0; + } + else { + *scntl3p = ((div+1) << 4) + (sfac < 25 ? 0x80 : 0); + *fakp = fak - 4; + } +} + +/*========================================================== +** +** Utility routine to return the current bus width +** synchronous period and offset. +** Utilizes target sval, wval and uval +** +**========================================================== +*/ +static void ncr_get_xfer_info(ncb_p np, tcb_p tp, u_char *factor, + u_char *offset, u_char *width) +{ + + u_char idiv; + u_long period; + + *width = (tp->wval & EWS) ? 1 : 0; + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + *offset = (tp->sval & 0x3f); + else + *offset = (tp->sval & 0x1f); + + /* + * Midlayer signal to the driver that all of the scsi commands + * for the integrity check have completed. Save the negotiated + * parameters (extracted from sval, wval and uval). + * See ncr_setsync for alg. details. + */ + + idiv = (tp->wval>>4) & 0x07; + + if ( *offset && idiv ) { + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)){ + if (tp->uval & 0x80) + period = (2*div_10M[idiv-1])/np->clock_khz; + else + period = (4*div_10M[idiv-1])/np->clock_khz; + } + else + period = (((tp->sval>>5)+4)*div_10M[idiv-1])/np->clock_khz; + } + else + period = 0xffff; + + if (period <= 125) *factor = 9; + else if (period <= 250) *factor = 10; + else if (period <= 303) *factor = 11; + else if (period <= 500) *factor = 12; + else *factor = (period + 40 - 1) / 40; + +} + + +/*========================================================== +** +** Set actual values, sync status and patch all ccbs of +** a target according to new sync/wide agreement. +** +**========================================================== +*/ + +static void ncr_set_sync_wide_status (ncb_p np, u_char target) +{ + ccb_p cp = np->ccbc; + tcb_p tp = &np->target[target]; + + /* + ** set actual value and sync_status + ** + ** TEMP register contains current scripts address + ** which is data type/direction/dependent. + */ + OUTB (nc_sxfer, tp->sval); + OUTB (nc_scntl3, tp->wval); + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + OUTB (nc_scntl4, tp->uval); + + /* + ** patch ALL ccbs of this target. + */ + for (cp = np->ccbc; cp; cp = cp->link_ccb) { + if (cp->host_status == HS_IDLE) + continue; + if (cp->target != target) + continue; + cp->phys.select.sel_scntl3 = tp->wval; + cp->phys.select.sel_sxfer = tp->sval; + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + cp->phys.select.sel_scntl4 = tp->uval; + }; +} + +/*========================================================== +** +** Switch sync mode for current job and it's target +** +**========================================================== +*/ + +static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, + u_char scntl4) +{ + tcb_p tp; + u_char target = INB (nc_sdid) & 0x0f; + u_char idiv; + u_char offset; + + assert (cp); + if (!cp) return; + + assert (target == (cp->target & 0xf)); + + tp = &np->target[target]; + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + offset = sxfer & 0x3f; /* bits 5-0 */ + scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS); + scntl4 = (scntl4 & 0x80); + } + else { + offset = sxfer & 0x1f; /* bits 4-0 */ + if (!scntl3 || !offset) + scntl3 = np->rv_scntl3; + + scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS) | + (np->rv_scntl3 & 0x07); + } + + + /* + ** Deduce the value of controller sync period from scntl3. + ** period is in tenths of nano-seconds. + */ + + idiv = ((scntl3 >> 4) & 0x7); + if ( offset && idiv) { + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + /* Note: If extra data hold clocks are used, + * the formulas below must be modified. + * When scntl4 == 0, ST mode. + */ + if (scntl4 & 0x80) + tp->period = (2*div_10M[idiv-1])/np->clock_khz; + else + tp->period = (4*div_10M[idiv-1])/np->clock_khz; + } + else + tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz; + } + else + tp->period = 0xffff; + + + /* + ** Stop there if sync parameters are unchanged + */ + if (tp->sval == sxfer && tp->wval == scntl3 && tp->uval == scntl4) return; + tp->sval = sxfer; + tp->wval = scntl3; + tp->uval = scntl4; + + /* + ** Bells and whistles ;-) + ** Donnot announce negotiations due to auto-sense, + ** unless user really want us to be verbose. :) + */ + if ( bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE)) + goto next; + PRINT_TARGET(np, target); + if (offset) { + unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0); + unsigned mb10 = (f10 + tp->period/2) / tp->period; + char *scsi; + + /* + ** Disable extended Sreq/Sack filtering + */ + if ((tp->period <= 2000) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + OUTOFFB (nc_stest2, EXT); + + /* + ** Bells and whistles ;-) + */ + if (tp->period < 250) scsi = "FAST-80"; + else if (tp->period < 500) scsi = "FAST-40"; + else if (tp->period < 1000) scsi = "FAST-20"; + else if (tp->period < 2000) scsi = "FAST-10"; + else scsi = "FAST-5"; + + printk ("%s %sSCSI %d.%d MB/s (%d.%d ns, offset %d)\n", scsi, + tp->widedone > 1 ? "WIDE " : "", + mb10 / 10, mb10 % 10, tp->period / 10, tp->period % 10, + offset); + } else + printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : ""); +next: + /* + ** set actual value and sync_status + ** patch ALL ccbs of this target. + */ + ncr_set_sync_wide_status(np, target); +} + + +/*========================================================== +** +** Switch wide mode for current job and it's target +** SCSI specs say: a SCSI device that accepts a WDTR +** message shall reset the synchronous agreement to +** asynchronous mode. +** +**========================================================== +*/ + +static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack) +{ + u_short target = INB (nc_sdid) & 0x0f; + tcb_p tp; + u_char scntl3; + u_char sxfer; + + assert (cp); + if (!cp) return; + + assert (target == (cp->target & 0xf)); + + tp = &np->target[target]; + tp->widedone = wide+1; + scntl3 = (tp->wval & (~EWS)) | (wide ? EWS : 0); + + sxfer = ack ? 0 : tp->sval; + + /* + ** Stop there if sync/wide parameters are unchanged + */ + if (tp->sval == sxfer && tp->wval == scntl3) return; + tp->sval = sxfer; + tp->wval = scntl3; + + /* + ** Bells and whistles ;-) + */ + if (bootverbose >= 2) { + PRINT_TARGET(np, target); + if (scntl3 & EWS) + printk ("WIDE SCSI (16 bit) enabled.\n"); + else + printk ("WIDE SCSI disabled.\n"); + } + + /* + ** set actual value and sync_status + ** patch ALL ccbs of this target. + */ + ncr_set_sync_wide_status(np, target); +} + + +/*========================================================== +** +** Switch sync/wide mode for current job and it's target +** PPR negotiations only +** +**========================================================== +*/ + +static void ncr_setsyncwide (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, + u_char scntl4, u_char wide) +{ + tcb_p tp; + u_char target = INB (nc_sdid) & 0x0f; + u_char idiv; + u_char offset; + + assert (cp); + if (!cp) return; + + assert (target == (cp->target & 0xf)); + + tp = &np->target[target]; + tp->widedone = wide+1; + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + offset = sxfer & 0x3f; /* bits 5-0 */ + scntl3 = (scntl3 & 0xf0) | (wide ? EWS : 0); + scntl4 = (scntl4 & 0x80); + } + else { + offset = sxfer & 0x1f; /* bits 4-0 */ + if (!scntl3 || !offset) + scntl3 = np->rv_scntl3; + + scntl3 = (scntl3 & 0xf0) | (wide ? EWS : 0) | + (np->rv_scntl3 & 0x07); + } + + + /* + ** Deduce the value of controller sync period from scntl3. + ** period is in tenths of nano-seconds. + */ + + idiv = ((scntl3 >> 4) & 0x7); + if ( offset && idiv) { + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + /* Note: If extra data hold clocks are used, + * the formulas below must be modified. + * When scntl4 == 0, ST mode. + */ + if (scntl4 & 0x80) + tp->period = (2*div_10M[idiv-1])/np->clock_khz; + else + tp->period = (4*div_10M[idiv-1])/np->clock_khz; + } + else + tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz; + } + else + tp->period = 0xffff; + + + /* + ** Stop there if sync parameters are unchanged + */ + if (tp->sval == sxfer && tp->wval == scntl3 && tp->uval == scntl4) return; + tp->sval = sxfer; + tp->wval = scntl3; + tp->uval = scntl4; + + /* + ** Bells and whistles ;-) + ** Donnot announce negotiations due to auto-sense, + ** unless user really want us to be verbose. :) + */ + if ( bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE)) + goto next; + PRINT_TARGET(np, target); + if (offset) { + unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0); + unsigned mb10 = (f10 + tp->period/2) / tp->period; + char *scsi; + + /* + ** Disable extended Sreq/Sack filtering + */ + if ((tp->period <= 2000) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + OUTOFFB (nc_stest2, EXT); + + /* + ** Bells and whistles ;-) + */ + if (tp->period < 250) scsi = "FAST-80"; + else if (tp->period < 500) scsi = "FAST-40"; + else if (tp->period < 1000) scsi = "FAST-20"; + else if (tp->period < 2000) scsi = "FAST-10"; + else scsi = "FAST-5"; + + printk ("%s %sSCSI %d.%d MB/s (%d.%d ns, offset %d)\n", scsi, + tp->widedone > 1 ? "WIDE " : "", + mb10 / 10, mb10 % 10, tp->period / 10, tp->period % 10, + offset); + } else + printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : ""); +next: + /* + ** set actual value and sync_status + ** patch ALL ccbs of this target. + */ + ncr_set_sync_wide_status(np, target); +} + + + + +/*========================================================== +** +** Switch tagged mode for a target. +** +**========================================================== +*/ + +static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = ncr_lp(np, tp, ln); + u_short reqtags, maxdepth; + + /* + ** Just in case ... + */ + if ((!tp) || (!lp)) + return; + + /* + ** If SCSI device queue depth is not yet set, leave here. + */ + if (!lp->scdev_depth) + return; + + /* + ** Donnot allow more tags than the SCSI driver can queue + ** for this device. + ** Donnot allow more tags than we can handle. + */ + maxdepth = lp->scdev_depth; + if (maxdepth > lp->maxnxs) maxdepth = lp->maxnxs; + if (lp->maxtags > maxdepth) lp->maxtags = maxdepth; + if (lp->numtags > maxdepth) lp->numtags = maxdepth; + + /* + ** only devices conformant to ANSI Version >= 2 + ** only devices capable of tagged commands + ** only if enabled by user .. + */ + if ((lp->inq_byte7 & INQ7_QUEUE) && lp->numtags > 1) { + reqtags = lp->numtags; + } else { + reqtags = 1; + }; + + /* + ** Update max number of tags + */ + lp->numtags = reqtags; + if (lp->numtags > lp->maxtags) + lp->maxtags = lp->numtags; + + /* + ** If we want to switch tag mode, we must wait + ** for no CCB to be active. + */ + if (reqtags > 1 && lp->usetags) { /* Stay in tagged mode */ + if (lp->queuedepth == reqtags) /* Already announced */ + return; + lp->queuedepth = reqtags; + } + else if (reqtags <= 1 && !lp->usetags) { /* Stay in untagged mode */ + lp->queuedepth = reqtags; + return; + } + else { /* Want to switch tag mode */ + if (lp->busyccbs) /* If not yet safe, return */ + return; + lp->queuedepth = reqtags; + lp->usetags = reqtags > 1 ? 1 : 0; + } + + /* + ** Patch the lun mini-script, according to tag mode. + */ + lp->resel_task = lp->usetags? + cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_tag)) : + cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_notag)); + + /* + ** Announce change to user. + */ + if (bootverbose) { + PRINT_LUN(np, tn, ln); + if (lp->usetags) + printk("tagged command queue depth set to %d\n", reqtags); + else + printk("tagged command queueing disabled\n"); + } +} + +/*---------------------------------------------------- +** +** handle user commands +** +**---------------------------------------------------- +*/ + +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT + +static void ncr_usercmd (ncb_p np) +{ + u_char t; + tcb_p tp; + int ln; + u_long size; + + switch (np->user.cmd) { + case 0: return; + + case UC_SETDEBUG: +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT + ncr_debug = np->user.data; +#endif + break; + + case UC_SETORDER: + np->order = np->user.data; + break; + + case UC_SETVERBOSE: + np->verbose = np->user.data; + break; + + default: + /* + ** We assume that other commands apply to targets. + ** This should always be the case and avoid the below + ** 4 lines to be repeated 5 times. + */ + for (t = 0; t < MAX_TARGET; t++) { + if (!((np->user.target >> t) & 1)) + continue; + tp = &np->target[t]; + + switch (np->user.cmd) { + + case UC_SETSYNC: + tp->usrsync = np->user.data; + ncr_negotiate (np, tp); + break; + + case UC_SETWIDE: + size = np->user.data; + if (size > np->maxwide) + size=np->maxwide; + tp->usrwide = size; + ncr_negotiate (np, tp); + break; + + case UC_SETTAGS: + tp->usrtags = np->user.data; + for (ln = 0; ln < MAX_LUN; ln++) { + lcb_p lp; + lp = ncr_lp(np, tp, ln); + if (!lp) + continue; + lp->numtags = np->user.data; + lp->maxtags = lp->numtags; + ncr_setup_tags (np, t, ln); + } + break; + + case UC_RESETDEV: + tp->to_reset = 1; + np->istat_sem = SEM; + OUTB (nc_istat, SIGP|SEM); + break; + + case UC_CLEARDEV: + for (ln = 0; ln < MAX_LUN; ln++) { + lcb_p lp; + lp = ncr_lp(np, tp, ln); + if (lp) + lp->to_clear = 1; + } + np->istat_sem = SEM; + OUTB (nc_istat, SIGP|SEM); + break; + + case UC_SETFLAG: + tp->usrflag = np->user.data; + break; + } + } + break; + } + np->user.cmd=0; +} +#endif + +/*========================================================== +** +** +** ncr timeout handler. +** +** +**========================================================== +** +** Misused to keep the driver running when +** interrupts are not configured correctly. +** +**---------------------------------------------------------- +*/ + +static void ncr_timeout (ncb_p np) +{ + u_long thistime = ktime_get(0); + + /* + ** If release process in progress, let's go + ** Set the release stage from 1 to 2 to synchronize + ** with the release process. + */ + + if (np->release_stage) { + if (np->release_stage == 1) np->release_stage = 2; + return; + } + +#ifdef SCSI_NCR_PCIQ_BROKEN_INTR + np->timer.expires = ktime_get((HZ+9)/10); +#else + np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL); +#endif + add_timer(&np->timer); + + /* + ** If we are resetting the ncr, wait for settle_time before + ** clearing it. Then command processing will be resumed. + */ + if (np->settle_time) { + if (np->settle_time <= thistime) { + if (bootverbose > 1) + printk("%s: command processing resumed\n", ncr_name(np)); + np->settle_time = 0; + requeue_waiting_list(np); + } + return; + } + + /* + ** Nothing to do for now, but that may come. + */ + if (np->lasttime + 4*HZ < thistime) { + np->lasttime = thistime; + } + +#ifdef SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS + /* + ** Some way-broken PCI bridges may lead to + ** completions being lost when the clearing + ** of the INTFLY flag by the CPU occurs + ** concurrently with the chip raising this flag. + ** If this ever happen, lost completions will + ** be reaped here. + */ + ncr_wakeup_done(np); +#endif + +#ifdef SCSI_NCR_PCIQ_BROKEN_INTR + if (INB(nc_istat) & (INTF|SIP|DIP)) { + + /* + ** Process pending interrupts. + */ + if (DEBUG_FLAGS & DEBUG_TINY) printk ("{"); + ncr_exception (np); + if (DEBUG_FLAGS & DEBUG_TINY) printk ("}"); + } +#endif /* SCSI_NCR_PCIQ_BROKEN_INTR */ +} + +/*========================================================== +** +** log message for real hard errors +** +** "ncr0 targ 0?: ERROR (ds:si) (so-si-sd) (sxfer/scntl3) @ name (dsp:dbc)." +** " reg: r0 r1 r2 r3 r4 r5 r6 ..... rf." +** +** exception register: +** ds: dstat +** si: sist +** +** SCSI bus lines: +** so: control lines as driver by NCR. +** si: control lines as seen by NCR. +** sd: scsi data lines as seen by NCR. +** +** wide/fastmode: +** sxfer: (see the manual) +** scntl3: (see the manual) +** +** current script command: +** dsp: script address (relative to start of script). +** dbc: first word of script command. +** +** First 24 register of the chip: +** r0..rf +** +**========================================================== +*/ + +static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat) +{ + u_int32 dsp; + int script_ofs; + int script_size; + char *script_name; + u_char *script_base; + int i; + + dsp = INL (nc_dsp); + + if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) { + script_ofs = dsp - np->p_script; + script_size = sizeof(struct script); + script_base = (u_char *) np->script0; + script_name = "script"; + } + else if (np->p_scripth < dsp && + dsp <= np->p_scripth + sizeof(struct scripth)) { + script_ofs = dsp - np->p_scripth; + script_size = sizeof(struct scripth); + script_base = (u_char *) np->scripth0; + script_name = "scripth"; + } else { + script_ofs = dsp; + script_size = 0; + script_base = 0; + script_name = "mem"; + } + + printk ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n", + ncr_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist, + (unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl), + (unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_name, script_ofs, + (unsigned)INL (nc_dbc)); + + if (((script_ofs & 3) == 0) && + (unsigned)script_ofs < script_size) { + printk ("%s: script cmd = %08x\n", ncr_name(np), + scr_to_cpu((int) *(ncrcmd *)(script_base + script_ofs))); + } + + printk ("%s: regdump:", ncr_name(np)); + for (i=0; i<24;i++) + printk (" %02x", (unsigned)INB_OFF(i)); + printk (".\n"); +} + +/*============================================================ +** +** ncr chip exception handler. +** +**============================================================ +** +** In normal situations, interrupt conditions occur one at +** a time. But when something bad happens on the SCSI BUS, +** the chip may raise several interrupt flags before +** stopping and interrupting the CPU. The additionnal +** interrupt flags are stacked in some extra registers +** after the SIP and/or DIP flag has been raised in the +** ISTAT. After the CPU has read the interrupt condition +** flag from SIST or DSTAT, the chip unstacks the other +** interrupt flags and sets the corresponding bits in +** SIST or DSTAT. Since the chip starts stacking once the +** SIP or DIP flag is set, there is a small window of time +** where the stacking does not occur. +** +** Typically, multiple interrupt conditions may happen in +** the following situations: +** +** - SCSI parity error + Phase mismatch (PAR|MA) +** When an parity error is detected in input phase +** and the device switches to msg-in phase inside a +** block MOV. +** - SCSI parity error + Unexpected disconnect (PAR|UDC) +** When a stupid device does not want to handle the +** recovery of an SCSI parity error. +** - Some combinations of STO, PAR, UDC, ... +** When using non compliant SCSI stuff, when user is +** doing non compliant hot tampering on the BUS, when +** something really bad happens to a device, etc ... +** +** The heuristic suggested by SYMBIOS to handle +** multiple interrupts is to try unstacking all +** interrupts conditions and to handle them on some +** priority based on error severity. +** This will work when the unstacking has been +** successful, but we cannot be 100 % sure of that, +** since the CPU may have been faster to unstack than +** the chip is able to stack. Hmmm ... But it seems that +** such a situation is very unlikely to happen. +** +** If this happen, for example STO catched by the CPU +** then UDC happenning before the CPU have restarted +** the SCRIPTS, the driver may wrongly complete the +** same command on UDC, since the SCRIPTS didn't restart +** and the DSA still points to the same command. +** We avoid this situation by setting the DSA to an +** invalid value when the CCB is completed and before +** restarting the SCRIPTS. +** +** Another issue is that we need some section of our +** recovery procedures to be somehow uninterruptible and +** that the SCRIPTS processor does not provides such a +** feature. For this reason, we handle recovery preferently +** from the C code and check against some SCRIPTS +** critical sections from the C code. +** +** Hopefully, the interrupt handling of the driver is now +** able to resist to weird BUS error conditions, but donnot +** ask me for any guarantee that it will never fail. :-) +** Use at your own decision and risk. +** +**============================================================ +*/ + +void ncr_exception (ncb_p np) +{ + u_char istat, istatc; + u_char dstat; + u_short sist; + int i; + + /* + ** interrupt on the fly ? + ** + ** A `dummy read' is needed to ensure that the + ** clear of the INTF flag reaches the device + ** before the scanning of the DONE queue. + */ + istat = INB (nc_istat); + if (istat & INTF) { + OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem); + istat = INB (nc_istat); /* DUMMY READ */ + if (DEBUG_FLAGS & DEBUG_TINY) printk ("F "); + (void)ncr_wakeup_done (np); + }; + + if (!(istat & (SIP|DIP))) + return; + +#if 0 /* We should never get this one */ + if (istat & CABRT) + OUTB (nc_istat, CABRT); +#endif + + /* + ** Steinbach's Guideline for Systems Programming: + ** Never test for an error condition you don't know how to handle. + */ + + /*======================================================== + ** PAR and MA interrupts may occur at the same time, + ** and we need to know of both in order to handle + ** this situation properly. We try to unstack SCSI + ** interrupts for that reason. BTW, I dislike a LOT + ** such a loop inside the interrupt routine. + ** Even if DMA interrupt stacking is very unlikely to + ** happen, we also try unstacking these ones, since + ** this has no performance impact. + **========================================================= + */ + sist = 0; + dstat = 0; + istatc = istat; + do { + if (istatc & SIP) + sist |= INW (nc_sist); + if (istatc & DIP) + dstat |= INB (nc_dstat); + istatc = INB (nc_istat); + istat |= istatc; + } while (istatc & (SIP|DIP)); + + if (DEBUG_FLAGS & DEBUG_TINY) + printk ("<%d|%x:%x|%x:%x>", + (int)INB(nc_scr0), + dstat,sist, + (unsigned)INL(nc_dsp), + (unsigned)INL(nc_dbc)); + + /* + ** On paper, a memory barrier may be needed here. + ** And since we are paranoid ... :) + */ + MEMORY_BARRIER(); + + /*======================================================== + ** First, interrupts we want to service cleanly. + ** + ** Phase mismatch (MA) is the most frequent interrupt + ** for chip earlier than the 896 and so we have to service + ** it as quickly as possible. + ** A SCSI parity error (PAR) may be combined with a phase + ** mismatch condition (MA). + ** Programmed interrupts (SIR) are used to call the C code + ** from SCRIPTS. + ** The single step interrupt (SSI) is not used in this + ** driver. + **========================================================= + */ + + if (!(sist & (STO|GEN|HTH|SGE|UDC|SBMC|RST)) && + !(dstat & (MDPE|BF|ABRT|IID))) { + if (sist & PAR) ncr_int_par (np, sist); + else if (sist & MA) ncr_int_ma (np); + else if (dstat & SIR) ncr_int_sir (np); + else if (dstat & SSI) OUTONB_STD (); + else goto unknown_int; + return; + }; + + /*======================================================== + ** Now, interrupts that donnot happen in normal + ** situations and that we may need to recover from. + ** + ** On SCSI RESET (RST), we reset everything. + ** On SCSI BUS MODE CHANGE (SBMC), we complete all + ** active CCBs with RESET status, prepare all devices + ** for negotiating again and restart the SCRIPTS. + ** On STO and UDC, we complete the CCB with the corres- + ** ponding status and restart the SCRIPTS. + **========================================================= + */ + + if (sist & RST) { + ncr_init (np, 1, bootverbose ? "scsi reset" : NULL, HS_RESET); + return; + }; + + OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ + OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ + + if (!(sist & (GEN|HTH|SGE)) && + !(dstat & (MDPE|BF|ABRT|IID))) { + if (sist & SBMC) ncr_int_sbmc (np); + else if (sist & STO) ncr_int_sto (np); + else if (sist & UDC) ncr_int_udc (np); + else goto unknown_int; + return; + }; + + /*========================================================= + ** Now, interrupts we are not able to recover cleanly. + ** + ** Do the register dump. + ** Log message for hard errors. + ** Reset everything. + **========================================================= + */ + if (ktime_exp(np->regtime)) { + np->regtime = ktime_get(10*HZ); + for (i = 0; iregdump); i++) + ((char*)&np->regdump)[i] = INB_OFF(i); + np->regdump.nc_dstat = dstat; + np->regdump.nc_sist = sist; + }; + + ncr_log_hard_error(np, sist, dstat); + + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { + u_char ctest4_o, ctest4_m; + u_char shadow; + + /* + * Get shadow register data + * Write 1 to ctest4 + */ + ctest4_o = INB(nc_ctest4); + + OUTB(nc_ctest4, ctest4_o | 0x10); + + ctest4_m = INB(nc_ctest4); + shadow = INW_OFF(0x42); + + OUTB(nc_ctest4, ctest4_o); + + printk("%s: ctest4/sist original 0x%x/0x%X mod: 0x%X/0x%x\n", + ncr_name(np), ctest4_o, sist, ctest4_m, shadow); + } + + if ((sist & (GEN|HTH|SGE)) || + (dstat & (MDPE|BF|ABRT|IID))) { + ncr_start_reset(np); + return; + }; + +unknown_int: + /*========================================================= + ** We just miss the cause of the interrupt. :( + ** Print a message. The timeout will do the real work. + **========================================================= + */ + printk( "%s: unknown interrupt(s) ignored, " + "ISTAT=0x%x DSTAT=0x%x SIST=0x%x\n", + ncr_name(np), istat, dstat, sist); +} + + +/*========================================================== +** +** generic recovery from scsi interrupt +** +**========================================================== +** +** The doc says that when the chip gets an SCSI interrupt, +** it tries to stop in an orderly fashion, by completing +** an instruction fetch that had started or by flushing +** the DMA fifo for a write to memory that was executing. +** Such a fashion is not enough to know if the instruction +** that was just before the current DSP value has been +** executed or not. +** +** There are 3 small SCRIPTS sections that deal with the +** start queue and the done queue that may break any +** assomption from the C code if we are interrupted +** inside, so we reset if it happens. Btw, since these +** SCRIPTS sections are executed while the SCRIPTS hasn't +** started SCSI operations, it is very unlikely to happen. +** +** All the driver data structures are supposed to be +** allocated from the same 4 GB memory window, so there +** is a 1 to 1 relationship between DSA and driver data +** structures. Since we are careful :) to invalidate the +** DSA when we complete a command or when the SCRIPTS +** pushes a DSA into a queue, we can trust it when it +** points to a CCB. +** +**---------------------------------------------------------- +*/ +static void ncr_recover_scsi_int (ncb_p np, u_char hsts) +{ + u_int32 dsp = INL (nc_dsp); + u_int32 dsa = INL (nc_dsa); + ccb_p cp = ncr_ccb_from_dsa(np, dsa); + + /* + ** If we haven't been interrupted inside the SCRIPTS + ** critical pathes, we can safely restart the SCRIPTS + ** and trust the DSA value if it matches a CCB. + */ + if ((!(dsp > NCB_SCRIPT_PHYS (np, getjob_begin) && + dsp < NCB_SCRIPT_PHYS (np, getjob_end) + 1)) && + (!(dsp > NCB_SCRIPT_PHYS (np, ungetjob) && + dsp < NCB_SCRIPT_PHYS (np, reselect) + 1)) && + (!(dsp > NCB_SCRIPTH_PHYS (np, sel_for_abort) && + dsp < NCB_SCRIPTH_PHYS (np, sel_for_abort_1) + 1)) && + (!(dsp > NCB_SCRIPT_PHYS (np, done) && + dsp < NCB_SCRIPT_PHYS (np, done_end) + 1))) { + if (cp) { + cp->host_status = hsts; + ncr_complete (np, cp); + } + OUTL (nc_dsa, DSA_INVALID); + OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ + OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ + OUTL_DSP (NCB_SCRIPT_PHYS (np, start)); + } + else + goto reset_all; + + return; + +reset_all: + ncr_start_reset(np); +} + +/*========================================================== +** +** ncr chip exception handler for selection timeout +** +**========================================================== +** +** There seems to be a bug in the 53c810. +** Although a STO-Interrupt is pending, +** it continues executing script commands. +** But it will fail and interrupt (IID) on +** the next instruction where it's looking +** for a valid phase. +** +**---------------------------------------------------------- +*/ + +void ncr_int_sto (ncb_p np) +{ + u_int32 dsp = INL (nc_dsp); + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("T"); + + if (dsp == NCB_SCRIPT_PHYS (np, wf_sel_done) + 8 || + !(driver_setup.recovery & 1)) + ncr_recover_scsi_int(np, HS_SEL_TIMEOUT); + else + ncr_start_reset(np); +} + +/*========================================================== +** +** ncr chip exception handler for unexpected disconnect +** +**========================================================== +** +**---------------------------------------------------------- +*/ +void ncr_int_udc (ncb_p np) +{ + u_int32 dsa = INL (nc_dsa); + ccb_p cp = ncr_ccb_from_dsa(np, dsa); + + /* + * Fix Up. Some disks respond to a PPR negotiation with + * a bus free instead of a message reject. + * Disable ppr negotiation if this is first time + * tried ppr negotiation. + */ + if (cp) { + tcb_p tp = &np->target[cp->target]; + if (tp->ppr_negotiation == 1) + tp->ppr_negotiation = 0; + } + + printk ("%s: unexpected disconnect\n", ncr_name(np)); + ncr_recover_scsi_int(np, HS_UNEXPECTED); +} + +/*========================================================== +** +** ncr chip exception handler for SCSI bus mode change +** +**========================================================== +** +** spi2-r12 11.2.3 says a transceiver mode change must +** generate a reset event and a device that detects a reset +** event shall initiate a hard reset. It says also that a +** device that detects a mode change shall set data transfer +** mode to eight bit asynchronous, etc... +** So, just resetting should be enough. +** +** +**---------------------------------------------------------- +*/ + +static void ncr_int_sbmc (ncb_p np) +{ + u_char scsi_mode = INB (nc_stest4) & SMODE; + + printk("%s: SCSI bus mode change from %x to %x.\n", + ncr_name(np), np->scsi_mode, scsi_mode); + + np->scsi_mode = scsi_mode; + + + /* + ** Suspend command processing for 1 second and + ** reinitialize all except the chip. + */ + np->settle_time = ktime_get(1*HZ); + ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET); +} + +/*========================================================== +** +** ncr chip exception handler for SCSI parity error. +** +**========================================================== +** +** When the chip detects a SCSI parity error and is +** currently executing a (CH)MOV instruction, it does +** not interrupt immediately, but tries to finish the +** transfer of the current scatter entry before +** interrupting. The following situations may occur: +** +** - The complete scatter entry has been transferred +** without the device having changed phase. +** The chip will then interrupt with the DSP pointing +** to the instruction that follows the MOV. +** +** - A phase mismatch occurs before the MOV finished +** and phase errors are to be handled by the C code. +** The chip will then interrupt with both PAR and MA +** conditions set. +** +** - A phase mismatch occurs before the MOV finished and +** phase errors are to be handled by SCRIPTS (895A or 896). +** The chip will load the DSP with the phase mismatch +** JUMP address and interrupt the host processor. +** +**---------------------------------------------------------- +*/ + +static void ncr_int_par (ncb_p np, u_short sist) +{ + u_char hsts = INB (HS_PRT); + u_int32 dsp = INL (nc_dsp); + u_int32 dbc = INL (nc_dbc); + u_int32 dsa = INL (nc_dsa); + u_char sbcl = INB (nc_sbcl); + u_char cmd = dbc >> 24; + int phase = cmd & 7; + ccb_p cp = ncr_ccb_from_dsa(np, dsa); + + printk("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n", + ncr_name(np), hsts, dbc, sbcl); + + /* + ** Check that the chip is connected to the SCSI BUS. + */ + if (!(INB (nc_scntl1) & ISCON)) { + if (!(driver_setup.recovery & 1)) { + ncr_recover_scsi_int(np, HS_FAIL); + return; + } + goto reset_all; + } + + /* + ** If the nexus is not clearly identified, reset the bus. + ** We will try to do better later. + */ + if (!cp) + goto reset_all; + + /* + ** Check instruction was a MOV, direction was INPUT and + ** ATN is asserted. + */ + if ((cmd & 0xc0) || !(phase & 1) || !(sbcl & 0x8)) + goto reset_all; + + /* + ** Keep track of the parity error. + */ + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_PARITY_ERR; + + /* + ** Prepare the message to send to the device. + */ + np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR; + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + /* + ** Save error message. For integrity check use only. + */ + if (np->check_integrity) + np->check_integ_par = np->msgout[0]; +#endif + + /* + ** If the old phase was DATA IN or DT DATA IN phase, + ** we have to deal with the 3 situations described above. + ** For other input phases (MSG IN and STATUS), the device + ** must resend the whole thing that failed parity checking + ** or signal error. So, jumping to dispatcher should be OK. + */ + if ((phase == 1) || (phase == 5)) { + /* Phase mismatch handled by SCRIPTS */ + if (dsp == NCB_SCRIPTH_PHYS (np, pm_handle)) + OUTL_DSP (dsp); + /* Phase mismatch handled by the C code */ + else if (sist & MA) + ncr_int_ma (np); + /* No phase mismatch occurred */ + else { + OUTL (nc_temp, dsp); + OUTL_DSP (NCB_SCRIPT_PHYS (np, dispatch)); + } + } + else + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); + return; + +reset_all: + ncr_start_reset(np); + return; +} + +/*========================================================== +** +** +** ncr chip exception handler for phase errors. +** +** +**========================================================== +** +** We have to construct a new transfer descriptor, +** to transfer the rest of the current block. +** +**---------------------------------------------------------- +*/ + +static void ncr_int_ma (ncb_p np) +{ + u_int32 dbc; + u_int32 rest; + u_int32 dsp; + u_int32 dsa; + u_int32 nxtdsp; + u_int32 *vdsp; + u_int32 oadr, olen; + u_int32 *tblp; + u_int32 newcmd; + u_int delta; + u_char cmd; + u_char hflags, hflags0; + struct pm_ctx *pm; + ccb_p cp; + + dsp = INL (nc_dsp); + dbc = INL (nc_dbc); + dsa = INL (nc_dsa); + + cmd = dbc >> 24; + rest = dbc & 0xffffff; + delta = 0; + + /* + ** locate matching cp. + */ + cp = ncr_ccb_from_dsa(np, dsa); + + if (DEBUG_FLAGS & DEBUG_PHASE) + printk("CCB = %2x %2x %2x %2x %2x %2x\n", + cp->cmd->cmnd[0], cp->cmd->cmnd[1], cp->cmd->cmnd[2], + cp->cmd->cmnd[3], cp->cmd->cmnd[4], cp->cmd->cmnd[5]); + + /* + ** Donnot take into account dma fifo and various buffers in + ** INPUT phase since the chip flushes everything before + ** raising the MA interrupt for interrupted INPUT phases. + ** For DATA IN phase, we will check for the SWIDE later. + */ + if ((cmd & 7) != 1 && (cmd & 7) != 5) { + u_int32 dfifo; + u_char ss0, ss2; + + /* + ** If C1010, DFBC contains number of bytes in DMA fifo. + ** else read DFIFO, CTEST[4-6] using 1 PCI bus ownership. + */ + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + delta = INL(nc_dfbc) & 0xffff; + else { + dfifo = INL(nc_dfifo); + + /* + ** Calculate remaining bytes in DMA fifo. + ** C1010 - always large fifo, value in dfbc + ** Otherwise, (CTEST5 = dfifo >> 16) + */ + if (dfifo & (DFS << 16)) + delta = ((((dfifo >> 8) & 0x300) | + (dfifo & 0xff)) - rest) & 0x3ff; + else + delta = ((dfifo & 0xff) - rest) & 0x7f; + + /* + ** The data in the dma fifo has not been + ** transferred to the target -> add the amount + ** to the rest and clear the data. + ** Check the sstat2 register in case of wide + ** transfer. + */ + + } + + rest += delta; + ss0 = INB (nc_sstat0); + if (ss0 & OLF) rest++; + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && (ss0 & ORF)) + rest++; + if (cp && (cp->phys.select.sel_scntl3 & EWS)) { + ss2 = INB (nc_sstat2); + if (ss2 & OLF1) rest++; + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && (ss2 & ORF)) + rest++; + }; + + /* + ** Clear fifos. + */ + OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* dma fifo */ + OUTB (nc_stest3, TE|CSF); /* scsi fifo */ + } + + /* + ** log the information + */ + + if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) + printk ("P%x%x RL=%d D=%d ", cmd&7, INB(nc_sbcl)&7, + (unsigned) rest, (unsigned) delta); + + /* + ** try to find the interrupted script command, + ** and the address at which to continue. + */ + vdsp = 0; + nxtdsp = 0; + if (dsp > np->p_script && + dsp <= np->p_script + sizeof(struct script)) { + vdsp = (u_int32 *)((char*)np->script0 + (dsp-np->p_script-8)); + nxtdsp = dsp; + } + else if (dsp > np->p_scripth && + dsp <= np->p_scripth + sizeof(struct scripth)) { + vdsp = (u_int32 *)((char*)np->scripth0 + (dsp-np->p_scripth-8)); + nxtdsp = dsp; + } + + /* + ** log the information + */ + if (DEBUG_FLAGS & DEBUG_PHASE) { + printk ("\nCP=%p DSP=%x NXT=%x VDSP=%p CMD=%x ", + cp, (unsigned)dsp, (unsigned)nxtdsp, vdsp, cmd); + }; + + if (!vdsp) { + printk ("%s: interrupted SCRIPT address not found.\n", + ncr_name (np)); + goto reset_all; + } + + if (!cp) { + printk ("%s: SCSI phase error fixup: CCB already dequeued.\n", + ncr_name (np)); + goto reset_all; + } + + /* + ** get old startaddress and old length. + */ + + oadr = scr_to_cpu(vdsp[1]); + + if (cmd & 0x10) { /* Table indirect */ + tblp = (u_int32 *) ((char*) &cp->phys + oadr); + olen = scr_to_cpu(tblp[0]); + oadr = scr_to_cpu(tblp[1]); + } else { + tblp = (u_int32 *) 0; + olen = scr_to_cpu(vdsp[0]) & 0xffffff; + }; + + if (DEBUG_FLAGS & DEBUG_PHASE) { + printk ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n", + (unsigned) (scr_to_cpu(vdsp[0]) >> 24), + tblp, + (unsigned) olen, + (unsigned) oadr); + }; + + /* + ** check cmd against assumed interrupted script command. + ** If dt data phase, the MOVE instruction hasn't bit 4 of + ** the phase. + */ + + if (((cmd & 2) ? cmd : (cmd & ~4)) != (scr_to_cpu(vdsp[0]) >> 24)) { + PRINT_ADDR(cp->cmd); + printk ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n", + (unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24); + + goto reset_all; + }; + + /* + ** if old phase not dataphase, leave here. + ** C/D line is low if data. + */ + + if (cmd & 0x02) { + PRINT_ADDR(cp->cmd); + printk ("phase change %x-%x %d@%08x resid=%d.\n", + cmd&7, INB(nc_sbcl)&7, (unsigned)olen, + (unsigned)oadr, (unsigned)rest); + goto unexpected_phase; + }; + + /* + ** Choose the correct PM save area. + ** + ** Look at the PM_SAVE SCRIPT if you want to understand + ** this stuff. The equivalent code is implemented in + ** SCRIPTS for the 895A and 896 that are able to handle + ** PM from the SCRIPTS processor. + */ + + hflags0 = INB (HF_PRT); + hflags = hflags0; + + if (hflags & (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED)) { + if (hflags & HF_IN_PM0) + nxtdsp = scr_to_cpu(cp->phys.pm0.ret); + else if (hflags & HF_IN_PM1) + nxtdsp = scr_to_cpu(cp->phys.pm1.ret); + + if (hflags & HF_DP_SAVED) + hflags ^= HF_ACT_PM; + } + + if (!(hflags & HF_ACT_PM)) { + pm = &cp->phys.pm0; + newcmd = NCB_SCRIPT_PHYS(np, pm0_data); + } + else { + pm = &cp->phys.pm1; + newcmd = NCB_SCRIPT_PHYS(np, pm1_data); + } + + hflags &= ~(HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED); + if (hflags != hflags0) + OUTB (HF_PRT, hflags); + + /* + ** fillin the phase mismatch context + */ + + pm->sg.addr = cpu_to_scr(oadr + olen - rest); + pm->sg.size = cpu_to_scr(rest); + pm->ret = cpu_to_scr(nxtdsp); + + /* + ** If we have a SWIDE, + ** - prepare the address to write the SWIDE from SCRIPTS, + ** - compute the SCRIPTS address to restart from, + ** - move current data pointer context by one byte. + */ + nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); + if ( ((cmd & 7) == 1 || (cmd & 7) == 5) + && cp && (cp->phys.select.sel_scntl3 & EWS) && + (INB (nc_scntl2) & WSR)) { + u32 tmp; + +#ifdef SYM_DEBUG_PM_WITH_WSR + PRINT_ADDR(cp); + printk ("MA interrupt with WSR set - " + "pm->sg.addr=%x - pm->sg.size=%d\n", + pm->sg.addr, pm->sg.size); +#endif + /* + * Set up the table indirect for the MOVE + * of the residual byte and adjust the data + * pointer context. + */ + tmp = scr_to_cpu(pm->sg.addr); + cp->phys.wresid.addr = cpu_to_scr(tmp); + pm->sg.addr = cpu_to_scr(tmp + 1); + tmp = scr_to_cpu(pm->sg.size); + cp->phys.wresid.size = cpu_to_scr((tmp&0xff000000) | 1); + pm->sg.size = cpu_to_scr(tmp - 1); + + /* + * If only the residual byte is to be moved, + * no PM context is needed. + */ + if ((tmp&0xffffff) == 1) + newcmd = pm->ret; + + /* + * Prepare the address of SCRIPTS that will + * move the residual byte to memory. + */ + nxtdsp = NCB_SCRIPTH_PHYS (np, wsr_ma_helper); + } + + if (DEBUG_FLAGS & DEBUG_PHASE) { + PRINT_ADDR(cp->cmd); + printk ("PM %x %x %x / %x %x %x.\n", + hflags0, hflags, newcmd, + (unsigned)scr_to_cpu(pm->sg.addr), + (unsigned)scr_to_cpu(pm->sg.size), + (unsigned)scr_to_cpu(pm->ret)); + } + + /* + ** Restart the SCRIPTS processor. + */ + + OUTL (nc_temp, newcmd); + OUTL_DSP (nxtdsp); + return; + + /* + ** Unexpected phase changes that occurs when the current phase + ** is not a DATA IN or DATA OUT phase are due to error conditions. + ** Such event may only happen when the SCRIPTS is using a + ** multibyte SCSI MOVE. + ** + ** Phase change Some possible cause + ** + ** COMMAND --> MSG IN SCSI parity error detected by target. + ** COMMAND --> STATUS Bad command or refused by target. + ** MSG OUT --> MSG IN Message rejected by target. + ** MSG OUT --> COMMAND Bogus target that discards extended + ** negotiation messages. + ** + ** The code below does not care of the new phase and so + ** trusts the target. Why to annoy it ? + ** If the interrupted phase is COMMAND phase, we restart at + ** dispatcher. + ** If a target does not get all the messages after selection, + ** the code assumes blindly that the target discards extended + ** messages and clears the negotiation status. + ** If the target does not want all our response to negotiation, + ** we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids + ** bloat for such a should_not_happen situation). + ** In all other situation, we reset the BUS. + ** Are these assumptions reasonnable ? (Wait and see ...) + */ +unexpected_phase: + dsp -= 8; + nxtdsp = 0; + + switch (cmd & 7) { + case 2: /* COMMAND phase */ + nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); + break; +#if 0 + case 3: /* STATUS phase */ + nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); + break; +#endif + case 6: /* MSG OUT phase */ + /* + ** If the device may want to use untagged when we want + ** tagged, we prepare an IDENTIFY without disc. granted, + ** since we will not be able to handle reselect. + ** Otherwise, we just don't care. + */ + if (dsp == NCB_SCRIPT_PHYS (np, send_ident)) { + if (cp->tag != NO_TAG && olen - rest <= 3) { + cp->host_status = HS_BUSY; + np->msgout[0] = M_IDENTIFY | cp->lun; + nxtdsp = NCB_SCRIPTH_PHYS (np, ident_break_atn); + } + else + nxtdsp = NCB_SCRIPTH_PHYS (np, ident_break); + } + else if (dsp == NCB_SCRIPTH_PHYS (np, send_wdtr) || + dsp == NCB_SCRIPTH_PHYS (np, send_sdtr) || + dsp == NCB_SCRIPTH_PHYS (np, send_ppr)) { + nxtdsp = NCB_SCRIPTH_PHYS (np, nego_bad_phase); + } + break; +#if 0 + case 7: /* MSG IN phase */ + nxtdsp = NCB_SCRIPT_PHYS (np, clrack); + break; +#endif + } + + if (nxtdsp) { + OUTL_DSP (nxtdsp); + return; + } + +reset_all: + ncr_start_reset(np); +} + +/*========================================================== +** +** ncr chip handler for QUEUE FULL and CHECK CONDITION +** +**========================================================== +** +** On QUEUE FULL status, we set the actual tagged command +** queue depth to the number of disconnected CCBs that is +** hopefully a good value to avoid further QUEUE FULL. +** +** On CHECK CONDITION or COMMAND TERMINATED, we use the +** CCB of the failed command for performing a REQUEST +** SENSE SCSI command. +** +** We do not want to change the order commands will be +** actually queued to the device after we received a +** QUEUE FULL status. We also want to properly deal with +** contingent allegiance condition. For these reasons, +** we remove from the start queue all commands for this +** LUN that haven't been yet queued to the device and +** put them back in the correponding LUN queue, then +** requeue the CCB that failed in front of the LUN queue. +** I just hope this not to be performed too often. :) +** +** If we are using IMMEDIATE ARBITRATION, we clear the +** IARB hint for every commands we encounter in order not +** to be stuck with a won arbitration and no job to queue +** to a device. +**---------------------------------------------------------- +*/ + +static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp) +{ + Scsi_Cmnd *cmd = cp->cmd; + tcb_p tp = &np->target[cp->target]; + lcb_p lp = ncr_lp(np, tp, cp->lun); + ccb_p cp2; + int busyccbs = 1; + u_int32 startp; + u_char s_status = INB (SS_PRT); + int msglen; + int i, j; + + + /* + ** If the LCB is not yet available, then only + ** 1 IO is accepted, so we should have it. + */ + if (!lp) + goto next; + /* + ** Remove all CCBs queued to the chip for that LUN and put + ** them back in the LUN CCB wait queue. + */ + busyccbs = lp->queuedccbs; + i = (INL (nc_scratcha) - np->p_squeue) / 4; + j = i; + while (i != np->squeueput) { + cp2 = ncr_ccb_from_dsa(np, scr_to_cpu(np->squeue[i])); + assert(cp2); +#ifdef SCSI_NCR_IARB_SUPPORT + /* IARB hints may not be relevant any more. Forget them. */ + cp2->host_flags &= ~HF_HINT_IARB; +#endif + if (cp2 && cp2->target == cp->target && cp2->lun == cp->lun) { + xpt_remque(&cp2->link_ccbq); + xpt_insque_head(&cp2->link_ccbq, &lp->wait_ccbq); + --lp->queuedccbs; + cp2->queued = 0; + } + else { + if (i != j) + np->squeue[j] = np->squeue[i]; + if ((j += 2) >= MAX_START*2) j = 0; + } + if ((i += 2) >= MAX_START*2) i = 0; + } + if (i != j) /* Copy back the idle task if needed */ + np->squeue[j] = np->squeue[i]; + np->squeueput = j; /* Update our current start queue pointer */ + + /* + ** Requeue the interrupted CCB in front of the + ** LUN CCB wait queue to preserve ordering. + */ + xpt_remque(&cp->link_ccbq); + xpt_insque_head(&cp->link_ccbq, &lp->wait_ccbq); + --lp->queuedccbs; + cp->queued = 0; + +next: + +#ifdef SCSI_NCR_IARB_SUPPORT + /* IARB hint may not be relevant any more. Forget it. */ + cp->host_flags &= ~HF_HINT_IARB; + if (np->last_cp) + np->last_cp = 0; +#endif + + /* + ** Now we can restart the SCRIPTS processor safely. + */ + OUTL_DSP (NCB_SCRIPT_PHYS (np, start)); + + switch(s_status) { + default: + case S_BUSY: + ncr_complete(np, cp); + break; + case S_QUEUE_FULL: + if (!lp || !lp->queuedccbs) { + ncr_complete(np, cp); + break; + } + if (bootverbose >= 1) { + PRINT_ADDR(cmd); + printk ("QUEUE FULL! %d busy, %d disconnected CCBs\n", + busyccbs, lp->queuedccbs); + } + /* + ** Decrease number of tags to the number of + ** disconnected commands. + */ + if (lp->queuedccbs < lp->numtags) { + lp->numtags = lp->queuedccbs; + lp->num_good = 0; + ncr_setup_tags (np, cp->target, cp->lun); + } + /* + ** Repair the offending CCB. + */ + cp->phys.header.savep = cp->startp; + cp->phys.header.lastp = cp->lastp0; + cp->host_status = HS_BUSY; + cp->scsi_status = S_ILLEGAL; + cp->xerr_status = 0; + cp->extra_bytes = 0; + cp->host_flags &= (HF_PM_TO_C|HF_DATA_IN); + + break; + + case S_TERMINATED: + case S_CHECK_COND: + /* + ** If we were requesting sense, give up. + */ + if (cp->host_flags & HF_AUTO_SENSE) { + ncr_complete(np, cp); + break; + } + + /* + ** Save SCSI status and extended error. + ** Compute the data residual now. + */ + cp->sv_scsi_status = cp->scsi_status; + cp->sv_xerr_status = cp->xerr_status; + cp->resid = ncr_compute_residual(np, cp); + + /* + ** Device returned CHECK CONDITION status. + ** Prepare all needed data strutures for getting + ** sense data. + */ + + /* + ** identify message + */ + cp->scsi_smsg2[0] = M_IDENTIFY | cp->lun; + msglen = 1; + + /* + ** If we are currently using anything different from + ** async. 8 bit data transfers with that target, + ** start a negotiation, since the device may want + ** to report us a UNIT ATTENTION condition due to + ** a cause we currently ignore, and we donnot want + ** to be stuck with WIDE and/or SYNC data transfer. + ** + ** cp->nego_status is filled by ncr_prepare_nego(). + ** + ** Do NOT negotiate if performing integrity check + ** or if integrity check has completed, all check + ** conditions will have been cleared. + */ + +#ifdef SCSI_NCR_INTEGRITY_CHECKING + if (DEBUG_FLAGS & DEBUG_IC) { + printk("%s: ncr_sir_to_redo: ic_done %2X, in_progress %2X\n", + ncr_name(np), tp->ic_done, cp->cmd->ic_in_progress); + } + + /* + ** If parity error during integrity check, + ** set the target width to narrow. Otherwise, + ** do not negotiate on a request sense. + */ + if ( np->check_integ_par && np->check_integrity + && cp->cmd->ic_in_progress ) { + cp->nego_status = 0; + msglen += + ncr_ic_nego (np, cp, cmd ,&cp->scsi_smsg2[msglen]); + } + + if (!np->check_integrity || + (np->check_integrity && + (!cp->cmd->ic_in_progress && !tp->ic_done)) ) { + ncr_negotiate(np, tp); + cp->nego_status = 0; + { + u_char sync_offset; + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) + sync_offset = tp->sval & 0x3f; + else + sync_offset = tp->sval & 0x1f; + + if ((tp->wval & EWS) || sync_offset) + msglen += + ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]); + } + + } +#else + ncr_negotiate(np, tp); + cp->nego_status = 0; + if ((tp->wval & EWS) || (tp->sval & 0x1f)) + msglen += + ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]); +#endif /* SCSI_NCR_INTEGRITY_CHECKING */ + + /* + ** Message table indirect structure. + */ + cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg2)); + cp->phys.smsg.size = cpu_to_scr(msglen); + + /* + ** sense command + */ + cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, sensecmd)); + cp->phys.cmd.size = cpu_to_scr(6); + + /* + ** patch requested size into sense command + */ + cp->sensecmd[0] = 0x03; + cp->sensecmd[1] = cp->lun << 5; + cp->sensecmd[4] = sizeof(cp->sense_buf); + + /* + ** sense data + */ + bzero(cp->sense_buf, sizeof(cp->sense_buf)); + cp->phys.sense.addr = cpu_to_scr(CCB_PHYS(cp,sense_buf[0])); + cp->phys.sense.size = cpu_to_scr(sizeof(cp->sense_buf)); + + /* + ** requeue the command. + */ + startp = NCB_SCRIPTH_PHYS (np, sdata_in); + + cp->phys.header.savep = cpu_to_scr(startp); + cp->phys.header.goalp = cpu_to_scr(startp + 16); + cp->phys.header.lastp = cpu_to_scr(startp); + cp->phys.header.wgoalp = cpu_to_scr(startp + 16); + cp->phys.header.wlastp = cpu_to_scr(startp); + + cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; + cp->scsi_status = S_ILLEGAL; + cp->host_flags = (HF_AUTO_SENSE|HF_DATA_IN); + + cp->phys.header.go.start = + cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); + + /* + ** If lp not yet allocated, requeue the command. + */ + if (!lp) + ncr_put_start_queue(np, cp); + break; + } + + /* + ** requeue awaiting scsi commands for this lun. + */ + if (lp) + ncr_start_next_ccb(np, lp, 1); + + return; +} + +/*---------------------------------------------------------- +** +** After a device has accepted some management message +** as BUS DEVICE RESET, ABORT TASK, etc ..., or when +** a device signals a UNIT ATTENTION condition, some +** tasks are thrown away by the device. We are required +** to reflect that on our tasks list since the device +** will never complete these tasks. +** +** This function completes all disconnected CCBs for a +** given target that matches the following criteria: +** - lun=-1 means any logical UNIT otherwise a given one. +** - task=-1 means any task, otherwise a given one. +**---------------------------------------------------------- +*/ +static int ncr_clear_tasks(ncb_p np, u_char hsts, + int target, int lun, int task) +{ + int i = 0; + ccb_p cp; + + for (cp = np->ccbc; cp; cp = cp->link_ccb) { + if (cp->host_status != HS_DISCONNECT) + continue; + if (cp->target != target) + continue; + if (lun != -1 && cp->lun != lun) + continue; + if (task != -1 && cp->tag != NO_TAG && cp->scsi_smsg[2] != task) + continue; + cp->host_status = hsts; + cp->scsi_status = S_ILLEGAL; + ncr_complete(np, cp); + ++i; + } + return i; +} + +/*========================================================== +** +** ncr chip handler for TASKS recovery. +** +**========================================================== +** +** We cannot safely abort a command, while the SCRIPTS +** processor is running, since we just would be in race +** with it. +** +** As long as we have tasks to abort, we keep the SEM +** bit set in the ISTAT. When this bit is set, the +** SCRIPTS processor interrupts (SIR_SCRIPT_STOPPED) +** each time it enters the scheduler. +** +** If we have to reset a target, clear tasks of a unit, +** or to perform the abort of a disconnected job, we +** restart the SCRIPTS for selecting the target. Once +** selected, the SCRIPTS interrupts (SIR_TARGET_SELECTED). +** If it loses arbitration, the SCRIPTS will interrupt again +** the next time it will enter its scheduler, and so on ... +** +** On SIR_TARGET_SELECTED, we scan for the more +** appropriate thing to do: +** +** - If nothing, we just sent a M_ABORT message to the +** target to get rid of the useless SCSI bus ownership. +** According to the specs, no tasks shall be affected. +** - If the target is to be reset, we send it a M_RESET +** message. +** - If a logical UNIT is to be cleared , we send the +** IDENTIFY(lun) + M_ABORT. +** - If an untagged task is to be aborted, we send the +** IDENTIFY(lun) + M_ABORT. +** - If a tagged task is to be aborted, we send the +** IDENTIFY(lun) + task attributes + M_ABORT_TAG. +** +** Once our 'kiss of death' :) message has been accepted +** by the target, the SCRIPTS interrupts again +** (SIR_ABORT_SENT). On this interrupt, we complete +** all the CCBs that should have been aborted by the +** target according to our message. +** +**---------------------------------------------------------- +*/ +static void ncr_sir_task_recovery(ncb_p np, int num) +{ + ccb_p cp; + tcb_p tp; + int target=-1, lun=-1, task; + int i, k; + u_char *p; + + switch(num) { + /* + ** The SCRIPTS processor stopped before starting + ** the next command in order to allow us to perform + ** some task recovery. + */ + case SIR_SCRIPT_STOPPED: + + /* + ** Do we have any target to reset or unit to clear ? + */ + for (i = 0 ; i < MAX_TARGET ; i++) { + tp = &np->target[i]; + if (tp->to_reset || (tp->l0p && tp->l0p->to_clear)) { + target = i; + break; + } + if (!tp->lmp) + continue; + for (k = 1 ; k < MAX_LUN ; k++) { + if (tp->lmp[k] && tp->lmp[k]->to_clear) { + target = i; + break; + } + } + if (target != -1) + break; + } + + /* + ** If not, look at the CCB list for any + ** disconnected CCB to be aborted. + */ + if (target == -1) { + for (cp = np->ccbc; cp; cp = cp->link_ccb) { + if (cp->host_status != HS_DISCONNECT) + continue; + if (cp->to_abort) { + target = cp->target; + break; + } + } + } + + /* + ** If some target is to be selected, + ** prepare and start the selection. + */ + if (target != -1) { + tp = &np->target[target]; + np->abrt_sel.sel_id = target; + np->abrt_sel.sel_scntl3 = tp->wval; + np->abrt_sel.sel_sxfer = tp->sval; + np->abrt_sel.sel_scntl4 = tp->uval; + OUTL(nc_dsa, np->p_ncb); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, sel_for_abort)); + return; + } + + /* + ** Nothing is to be selected, so we donnot need + ** to synchronize with the SCRIPTS anymore. + ** Remove the SEM flag from the ISTAT. + */ + np->istat_sem = 0; + OUTB (nc_istat, SIGP); + + /* + ** Now look at CCBs to abort that haven't started yet. + ** Remove all those CCBs from the start queue and + ** complete them with appropriate status. + ** Btw, the SCRIPTS processor is still stopped, so + ** we are not in race. + */ + for (cp = np->ccbc; cp; cp = cp->link_ccb) { + if (cp->host_status != HS_BUSY && + cp->host_status != HS_NEGOTIATE) + continue; + if (!cp->to_abort) + continue; +#ifdef SCSI_NCR_IARB_SUPPORT + /* + ** If we are using IMMEDIATE ARBITRATION, we donnot + ** want to cancel the last queued CCB, since the + ** SCRIPTS may have anticipated the selection. + */ + if (cp == np->last_cp) { + cp->to_abort = 0; + continue; + } +#endif + /* + ** Compute index of next position in the start + ** queue the SCRIPTS will schedule. + */ + i = (INL (nc_scratcha) - np->p_squeue) / 4; + + /* + ** Remove the job from the start queue. + */ + k = -1; + while (1) { + if (i == np->squeueput) + break; + if (k == -1) { /* Not found yet */ + if (cp == ncr_ccb_from_dsa(np, + scr_to_cpu(np->squeue[i]))) + k = i; /* Found */ + } + else { + /* + ** Once found, we have to move + ** back all jobs by 1 position. + */ + np->squeue[k] = np->squeue[i]; + k += 2; + if (k >= MAX_START*2) + k = 0; + } + + i += 2; + if (i >= MAX_START*2) + i = 0; + } + /* + ** If job removed, repair the start queue. + */ + if (k != -1) { + np->squeue[k] = np->squeue[i]; /* Idle task */ + np->squeueput = k; /* Start queue pointer */ + } + cp->host_status = HS_ABORTED; + cp->scsi_status = S_ILLEGAL; + ncr_complete(np, cp); + } + break; + /* + ** The SCRIPTS processor has selected a target + ** we may have some manual recovery to perform for. + */ + case SIR_TARGET_SELECTED: + target = (INB (nc_sdid) & 0xf); + tp = &np->target[target]; + + np->abrt_tbl.addr = cpu_to_scr(vtobus(np->abrt_msg)); + + /* + ** If the target is to be reset, prepare a + ** M_RESET message and clear the to_reset flag + ** since we donnot expect this operation to fail. + */ + if (tp->to_reset) { + np->abrt_msg[0] = M_RESET; + np->abrt_tbl.size = 1; + tp->to_reset = 0; + break; + } + + /* + ** Otherwise, look for some logical unit to be cleared. + */ + if (tp->l0p && tp->l0p->to_clear) + lun = 0; + else if (tp->lmp) { + for (k = 1 ; k < MAX_LUN ; k++) { + if (tp->lmp[k] && tp->lmp[k]->to_clear) { + lun = k; + break; + } + } + } + + /* + ** If a logical unit is to be cleared, prepare + ** an IDENTIFY(lun) + ABORT MESSAGE. + */ + if (lun != -1) { + lcb_p lp = ncr_lp(np, tp, lun); + lp->to_clear = 0; /* We donnot expect to fail here */ + np->abrt_msg[0] = M_IDENTIFY | lun; + np->abrt_msg[1] = M_ABORT; + np->abrt_tbl.size = 2; + break; + } + + /* + ** Otherwise, look for some disconnected job to + ** abort for this target. + */ + for (cp = np->ccbc; cp; cp = cp->link_ccb) { + if (cp->host_status != HS_DISCONNECT) + continue; + if (cp->target != target) + continue; + if (cp->to_abort) + break; + } + + /* + ** If we have none, probably since the device has + ** completed the command before we won abitration, + ** send a M_ABORT message without IDENTIFY. + ** According to the specs, the device must just + ** disconnect the BUS and not abort any task. + */ + if (!cp) { + np->abrt_msg[0] = M_ABORT; + np->abrt_tbl.size = 1; + break; + } + + /* + ** We have some task to abort. + ** Set the IDENTIFY(lun) + */ + np->abrt_msg[0] = M_IDENTIFY | cp->lun; + + /* + ** If we want to abort an untagged command, we + ** will send a IDENTIFY + M_ABORT. + ** Otherwise (tagged command), we will send + ** a IDENTITFY + task attributes + ABORT TAG. + */ + if (cp->tag == NO_TAG) { + np->abrt_msg[1] = M_ABORT; + np->abrt_tbl.size = 2; + } + else { + np->abrt_msg[1] = cp->scsi_smsg[1]; + np->abrt_msg[2] = cp->scsi_smsg[2]; + np->abrt_msg[3] = M_ABORT_TAG; + np->abrt_tbl.size = 4; + } + cp->to_abort = 0; /* We donnot expect to fail here */ + break; + + /* + ** The target has accepted our message and switched + ** to BUS FREE phase as we expected. + */ + case SIR_ABORT_SENT: + target = (INB (nc_sdid) & 0xf); + tp = &np->target[target]; + + /* + ** If we didn't abort anything, leave here. + */ + if (np->abrt_msg[0] == M_ABORT) + break; + + /* + ** If we sent a M_RESET, then a hardware reset has + ** been performed by the target. + ** - Reset everything to async 8 bit + ** - Tell ourself to negotiate next time :-) + ** - Prepare to clear all disconnected CCBs for + ** this target from our task list (lun=task=-1) + */ + lun = -1; + task = -1; + if (np->abrt_msg[0] == M_RESET) { + tp->sval = 0; + tp->wval = np->rv_scntl3; + tp->uval = np->rv_scntl4; + ncr_set_sync_wide_status(np, target); + ncr_negotiate(np, tp); + } + + /* + ** Otherwise, check for the LUN and TASK(s) + ** concerned by the cancelation. + ** If it is not ABORT_TAG then it is CLEAR_QUEUE + ** or an ABORT message :-) + */ + else { + lun = np->abrt_msg[0] & 0x3f; + if (np->abrt_msg[1] == M_ABORT_TAG) + task = np->abrt_msg[2]; + } + + /* + ** Complete all the CCBs the device should have + ** aborted due to our 'kiss of death' message. + */ + (void) ncr_clear_tasks(np, HS_ABORTED, target, lun, task); + break; + + /* + ** We have performed a auto-sense that succeeded. + ** If the device reports a UNIT ATTENTION condition + ** due to a RESET condition, we must complete all + ** disconnect CCBs for this unit since the device + ** shall have thrown them away. + ** Since I haven't time to guess what the specs are + ** expecting for other UNIT ATTENTION conditions, I + ** decided to only care about RESET conditions. :) + */ + case SIR_AUTO_SENSE_DONE: + cp = ncr_ccb_from_dsa(np, INL (nc_dsa)); + if (!cp) + break; + memcpy(cp->cmd->sense_buffer, cp->sense_buf, + sizeof(cp->cmd->sense_buffer)); + p = &cp->cmd->sense_buffer[0]; + + if (p[0] != 0x70 || p[2] != 0x6 || p[12] != 0x29) + break; +#if 0 + (void) ncr_clear_tasks(np, HS_RESET, cp->target, cp->lun, -1); +#endif + break; + } + + /* + ** Print to the log the message we intend to send. + */ + if (num == SIR_TARGET_SELECTED) { + PRINT_TARGET(np, target); + ncr_printl_hex("control msgout:", np->abrt_msg, + np->abrt_tbl.size); + np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size); + } + + /* + ** Let the SCRIPTS processor continue. + */ + OUTONB_STD (); +} + + +/*========================================================== +** +** Gérard's alchemy:) that deals with with the data +** pointer for both MDP and the residual calculation. +** +**========================================================== +** +** I didn't want to bloat the code by more than 200 +** lignes for the handling of both MDP and the residual. +** This has been achieved by using a data pointer +** representation consisting in an index in the data +** array (dp_sg) and a negative offset (dp_ofs) that +** have the following meaning: +** +** - dp_sg = MAX_SCATTER +** we are at the end of the data script. +** - dp_sg < MAX_SCATTER +** dp_sg points to the next entry of the scatter array +** we want to transfer. +** - dp_ofs < 0 +** dp_ofs represents the residual of bytes of the +** previous entry scatter entry we will send first. +** - dp_ofs = 0 +** no residual to send first. +** +** The function ncr_evaluate_dp() accepts an arbitray +** offset (basically from the MDP message) and returns +** the corresponding values of dp_sg and dp_ofs. +** +**---------------------------------------------------------- +*/ + +static int ncr_evaluate_dp(ncb_p np, ccb_p cp, u_int32 scr, int *ofs) +{ + u_int32 dp_scr; + int dp_ofs, dp_sg, dp_sgmin; + int tmp; + struct pm_ctx *pm; + + /* + ** Compute the resulted data pointer in term of a script + ** address within some DATA script and a signed byte offset. + */ + dp_scr = scr; + dp_ofs = *ofs; + if (dp_scr == NCB_SCRIPT_PHYS (np, pm0_data)) + pm = &cp->phys.pm0; + else if (dp_scr == NCB_SCRIPT_PHYS (np, pm1_data)) + pm = &cp->phys.pm1; + else + pm = 0; + + if (pm) { + dp_scr = scr_to_cpu(pm->ret); + dp_ofs -= scr_to_cpu(pm->sg.size); + } + + /* + ** Deduce the index of the sg entry. + ** Keep track of the index of the first valid entry. + ** If result is dp_sg = MAX_SCATTER, then we are at the + ** end of the data and vice-versa. + */ + tmp = scr_to_cpu(cp->phys.header.goalp); + dp_sg = MAX_SCATTER; + if (dp_scr != tmp) + dp_sg -= (tmp - 8 - (int)dp_scr) / (SCR_SG_SIZE*4); + dp_sgmin = MAX_SCATTER - cp->segments; + + /* + ** Move to the sg entry the data pointer belongs to. + ** + ** If we are inside the data area, we expect result to be: + ** + ** Either, + ** dp_ofs = 0 and dp_sg is the index of the sg entry + ** the data pointer belongs to (or the end of the data) + ** Or, + ** dp_ofs < 0 and dp_sg is the index of the sg entry + ** the data pointer belongs to + 1. + */ + if (dp_ofs < 0) { + int n; + while (dp_sg > dp_sgmin) { + --dp_sg; + tmp = scr_to_cpu(cp->phys.data[dp_sg].size); + n = dp_ofs + (tmp & 0xffffff); + if (n > 0) { + ++dp_sg; + break; + } + dp_ofs = n; + } + } + else if (dp_ofs > 0) { + while (dp_sg < MAX_SCATTER) { + tmp = scr_to_cpu(cp->phys.data[dp_sg].size); + dp_ofs -= (tmp & 0xffffff); + ++dp_sg; + if (dp_ofs <= 0) + break; + } + } + + /* + ** Make sure the data pointer is inside the data area. + ** If not, return some error. + */ + if (dp_sg < dp_sgmin || (dp_sg == dp_sgmin && dp_ofs < 0)) + goto out_err; + else if (dp_sg > MAX_SCATTER || (dp_sg == MAX_SCATTER && dp_ofs > 0)) + goto out_err; + + /* + ** Save the extreme pointer if needed. + */ + if (dp_sg > cp->ext_sg || + (dp_sg == cp->ext_sg && dp_ofs > cp->ext_ofs)) { + cp->ext_sg = dp_sg; + cp->ext_ofs = dp_ofs; + } + + /* + ** Return data. + */ + *ofs = dp_ofs; + return dp_sg; + +out_err: + return -1; +} + +/*========================================================== +** +** ncr chip handler for MODIFY DATA POINTER MESSAGE +** +**========================================================== +** +** We also call this function on IGNORE WIDE RESIDUE +** messages that do not match a SWIDE full condition. +** Btw, we assume in that situation that such a message +** is equivalent to a MODIFY DATA POINTER (offset=-1). +** +**---------------------------------------------------------- +*/ + +static void ncr_modify_dp(ncb_p np, tcb_p tp, ccb_p cp, int ofs) +{ + int dp_ofs = ofs; + u_int32 dp_scr = INL (nc_temp); + u_int32 dp_ret; + u_int32 tmp; + u_char hflags; + int dp_sg; + struct pm_ctx *pm; + + /* + ** Not supported for auto_sense; + */ + if (cp->host_flags & HF_AUTO_SENSE) + goto out_reject; + + /* + ** Apply our alchemy:) (see comments in ncr_evaluate_dp()), + ** to the resulted data pointer. + */ + dp_sg = ncr_evaluate_dp(np, cp, dp_scr, &dp_ofs); + if (dp_sg < 0) + goto out_reject; + + /* + ** And our alchemy:) allows to easily calculate the data + ** script address we want to return for the next data phase. + */ + dp_ret = cpu_to_scr(cp->phys.header.goalp); + dp_ret = dp_ret - 8 - (MAX_SCATTER - dp_sg) * (SCR_SG_SIZE*4); + + /* + ** If offset / scatter entry is zero we donnot need + ** a context for the new current data pointer. + */ + if (dp_ofs == 0) { + dp_scr = dp_ret; + goto out_ok; + } + + /* + ** Get a context for the new current data pointer. + */ + hflags = INB (HF_PRT); + + if (hflags & HF_DP_SAVED) + hflags ^= HF_ACT_PM; + + if (!(hflags & HF_ACT_PM)) { + pm = &cp->phys.pm0; + dp_scr = NCB_SCRIPT_PHYS (np, pm0_data); + } + else { + pm = &cp->phys.pm1; + dp_scr = NCB_SCRIPT_PHYS (np, pm1_data); + } + + hflags &= ~(HF_DP_SAVED); + + OUTB (HF_PRT, hflags); + + /* + ** Set up the new current data pointer. + ** ofs < 0 there, and for the next data phase, we + ** want to transfer part of the data of the sg entry + ** corresponding to index dp_sg-1 prior to returning + ** to the main data script. + */ + pm->ret = cpu_to_scr(dp_ret); + tmp = scr_to_cpu(cp->phys.data[dp_sg-1].addr); + tmp += scr_to_cpu(cp->phys.data[dp_sg-1].size) + dp_ofs; + pm->sg.addr = cpu_to_scr(tmp); + pm->sg.size = cpu_to_scr(-dp_ofs); + +out_ok: + OUTL (nc_temp, dp_scr); + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); + return; + +out_reject: + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); +} + + +/*========================================================== +** +** ncr chip calculation of the data residual. +** +**========================================================== +** +** As I used to say, the requirement of data residual +** in SCSI is broken, useless and cannot be achieved +** without huge complexity. +** But most OSes and even the official CAM require it. +** When stupidity happens to be so widely spread inside +** a community, it gets hard to convince. +** +** Anyway, I don't care, since I am not going to use +** any software that considers this data residual as +** a relevant information. :) +** +**---------------------------------------------------------- +*/ + +static int ncr_compute_residual(ncb_p np, ccb_p cp) +{ + int dp_sg, dp_sgmin, tmp; + int resid=0; + int dp_ofs = 0; + + /* + * Check for some data lost or just thrown away. + * We are not required to be quite accurate in this + * situation. Btw, if we are odd for output and the + * device claims some more data, it may well happen + * than our residual be zero. :-) + */ + if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) { + if (cp->xerr_status & XE_EXTRA_DATA) + resid -= cp->extra_bytes; + if (cp->xerr_status & XE_SODL_UNRUN) + ++resid; + if (cp->xerr_status & XE_SWIDE_OVRUN) + --resid; + } + + + /* + ** If SCRIPTS reaches its goal point, then + ** there is no additionnal residual. + */ + if (cp->phys.header.lastp == cp->phys.header.goalp) + return resid; + + /* + ** If the last data pointer is data_io (direction + ** unknown), then no data transfer should have + ** taken place. + */ + if (cp->phys.header.lastp == NCB_SCRIPTH_PHYS (np, data_io)) + return cp->data_len; + + /* + ** If no data transfer occurs, or if the data + ** pointer is weird, return full residual. + */ + if (cp->startp == cp->phys.header.lastp || + ncr_evaluate_dp(np, cp, scr_to_cpu(cp->phys.header.lastp), + &dp_ofs) < 0) { + return cp->data_len; + } + + /* + ** We are now full comfortable in the computation + ** of the data residual (2's complement). + */ + dp_sgmin = MAX_SCATTER - cp->segments; + resid = -cp->ext_ofs; + for (dp_sg = cp->ext_sg; dp_sg < MAX_SCATTER; ++dp_sg) { + tmp = scr_to_cpu(cp->phys.data[dp_sg].size); + resid += (tmp & 0xffffff); + } + + /* + ** Hopefully, the result is not too wrong. + */ + return resid; +} + +/*========================================================== +** +** Print out the containt of a SCSI message. +** +**========================================================== +*/ + +static int ncr_show_msg (u_char * msg) +{ + u_char i; + printk ("%x",*msg); + if (*msg==M_EXTENDED) { + for (i=1;i<8;i++) { + if (i-1>msg[1]) break; + printk ("-%x",msg[i]); + }; + return (i+1); + } else if ((*msg & 0xf0) == 0x20) { + printk ("-%x",msg[1]); + return (2); + }; + return (1); +} + +static void ncr_print_msg (ccb_p cp, char *label, u_char *msg) +{ + if (cp) + PRINT_ADDR(cp->cmd); + if (label) + printk ("%s: ", label); + + (void) ncr_show_msg (msg); + printk (".\n"); +} + +/*=================================================================== +** +** Negotiation for WIDE and SYNCHRONOUS DATA TRANSFER. +** +**=================================================================== +** +** Was Sie schon immer ueber transfermode negotiation wissen wollten ... +** +** We try to negotiate sync and wide transfer only after +** a successful inquire command. We look at byte 7 of the +** inquire data to determine the capabilities of the target. +** +** When we try to negotiate, we append the negotiation message +** to the identify and (maybe) simple tag message. +** The host status field is set to HS_NEGOTIATE to mark this +** situation. +** +** If the target doesn't answer this message immediately +** (as required by the standard), the SIR_NEGO_FAILED interrupt +** will be raised eventually. +** The handler removes the HS_NEGOTIATE status, and sets the +** negotiated value to the default (async / nowide). +** +** If we receive a matching answer immediately, we check it +** for validity, and set the values. +** +** If we receive a Reject message immediately, we assume the +** negotiation has failed, and fall back to standard values. +** +** If we receive a negotiation message while not in HS_NEGOTIATE +** state, it's a target initiated negotiation. We prepare a +** (hopefully) valid answer, set our parameters, and send back +** this answer to the target. +** +** If the target doesn't fetch the answer (no message out phase), +** we assume the negotiation has failed, and fall back to default +** settings (SIR_NEGO_PROTO interrupt). +** +** When we set the values, we adjust them in all ccbs belonging +** to this target, in the controller's register, and in the "phys" +** field of the controller's struct ncb. +** +**--------------------------------------------------------------------- +*/ + +/*========================================================== +** +** ncr chip handler for SYNCHRONOUS DATA TRANSFER +** REQUEST (SDTR) message. +** +**========================================================== +** +** Read comments above. +** +**---------------------------------------------------------- +*/ +static void ncr_sync_nego(ncb_p np, tcb_p tp, ccb_p cp) +{ + u_char scntl3, scntl4; + u_char chg, ofs, per, fak; + + /* + ** Synchronous request message received. + */ + + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "sync msg in", np->msgin); + }; + + /* + ** get requested values. + */ + + chg = 0; + per = np->msgin[3]; + ofs = np->msgin[4]; + if (ofs==0) per=255; + + /* + ** if target sends SDTR message, + ** it CAN transfer synch. + */ + + if (ofs) + tp->inq_byte7 |= INQ7_SYNC; + + /* + ** check values against driver limits. + */ + + if (per < np->minsync) + {chg = 1; per = np->minsync;} + if (per < tp->minsync) + {chg = 1; per = tp->minsync;} + if (ofs > np->maxoffs_st) + {chg = 1; ofs = np->maxoffs_st;} + if (ofs > tp->maxoffs) + {chg = 1; ofs = tp->maxoffs;} + + /* + ** Check against controller limits. + */ + fak = 7; + scntl3 = 0; + scntl4 = 0; + if (ofs != 0) { + ncr_getsync(np, per, &fak, &scntl3); + if (fak > 7) { + chg = 1; + ofs = 0; + } + } + if (ofs == 0) { + fak = 7; + per = 0; + scntl3 = 0; + scntl4 = 0; + tp->minsync = 0; + } + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("sync: per=%d scntl3=0x%x scntl4=0x%x ofs=%d fak=%d chg=%d.\n", + per, scntl3, scntl4, ofs, fak, chg); + } + + if (INB (HS_PRT) == HS_NEGOTIATE) { + OUTB (HS_PRT, HS_BUSY); + switch (cp->nego_status) { + case NS_SYNC: + /* + ** This was an answer message + */ + if (chg) { + /* + ** Answer wasn't acceptable. + */ + ncr_setsync (np, cp, 0, 0xe0, 0); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); + } else { + /* + ** Answer is ok. + */ + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + ncr_setsync (np, cp, scntl3, (fak<<5)|ofs,0); + else + ncr_setsync (np, cp, scntl3, ofs, scntl4); + + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); + }; + return; + + case NS_WIDE: + ncr_setwide (np, cp, 0, 0); + break; + }; + }; + + /* + ** It was a request. Set value and + ** prepare an answer message + */ + + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + ncr_setsync (np, cp, scntl3, (fak<<5)|ofs,0); + else + ncr_setsync (np, cp, scntl3, ofs, scntl4); + + np->msgout[0] = M_EXTENDED; + np->msgout[1] = 3; + np->msgout[2] = M_X_SYNC_REQ; + np->msgout[3] = per; + np->msgout[4] = ofs; + + cp->nego_status = NS_SYNC; + + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "sync msgout", np->msgout); + } + + np->msgin [0] = M_NOOP; + + if (!ofs) + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); + else + OUTL_DSP (NCB_SCRIPTH_PHYS (np, sdtr_resp)); +} + +/*========================================================== +** +** ncr chip handler for WIDE DATA TRANSFER REQUEST +** (WDTR) message. +** +**========================================================== +** +** Read comments above. +** +**---------------------------------------------------------- +*/ +static void ncr_wide_nego(ncb_p np, tcb_p tp, ccb_p cp) +{ + u_char chg, wide; + + /* + ** Wide request message received. + */ + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "wide msgin", np->msgin); + }; + + /* + ** get requested values. + */ + + chg = 0; + wide = np->msgin[3]; + + /* + ** if target sends WDTR message, + ** it CAN transfer wide. + */ + + if (wide) + tp->inq_byte7 |= INQ7_WIDE16; + + /* + ** check values against driver limits. + */ + + if (wide > tp->usrwide) + {chg = 1; wide = tp->usrwide;} + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("wide: wide=%d chg=%d.\n", wide, chg); + } + + if (INB (HS_PRT) == HS_NEGOTIATE) { + OUTB (HS_PRT, HS_BUSY); + switch (cp->nego_status) { + case NS_WIDE: + /* + ** This was an answer message + */ + if (chg) { + /* + ** Answer wasn't acceptable. + */ + ncr_setwide (np, cp, 0, 1); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); + } else { + /* + ** Answer is ok. + */ + ncr_setwide (np, cp, wide, 1); + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); + }; + return; + + case NS_SYNC: + ncr_setsync (np, cp, 0, 0xe0, 0); + break; + }; + }; + + /* + ** It was a request, set value and + ** prepare an answer message + */ + + ncr_setwide (np, cp, wide, 1); + + np->msgout[0] = M_EXTENDED; + np->msgout[1] = 2; + np->msgout[2] = M_X_WIDE_REQ; + np->msgout[3] = wide; + + np->msgin [0] = M_NOOP; + + cp->nego_status = NS_WIDE; + + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "wide msgout", np->msgout); + } + + OUTL_DSP (NCB_SCRIPTH_PHYS (np, wdtr_resp)); +} +/*========================================================== +** +** ncr chip handler for PARALLEL PROTOCOL REQUEST +** (PPR) message. +** +**========================================================== +** +** Read comments above. +** +**---------------------------------------------------------- +*/ +static void ncr_ppr_nego(ncb_p np, tcb_p tp, ccb_p cp) +{ + u_char scntl3, scntl4; + u_char chg, ofs, per, fak, wth, dt; + + /* + ** PPR message received. + */ + + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "ppr msg in", np->msgin); + }; + + /* + ** get requested values. + */ + + chg = 0; + per = np->msgin[3]; + ofs = np->msgin[5]; + wth = np->msgin[6]; + dt = np->msgin[7]; + if (ofs==0) per=255; + + /* + ** if target sends sync (wide), + ** it CAN transfer synch (wide). + */ + + if (ofs) + tp->inq_byte7 |= INQ7_SYNC; + + if (wth) + tp->inq_byte7 |= INQ7_WIDE16; + + /* + ** check values against driver limits. + */ + + if (wth > tp->usrwide) + {chg = 1; wth = tp->usrwide;} + if (per < np->minsync) + {chg = 1; per = np->minsync;} + if (per < tp->minsync) + {chg = 1; per = tp->minsync;} + if (ofs > tp->maxoffs) + {chg = 1; ofs = tp->maxoffs;} + + /* + ** Check against controller limits. + */ + fak = 7; + scntl3 = 0; + scntl4 = 0; + if (ofs != 0) { + scntl4 = dt ? 0x80 : 0; + ncr_getsync(np, per, &fak, &scntl3); + if (fak > 7) { + chg = 1; + ofs = 0; + } + } + if (ofs == 0) { + fak = 7; + per = 0; + scntl3 = 0; + scntl4 = 0; + tp->minsync = 0; + } + + /* + ** If target responds with Ultra 3 speed + ** but narrow or not DT, reject. + ** If target responds with DT request + ** but not Ultra3 speeds, reject message, + ** reset min sync for target to 0x0A and + ** set flags to re-negotiate. + */ + + if ((per == 0x09) && ofs && (!wth || !dt)) + chg = 1; + else if (( (per > 0x09) && dt) ) + chg = 2; + + /* Not acceptable since beyond controller limit */ + if (!dt && ofs > np->maxoffs_st) + {chg = 2; ofs = np->maxoffs_st;} + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printk ("ppr: wth=%d per=%d scntl3=0x%x scntl4=0x%x ofs=%d fak=%d chg=%d.\n", + wth, per, scntl3, scntl4, ofs, fak, chg); + } + + if (INB (HS_PRT) == HS_NEGOTIATE) { + OUTB (HS_PRT, HS_BUSY); + switch (cp->nego_status) { + case NS_PPR: + /* + ** This was an answer message + */ + if (chg) { + /* + ** Answer wasn't acceptable. + */ + if (chg == 2) { + /* Send message reject and reset flags for + ** host to re-negotiate with min period 0x0A. + */ + tp->minsync = 0x0A; + tp->period = 0; + tp->widedone = 0; + } + ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); + } else { + /* + ** Answer is ok. + */ + + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + ncr_setsyncwide (np, cp, scntl3, (fak<<5)|ofs,0, wth); + else + ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth); + + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); + + }; + return; + + case NS_SYNC: + ncr_setsync (np, cp, 0, 0xe0, 0); + break; + + case NS_WIDE: + ncr_setwide (np, cp, 0, 0); + break; + }; + }; + + /* + ** It was a request. Set value and + ** prepare an answer message + ** + ** If narrow or not DT and requesting Ultra3 + ** slow the bus down and force ST. If not + ** requesting Ultra3, force ST. + ** Max offset is 31=0x1f if ST mode. + */ + + if ((per == 0x09) && ofs && (!wth || !dt)) { + per = 0x0A; + dt = 0; + } + else if ( (per > 0x09) && dt) { + dt = 0; + } + if (!dt && ofs > np->maxoffs_st) + ofs = np->maxoffs_st; + + if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) + ncr_setsyncwide (np, cp, scntl3, (fak<<5)|ofs,0, wth); + else + ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth); + + np->msgout[0] = M_EXTENDED; + np->msgout[1] = 6; + np->msgout[2] = M_X_PPR_REQ; + np->msgout[3] = per; + np->msgout[4] = 0; + np->msgout[5] = ofs; + np->msgout[6] = wth; + np->msgout[7] = dt; + + cp->nego_status = NS_PPR; + + if (DEBUG_FLAGS & DEBUG_NEGO) { + ncr_print_msg(cp, "ppr msgout", np->msgout); + } + + np->msgin [0] = M_NOOP; + + if (!ofs) + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); + else + OUTL_DSP (NCB_SCRIPTH_PHYS (np, ppr_resp)); +} + + + +/* +** Reset SYNC or WIDE to default settings. +** Called when a negotiation does not succeed either +** on rejection or on protocol error. +*/ +static void ncr_nego_default(ncb_p np, tcb_p tp, ccb_p cp) +{ + /* + ** any error in negotiation: + ** fall back to default mode. + */ + switch (cp->nego_status) { + + case NS_SYNC: + ncr_setsync (np, cp, 0, 0xe0, 0); + break; + + case NS_WIDE: + ncr_setwide (np, cp, 0, 0); + break; + + case NS_PPR: + /* + * ppr_negotiation is set to 1 on the first ppr nego command. + * If ppr is successful, it is reset to 2. + * If unsuccessful it is reset to 0. + */ + if (DEBUG_FLAGS & DEBUG_NEGO) { + tcb_p tp=&np->target[cp->target]; + u_char factor, offset, width; + + ncr_get_xfer_info ( np, tp, &factor, &offset, &width); + + printk("Current factor %d offset %d width %d\n", + factor, offset, width); + } + if (tp->ppr_negotiation == 2) + ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0); + else if (tp->ppr_negotiation == 1) { + + /* First ppr command has received a M REJECT. + * Do not change the existing wide/sync parameter + * values (asyn/narrow if this as the first nego; + * may be different if target initiates nego.). + */ + tp->ppr_negotiation = 0; + } + else + { + tp->ppr_negotiation = 0; + ncr_setwide (np, cp, 0, 0); + } + break; + }; + np->msgin [0] = M_NOOP; + np->msgout[0] = M_NOOP; + cp->nego_status = 0; +} + +/*========================================================== +** +** ncr chip handler for MESSAGE REJECT received for +** a WIDE or SYNCHRONOUS negotiation. +** +** clear the PPR negotiation flag, all future nego. +** will be SDTR and WDTR +** +**========================================================== +** +** Read comments above. +** +**---------------------------------------------------------- +*/ +static void ncr_nego_rejected(ncb_p np, tcb_p tp, ccb_p cp) +{ + ncr_nego_default(np, tp, cp); + OUTB (HS_PRT, HS_BUSY); +} + + +/*========================================================== +** +** +** ncr chip exception handler for programmed interrupts. +** +** +**========================================================== +*/ + +void ncr_int_sir (ncb_p np) +{ + u_char num = INB (nc_dsps); + u_long dsa = INL (nc_dsa); + ccb_p cp = ncr_ccb_from_dsa(np, dsa); + u_char target = INB (nc_sdid) & 0x0f; + tcb_p tp = &np->target[target]; + int tmp; + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num); + + switch (num) { + /* + ** See comments in the SCRIPTS code. + */ +#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR + case SIR_DUMMY_INTERRUPT: + goto out; +#endif + + /* + ** The C code is currently trying to recover from something. + ** Typically, user want to abort some command. + */ + case SIR_SCRIPT_STOPPED: + case SIR_TARGET_SELECTED: + case SIR_ABORT_SENT: + case SIR_AUTO_SENSE_DONE: + ncr_sir_task_recovery(np, num); + return; + /* + ** The device didn't go to MSG OUT phase after having + ** been selected with ATN. We donnot want to handle + ** that. + */ + case SIR_SEL_ATN_NO_MSG_OUT: + printk ("%s:%d: No MSG OUT phase after selection with ATN.\n", + ncr_name (np), target); + goto out_stuck; + /* + ** The device didn't switch to MSG IN phase after + ** having reseleted the initiator. + */ + case SIR_RESEL_NO_MSG_IN: + /* + ** After reselection, the device sent a message that wasn't + ** an IDENTIFY. + */ + case SIR_RESEL_NO_IDENTIFY: + /* + ** If devices reselecting without sending an IDENTIFY + ** message still exist, this should help. + ** We just assume lun=0, 1 CCB, no tag. + */ + if (tp->l0p) { + OUTL (nc_dsa, scr_to_cpu(tp->l0p->tasktbl[0])); + OUTL_DSP (NCB_SCRIPT_PHYS (np, resel_go)); + return; + } + /* + ** The device reselected a LUN we donnot know of. + */ + case SIR_RESEL_BAD_LUN: + np->msgout[0] = M_RESET; + goto out; + /* + ** The device reselected for an untagged nexus and we + ** haven't any. + */ + case SIR_RESEL_BAD_I_T_L: + np->msgout[0] = M_ABORT; + goto out; + /* + ** The device reselected for a tagged nexus that we donnot + ** have. + */ + case SIR_RESEL_BAD_I_T_L_Q: + np->msgout[0] = M_ABORT_TAG; + goto out; + /* + ** The SCRIPTS let us know that the device has grabbed + ** our message and will abort the job. + */ + case SIR_RESEL_ABORTED: + np->lastmsg = np->msgout[0]; + np->msgout[0] = M_NOOP; + printk ("%s:%d: message %x sent on bad reselection.\n", + ncr_name (np), target, np->lastmsg); + goto out; + /* + ** The SCRIPTS let us know that a message has been + ** successfully sent to the device. + */ + case SIR_MSG_OUT_DONE: + np->lastmsg = np->msgout[0]; + np->msgout[0] = M_NOOP; + /* Should we really care of that */ + if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) { + if (cp) { + cp->xerr_status &= ~XE_PARITY_ERR; + if (!cp->xerr_status) + OUTOFFB (HF_PRT, HF_EXT_ERR); + } + } + goto out; + /* + ** The device didn't send a GOOD SCSI status. + ** We may have some work to do prior to allow + ** the SCRIPTS processor to continue. + */ + case SIR_BAD_STATUS: + if (!cp) + goto out; + ncr_sir_to_redo(np, num, cp); + return; + /* + ** We are asked by the SCRIPTS to prepare a + ** REJECT message. + */ + case SIR_REJECT_TO_SEND: + ncr_print_msg(cp, "M_REJECT to send for ", np->msgin); + np->msgout[0] = M_REJECT; + goto out; + /* + ** We have been ODD at the end of a DATA IN + ** transfer and the device didn't send a + ** IGNORE WIDE RESIDUE message. + ** It is a data overrun condition. + */ + case SIR_SWIDE_OVERRUN: + if (cp) { + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_SWIDE_OVRUN; + } + goto out; + /* + ** We have been ODD at the end of a DATA OUT + ** transfer. + ** It is a data underrun condition. + */ + case SIR_SODL_UNDERRUN: + if (cp) { + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_SODL_UNRUN; + } + goto out; + /* + ** The device wants us to tranfer more data than + ** expected or in the wrong direction. + ** The number of extra bytes is in scratcha. + ** It is a data overrun condition. + */ + case SIR_DATA_OVERRUN: + if (cp) { + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_EXTRA_DATA; + cp->extra_bytes += INL (nc_scratcha); + } + goto out; + /* + ** The device switched to an illegal phase (4/5). + */ + case SIR_BAD_PHASE: + if (cp) { + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_BAD_PHASE; + } + goto out; + /* + ** We received a message. + */ + case SIR_MSG_RECEIVED: + if (!cp) + goto out_stuck; + switch (np->msgin [0]) { + /* + ** We received an extended message. + ** We handle MODIFY DATA POINTER, SDTR, WDTR + ** and reject all other extended messages. + */ + case M_EXTENDED: + switch (np->msgin [2]) { + case M_X_MODIFY_DP: + if (DEBUG_FLAGS & DEBUG_POINTER) + ncr_print_msg(cp,"modify DP",np->msgin); + tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + + (np->msgin[5]<<8) + (np->msgin[6]); + ncr_modify_dp(np, tp, cp, tmp); + return; + case M_X_SYNC_REQ: + ncr_sync_nego(np, tp, cp); + return; + case M_X_WIDE_REQ: + ncr_wide_nego(np, tp, cp); + return; + case M_X_PPR_REQ: + ncr_ppr_nego(np, tp, cp); + return; + default: + goto out_reject; + } + break; + /* + ** We received a 1/2 byte message not handled from SCRIPTS. + ** We are only expecting MESSAGE REJECT and IGNORE WIDE + ** RESIDUE messages that haven't been anticipated by + ** SCRIPTS on SWIDE full condition. Unanticipated IGNORE + ** WIDE RESIDUE messages are aliased as MODIFY DP (-1). + */ + case M_IGN_RESIDUE: + if (DEBUG_FLAGS & DEBUG_POINTER) + ncr_print_msg(cp,"ign wide residue", np->msgin); + ncr_modify_dp(np, tp, cp, -1); + return; + case M_REJECT: + if (INB (HS_PRT) == HS_NEGOTIATE) + ncr_nego_rejected(np, tp, cp); + else { + PRINT_ADDR(cp->cmd); + printk ("M_REJECT received (%x:%x).\n", + scr_to_cpu(np->lastmsg), np->msgout[0]); + } + goto out_clrack; + break; + default: + goto out_reject; + } + break; + /* + ** We received an unknown message. + ** Ignore all MSG IN phases and reject it. + */ + case SIR_MSG_WEIRD: + ncr_print_msg(cp, "WEIRD message received", np->msgin); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_weird)); + return; + /* + ** Negotiation failed. + ** Target does not send us the reply. + ** Remove the HS_NEGOTIATE status. + */ + case SIR_NEGO_FAILED: + OUTB (HS_PRT, HS_BUSY); + /* + ** Negotiation failed. + ** Target does not want answer message. + */ + case SIR_NEGO_PROTO: + ncr_nego_default(np, tp, cp); + goto out; + }; + +out: + OUTONB_STD (); + return; +out_reject: + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); + return; +out_clrack: + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); + return; +out_stuck: + return; +} + + +/*========================================================== +** +** +** Acquire a control block +** +** +**========================================================== +*/ + +static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = ncr_lp(np, tp, ln); + u_short tag = NO_TAG; + XPT_QUEHEAD *qp; + ccb_p cp = (ccb_p) 0; + + /* + ** Allocate a new CCB if needed. + */ + if (xpt_que_empty(&np->free_ccbq)) + (void) ncr_alloc_ccb(np); + + /* + ** Look for a free CCB + */ + qp = xpt_remque_head(&np->free_ccbq); + if (!qp) + goto out; + cp = xpt_que_entry(qp, struct ccb, link_ccbq); + + /* + ** If the LCB is not yet available and we already + ** have queued a CCB for a LUN without LCB, + ** give up. Otherwise all is fine. :-) + */ + if (!lp) { + if (xpt_que_empty(&np->b0_ccbq)) + xpt_insque_head(&cp->link_ccbq, &np->b0_ccbq); + else + goto out_free; + } else { + /* + ** Tune tag mode if asked by user. + */ + if (lp->queuedepth != lp->numtags) { + ncr_setup_tags(np, tn, ln); + } + + /* + ** Get a tag for this nexus if required. + ** Keep from using more tags than we can handle. + */ + if (lp->usetags) { + if (lp->busyccbs < lp->maxnxs) { + tag = lp->cb_tags[lp->ia_tag]; + ++lp->ia_tag; + if (lp->ia_tag == MAX_TAGS) + lp->ia_tag = 0; + cp->tags_si = lp->tags_si; + ++lp->tags_sum[cp->tags_si]; + } + else + goto out_free; + } + + /* + ** Put the CCB in the LUN wait queue and + ** count it as busy. + */ + xpt_insque_tail(&cp->link_ccbq, &lp->wait_ccbq); + ++lp->busyccbs; + } + + /* + ** Remember all informations needed to free this CCB. + */ + cp->to_abort = 0; + cp->tag = tag; + cp->target = tn; + cp->lun = ln; + + if (DEBUG_FLAGS & DEBUG_TAGS) { + PRINT_LUN(np, tn, ln); + printk ("ccb @%p using tag %d.\n", cp, tag); + } + +out: + return cp; +out_free: + xpt_insque_head(&cp->link_ccbq, &np->free_ccbq); + return (ccb_p) 0; +} + +/*========================================================== +** +** +** Release one control block +** +** +**========================================================== +*/ + +static void ncr_free_ccb (ncb_p np, ccb_p cp) +{ + tcb_p tp = &np->target[cp->target]; + lcb_p lp = ncr_lp(np, tp, cp->lun); + + if (DEBUG_FLAGS & DEBUG_TAGS) { + PRINT_LUN(np, cp->target, cp->lun); + printk ("ccb @%p freeing tag %d.\n", cp, cp->tag); + } + + /* + ** If lun control block available, make available + ** the task slot and the tag if any. + ** Decrement counters. + */ + if (lp) { + if (cp->tag != NO_TAG) { + lp->cb_tags[lp->if_tag++] = cp->tag; + if (lp->if_tag == MAX_TAGS) + lp->if_tag = 0; + --lp->tags_sum[cp->tags_si]; + lp->tasktbl[cp->tag] = cpu_to_scr(np->p_bad_i_t_l_q); + } else { + lp->tasktbl[0] = cpu_to_scr(np->p_bad_i_t_l); + } + --lp->busyccbs; + if (cp->queued) { + --lp->queuedccbs; + } + } + + /* + ** Make this CCB available. + */ + xpt_remque(&cp->link_ccbq); + xpt_insque_head(&cp->link_ccbq, &np->free_ccbq); + cp -> host_status = HS_IDLE; + cp -> queued = 0; +} + +/*------------------------------------------------------------------------ +** Allocate a CCB and initialize its fixed part. +**------------------------------------------------------------------------ +**------------------------------------------------------------------------ +*/ +static ccb_p ncr_alloc_ccb(ncb_p np) +{ + ccb_p cp = 0; + int hcode; + + /* + ** Allocate memory for this CCB. + */ + cp = m_calloc_dma(sizeof(struct ccb), "CCB"); + if (!cp) + return 0; + + /* + ** Count it and initialyze it. + */ + np->actccbs++; + + /* + ** Remember virtual and bus address of this ccb. + */ + cp->p_ccb = vtobus(cp); + + /* + ** Insert this ccb into the hashed list. + */ + hcode = CCB_HASH_CODE(cp->p_ccb); + cp->link_ccbh = np->ccbh[hcode]; + np->ccbh[hcode] = cp; + + /* + ** Initialyze the start and restart actions. + */ + cp->phys.header.go.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + cp->phys.header.go.restart = cpu_to_scr(NCB_SCRIPTH_PHYS(np,bad_i_t_l)); + + /* + ** Initilialyze some other fields. + */ + cp->phys.smsg_ext.addr = cpu_to_scr(NCB_PHYS(np, msgin[2])); + + /* + ** Chain into wakeup list and free ccb queue. + */ + cp->link_ccb = np->ccbc; + np->ccbc = cp; + + xpt_insque_head(&cp->link_ccbq, &np->free_ccbq); + + return cp; +} + +/*------------------------------------------------------------------------ +** Look up a CCB from a DSA value. +**------------------------------------------------------------------------ +**------------------------------------------------------------------------ +*/ +static ccb_p ncr_ccb_from_dsa(ncb_p np, u_long dsa) +{ + int hcode; + ccb_p cp; + + hcode = CCB_HASH_CODE(dsa); + cp = np->ccbh[hcode]; + while (cp) { + if (cp->p_ccb == dsa) + break; + cp = cp->link_ccbh; + } + + return cp; +} + +/*========================================================== +** +** +** Allocation of resources for Targets/Luns/Tags. +** +** +**========================================================== +*/ + + +/*------------------------------------------------------------------------ +** Target control block initialisation. +**------------------------------------------------------------------------ +** This data structure is fully initialized after a SCSI command +** has been successfully completed for this target. +**------------------------------------------------------------------------ +*/ +static void ncr_init_tcb (ncb_p np, u_char tn) +{ + /* + ** Check some alignments required by the chip. + */ + assert (( (offsetof(struct ncr_reg, nc_sxfer) ^ + offsetof(struct tcb , sval )) &3) == 0); + assert (( (offsetof(struct ncr_reg, nc_scntl3) ^ + offsetof(struct tcb , wval )) &3) == 0); + if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || + (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)){ + assert (( (offsetof(struct ncr_reg, nc_scntl4) ^ + offsetof(struct tcb , uval )) &3) == 0); + } +} + +/*------------------------------------------------------------------------ +** Lun control block allocation and initialization. +**------------------------------------------------------------------------ +** This data structure is allocated and initialized after a SCSI +** command has been successfully completed for this target/lun. +**------------------------------------------------------------------------ +*/ +static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = ncr_lp(np, tp, ln); + + /* + ** Already done, return. + */ + if (lp) + return lp; + + /* + ** Initialize the target control block if not yet. + */ + ncr_init_tcb(np, tn); + + /* + ** Allocate the lcb bus address array. + ** Compute the bus address of this table. + */ + if (ln && !tp->luntbl) { + int i; + + tp->luntbl = m_calloc_dma(256, "LUNTBL"); + if (!tp->luntbl) + goto fail; + for (i = 0 ; i < 64 ; i++) + tp->luntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun)); + tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl)); + } + + /* + ** Allocate the table of pointers for LUN(s) > 0, if needed. + */ + if (ln && !tp->lmp) { + tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP"); + if (!tp->lmp) + goto fail; + } + + /* + ** Allocate the lcb. + ** Make it available to the chip. + */ + lp = m_calloc_dma(sizeof(struct lcb), "LCB"); + if (!lp) + goto fail; + if (ln) { + tp->lmp[ln] = lp; + tp->luntbl[ln] = cpu_to_scr(vtobus(lp)); + } + else { + tp->l0p = lp; + tp->b_lun0 = cpu_to_scr(vtobus(lp)); + } + + /* + ** Initialize the CCB queue headers. + */ + xpt_que_init(&lp->busy_ccbq); + xpt_que_init(&lp->wait_ccbq); + + /* + ** Set max CCBs to 1 and use the default task array + ** by default. + */ + lp->maxnxs = 1; + lp->tasktbl = &lp->tasktbl_0; + lp->b_tasktbl = cpu_to_scr(vtobus(lp->tasktbl)); + lp->tasktbl[0] = cpu_to_scr(np->p_notask); + lp->resel_task = cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_notag)); + + /* + ** Initialize command queuing control. + */ + lp->busyccbs = 1; + lp->queuedccbs = 1; + lp->queuedepth = 1; +fail: + return lp; +} + + +/*------------------------------------------------------------------------ +** Lun control block setup on INQUIRY data received. +**------------------------------------------------------------------------ +** We only support WIDE, SYNC for targets and CMDQ for logical units. +** This setup is done on each INQUIRY since we are expecting user +** will play with CHANGE DEFINITION commands. :-) +**------------------------------------------------------------------------ +*/ +static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = ncr_lp(np, tp, ln); + u_char inq_byte7; + int i; + + /* + ** If no lcb, try to allocate it. + */ + if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln))) + goto fail; + +#if 0 /* No more used. Left here as provision */ + /* + ** Get device quirks. + */ + tp->quirks = 0; + if (tp->quirks && bootverbose) { + PRINT_LUN(np, tn, ln); + printk ("quirks=%x.\n", tp->quirks); + } +#endif + + /* + ** Evaluate trustable target/unit capabilities. + ** We only believe device version >= SCSI-2 that + ** use appropriate response data format (2). + ** But it seems that some CCS devices also + ** support SYNC and I donnot want to frustrate + ** anybody. ;-) + */ + inq_byte7 = 0; + if ((inq_data[2] & 0x7) >= 2 && (inq_data[3] & 0xf) == 2) + inq_byte7 = inq_data[7]; + else if ((inq_data[2] & 0x7) == 1 && (inq_data[3] & 0xf) == 1) + inq_byte7 = INQ7_SYNC; + + /* + ** Throw away announced LUN capabilities if we are told + ** that there is no real device supported by the logical unit. + */ + if ((inq_data[0] & 0xe0) > 0x20 || (inq_data[0] & 0x1f) == 0x1f) + inq_byte7 &= (INQ7_SYNC | INQ7_WIDE16); + + /* + ** If user is wanting SYNC, force this feature. + */ + if (driver_setup.force_sync_nego) + inq_byte7 |= INQ7_SYNC; + + /* + ** Prepare negotiation if SIP capabilities have changed. + */ + tp->inq_done = 1; + if ((inq_byte7 ^ tp->inq_byte7) & (INQ7_SYNC | INQ7_WIDE16)) { + tp->inq_byte7 = inq_byte7; + ncr_negotiate(np, tp); + } + + /* + ** If unit supports tagged commands, allocate and + ** initialyze the task table if not yet. + */ + if ((inq_byte7 & INQ7_QUEUE) && lp->tasktbl == &lp->tasktbl_0) { + lp->tasktbl = m_calloc_dma(MAX_TASKS*4, "TASKTBL"); + if (!lp->tasktbl) { + lp->tasktbl = &lp->tasktbl_0; + goto fail; + } + lp->b_tasktbl = cpu_to_scr(vtobus(lp->tasktbl)); + for (i = 0 ; i < MAX_TASKS ; i++) + lp->tasktbl[i] = cpu_to_scr(np->p_notask); + + lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS"); + if (!lp->cb_tags) + goto fail; + for (i = 0 ; i < MAX_TAGS ; i++) + lp->cb_tags[i] = i; + + lp->maxnxs = MAX_TAGS; + lp->tags_stime = ktime_get(3*HZ); + } + + /* + ** Adjust tagged queueing status if needed. + */ + if ((inq_byte7 ^ lp->inq_byte7) & INQ7_QUEUE) { + lp->inq_byte7 = inq_byte7; + lp->numtags = lp->maxtags; + ncr_setup_tags (np, tn, ln); + } + +fail: + return lp; +} + +/*========================================================== +** +** +** Build Scatter Gather Block +** +** +**========================================================== +** +** The transfer area may be scattered among +** several non adjacent physical pages. +** +** We may use MAX_SCATTER blocks. +** +**---------------------------------------------------------- +*/ + +/* +** We try to reduce the number of interrupts caused +** by unexpected phase changes due to disconnects. +** A typical harddisk may disconnect before ANY block. +** If we wanted to avoid unexpected phase changes at all +** we had to use a break point every 512 bytes. +** Of course the number of scatter/gather blocks is +** limited. +** Under Linux, the scatter/gatter blocks are provided by +** the generic driver. We just have to copy addresses and +** sizes to the data segment array. +*/ + +/* +** For 64 bit systems, we use the 8 upper bits of the size field +** to provide bus address bits 32-39 to the SCRIPTS processor. +** This allows the 895A and 896 to address up to 1 TB of memory. +** For 32 bit chips on 64 bit systems, we must be provided with +** memory addresses that fit into the first 32 bit bus address +** range and so, this does not matter and we expect an error from +** the chip if this ever happen. +** +** We use a separate function for the case Linux does not provide +** a scatter list in order to allow better code optimization +** for the case we have a scatter list (BTW, for now this just wastes +** about 40 bytes of code for x86, but my guess is that the scatter +** code will get more complex later). +*/ + +#define SCATTER_ONE(data, badd, len) \ + (data)->addr = cpu_to_scr(badd); \ + (data)->size = cpu_to_scr((((badd) >> 8) & 0xff000000) + len); + +#define CROSS_16MB(p, n) (((((u_long) p) + n - 1) ^ ((u_long) p)) & ~0xffffff) + +static int ncr_scatter_no_sglist(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) +{ + struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER-1]; + int segment; + + cp->data_len = cmd->request_bufflen; + + if (cmd->request_bufflen) { + dma_addr_t baddr = map_scsi_single_data(np, cmd); + + SCATTER_ONE(data, baddr, cmd->request_bufflen); + if (CROSS_16MB(baddr, cmd->request_bufflen)) { + cp->host_flags |= HF_PM_TO_C; +#ifdef DEBUG_896R1 +printk("He! we are crossing a 16 MB boundary (0x%lx, 0x%x)\n", + baddr, cmd->request_bufflen); +#endif + } + segment = 1; + } + else + segment = 0; + + return segment; +} + +/* +** DEL 472 - 53C896 Rev 1 - Part Number 609-0393055 - ITEM 5. +** +** We disable data phase mismatch handling from SCRIPTS for data +** transfers that contains scatter/gather entries that cross +** a 16 MB boundary. +** We use a different scatter function for 896 rev. 1 that needs +** such a work-around. Doing so, we do not affect performance for +** other chips. +** This problem should not be triggered for disk IOs under Linux, +** since such IOs are performed using pages and buffers that are +** nicely power-of-two sized and aligned. But, since this may change +** at any time, a work-around was required. +*/ +static int ncr_scatter_896R1(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) +{ + int segn; + int use_sg = (int) cmd->use_sg; + + cp->data_len = 0; + + if (!use_sg) + segn = ncr_scatter_no_sglist(np, cp, cmd); + else { + struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; + struct scr_tblmove *data; + + use_sg = map_scsi_sg_data(np, cmd); + if (use_sg > MAX_SCATTER) { + unmap_scsi_data(np, cmd); + return -1; + } + + data = &cp->phys.data[MAX_SCATTER - use_sg]; + + for (segn = 0; segn < use_sg; segn++) { + dma_addr_t baddr = scsi_sg_dma_address(&scatter[segn]); + unsigned int len = scsi_sg_dma_len(&scatter[segn]); + + SCATTER_ONE(&data[segn], + baddr, + len); + if (CROSS_16MB(baddr, scatter[segn].length)) { + cp->host_flags |= HF_PM_TO_C; +#ifdef DEBUG_896R1 +printk("He! we are crossing a 16 MB boundary (0x%lx, 0x%x)\n", + baddr, scatter[segn].length); +#endif + } + cp->data_len += len; + } + } + + return segn; +} + +static int ncr_scatter(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) +{ + int segment; + int use_sg = (int) cmd->use_sg; + + cp->data_len = 0; + + if (!use_sg) + segment = ncr_scatter_no_sglist(np, cp, cmd); + else { + struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; + struct scr_tblmove *data; + + use_sg = map_scsi_sg_data(np, cmd); + if (use_sg > MAX_SCATTER) { + unmap_scsi_data(np, cmd); + return -1; + } + data = &cp->phys.data[MAX_SCATTER - use_sg]; + + for (segment = 0; segment < use_sg; segment++) { + dma_addr_t baddr = scsi_sg_dma_address(&scatter[segment]); + unsigned int len = scsi_sg_dma_len(&scatter[segment]); + + SCATTER_ONE(&data[segment], + baddr, + len); + cp->data_len += len; + } + } + + return segment; +} + +/*========================================================== +** +** +** Test the pci bus snoop logic :-( +** +** Has to be called with interrupts disabled. +** +** +**========================================================== +*/ + +#ifndef SCSI_NCR_IOMAPPED +static int __init ncr_regtest (struct ncb* np) +{ + register volatile u_int32 data; + /* + ** ncr registers may NOT be cached. + ** write 0xffffffff to a read only register area, + ** and try to read it back. + */ + data = 0xffffffff; + OUTL_OFF(offsetof(struct ncr_reg, nc_dstat), data); + data = INL_OFF(offsetof(struct ncr_reg, nc_dstat)); +#if 1 + if (data == 0xffffffff) { +#else + if ((data & 0xe2f0fffd) != 0x02000080) { +#endif + printk ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", + (unsigned) data); + return (0x10); + }; + return (0); +} +#endif + +static int __init ncr_snooptest (struct ncb* np) +{ + u_int32 ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc; + u_char dstat; + int i, err=0; +#ifndef SCSI_NCR_IOMAPPED + if (np->reg) { + err |= ncr_regtest (np); + if (err) return (err); + } +#endif +restart_test: + /* + ** Enable Master Parity Checking as we intend + ** to enable it for normal operations. + */ + OUTB (nc_ctest4, (np->rv_ctest4 & MPEE)); + /* + ** init + */ + pc = NCB_SCRIPTH0_PHYS (np, snooptest); + host_wr = 1; + ncr_wr = 2; + /* + ** Set memory and register. + */ + np->ncr_cache = cpu_to_scr(host_wr); + OUTL (nc_temp, ncr_wr); + /* + ** Start script (exchange values) + */ + OUTL (nc_dsa, np->p_ncb); + OUTL_DSP (pc); + /* + ** Wait 'til done (with timeout) + */ + for (i=0; i=NCR_SNOOP_TIMEOUT) { + printk ("CACHE TEST FAILED: timeout.\n"); + return (0x20); + }; + /* + ** Check for fatal DMA errors. + */ + dstat = INB (nc_dstat); +#if 1 /* Band aiding for broken hardwares that fail PCI parity */ + if ((dstat & MDPE) && (np->rv_ctest4 & MPEE)) { + printk ("%s: PCI DATA PARITY ERROR DETECTED - " + "DISABLING MASTER DATA PARITY CHECKING.\n", + ncr_name(np)); + np->rv_ctest4 &= ~MPEE; + goto restart_test; + } +#endif + if (dstat & (MDPE|BF|IID)) { + printk ("CACHE TEST FAILED: DMA error (dstat=0x%02x).", dstat); + return (0x80); + } + /* + ** Save termination position. + */ + pc = INL (nc_dsp); + /* + ** Read memory and register. + */ + host_rd = scr_to_cpu(np->ncr_cache); + ncr_rd = INL (nc_scratcha); + ncr_bk = INL (nc_temp); + /* + ** Check termination position. + */ + if (pc != NCB_SCRIPTH0_PHYS (np, snoopend)+8) { + printk ("CACHE TEST FAILED: script execution failed.\n"); + printk ("start=%08lx, pc=%08lx, end=%08lx\n", + (u_long) NCB_SCRIPTH0_PHYS (np, snooptest), (u_long) pc, + (u_long) NCB_SCRIPTH0_PHYS (np, snoopend) +8); + return (0x40); + }; + /* + ** Show results. + */ + if (host_wr != ncr_rd) { + printk ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n", + (int) host_wr, (int) ncr_rd); + err |= 1; + }; + if (host_rd != ncr_wr) { + printk ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n", + (int) ncr_wr, (int) host_rd); + err |= 2; + }; + if (ncr_bk != ncr_wr) { + printk ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n", + (int) ncr_wr, (int) ncr_bk); + err |= 4; + }; + return (err); +} + +/*========================================================== +** +** Determine the ncr's clock frequency. +** This is essential for the negotiation +** of the synchronous transfer rate. +** +**========================================================== +** +** Note: we have to return the correct value. +** THERE IS NO SAFE DEFAULT VALUE. +** +** Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock. +** 53C860 and 53C875 rev. 1 support fast20 transfers but +** do not have a clock doubler and so are provided with a +** 80 MHz clock. All other fast20 boards incorporate a doubler +** and so should be delivered with a 40 MHz clock. +** The recent fast40 chips (895/896/895A) and the +** fast80 chip (C1010) use a 40 Mhz base clock +** and provide a clock quadrupler (160 Mhz). The code below +** tries to deal as cleverly as possible with all this stuff. +** +**---------------------------------------------------------- +*/ + +/* + * Select NCR SCSI clock frequency + */ +static void ncr_selectclock(ncb_p np, u_char scntl3) +{ + if (np->multiplier < 2) { + OUTB(nc_scntl3, scntl3); + return; + } + + if (bootverbose >= 2) + printk ("%s: enabling clock multiplier\n", ncr_name(np)); + + OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */ + + if ( (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && + (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && + (np->multiplier > 2)) { + int i = 20; /* Poll bit 5 of stest4 for quadrupler */ + while (!(INB(nc_stest4) & LCKFRQ) && --i > 0) + UDELAY (20); + if (!i) + printk("%s: the chip cannot lock the frequency\n", + ncr_name(np)); + + } else /* Wait 120 micro-seconds for multiplier*/ + UDELAY (120); + + OUTB(nc_stest3, HSC); /* Halt the scsi clock */ + OUTB(nc_scntl3, scntl3); + OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ + OUTB(nc_stest3, 0x00); /* Restart scsi clock */ +} + + +/* + * calculate NCR SCSI clock frequency (in KHz) + */ +static unsigned __init ncrgetfreq (ncb_p np, int gen) +{ + unsigned int ms = 0; + unsigned int f; + int count; + + /* + * Measure GEN timer delay in order + * to calculate SCSI clock frequency + * + * This code will never execute too + * many loop iterations (if DELAY is + * reasonably correct). It could get + * too low a delay (too high a freq.) + * if the CPU is slow executing the + * loop for some reason (an NMI, for + * example). For this reason we will + * if multiple measurements are to be + * performed trust the higher delay + * (lower frequency returned). + */ + OUTW (nc_sien , 0x0);/* mask all scsi interrupts */ + /* enable general purpose timer */ + (void) INW (nc_sist); /* clear pending scsi interrupt */ + OUTB (nc_dien , 0); /* mask all dma interrupts */ + (void) INW (nc_sist); /* another one, just to be sure :) */ + OUTB (nc_scntl3, 4); /* set pre-scaler to divide by 3 */ + OUTB (nc_stime1, 0); /* disable general purpose timer */ + OUTB (nc_stime1, gen); /* set to nominal delay of 1<= 2) + printk ("%s: Delay (GEN=%d): %u msec, %u KHz\n", + ncr_name(np), gen, ms, f); + + return f; +} + +static unsigned __init ncr_getfreq (ncb_p np) +{ + u_int f1, f2; + int gen = 11; + + (void) ncrgetfreq (np, gen); /* throw away first result */ + f1 = ncrgetfreq (np, gen); + f2 = ncrgetfreq (np, gen); + if (f1 > f2) f1 = f2; /* trust lower result */ + return f1; +} + +/* + * Get/probe NCR SCSI clock frequency + */ +static void __init ncr_getclock (ncb_p np, int mult) +{ + unsigned char scntl3 = np->sv_scntl3; + unsigned char stest1 = np->sv_stest1; + unsigned f1; + + np->multiplier = 1; + f1 = 40000; + + /* + ** True with 875/895/896/895A with clock multiplier selected + */ + if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) { + if (bootverbose >= 2) + printk ("%s: clock multiplier found\n", ncr_name(np)); + np->multiplier = mult; + } + + /* + ** If multiplier not found or scntl3 not 7,5,3, + ** reset chip and get frequency from general purpose timer. + ** Otherwise trust scntl3 BIOS setting. + */ + if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { + OUTB (nc_stest1, 0); /* make sure doubler is OFF */ + f1 = ncr_getfreq (np); + + if (bootverbose) + printk ("%s: NCR clock is %uKHz\n", ncr_name(np), f1); + + if (f1 < 55000) f1 = 40000; + else f1 = 80000; + + /* + ** Suggest to also check the PCI clock frequency + ** to make sure our frequency calculation algorithm + ** is not too biased. + */ + if (np->features & FE_66MHZ) { + np->pciclock_min = (66000*55+80-1)/80; + np->pciclock_max = (66000*55)/40; + } + else { + np->pciclock_min = (33000*55+80-1)/80; + np->pciclock_max = (33000*55)/40; + } + + if (f1 == 40000 && mult > 1) { + if (bootverbose >= 2) + printk ("%s: clock multiplier assumed\n", ncr_name(np)); + np->multiplier = mult; + } + } else { + if ((scntl3 & 7) == 3) f1 = 40000; + else if ((scntl3 & 7) == 5) f1 = 80000; + else f1 = 160000; + + f1 /= np->multiplier; + } + + /* + ** Compute controller synchronous parameters. + */ + f1 *= np->multiplier; + np->clock_khz = f1; +} + +/* + * Get/probe PCI clock frequency + */ +static u_int __init ncr_getpciclock (ncb_p np) +{ + static u_int f; + + OUTB (nc_stest1, SCLK); /* Use the PCI clock as SCSI clock */ + f = ncr_getfreq (np); + OUTB (nc_stest1, 0); + + return f; +} + +/*===================== LINUX ENTRY POINTS SECTION ==========================*/ + +#ifndef uchar +#define uchar unsigned char +#endif + +#ifndef ushort +#define ushort unsigned short +#endif + +#ifndef ulong +#define ulong unsigned long +#endif + +/* --------------------------------------------------------------------- +** +** Driver setup from the boot command line +** +** --------------------------------------------------------------------- +*/ + +#ifdef MODULE +#define ARG_SEP ' ' +#else +#define ARG_SEP ',' +#endif + +#define OPT_TAGS 1 +#define OPT_MASTER_PARITY 2 +#define OPT_SCSI_PARITY 3 +#define OPT_DISCONNECTION 4 +#define OPT_SPECIAL_FEATURES 5 +#define OPT_RESERVED_1 6 +#define OPT_FORCE_SYNC_NEGO 7 +#define OPT_REVERSE_PROBE 8 +#define OPT_DEFAULT_SYNC 9 +#define OPT_VERBOSE 10 +#define OPT_DEBUG 11 +#define OPT_BURST_MAX 12 +#define OPT_LED_PIN 13 +#define OPT_MAX_WIDE 14 +#define OPT_SETTLE_DELAY 15 +#define OPT_DIFF_SUPPORT 16 +#define OPT_IRQM 17 +#define OPT_PCI_FIX_UP 18 +#define OPT_BUS_CHECK 19 +#define OPT_OPTIMIZE 20 +#define OPT_RECOVERY 21 +#define OPT_SAFE_SETUP 22 +#define OPT_USE_NVRAM 23 +#define OPT_EXCLUDE 24 +#define OPT_HOST_ID 25 + +#ifdef SCSI_NCR_IARB_SUPPORT +#define OPT_IARB 26 +#endif + +static char setup_token[] __initdata = + "tags:" "mpar:" + "spar:" "disc:" + "specf:" "_rsvd1:" + "fsn:" "revprob:" + "sync:" "verb:" + "debug:" "burst:" + "led:" "wide:" + "settle:" "diff:" + "irqm:" "pcifix:" + "buschk:" "optim:" + "recovery:" + "safe:" "nvram:" + "excl:" "hostid:" +#ifdef SCSI_NCR_IARB_SUPPORT + "iarb:" +#endif + ; /* DONNOT REMOVE THIS ';' */ + +#ifdef MODULE +#define ARG_SEP ' ' +#else +#define ARG_SEP ',' +#endif + +static int __init get_setup_token(char *p) +{ + char *cur = setup_token; + char *pc; + int i = 0; + + while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { + ++pc; + ++i; + if (!strncmp(p, cur, pc - cur)) + return i; + cur = pc; + } + return 0; +} + + +int __init sym53c8xx_setup(char *str) +{ +#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT + char *cur = str; + char *pc, *pv; + unsigned long val; + int i, c; + int xi = 0; + + while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { + char *pe; + + val = 0; + pv = pc; + c = *++pv; + + if (c == 'n') + val = 0; + else if (c == 'y') + val = 1; + else + val = (int) simple_strtoul(pv, &pe, 0); + + switch (get_setup_token(cur)) { + case OPT_TAGS: + driver_setup.default_tags = val; + if (pe && *pe == '/') { + i = 0; + while (*pe && *pe != ARG_SEP && + i < sizeof(driver_setup.tag_ctrl)-1) { + driver_setup.tag_ctrl[i++] = *pe++; + } + driver_setup.tag_ctrl[i] = '\0'; + } + break; + case OPT_MASTER_PARITY: + driver_setup.master_parity = val; + break; + case OPT_SCSI_PARITY: + driver_setup.scsi_parity = val; + break; + case OPT_DISCONNECTION: + driver_setup.disconnection = val; + break; + case OPT_SPECIAL_FEATURES: + driver_setup.special_features = val; + break; + case OPT_FORCE_SYNC_NEGO: + driver_setup.force_sync_nego = val; + break; + case OPT_REVERSE_PROBE: + driver_setup.reverse_probe = val; + break; + case OPT_DEFAULT_SYNC: + driver_setup.default_sync = val; + break; + case OPT_VERBOSE: + driver_setup.verbose = val; + break; + case OPT_DEBUG: + driver_setup.debug = val; + break; + case OPT_BURST_MAX: + driver_setup.burst_max = val; + break; + case OPT_LED_PIN: + driver_setup.led_pin = val; + break; + case OPT_MAX_WIDE: + driver_setup.max_wide = val? 1:0; + break; + case OPT_SETTLE_DELAY: + driver_setup.settle_delay = val; + break; + case OPT_DIFF_SUPPORT: + driver_setup.diff_support = val; + break; + case OPT_IRQM: + driver_setup.irqm = val; + break; + case OPT_PCI_FIX_UP: + driver_setup.pci_fix_up = val; + break; + case OPT_BUS_CHECK: + driver_setup.bus_check = val; + break; + case OPT_OPTIMIZE: + driver_setup.optimize = val; + break; + case OPT_RECOVERY: + driver_setup.recovery = val; + break; + case OPT_USE_NVRAM: + driver_setup.use_nvram = val; + break; + case OPT_SAFE_SETUP: + memcpy(&driver_setup, &driver_safe_setup, + sizeof(driver_setup)); + break; + case OPT_EXCLUDE: + if (xi < SCSI_NCR_MAX_EXCLUDES) + driver_setup.excludes[xi++] = val; + break; + case OPT_HOST_ID: + driver_setup.host_id = val; + break; +#ifdef SCSI_NCR_IARB_SUPPORT + case OPT_IARB: + driver_setup.iarb = val; + break; +#endif + default: + printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur); + break; + } + + if ((cur = strchr(cur, ARG_SEP)) != NULL) + ++cur; + } +#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */ + return 1; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) +#ifndef MODULE +__setup("sym53c8xx=", sym53c8xx_setup); +#endif +#endif + +static int +sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device); + +/* +** Linux entry point for SYM53C8XX devices detection routine. +** +** Called by the middle-level scsi drivers at initialization time, +** or at module installation. +** +** Read the PCI configuration and try to attach each +** detected NCR board. +** +** If NVRAM is present, try to attach boards according to +** the used defined boot order. +** +** Returns the number of boards successfully attached. +*/ + +static void __init ncr_print_driver_setup(void) +{ +#define YesNo(y) y ? 'y' : 'n' + printk (NAME53C8XX ": setup=disc:%c,specf:%d,tags:%d,sync:%d," + "burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n", + YesNo(driver_setup.disconnection), + driver_setup.special_features, + driver_setup.default_tags, + driver_setup.default_sync, + driver_setup.burst_max, + YesNo(driver_setup.max_wide), + driver_setup.diff_support, + YesNo(driver_setup.reverse_probe), + driver_setup.bus_check); + + printk (NAME53C8XX ": setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x," + "led:%c,settle:%d,irqm:0x%x,nvram:0x%x,pcifix:0x%x\n", + YesNo(driver_setup.master_parity), + YesNo(driver_setup.scsi_parity), + YesNo(driver_setup.force_sync_nego), + driver_setup.verbose, + driver_setup.debug, + YesNo(driver_setup.led_pin), + driver_setup.settle_delay, + driver_setup.irqm, + driver_setup.use_nvram, + driver_setup.pci_fix_up); +#undef YesNo +} + +/*=================================================================== +** SYM53C8XX devices description table and chip ids list. +**=================================================================== +*/ + +static ncr_chip ncr_chip_table[] __initdata = SCSI_NCR_CHIP_TABLE; +static ushort ncr_chip_ids[] __initdata = SCSI_NCR_CHIP_IDS; + +#ifdef SCSI_NCR_PQS_PDS_SUPPORT +/*=================================================================== +** Detect all NCR PQS/PDS boards and keep track of their bus nr. +** +** The NCR PQS or PDS card is constructed as a DEC bridge +** behind which sit a proprietary NCR memory controller and +** four or two 53c875s as separate devices. In its usual mode +** of operation, the 875s are slaved to the memory controller +** for all transfers. We can tell if an 875 is part of a +** PQS/PDS or not since if it is, it will be on the same bus +** as the memory controller. To operate with the Linux +** driver, the memory controller is disabled and the 875s +** freed to function independently. The only wrinkle is that +** the preset SCSI ID (which may be zero) must be read in from +** a special configuration space register of the 875 +**=================================================================== +*/ +#define SCSI_NCR_MAX_PQS_BUS 16 +static int pqs_bus[SCSI_NCR_MAX_PQS_BUS] __initdata = { 0 }; + +static void __init ncr_detect_pqs_pds(void) +{ + short index; + pcidev_t dev = PCIDEV_NULL; + + for(index=0; index < SCSI_NCR_MAX_PQS_BUS; index++) { + u_char tmp; + + dev = pci_find_device(0x101a, 0x0009, dev); + if (dev == PCIDEV_NULL) { + pqs_bus[index] = -1; + break; + } + printk(KERN_INFO NAME53C8XX ": NCR PQS/PDS memory controller detected on bus %d\n", PciBusNumber(dev)); + pci_read_config_byte(dev, 0x44, &tmp); + /* bit 1: allow individual 875 configuration */ + tmp |= 0x2; + pci_write_config_byte(dev, 0x44, tmp); + pci_read_config_byte(dev, 0x45, &tmp); + /* bit 2: drive individual 875 interrupts to the bus */ + tmp |= 0x4; + pci_write_config_byte(dev, 0x45, tmp); + + pqs_bus[index] = PciBusNumber(dev); + } +} +#endif /* SCSI_NCR_PQS_PDS_SUPPORT */ + +/*=================================================================== +** Detect all 53c8xx hosts and then attach them. +** +** If we are using NVRAM, once all hosts are detected, we need to +** check any NVRAM for boot order in case detect and boot order +** differ and attach them using the order in the NVRAM. +** +** If no NVRAM is found or data appears invalid attach boards in +** the order they are detected. +**=================================================================== +*/ +int __init sym53c8xx_detect(Scsi_Host_Template *tpnt) +{ + pcidev_t pcidev; + int i, j, chips, hosts, count; + int attach_count = 0; + ncr_device *devtbl, *devp; +#ifdef SCSI_NCR_NVRAM_SUPPORT + ncr_nvram nvram0, nvram, *nvp; +#endif + + /* + ** PCI is required. + */ + if (!pci_present()) + return 0; + + /* + ** Initialize driver general stuff. + */ +#ifdef SCSI_NCR_PROC_INFO_SUPPORT +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,27) + tpnt->proc_dir = &proc_scsi_sym53c8xx; +#else + tpnt->proc_name = NAME53C8XX; +#endif + tpnt->proc_info = sym53c8xx_proc_info; +#endif + +#if defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE) +if (sym53c8xx) + sym53c8xx_setup(sym53c8xx); +#endif +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT + ncr_debug = driver_setup.debug; +#endif + + if (initverbose >= 2) + ncr_print_driver_setup(); + + /* + ** Allocate the device table since we donnot want to + ** overflow the kernel stack. + ** 1 x 4K PAGE is enough for more than 40 devices for i386. + */ + devtbl = m_calloc(PAGE_SIZE, "devtbl"); + if (!devtbl) + return 0; + + /* + ** Detect all NCR PQS/PDS memory controllers. + */ +#ifdef SCSI_NCR_PQS_PDS_SUPPORT + ncr_detect_pqs_pds(); +#endif + + /* + ** Detect all 53c8xx hosts. + ** Save the first Symbios NVRAM content if any + ** for the boot order. + */ + chips = sizeof(ncr_chip_ids) / sizeof(ncr_chip_ids[0]); + hosts = PAGE_SIZE / sizeof(*devtbl); +#ifdef SCSI_NCR_NVRAM_SUPPORT + nvp = (driver_setup.use_nvram & 0x1) ? &nvram0 : 0; +#endif + j = 0; + count = 0; + pcidev = PCIDEV_NULL; + while (1) { + char *msg = ""; + if (count >= hosts) + break; + if (j >= chips) + break; + i = driver_setup.reverse_probe ? chips - 1 - j : j; + pcidev = pci_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i], + pcidev); + if (pcidev == PCIDEV_NULL) { + ++j; + continue; + } + if (pci_enable_device(pcidev)) /* @!*!$&*!%-*#;! */ + continue; + /* Some HW as the HP LH4 may report twice PCI devices */ + for (i = 0; i < count ; i++) { + if (devtbl[i].slot.bus == PciBusNumber(pcidev) && + devtbl[i].slot.device_fn == PciDeviceFn(pcidev)) + break; + } + if (i != count) /* Ignore this device if we already have it */ + continue; + pci_set_master(pcidev); + devp = &devtbl[count]; + devp->host_id = driver_setup.host_id; + devp->attach_done = 0; + if (sym53c8xx_pci_init(tpnt, pcidev, devp)) { + continue; + } + ++count; +#ifdef SCSI_NCR_NVRAM_SUPPORT + if (nvp) { + ncr_get_nvram(devp, nvp); + switch(nvp->type) { + case SCSI_NCR_SYMBIOS_NVRAM: + /* + * Switch to the other nvram buffer, so that + * nvram0 will contain the first Symbios + * format NVRAM content with boot order. + */ + nvp = &nvram; + msg = "with Symbios NVRAM"; + break; + case SCSI_NCR_TEKRAM_NVRAM: + msg = "with Tekram NVRAM"; + break; + } + } +#endif +#ifdef SCSI_NCR_PQS_PDS_SUPPORT + if (devp->pqs_pds) + msg = "(NCR PQS/PDS)"; +#endif + printk(KERN_INFO NAME53C8XX ": 53c%s detected %s\n", + devp->chip.name, msg); + } + + /* + ** If we have found a SYMBIOS NVRAM, use first the NVRAM boot + ** sequence as device boot order. + ** check devices in the boot record against devices detected. + ** attach devices if we find a match. boot table records that + ** do not match any detected devices will be ignored. + ** devices that do not match any boot table will not be attached + ** here but will attempt to be attached during the device table + ** rescan. + */ +#ifdef SCSI_NCR_NVRAM_SUPPORT + if (!nvp || nvram0.type != SCSI_NCR_SYMBIOS_NVRAM) + goto next; + for (i = 0; i < 4; i++) { + Symbios_host *h = &nvram0.data.Symbios.host[i]; + for (j = 0 ; j < count ; j++) { + devp = &devtbl[j]; + if (h->device_fn != devp->slot.device_fn || + h->bus_nr != devp->slot.bus || + h->device_id != devp->chip.device_id) + continue; + if (devp->attach_done) + continue; + if (h->flags & SYMBIOS_INIT_SCAN_AT_BOOT) { + ncr_get_nvram(devp, nvp); + if (!ncr_attach (tpnt, attach_count, devp)) + attach_count++; + } + else if (!(driver_setup.use_nvram & 0x80)) + printk(KERN_INFO NAME53C8XX + ": 53c%s state OFF thus not attached\n", + devp->chip.name); + else + continue; + + devp->attach_done = 1; + break; + } + } +next: +#endif + + /* + ** Rescan device list to make sure all boards attached. + ** Devices without boot records will not be attached yet + ** so try to attach them here. + */ + for (i= 0; i < count; i++) { + devp = &devtbl[i]; + if (!devp->attach_done) { +#ifdef SCSI_NCR_NVRAM_SUPPORT + ncr_get_nvram(devp, nvp); +#endif + if (!ncr_attach (tpnt, attach_count, devp)) + attach_count++; + } + } + + m_free(devtbl, PAGE_SIZE, "devtbl"); + + return attach_count; +} + +/*=================================================================== +** Read and check the PCI configuration for any detected NCR +** boards and save data for attaching after all boards have +** been detected. +**=================================================================== +*/ +static int __init +sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device) +{ + u_short vendor_id, device_id, command, status_reg; + u_char cache_line_size, latency_timer; + u_char suggested_cache_line_size = 0; + u_char pci_fix_up = driver_setup.pci_fix_up; + u_char revision; + u_int irq; + u_long base, base_c, base_2, base_2_c, io_port; + int i; + ncr_chip *chip; + + printk(KERN_INFO NAME53C8XX ": at PCI bus %d, device %d, function %d\n", + PciBusNumber(pdev), + (int) (PciDeviceFn(pdev) & 0xf8) >> 3, + (int) (PciDeviceFn(pdev) & 7)); + + /* + ** Read info from the PCI config space. + ** pci_read_config_xxx() functions are assumed to be used for + ** successfully detected PCI devices. + */ + vendor_id = PciVendorId(pdev); + device_id = PciDeviceId(pdev); + irq = PciIrqLine(pdev); + + i = pci_get_base_address(pdev, 0, &io_port); + io_port = pci_get_base_cookie(pdev, 0); + + base_c = pci_get_base_cookie(pdev, i); + i = pci_get_base_address(pdev, i, &base); + + base_2_c = pci_get_base_cookie(pdev, i); + (void) pci_get_base_address(pdev, i, &base_2); + + pci_read_config_word(pdev, PCI_COMMAND, &command); + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer); + pci_read_config_word(pdev, PCI_STATUS, &status_reg); + +#ifdef SCSI_NCR_PQS_PDS_SUPPORT + /* + ** Match the BUS number for PQS/PDS devices. + ** Read the SCSI ID from a special register mapped + ** into the configuration space of the individual + ** 875s. This register is set up by the PQS bios + */ + for(i = 0; i < SCSI_NCR_MAX_PQS_BUS && pqs_bus[i] != -1; i++) { + u_char tmp; + if (pqs_bus[i] == PciBusNumber(pdev)) { + pci_read_config_byte(pdev, 0x84, &tmp); + device->pqs_pds = 1; + device->host_id = tmp; + break; + } + } +#endif /* SCSI_NCR_PQS_PDS_SUPPORT */ + + /* + ** If user excludes this chip, donnot initialize it. + */ + for (i = 0 ; i < SCSI_NCR_MAX_EXCLUDES ; i++) { + if (driver_setup.excludes[i] == + (io_port & PCI_BASE_ADDRESS_IO_MASK)) + return -1; + } + /* + ** Check if the chip is supported + */ + chip = 0; + for (i = 0; i < sizeof(ncr_chip_table)/sizeof(ncr_chip_table[0]); i++) { + if (device_id != ncr_chip_table[i].device_id) + continue; + if (revision > ncr_chip_table[i].revision_id) + continue; + if (!(ncr_chip_table[i].features & FE_LDSTR)) + break; + chip = &device->chip; + memcpy(chip, &ncr_chip_table[i], sizeof(*chip)); + chip->revision_id = revision; + break; + } + +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + /* Configure DMA attributes. For DAC capable boards, we can encode + ** 32+8 bits for SCSI DMA data addresses with the extra bits used + ** in the size field. We use normal 32-bit PCI addresses for + ** descriptors. + */ + if (chip && (chip->features & FE_DAC)) { + if (pci_set_dma_mask(pdev, (u64) 0xffffffffff)) + chip->features &= ~FE_DAC_IN_USE; + else + chip->features |= FE_DAC_IN_USE; + } + + if (chip && !(chip->features & FE_DAC_IN_USE)) { + if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) { + printk(KERN_WARNING NAME53C8XX + "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); + return -1; + } + } +#endif + + /* + ** Ignore Symbios chips controlled by SISL RAID controller. + ** This controller sets value 0x52414944 at RAM end - 16. + */ +#if defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED) + if (chip && (base_2_c & PCI_BASE_ADDRESS_MEM_MASK)) { + unsigned int ram_size, ram_val; + u_long ram_ptr; + + if (chip->features & FE_RAM8K) + ram_size = 8192; + else + ram_size = 4096; + + ram_ptr = remap_pci_mem(base_2_c & PCI_BASE_ADDRESS_MEM_MASK, + ram_size); + if (ram_ptr) { + ram_val = readl_raw(ram_ptr + ram_size - 16); + unmap_pci_mem(ram_ptr, ram_size); + if (ram_val == 0x52414944) { + printk(NAME53C8XX": not initializing, " + "driven by SISL RAID controller.\n"); + return -1; + } + } + } +#endif /* i386 and PCI MEMORY accessible */ + + if (!chip) { + printk(NAME53C8XX ": not initializing, device not supported\n"); + return -1; + } + +#if defined(__powerpc__) || defined(__hppa__) + /* + ** Fix-up for power/pc and hppa. + ** Should not be performed by the driver. + */ + if ((command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) + != (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { + printk(NAME53C8XX ": setting%s%s...\n", + (command & PCI_COMMAND_IO) ? "" : " PCI_COMMAND_IO", + (command & PCI_COMMAND_MEMORY) ? "" : " PCI_COMMAND_MEMORY"); + command |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(pdev, PCI_COMMAND, command); + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) + if ( is_prep ) { + if (io_port >= 0x10000000) { + printk(NAME53C8XX ": reallocating io_port (Wacky IBM)"); + io_port = (io_port & 0x00FFFFFF) | 0x01000000; + pci_write_config_dword(pdev, + PCI_BASE_ADDRESS_0, io_port); + } + if (base >= 0x10000000) { + printk(NAME53C8XX ": reallocating base (Wacky IBM)"); + base = (base & 0x00FFFFFF) | 0x01000000; + pci_write_config_dword(pdev, + PCI_BASE_ADDRESS_1, base); + } + if (base_2 >= 0x10000000) { + printk(NAME53C8XX ": reallocating base2 (Wacky IBM)"); + base_2 = (base_2 & 0x00FFFFFF) | 0x01000000; + pci_write_config_dword(pdev, + PCI_BASE_ADDRESS_2, base_2); + } + } +#endif +#endif /* __powerpc__ */ + +#if defined(__i386__) && !defined(MODULE) + if (!cache_line_size) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,75) + extern char x86; + switch(x86) { +#else + switch(boot_cpu_data.x86) { +#endif + case 4: suggested_cache_line_size = 4; break; + case 6: + case 5: suggested_cache_line_size = 8; break; + } + } +#endif /* __i386__ */ + + /* + ** Check availability of IO space, memory space. + ** Enable master capability if not yet. + ** + ** We shouldn't have to care about the IO region when + ** we are using MMIO. But calling check_region() from + ** both the ncr53c8xx and the sym53c8xx drivers prevents + ** from attaching devices from the both drivers. + ** If you have a better idea, let me know. + */ +/* #ifdef SCSI_NCR_IOMAPPED */ +#if 1 + if (!(command & PCI_COMMAND_IO)) { + printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n", + (long) io_port); + io_port = 0; + } +#endif + if (!(command & PCI_COMMAND_MEMORY)) { + printk(NAME53C8XX ": PCI_COMMAND_MEMORY not set.\n"); + base = 0; + base_2 = 0; + } + io_port &= PCI_BASE_ADDRESS_IO_MASK; + base &= PCI_BASE_ADDRESS_MEM_MASK; + base_2 &= PCI_BASE_ADDRESS_MEM_MASK; + +/* #ifdef SCSI_NCR_IOMAPPED */ +#if 1 + if (io_port && check_region (io_port, 128)) { + printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n", + (long) io_port); + io_port = 0; + } + if (!io_port) + return -1; +#endif +#ifndef SCSI_NCR_IOMAPPED + if (!base) { + printk(NAME53C8XX ": MMIO base address disabled.\n"); + return -1; + } +#endif + + /* + ** Set MASTER capable and PARITY bit, if not yet. + */ + if ((command & (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY)) + != (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY)) { + printk(NAME53C8XX ": setting%s%s...(fix-up)\n", + (command & PCI_COMMAND_MASTER) ? "" : " PCI_COMMAND_MASTER", + (command & PCI_COMMAND_PARITY) ? "" : " PCI_COMMAND_PARITY"); + command |= (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY); + pci_write_config_word(pdev, PCI_COMMAND, command); + } + + /* + ** Fix some features according to driver setup. + */ + if (!(driver_setup.special_features & 1)) + chip->features &= ~FE_SPECIAL_SET; + else { + if (driver_setup.special_features & 2) + chip->features &= ~FE_WRIE; + if (driver_setup.special_features & 4) + chip->features &= ~FE_NOPM; + } + + /* + ** Work around for errant bit in 895A. The 66Mhz + ** capable bit is set erroneously. Clear this bit. + ** (Item 1 DEL 533) + ** + ** Make sure Config space and Features agree. + ** + ** Recall: writes are not normal to status register - + ** write a 1 to clear and a 0 to leave unchanged. + ** Can only reset bits. + */ + if (chip->features & FE_66MHZ) { + if (!(status_reg & PCI_STATUS_66MHZ)) + chip->features &= ~FE_66MHZ; + } + else { + if (status_reg & PCI_STATUS_66MHZ) { + status_reg = PCI_STATUS_66MHZ; + pci_write_config_word(pdev, PCI_STATUS, status_reg); + pci_read_config_word(pdev, PCI_STATUS, &status_reg); + } + } + + /* + ** Some features are required to be enabled in order to + ** work around some chip problems. :) ;) + ** (ITEM 12 of a DEL about the 896 I haven't yet). + ** We must ensure the chip will use WRITE AND INVALIDATE. + ** The revision number limit is for now arbitrary. + */ + if (device_id == PCI_DEVICE_ID_NCR_53C896 && revision <= 0x10) { + chip->features |= (FE_WRIE | FE_CLSE); + pci_fix_up |= 3; /* Force appropriate PCI fix-up */ + } + +#ifdef SCSI_NCR_PCI_FIX_UP_SUPPORT + /* + ** Try to fix up PCI config according to wished features. + */ + if ((pci_fix_up & 1) && (chip->features & FE_CLSE) && + !cache_line_size && suggested_cache_line_size) { + cache_line_size = suggested_cache_line_size; + pci_write_config_byte(pdev, + PCI_CACHE_LINE_SIZE, cache_line_size); + printk(NAME53C8XX ": PCI_CACHE_LINE_SIZE set to %d (fix-up).\n", + cache_line_size); + } + + if ((pci_fix_up & 2) && cache_line_size && + (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) { + printk(NAME53C8XX": setting PCI_COMMAND_INVALIDATE (fix-up)\n"); + command |= PCI_COMMAND_INVALIDATE; + pci_write_config_word(pdev, PCI_COMMAND, command); + } + + /* + ** Tune PCI LATENCY TIMER according to burst max length transfer. + ** (latency timer >= burst length + 6, we add 10 to be quite sure) + */ + + if (chip->burst_max && (latency_timer == 0 || (pci_fix_up & 4))) { + uchar lt = (1 << chip->burst_max) + 6 + 10; + if (latency_timer < lt) { + printk(NAME53C8XX + ": changing PCI_LATENCY_TIMER from %d to %d.\n", + (int) latency_timer, (int) lt); + latency_timer = lt; + pci_write_config_byte(pdev, + PCI_LATENCY_TIMER, latency_timer); + } + } + +#endif /* SCSI_NCR_PCI_FIX_UP_SUPPORT */ + + /* + ** Initialise ncr_device structure with items required by ncr_attach. + */ + device->pdev = pdev; + device->slot.bus = PciBusNumber(pdev); + device->slot.device_fn = PciDeviceFn(pdev); + device->slot.base = base; + device->slot.base_2 = base_2; + device->slot.base_c = base_c; + device->slot.base_2_c = base_2_c; + device->slot.io_port = io_port; + device->slot.irq = irq; + device->attach_done = 0; + + return 0; +} + + +/*=================================================================== +** Detect and try to read SYMBIOS and TEKRAM NVRAM. +** +** Data can be used to order booting of boards. +** +** Data is saved in ncr_device structure if NVRAM found. This +** is then used to find drive boot order for ncr_attach(). +** +** NVRAM data is passed to Scsi_Host_Template later during +** ncr_attach() for any device set up. +*=================================================================== +*/ +#ifdef SCSI_NCR_NVRAM_SUPPORT +static void __init ncr_get_nvram(ncr_device *devp, ncr_nvram *nvp) +{ + devp->nvram = nvp; + if (!nvp) + return; + /* + ** Get access to chip IO registers + */ +#ifdef SCSI_NCR_IOMAPPED + request_region(devp->slot.io_port, 128, NAME53C8XX); + devp->slot.base_io = devp->slot.io_port; +#else + devp->slot.reg = + (struct ncr_reg *) remap_pci_mem(devp->slot.base_c, 128); + if (!devp->slot.reg) + return; +#endif + + /* + ** Try to read SYMBIOS nvram. + ** Try to read TEKRAM nvram if Symbios nvram not found. + */ + if (!sym_read_Symbios_nvram(&devp->slot, &nvp->data.Symbios)) + nvp->type = SCSI_NCR_SYMBIOS_NVRAM; + else if (!sym_read_Tekram_nvram(&devp->slot, devp->chip.device_id, + &nvp->data.Tekram)) + nvp->type = SCSI_NCR_TEKRAM_NVRAM; + else { + nvp->type = 0; + devp->nvram = 0; + } + + /* + ** Release access to chip IO registers + */ +#ifdef SCSI_NCR_IOMAPPED + release_region(devp->slot.base_io, 128); +#else + unmap_pci_mem((u_long) devp->slot.reg, 128ul); +#endif + +} +#endif /* SCSI_NCR_NVRAM_SUPPORT */ + +/* +** Linux select queue depths function +*/ + +#define DEF_DEPTH (driver_setup.default_tags) +#define ALL_TARGETS -2 +#define NO_TARGET -1 +#define ALL_LUNS -2 +#define NO_LUN -1 + +static int device_queue_depth(ncb_p np, int target, int lun) +{ + int c, h, t, u, v; + char *p = driver_setup.tag_ctrl; + char *ep; + + h = -1; + t = NO_TARGET; + u = NO_LUN; + while ((c = *p++) != 0) { + v = simple_strtoul(p, &ep, 0); + switch(c) { + case '/': + ++h; + t = ALL_TARGETS; + u = ALL_LUNS; + break; + case 't': + if (t != target) + t = (target == v) ? v : NO_TARGET; + u = ALL_LUNS; + break; + case 'u': + if (u != lun) + u = (lun == v) ? v : NO_LUN; + break; + case 'q': + if (h == np->unit && + (t == ALL_TARGETS || t == target) && + (u == ALL_LUNS || u == lun)) + return v; + break; + case '-': + t = ALL_TARGETS; + u = ALL_LUNS; + break; + default: + break; + } + p = ep; + } + return DEF_DEPTH; +} + +int sym53c8xx_slave_configure(Scsi_Device *device) +{ + struct Scsi_Host *host = device->host; + ncb_p np; + tcb_p tp; + lcb_p lp; + int numtags, depth_to_use; + + np = ((struct host_data *) host->hostdata)->ncb; + tp = &np->target[device->id]; + lp = ncr_lp(np, tp, device->lun); + + /* + ** Select queue depth from driver setup. + ** Donnot use more than configured by user. + ** Use at least 2. + ** Donnot use more than our maximum. + */ + numtags = device_queue_depth(np, device->id, device->lun); + if (numtags > tp->usrtags) + numtags = tp->usrtags; + if (!device->tagged_supported) + numtags = 1; + depth_to_use = numtags; + if (depth_to_use < 2) + depth_to_use = 2; + if (depth_to_use > MAX_TAGS) + depth_to_use = MAX_TAGS; + + scsi_adjust_queue_depth(device, + (device->tagged_supported ? + MSG_SIMPLE_TAG : 0), + depth_to_use); + + /* + ** Since the queue depth is not tunable under Linux, + ** we need to know this value in order not to + ** announce stupid things to user. + */ + if (lp) { + lp->numtags = lp->maxtags = numtags; + lp->scdev_depth = depth_to_use; + } + ncr_setup_tags (np, device->id, device->lun); + +#ifdef DEBUG_SYM53C8XX + printk("sym53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n", + np->unit, device->id, device->lun, depth_to_use); +#endif + + return 0; +} + +/* +** Linux entry point for info() function +*/ +const char *sym53c8xx_info (struct Scsi_Host *host) +{ + return SCSI_NCR_DRIVER_NAME; +} + +/* +** Linux entry point of queuecommand() function +*/ + +int sym53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) +{ + ncb_p np = ((struct host_data *) cmd->device->host->hostdata)->ncb; + unsigned long flags; + int sts; + +#ifdef DEBUG_SYM53C8XX +printk("sym53c8xx_queue_command\n"); +#endif + + cmd->scsi_done = done; + cmd->host_scribble = NULL; + cmd->SCp.ptr = NULL; + cmd->SCp.buffer = NULL; +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + __data_mapped(cmd) = 0; + __data_mapping(cmd) = 0; +#endif + + NCR_LOCK_NCB(np, flags); + + if ((sts = ncr_queue_command(np, cmd)) != DID_OK) { + SetScsiResult(cmd, sts, 0); +#ifdef DEBUG_SYM53C8XX +printk("sym53c8xx : command not queued - result=%d\n", sts); +#endif + } +#ifdef DEBUG_SYM53C8XX + else +printk("sym53c8xx : command successfully queued\n"); +#endif + + NCR_UNLOCK_NCB(np, flags); + + if (sts != DID_OK) { + unmap_scsi_data(np, cmd); + done(cmd); + } + + return sts; +} + +/* +** Linux entry point of the interrupt handler. +** Since linux versions > 1.3.70, we trust the kernel for +** passing the internal host descriptor as 'dev_id'. +** Otherwise, we scan the host list and call the interrupt +** routine for each host that uses this IRQ. +*/ + +static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) +{ + unsigned long flags; + ncb_p np = (ncb_p) dev_id; + Scsi_Cmnd *done_list; + +#ifdef DEBUG_SYM53C8XX + printk("sym53c8xx : interrupt received\n"); +#endif + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("["); + + NCR_LOCK_NCB(np, flags); + ncr_exception(np); + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("]\n"); + + if (done_list) { + NCR_LOCK_SCSI_DONE(done_list->device->host, flags); + ncr_flush_done_cmds(done_list); + NCR_UNLOCK_SCSI_DONE(done_list->device->host, flags); + } +} + +/* +** Linux entry point of the timer handler +*/ + +static void sym53c8xx_timeout(unsigned long npref) +{ + ncb_p np = (ncb_p) npref; + unsigned long flags; + Scsi_Cmnd *done_list; + + NCR_LOCK_NCB(np, flags); + ncr_timeout((ncb_p) np); + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + if (done_list) { + NCR_LOCK_SCSI_DONE(done_list->device->host, flags); + ncr_flush_done_cmds(done_list); + NCR_UNLOCK_SCSI_DONE(done_list->device->host, flags); + } +} + +/* +** Linux entry point of reset() function +*/ + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS +int sym53c8xx_reset(Scsi_Cmnd *cmd, unsigned int reset_flags) +#else +int sym53c8xx_reset(Scsi_Cmnd *cmd) +#endif +{ + ncb_p np = ((struct host_data *) cmd->device->host->hostdata)->ncb; + int sts; + unsigned long flags; + Scsi_Cmnd *done_list; + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + printk("sym53c8xx_reset: pid=%lu reset_flags=%x serial_number=%ld serial_number_at_timeout=%ld\n", + cmd->pid, reset_flags, cmd->serial_number, cmd->serial_number_at_timeout); +#else + printk("sym53c8xx_reset: command pid %lu\n", cmd->pid); +#endif + + NCR_LOCK_NCB(np, flags); + + /* + * We have to just ignore reset requests in some situations. + */ +#if defined SCSI_RESET_NOT_RUNNING + if (cmd->serial_number != cmd->serial_number_at_timeout) { + sts = SCSI_RESET_NOT_RUNNING; + goto out; + } +#endif + /* + * If the mid-level driver told us reset is synchronous, it seems + * that we must call the done() callback for the involved command, + * even if this command was not queued to the low-level driver, + * before returning SCSI_RESET_SUCCESS. + */ + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + sts = ncr_reset_bus(np, cmd, + (reset_flags & (SCSI_RESET_SYNCHRONOUS | SCSI_RESET_ASYNCHRONOUS)) == SCSI_RESET_SYNCHRONOUS); +#else + sts = ncr_reset_bus(np, cmd, 0); +#endif + + /* + * Since we always reset the controller, when we return success, + * we add this information to the return code. + */ +#if defined SCSI_RESET_HOST_RESET + if (sts == SCSI_RESET_SUCCESS) + sts |= SCSI_RESET_HOST_RESET; +#endif + +out: + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + ncr_flush_done_cmds(done_list); + + return sts; +} + +/* +** Linux entry point of abort() function +*/ + +int sym53c8xx_abort(Scsi_Cmnd *cmd) +{ + ncb_p np = ((struct host_data *) cmd->device->host->hostdata)->ncb; + int sts; + unsigned long flags; + Scsi_Cmnd *done_list; + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + printk("sym53c8xx_abort: pid=%lu serial_number=%ld serial_number_at_timeout=%ld\n", + cmd->pid, cmd->serial_number, cmd->serial_number_at_timeout); +#else + printk("sym53c8xx_abort: command pid %lu\n", cmd->pid); +#endif + + NCR_LOCK_NCB(np, flags); + +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + /* + * We have to just ignore abort requests in some situations. + */ + if (cmd->serial_number != cmd->serial_number_at_timeout) { + sts = SCSI_ABORT_NOT_RUNNING; + goto out; + } +#endif + + sts = ncr_abort_command(np, cmd); +out: + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + ncr_flush_done_cmds(done_list); + + return sts; +} + + +int sym53c8xx_release(struct Scsi_Host *host) +{ +#ifdef DEBUG_SYM53C8XX +printk("sym53c8xx : release\n"); +#endif + ncr_detach(((struct host_data *) host->hostdata)->ncb); + + return 1; +} + + +/* +** Scsi command waiting list management. +** +** It may happen that we cannot insert a scsi command into the start queue, +** in the following circumstances. +** Too few preallocated ccb(s), +** maxtags < cmd_per_lun of the Linux host control block, +** etc... +** Such scsi commands are inserted into a waiting list. +** When a scsi command complete, we try to requeue the commands of the +** waiting list. +*/ + +#define next_wcmd host_scribble + +static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd) +{ + Scsi_Cmnd *wcmd; + +#ifdef DEBUG_WAITING_LIST + printk("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd); +#endif + cmd->next_wcmd = 0; + if (!(wcmd = np->waiting_list)) np->waiting_list = cmd; + else { + while ((wcmd->next_wcmd) != 0) + wcmd = (Scsi_Cmnd *) wcmd->next_wcmd; + wcmd->next_wcmd = (char *) cmd; + } +} + +static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd) +{ + Scsi_Cmnd **pcmd = &np->waiting_list; + + while (*pcmd) { + if (cmd == *pcmd) { + if (to_remove) { + *pcmd = (Scsi_Cmnd *) cmd->next_wcmd; + cmd->next_wcmd = 0; + } +#ifdef DEBUG_WAITING_LIST + printk("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd); +#endif + return cmd; + } + pcmd = (Scsi_Cmnd **) &(*pcmd)->next_wcmd; + } + return 0; +} + +static void process_waiting_list(ncb_p np, int sts) +{ + Scsi_Cmnd *waiting_list, *wcmd; + + waiting_list = np->waiting_list; + np->waiting_list = 0; + +#ifdef DEBUG_WAITING_LIST + if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts); +#endif + while ((wcmd = waiting_list) != 0) { + waiting_list = (Scsi_Cmnd *) wcmd->next_wcmd; + wcmd->next_wcmd = 0; + if (sts == DID_OK) { +#ifdef DEBUG_WAITING_LIST + printk("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd); +#endif + sts = ncr_queue_command(np, wcmd); + } + if (sts != DID_OK) { +#ifdef DEBUG_WAITING_LIST + printk("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts); +#endif + SetScsiResult(wcmd, sts, 0); + ncr_queue_done_cmd(np, wcmd); + } + } +} + +#undef next_wcmd + +#ifdef SCSI_NCR_PROC_INFO_SUPPORT + +/*========================================================================= +** Proc file system stuff +** +** A read operation returns adapter information. +** A write operation is a control command. +** The string is parsed in the driver code and the command is passed +** to the ncr_usercmd() function. +**========================================================================= +*/ + +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT + +#define is_digit(c) ((c) >= '0' && (c) <= '9') +#define digit_to_bin(c) ((c) - '0') +#define is_space(c) ((c) == ' ' || (c) == '\t') + +static int skip_spaces(char *ptr, int len) +{ + int cnt, c; + + for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt--); + + return (len - cnt); +} + +static int get_int_arg(char *ptr, int len, u_long *pv) +{ + int cnt, c; + u_long v; + + for (v = 0, cnt = len; cnt > 0 && (c = *ptr++) && is_digit(c); cnt--) { + v = (v * 10) + digit_to_bin(c); + } + + if (pv) + *pv = v; + + return (len - cnt); +} + +static int is_keyword(char *ptr, int len, char *verb) +{ + int verb_len = strlen(verb); + + if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len)) + return verb_len; + else + return 0; + +} + +#define SKIP_SPACES(min_spaces) \ + if ((arg_len = skip_spaces(ptr, len)) < (min_spaces)) \ + return -EINVAL; \ + ptr += arg_len; len -= arg_len; + +#define GET_INT_ARG(v) \ + if (!(arg_len = get_int_arg(ptr, len, &(v)))) \ + return -EINVAL; \ + ptr += arg_len; len -= arg_len; + + +/* +** Parse a control command +*/ + +static int ncr_user_command(ncb_p np, char *buffer, int length) +{ + char *ptr = buffer; + int len = length; + struct usrcmd *uc = &np->user; + int arg_len; + u_long target; + + bzero(uc, sizeof(*uc)); + + if (len > 0 && ptr[len-1] == '\n') + --len; + + if ((arg_len = is_keyword(ptr, len, "setsync")) != 0) + uc->cmd = UC_SETSYNC; + else if ((arg_len = is_keyword(ptr, len, "settags")) != 0) + uc->cmd = UC_SETTAGS; + else if ((arg_len = is_keyword(ptr, len, "setorder")) != 0) + uc->cmd = UC_SETORDER; + else if ((arg_len = is_keyword(ptr, len, "setverbose")) != 0) + uc->cmd = UC_SETVERBOSE; + else if ((arg_len = is_keyword(ptr, len, "setwide")) != 0) + uc->cmd = UC_SETWIDE; + else if ((arg_len = is_keyword(ptr, len, "setdebug")) != 0) + uc->cmd = UC_SETDEBUG; + else if ((arg_len = is_keyword(ptr, len, "setflag")) != 0) + uc->cmd = UC_SETFLAG; + else if ((arg_len = is_keyword(ptr, len, "resetdev")) != 0) + uc->cmd = UC_RESETDEV; + else if ((arg_len = is_keyword(ptr, len, "cleardev")) != 0) + uc->cmd = UC_CLEARDEV; + else + arg_len = 0; + +#ifdef DEBUG_PROC_INFO +printk("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd); +#endif + + if (!arg_len) + return -EINVAL; + ptr += arg_len; len -= arg_len; + + switch(uc->cmd) { + case UC_SETSYNC: + case UC_SETTAGS: + case UC_SETWIDE: + case UC_SETFLAG: + case UC_RESETDEV: + case UC_CLEARDEV: + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "all")) != 0) { + ptr += arg_len; len -= arg_len; + uc->target = ~0; + } else { + GET_INT_ARG(target); + uc->target = (1<cmd) { + case UC_SETVERBOSE: + case UC_SETSYNC: + case UC_SETTAGS: + case UC_SETWIDE: + SKIP_SPACES(1); + GET_INT_ARG(uc->data); +#ifdef DEBUG_PROC_INFO +printk("ncr_user_command: data=%ld\n", uc->data); +#endif + break; + case UC_SETORDER: + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "simple"))) + uc->data = M_SIMPLE_TAG; + else if ((arg_len = is_keyword(ptr, len, "ordered"))) + uc->data = M_ORDERED_TAG; + else if ((arg_len = is_keyword(ptr, len, "default"))) + uc->data = 0; + else + return -EINVAL; + break; + case UC_SETDEBUG: + while (len > 0) { + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "alloc"))) + uc->data |= DEBUG_ALLOC; + else if ((arg_len = is_keyword(ptr, len, "phase"))) + uc->data |= DEBUG_PHASE; + else if ((arg_len = is_keyword(ptr, len, "queue"))) + uc->data |= DEBUG_QUEUE; + else if ((arg_len = is_keyword(ptr, len, "result"))) + uc->data |= DEBUG_RESULT; + else if ((arg_len = is_keyword(ptr, len, "pointer"))) + uc->data |= DEBUG_POINTER; + else if ((arg_len = is_keyword(ptr, len, "script"))) + uc->data |= DEBUG_SCRIPT; + else if ((arg_len = is_keyword(ptr, len, "tiny"))) + uc->data |= DEBUG_TINY; + else if ((arg_len = is_keyword(ptr, len, "timing"))) + uc->data |= DEBUG_TIMING; + else if ((arg_len = is_keyword(ptr, len, "nego"))) + uc->data |= DEBUG_NEGO; + else if ((arg_len = is_keyword(ptr, len, "tags"))) + uc->data |= DEBUG_TAGS; + else + return -EINVAL; + ptr += arg_len; len -= arg_len; + } +#ifdef DEBUG_PROC_INFO +printk("ncr_user_command: data=%ld\n", uc->data); +#endif + break; + case UC_SETFLAG: + while (len > 0) { + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "trace"))) + uc->data |= UF_TRACE; + else if ((arg_len = is_keyword(ptr, len, "no_disc"))) + uc->data |= UF_NODISC; + else + return -EINVAL; + ptr += arg_len; len -= arg_len; + } + break; + default: + break; + } + + if (len) + return -EINVAL; + else { + unsigned long flags; + + NCR_LOCK_NCB(np, flags); + ncr_usercmd (np); + NCR_UNLOCK_NCB(np, flags); + } + return length; +} + +#endif /* SCSI_NCR_USER_COMMAND_SUPPORT */ + +#ifdef SCSI_NCR_USER_INFO_SUPPORT + +struct info_str +{ + char *buffer; + int length; + int offset; + int pos; +}; + +static void copy_mem_info(struct info_str *info, char *data, int len) +{ + if (info->pos + len > info->length) + len = info->length - info->pos; + + if (info->pos + len < info->offset) { + info->pos += len; + return; + } + if (info->pos < info->offset) { + data += (info->offset - info->pos); + len -= (info->offset - info->pos); + } + + if (len > 0) { + memcpy(info->buffer + info->pos, data, len); + info->pos += len; + } +} + +static int copy_info(struct info_str *info, char *fmt, ...) +{ + va_list args; + char buf[81]; + int len; + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + copy_mem_info(info, buf, len); + return len; +} + +/* +** Copy formatted information into the input buffer. +*/ + +static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) +{ + struct info_str info; + + info.buffer = ptr; + info.length = len; + info.offset = offset; + info.pos = 0; + + copy_info(&info, "General information:\n"); + copy_info(&info, " Chip " NAME53C "%s, device id 0x%x, " + "revision id 0x%x\n", + np->chip_name, np->device_id, np->revision_id); + copy_info(&info, " On PCI bus %d, device %d, function %d, " +#ifdef __sparc__ + "IRQ %s\n", +#else + "IRQ %d\n", +#endif + np->bus, (np->device_fn & 0xf8) >> 3, np->device_fn & 7, +#ifdef __sparc__ + __irq_itoa(np->irq)); +#else + (int) np->irq); +#endif + copy_info(&info, " Synchronous period factor %d, " + "max commands per lun %d\n", + (int) np->minsync, MAX_TAGS); + + if (driver_setup.debug || driver_setup.verbose > 1) { + copy_info(&info, " Debug flags 0x%x, verbosity level %d\n", + driver_setup.debug, driver_setup.verbose); + } + + return info.pos > info.offset? info.pos - info.offset : 0; +} + +#endif /* SCSI_NCR_USER_INFO_SUPPORT */ + +/* +** Entry point of the scsi proc fs of the driver. +** - func = 0 means read (returns adapter infos) +** - func = 1 means write (parse user control command) +*/ + +static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int func) +{ + struct host_data *host_data; + ncb_p ncb = 0; + int retv; + +#ifdef DEBUG_PROC_INFO +printk("sym53c8xx_proc_info: hostno=%d, func=%d\n", host->host_no, func); +#endif + + host_data = (struct host_data *) host->hostdata; + ncb = host_data->ncb; + retv = -EINVAL; + if (!ncb) + goto out; + + if (func) { +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT + retv = ncr_user_command(ncb, buffer, length); +#endif + } else { + if (start) + *start = buffer; +#ifdef SCSI_NCR_USER_INFO_SUPPORT + retv = ncr_host_info(ncb, buffer, offset, length); +#endif + } + +out: + return retv; +} + + +/*========================================================================= +** End of proc file system stuff +**========================================================================= +*/ +#endif + + +#ifdef SCSI_NCR_NVRAM_SUPPORT + +/* + * 24C16 EEPROM reading. + * + * GPOI0 - data in/data out + * GPIO1 - clock + * Symbios NVRAM wiring now also used by Tekram. + */ + +#define SET_BIT 0 +#define CLR_BIT 1 +#define SET_CLK 2 +#define CLR_CLK 3 + +/* + * Set/clear data/clock bit in GPIO0 + */ +static void __init +S24C16_set_bit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode) +{ + UDELAY (5); + switch (bit_mode){ + case SET_BIT: + *gpreg |= write_bit; + break; + case CLR_BIT: + *gpreg &= 0xfe; + break; + case SET_CLK: + *gpreg |= 0x02; + break; + case CLR_CLK: + *gpreg &= 0xfd; + break; + + } + OUTB (nc_gpreg, *gpreg); + UDELAY (5); +} + +/* + * Send START condition to NVRAM to wake it up. + */ +static void __init S24C16_start(ncr_slot *np, u_char *gpreg) +{ + S24C16_set_bit(np, 1, gpreg, SET_BIT); + S24C16_set_bit(np, 0, gpreg, SET_CLK); + S24C16_set_bit(np, 0, gpreg, CLR_BIT); + S24C16_set_bit(np, 0, gpreg, CLR_CLK); +} + +/* + * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!! + */ +static void __init S24C16_stop(ncr_slot *np, u_char *gpreg) +{ + S24C16_set_bit(np, 0, gpreg, SET_CLK); + S24C16_set_bit(np, 1, gpreg, SET_BIT); +} + +/* + * Read or write a bit to the NVRAM, + * read if GPIO0 input else write if GPIO0 output + */ +static void __init +S24C16_do_bit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg) +{ + S24C16_set_bit(np, write_bit, gpreg, SET_BIT); + S24C16_set_bit(np, 0, gpreg, SET_CLK); + if (read_bit) + *read_bit = INB (nc_gpreg); + S24C16_set_bit(np, 0, gpreg, CLR_CLK); + S24C16_set_bit(np, 0, gpreg, CLR_BIT); +} + +/* + * Output an ACK to the NVRAM after reading, + * change GPIO0 to output and when done back to an input + */ +static void __init +S24C16_write_ack(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl) +{ + OUTB (nc_gpcntl, *gpcntl & 0xfe); + S24C16_do_bit(np, 0, write_bit, gpreg); + OUTB (nc_gpcntl, *gpcntl); +} + +/* + * Input an ACK from NVRAM after writing, + * change GPIO0 to input and when done back to an output + */ +static void __init +S24C16_read_ack(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl) +{ + OUTB (nc_gpcntl, *gpcntl | 0x01); + S24C16_do_bit(np, read_bit, 1, gpreg); + OUTB (nc_gpcntl, *gpcntl); +} + +/* + * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK, + * GPIO0 must already be set as an output + */ +static void __init +S24C16_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, + u_char *gpreg, u_char *gpcntl) +{ + int x; + + for (x = 0; x < 8; x++) + S24C16_do_bit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg); + + S24C16_read_ack(np, ack_data, gpreg, gpcntl); +} + +/* + * READ a byte from the NVRAM and then send an ACK to say we have got it, + * GPIO0 must already be set as an input + */ +static void __init +S24C16_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, + u_char *gpreg, u_char *gpcntl) +{ + int x; + u_char read_bit; + + *read_data = 0; + for (x = 0; x < 8; x++) { + S24C16_do_bit(np, &read_bit, 1, gpreg); + *read_data |= ((read_bit & 0x01) << (7 - x)); + } + + S24C16_write_ack(np, ack_data, gpreg, gpcntl); +} + +/* + * Read 'len' bytes starting at 'offset'. + */ +static int __init +sym_read_S24C16_nvram (ncr_slot *np, int offset, u_char *data, int len) +{ + u_char gpcntl, gpreg; + u_char old_gpcntl, old_gpreg; + u_char ack_data; + int retv = 1; + int x; + + /* save current state of GPCNTL and GPREG */ + old_gpreg = INB (nc_gpreg); + old_gpcntl = INB (nc_gpcntl); + gpcntl = old_gpcntl & 0x1c; + + /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ + OUTB (nc_gpreg, old_gpreg); + OUTB (nc_gpcntl, gpcntl); + + /* this is to set NVRAM into a known state with GPIO0/1 both low */ + gpreg = old_gpreg; + S24C16_set_bit(np, 0, &gpreg, CLR_CLK); + S24C16_set_bit(np, 0, &gpreg, CLR_BIT); + + /* now set NVRAM inactive with GPIO0/1 both high */ + S24C16_stop(np, &gpreg); + + /* activate NVRAM */ + S24C16_start(np, &gpreg); + + /* write device code and random address MSB */ + S24C16_write_byte(np, &ack_data, + 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); + if (ack_data & 0x01) + goto out; + + /* write random address LSB */ + S24C16_write_byte(np, &ack_data, + offset & 0xff, &gpreg, &gpcntl); + if (ack_data & 0x01) + goto out; + + /* regenerate START state to set up for reading */ + S24C16_start(np, &gpreg); + + /* rewrite device code and address MSB with read bit set (lsb = 0x01) */ + S24C16_write_byte(np, &ack_data, + 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); + if (ack_data & 0x01) + goto out; + + /* now set up GPIO0 for inputting data */ + gpcntl |= 0x01; + OUTB (nc_gpcntl, gpcntl); + + /* input all requested data - only part of total NVRAM */ + for (x = 0; x < len; x++) + S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl); + + /* finally put NVRAM back in inactive mode */ + gpcntl &= 0xfe; + OUTB (nc_gpcntl, gpcntl); + S24C16_stop(np, &gpreg); + retv = 0; +out: + /* return GPIO0/1 to original states after having accessed NVRAM */ + OUTB (nc_gpcntl, old_gpcntl); + OUTB (nc_gpreg, old_gpreg); + + return retv; +} + +#undef SET_BIT +#undef CLR_BIT +#undef SET_CLK +#undef CLR_CLK + +/* + * Try reading Symbios NVRAM. + * Return 0 if OK. + */ +static int __init sym_read_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram) +{ + static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0}; + u_char *data = (u_char *) nvram; + int len = sizeof(*nvram); + u_short csum; + int x; + + /* probe the 24c16 and read the SYMBIOS 24c16 area */ + if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len)) + return 1; + + /* check valid NVRAM signature, verify byte count and checksum */ + if (nvram->type != 0 || + memcmp(nvram->trailer, Symbios_trailer, 6) || + nvram->byte_count != len - 12) + return 1; + + /* verify checksum */ + for (x = 6, csum = 0; x < len - 6; x++) + csum += data[x]; + if (csum != nvram->checksum) + return 1; + + return 0; +} + +/* + * 93C46 EEPROM reading. + * + * GPOI0 - data in + * GPIO1 - data out + * GPIO2 - clock + * GPIO4 - chip select + * + * Used by Tekram. + */ + +/* + * Pulse clock bit in GPIO0 + */ +static void __init T93C46_Clk(ncr_slot *np, u_char *gpreg) +{ + OUTB (nc_gpreg, *gpreg | 0x04); + UDELAY (2); + OUTB (nc_gpreg, *gpreg); +} + +/* + * Read bit from NVRAM + */ +static void __init T93C46_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg) +{ + UDELAY (2); + T93C46_Clk(np, gpreg); + *read_bit = INB (nc_gpreg); +} + +/* + * Write bit to GPIO0 + */ +static void __init T93C46_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg) +{ + if (write_bit & 0x01) + *gpreg |= 0x02; + else + *gpreg &= 0xfd; + + *gpreg |= 0x10; + + OUTB (nc_gpreg, *gpreg); + UDELAY (2); + + T93C46_Clk(np, gpreg); +} + +/* + * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!! + */ +static void __init T93C46_Stop(ncr_slot *np, u_char *gpreg) +{ + *gpreg &= 0xef; + OUTB (nc_gpreg, *gpreg); + UDELAY (2); + + T93C46_Clk(np, gpreg); +} + +/* + * Send read command and address to NVRAM + */ +static void __init +T93C46_Send_Command(ncr_slot *np, u_short write_data, + u_char *read_bit, u_char *gpreg) +{ + int x; + + /* send 9 bits, start bit (1), command (2), address (6) */ + for (x = 0; x < 9; x++) + T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg); + + *read_bit = INB (nc_gpreg); +} + +/* + * READ 2 bytes from the NVRAM + */ +static void __init +T93C46_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg) +{ + int x; + u_char read_bit; + + *nvram_data = 0; + for (x = 0; x < 16; x++) { + T93C46_Read_Bit(np, &read_bit, gpreg); + + if (read_bit & 0x01) + *nvram_data |= (0x01 << (15 - x)); + else + *nvram_data &= ~(0x01 << (15 - x)); + } +} + +/* + * Read Tekram NvRAM data. + */ +static int __init +T93C46_Read_Data(ncr_slot *np, u_short *data,int len,u_char *gpreg) +{ + u_char read_bit; + int x; + + for (x = 0; x < len; x++) { + + /* output read command and address */ + T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg); + if (read_bit & 0x01) + return 1; /* Bad */ + T93C46_Read_Word(np, &data[x], gpreg); + T93C46_Stop(np, gpreg); + } + + return 0; +} + +/* + * Try reading 93C46 Tekram NVRAM. + */ +static int __init +sym_read_T93C46_nvram (ncr_slot *np, Tekram_nvram *nvram) +{ + u_char gpcntl, gpreg; + u_char old_gpcntl, old_gpreg; + int retv = 1; + + /* save current state of GPCNTL and GPREG */ + old_gpreg = INB (nc_gpreg); + old_gpcntl = INB (nc_gpcntl); + + /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in, + 1/2/4 out */ + gpreg = old_gpreg & 0xe9; + OUTB (nc_gpreg, gpreg); + gpcntl = (old_gpcntl & 0xe9) | 0x09; + OUTB (nc_gpcntl, gpcntl); + + /* input all of NVRAM, 64 words */ + retv = T93C46_Read_Data(np, (u_short *) nvram, + sizeof(*nvram) / sizeof(short), &gpreg); + + /* return GPIO0/1/2/4 to original states after having accessed NVRAM */ + OUTB (nc_gpcntl, old_gpcntl); + OUTB (nc_gpreg, old_gpreg); + + return retv; +} + +/* + * Try reading Tekram NVRAM. + * Return 0 if OK. + */ +static int __init +sym_read_Tekram_nvram (ncr_slot *np, u_short device_id, Tekram_nvram *nvram) +{ + u_char *data = (u_char *) nvram; + int len = sizeof(*nvram); + u_short csum; + int x; + + switch (device_id) { + case PCI_DEVICE_ID_NCR_53C885: + case PCI_DEVICE_ID_NCR_53C895: + case PCI_DEVICE_ID_NCR_53C896: + x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, + data, len); + break; + case PCI_DEVICE_ID_NCR_53C875: + x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, + data, len); + if (!x) + break; + default: + x = sym_read_T93C46_nvram(np, nvram); + break; + } + if (x) + return 1; + + /* verify checksum */ + for (x = 0, csum = 0; x < len - 1; x += 2) + csum += data[x] + (data[x+1] << 8); + if (csum != 0x1234) + return 1; + + return 0; +} + +#endif /* SCSI_NCR_NVRAM_SUPPORT */ + +/* +** Module stuff +*/ + +MODULE_LICENSE("GPL"); + +static Scsi_Host_Template driver_template = { + .name = "sym53c8xx", + .detect = sym53c8xx_detect, + .release = sym53c8xx_release, + .info = sym53c8xx_info, + .queuecommand = sym53c8xx_queue_command, + .slave_configure = sym53c8xx_slave_configure, + .abort = sym53c8xx_abort, + .reset = sym53c8xx_reset, + .can_queue = SCSI_NCR_CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SCSI_NCR_SG_TABLESIZE, + .cmd_per_lun = SCSI_NCR_CMD_PER_LUN, + .max_sectors = MAX_HW_SEGMENTS*8, + .use_clustering = DISABLE_CLUSTERING, + .highmem_io = 1 +}; +#include "scsi_module.c" diff --git a/demos/foo.c b/demos/foo.c new file mode 100644 index 0000000..a50d483 --- /dev/null +++ b/demos/foo.c @@ -0,0 +1,8 @@ +void main() +{ + g(); + foo(); + g(); + foo(); + +} diff --git a/demos/foo.cocci b/demos/foo.cocci new file mode 100644 index 0000000..932f741 --- /dev/null +++ b/demos/foo.cocci @@ -0,0 +1,4 @@ +@@ +@@ + +- foo(); \ No newline at end of file diff --git a/demos/foobar.c b/demos/foobar.c new file mode 100644 index 0000000..27ede13 --- /dev/null +++ b/demos/foobar.c @@ -0,0 +1,13 @@ +// cf first slide of OLS + +void main (int x) { + foo(1); + h("toto"); + foo(2); + foo(foo(2)); + + if(foo(3)) { + int foo; + do_something(foo); + } +} diff --git a/demos/foobar.cocci b/demos/foobar.cocci new file mode 100644 index 0000000..8246ff0 --- /dev/null +++ b/demos/foobar.cocci @@ -0,0 +1,14 @@ +@@ @@ + +- foo ++ bar + (...) + +// @@ @@ +// - foo +// + bar + +//@@ expression list XS; @@ +// +//- foo(XS) +//+ bar(XS) \ No newline at end of file diff --git a/demos/headers.cocci b/demos/headers.cocci new file mode 100644 index 0000000..cd7c591 --- /dev/null +++ b/demos/headers.cocci @@ -0,0 +1,54 @@ +// This file illustrates the various items that can be used at the beginning +// of a semantic patch, or at the beginning of a rule + +// The following illustrates how to include a file of isomorphisms located +// in the default path, as indicated by config. Uncommenting the following +// will give and error, because standard.iso is already loaded by default +// and it is not allowed to load two isomorphisms with the same name +// using +using "headers.iso" // an iso file in the current directory + +@ rule0 @ +@@ + +- a ++ b + +@ +rule1 // rule name +extends rule0 // inherit the metavariables from rule0 +depends on rule0 && !rule0 // now this rule will never be applied ... +using "headers2.iso" // more iso files can be included, separated by commas +disable three, drop_cast // isos should apply to f and x, but not m +@ +@@ + +( +- f(3) ++ fff(12) +| +- x(3) ++ xxx(12) +| +- m(3) ++ mmm(12) +) + +@ +rule2 // rule name +extends rule0 // inherit the metavariables from rule0 +depends on rule0 && !rule0 // now this rule will never be applied ... +using "headers2.iso" // more iso files can be included, separated by commas +@ +@@ + +( +- f(3) ++ fff(12) +| +- x(3) ++ xxx(12) +| +- m(3) ++ mmm(12) +) diff --git a/demos/headers.iso b/demos/headers.iso new file mode 100644 index 0000000..b9ec4fe --- /dev/null +++ b/demos/headers.iso @@ -0,0 +1,6 @@ +Expression +@ one @ +expression E; +@@ + +f(E) => g(E) diff --git a/demos/headers2.iso b/demos/headers2.iso new file mode 100644 index 0000000..8915220 --- /dev/null +++ b/demos/headers2.iso @@ -0,0 +1,13 @@ +Expression +@ two @ +expression E; +@@ + +x(E) => y(E) + +Expression +@ three @ +expression E; +@@ + +m(E) => n(E) diff --git a/demos/interprocedural_adhoc.c b/demos/interprocedural_adhoc.c new file mode 100644 index 0000000..011a051 --- /dev/null +++ b/demos/interprocedural_adhoc.c @@ -0,0 +1,30 @@ + +void ioctl(int i) +{ + + g(1); + h(2); + w(3); + z(4); + +} + + + + + +void g(int i) { + bar(1); +} + +void h(int i) { + bar(1); +} + +void w(int i) { + bar(1); +} + +void z(int i) { + bar(1); +} diff --git a/demos/interprocedural_adhoc.cocci b/demos/interprocedural_adhoc.cocci new file mode 100644 index 0000000..a8c726d --- /dev/null +++ b/demos/interprocedural_adhoc.cocci @@ -0,0 +1,28 @@ +// Even if our analysis does not go through nodes containing +// funcall, we can still do some (limited) interprocedural modification. + +@ rule1 @ +identifier foo; +@@ + + +ioctl (...) { + ... + foo(3); + ... +} + + + +@@ +identifier rule1.foo; +@@ + + +foo(...) +{ + +- bar(1); ++ bar(2); + +} \ No newline at end of file diff --git a/demos/ioctl_multiple_rules.c b/demos/ioctl_multiple_rules.c new file mode 100644 index 0000000..d366b9c --- /dev/null +++ b/demos/ioctl_multiple_rules.c @@ -0,0 +1,23 @@ + + +struct file_operations fops; + +void init(int i) +{ + + fops.ioctl = my_ioctl; +} + + + +void my_ioctl(int i) +{ + foo(1); +} + + + +void not_ioctl(int i) +{ + foo(1); +} diff --git a/demos/ioctl_multiple_rules.cocci b/demos/ioctl_multiple_rules.cocci new file mode 100644 index 0000000..2a0aae4 --- /dev/null +++ b/demos/ioctl_multiple_rules.cocci @@ -0,0 +1,21 @@ +// can constraint to specific function by using multiple rules + +@ rule1 @ +struct file_operations x; +identifier ioctl_fn; +@@ + +x.ioctl = ioctl_fn; + + +@@ +identifier rule1.ioctl_fn; +@@ + + ioctl_fn(...) +{ + +- foo(1); ++ foo(2); +} + diff --git a/demos/iso-kzalloc.c b/demos/iso-kzalloc.c new file mode 100644 index 0000000..b0c63bd --- /dev/null +++ b/demos/iso-kzalloc.c @@ -0,0 +1,7 @@ +void main(int i) +{ + + kzalloc(2 * sizeof(int), GFP_KERNEL); + kzalloc(sizeof(int) * 2, GFP_KERNEL); + +} diff --git a/demos/iso-kzalloc.cocci b/demos/iso-kzalloc.cocci new file mode 100644 index 0000000..bdce179 --- /dev/null +++ b/demos/iso-kzalloc.cocci @@ -0,0 +1,10 @@ +// A*B is not just a toy isomorphism :) it's really useful sometimes. + +@@ +expression E; +constant c; +type T; +@@ + +-kzalloc(c * sizeof(T), E) ++kcalloc(c, sizeof(T), E) diff --git a/demos/itimer.c b/demos/itimer.c new file mode 100644 index 0000000..ff3e196 --- /dev/null +++ b/demos/itimer.c @@ -0,0 +1,30 @@ +int do_setitimer(int which, struct itimerval *value, + struct itimerval *ovalue) +{ + unsigned long expire; + cputime_t cputime; + int k; + if (ovalue && (k = do_getitimer(which, ovalue)) < 0) + return k; + switch (which) { + case ITIMER_VIRTUAL: + cputime = timeval_to_cputime(&value->it_value); + if (cputime_eq(cputime, cputime_zero)) + cputime = jiffies_to_cputime(1); + current->it_virt_value = cputime; + cputime = timeval_to_cputime(&value->it_interval); + current->it_virt_incr = cputime; + break; + case ITIMER_PROF: + cputime = timeval_to_cputime(&value->it_value); + if (cputime_eq(cputime, cputime_zero)) + cputime = jiffies_to_cputime(1); + current->it_prof_value = cputime; + cputime = timeval_to_cputime(&value->it_interval); + current->it_prof_incr = cputime; + break; + default: + return -EINVAL; + } + return 0; +} diff --git a/demos/itimer.cocci b/demos/itimer.cocci new file mode 100644 index 0000000..632ceec --- /dev/null +++ b/demos/itimer.cocci @@ -0,0 +1,8 @@ +@@ +@@ + +- if (cputime_eq(cputime, cputime_zero)) +- cputime = jiffies_to_cputime(1); ++ if (cputime_gt(cputime, cputime_zero)) ++ cputime = cputime_add(cputime, ++ jiffies_to_cputime(1)); diff --git a/demos/itimer.patch b/demos/itimer.patch new file mode 100644 index 0000000..3fb19c7 --- /dev/null +++ b/demos/itimer.patch @@ -0,0 +1,36 @@ + int do_setitimer(int which, struct itimerval *value, + struct itimerval *ovalue) +{ + unsigned long expire; + cputime_t cputime; + int k; + if (ovalue && (k = do_getitimer(which, ovalue)) < 0) + return k; + switch (which) { + case ITIMER_VIRTUAL: + cputime = timeval_to_cputime(&value->it_value); +- if (cputime_eq(cputime, cputime_zero)) +- cputime = jiffies_to_cputime(1); ++ if (cputime_gt(cputime, cputime_zero)) ++ cputime = cputime_add(cputime, ++ jiffies_to_cputime(1)); + current->it_virt_value = cputime; + cputime = timeval_to_cputime(&value->it_interval); + current->it_virt_incr = cputime; + break; + case ITIMER_PROF: + cputime = timeval_to_cputime(&value->it_value); +- if (cputime_eq(cputime, cputime_zero)) +- cputime = jiffies_to_cputime(1); ++ if (cputime_gt(cputime, cputime_zero)) ++ cputime = cputime_add(cputime, ++ jiffies_to_cputime(1)); + current->it_prof_value = cputime; + cputime = timeval_to_cputime(&value->it_interval); + current->it_prof_incr = cputime; + break; + default: + return -EINVAL; + } + return 0; +} \ No newline at end of file diff --git a/demos/itimer.res b/demos/itimer.res new file mode 100644 index 0000000..4a4f206 --- /dev/null +++ b/demos/itimer.res @@ -0,0 +1,32 @@ + int do_setitimer(int which, struct itimerval *value, + struct itimerval *ovalue) +{ + unsigned long expire; + cputime_t cputime; + int k; + if (ovalue && (k = do_getitimer(which, ovalue)) < 0) + return k; + switch (which) { + case ITIMER_VIRTUAL: + cputime = timeval_to_cputime(&value->it_value); + if (cputime_gt(cputime, cputime_zero)) + cputime = cputime_add(cputime, + jiffies_to_cputime(1)); + current->it_virt_value = cputime; + cputime = timeval_to_cputime(&value->it_interval); + current->it_virt_incr = cputime; + break; + case ITIMER_PROF: + cputime = timeval_to_cputime(&value->it_value); + if (cputime_gt(cputime, cputime_zero)) + cputime = cputime_add(cputime, + jiffies_to_cputime(1)); + current->it_prof_value = cputime; + cputime = timeval_to_cputime(&value->it_interval); + current->it_prof_incr = cputime; + break; + default: + return -EINVAL; + } + return 0; +} \ No newline at end of file diff --git a/demos/itimerfullfunc.sgrep b/demos/itimerfullfunc.sgrep new file mode 100644 index 0000000..a641bdc --- /dev/null +++ b/demos/itimerfullfunc.sgrep @@ -0,0 +1,37 @@ +// ex 2.1 +@@ +@@ + +int do_setitimer(int which, struct itimerval *value, + struct itimerval *ovalue) +{ + unsigned long expire; + cputime_t cputime; + int k; + if (ovalue && (k = do_getitimer(which, ovalue)) < 0) + return k; + switch (which) { + // work even when reversed case + case ITIMER_PROF: + cputime = timeval_to_cputime(&value->it_value); + if (cputime_eq(cputime, cputime_zero)) + cputime = jiffies_to_cputime(1); + current->it_prof_value = cputime; + cputime = timeval_to_cputime(&value->it_interval); +- current->it_prof_incr = cputime; ++ B; + break; + case ITIMER_VIRTUAL: + cputime = timeval_to_cputime(&value->it_value); + if (cputime_eq(cputime, cputime_zero)) + cputime = jiffies_to_cputime(1); + current->it_virt_value = cputime; +- cputime = timeval_to_cputime(&value->it_interval); ++ A; + current->it_virt_incr = cputime; + break; + default: + return -EINVAL; + } + return 0; +} diff --git a/demos/janitorings/ARRAY_SIZE.cocci b/demos/janitorings/ARRAY_SIZE.cocci new file mode 100644 index 0000000..bf593bf --- /dev/null +++ b/demos/janitorings/ARRAY_SIZE.cocci @@ -0,0 +1,106 @@ +// empty.iso is used because there is an iso that converts sizeof(E) to +// sizeof E, which causes a double match in an expression, and thus a +// double modification + +@ rule1 using "empty.iso" @ +expression E; +@@ + +- (sizeof(E)/sizeof(*E)) ++ ARRAY_SIZE(E) + +@ rule2 using "empty.iso" @ +expression E; +@@ + +- sizeof(E)/sizeof(*E) ++ ARRAY_SIZE(E) + +@ rule3 using "empty.iso" @ +expression E, E1; +@@ + +- (sizeof(E)/sizeof(E[E1])) ++ ARRAY_SIZE(E) + +@ rule4 using "empty.iso" @ +expression E, E1; +@@ + +- sizeof(E)/sizeof(E[E1]) ++ ARRAY_SIZE(E) + +@ rule5 using "empty.iso" @ +type T; +T[] E; +@@ + +- (sizeof(E)/sizeof(T)) ++ ARRAY_SIZE(E) + +@ rule6 using "empty.iso" @ +type T; +T[] E; +@@ + +- sizeof(E)/sizeof(T) ++ ARRAY_SIZE(E) + +// --------------------------------------------------------------------------- +// some of the above rules with more parentheses +// this can't be done with an isomorphism, as described above + +@ rule1p using "empty.iso" @ +expression E; +@@ + +- (sizeof(E)/sizeof(*(E))) ++ ARRAY_SIZE(E) + +@ rule2p using "empty.iso" @ +expression E; +@@ + +- sizeof(E)/sizeof(*(E)) ++ ARRAY_SIZE(E) + +@ rule3p using "empty.iso" @ +expression E, E1; +@@ + +- (sizeof(E)/sizeof((E)[E1])) ++ ARRAY_SIZE(E) + +@ rule4p using "empty.iso" @ +expression E, E1; +@@ + +- sizeof(E)/sizeof((E)[E1]) ++ ARRAY_SIZE(E) + +// --------------------------------------------------------------------------- +@@ expression E; @@ + +- NUM_ELEMENTS(E) ++ ARRAY_SIZE(E) + +@ rule53 @ +identifier NUM, x; +@@ + +- #define NUM(x) ARRAY_SIZE(x) + +@@ +expression E; +identifier rule53.NUM; +@@ + +- NUM(E) ++ ARRAY_SIZE(E) + +@@ +expression E; +@@ + +- ((int)ARRAY_SIZE(E)) ++ ARRAY_SIZE(E) diff --git a/demos/janitorings/BUG_ON.cocci b/demos/janitorings/BUG_ON.cocci new file mode 100644 index 0000000..1788110 --- /dev/null +++ b/demos/janitorings/BUG_ON.cocci @@ -0,0 +1,18 @@ +// is also mega10.cocci + + +@@ expression E; @@ + +// super unreadable, but we don't want the isomorphism to apply, because then +// two bindings of E drift up to the top + +- if (unlikely( ++ BUG_ON( + E ++ ); +- )) { BUG(); } + +@@ expression E; @@ + +- if (E) { BUG(); } ++ BUG_ON(E); diff --git a/demos/janitorings/BUG_ON.sgrep b/demos/janitorings/BUG_ON.sgrep new file mode 100644 index 0000000..d310451 --- /dev/null +++ b/demos/janitorings/BUG_ON.sgrep @@ -0,0 +1,3 @@ +@@ +@@ +- BUG() diff --git a/demos/janitorings/alloc_page.cocci b/demos/janitorings/alloc_page.cocci new file mode 100644 index 0000000..73f4de9 --- /dev/null +++ b/demos/janitorings/alloc_page.cocci @@ -0,0 +1,35 @@ +// From: Shani Moideen +// Subject: [KJ] [KJ PATCH] Replacing alloc_pages(gfp, +// 0) with alloc_page(gfp) in net/core/sock.c +// To: jgarzik@pobox.com, akpm@linux-foundation.org +// Cc: netdev@vger.kernel.org, kernel-janitors@lists.osdl.org +// Date: Wed, 13 Jun 2007 08:16:42 +0530 +// Organization: Linux COE, Wipro Technolgies +// +// +// Replacing alloc_pages(gfp,0) with alloc_page(gfp) +// in net/core/sock.c +// +// Signed-off-by: Shani Moideen +// ---- +// +// diff --git a/net/core/sock.c b/net/core/sock.c +// index 22183c2..25bb52b 100644 +// --- a/net/core/sock.c +// +++ b/net/core/sock.c +// @@ -1193,7 +1193,7 @@ static struct sk_buff *sock_alloc_send_pskb(struct sock *sk, +// struct page *page; +// skb_frag_t *frag; +// +// - page = alloc_pages(sk->sk_allocation, 0); +// + page = alloc_page(sk->sk_allocation); +// if (!page) { +// err = -ENOBUFS; +// skb_shinfo(skb)->nr_frags = i; + +@@ +expression X; +@@ + +- alloc_pages(X, 0) ++ alloc_page(X) \ No newline at end of file diff --git a/demos/janitorings/bad_zero-orig.cocci b/demos/janitorings/bad_zero-orig.cocci new file mode 100644 index 0000000..818fc1a --- /dev/null +++ b/demos/janitorings/bad_zero-orig.cocci @@ -0,0 +1,33 @@ + +@@ +expression *E; +@@ + + E == +- 0 ++ NULL + +@@ +expression *E; +@@ + +- 0 ++ NULL + == E + +@@ +expression *E; +@@ + + E != +- 0 ++ NULL + +@@ +expression *E; +@@ + +- 0 ++ NULL + != E + diff --git a/demos/janitorings/bad_zero.c b/demos/janitorings/bad_zero.c new file mode 100644 index 0000000..753a382 --- /dev/null +++ b/demos/janitorings/bad_zero.c @@ -0,0 +1,10 @@ +void main(int i) +{ + struct netdev *bc; + + if ((bc = ch->brdchan) == 0) { + tty->driver_data = NULL; + return -ENODEV; + } + +} diff --git a/demos/janitorings/bad_zero.cocci b/demos/janitorings/bad_zero.cocci new file mode 100644 index 0000000..79c68f1 --- /dev/null +++ b/demos/janitorings/bad_zero.cocci @@ -0,0 +1,51 @@ + +@ disable is_zero @ +expression *E; +@@ + + E == +- 0 ++ NULL + +@ disable is_zero @ +expression *E; +@@ + +- 0 ++ NULL + == E + +@ disable isnt_zero @ +expression *E; +@@ + + E != +- 0 ++ NULL + +@ disable isnt_zero @ +expression *E; +@@ + +- 0 ++ NULL + != E + + +@@ +identifier *X; +statement S; +@@ + +- if(X == NULL) ++ if(!X) + S + +@@ +identifier *X; +statement S; +@@ + +- if(X != NULL) ++ if(X) + S diff --git a/demos/janitorings/bad_zero_affect.cocci b/demos/janitorings/bad_zero_affect.cocci new file mode 100644 index 0000000..d315f0e --- /dev/null +++ b/demos/janitorings/bad_zero_affect.cocci @@ -0,0 +1,9 @@ + +@@ +expression *E; +@@ + + E = +- 0 ++ NULL + diff --git a/demos/janitorings/clear_page.cocci b/demos/janitorings/clear_page.cocci new file mode 100644 index 0000000..76b52ce --- /dev/null +++ b/demos/janitorings/clear_page.cocci @@ -0,0 +1,32 @@ +// From: Shani Moideen +// Subject: [KJ] [KJ PATCH] Replacing memset(,0,PAGE_SIZE) with +// clear_page() in drivers/char/drm/i810_dma.c +// +// Replacing memset(,0,PAGE_SIZE) with clear_page() +// in drivers/char/drm/i810_dma.c +// +// Signed-off-by: Shani Moideen +// ---- +// +// diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c +// index 603d17f..4dbd97f 100644 +// --- a/drivers/char/drm/i810_dma.c +// +++ b/drivers/char/drm/i810_dma.c +// @@ -413,7 +413,7 @@ static int i810_dma_initialize(drm_device_t * dev, +// DRM_ERROR("Can not allocate hardware status page\n"); +// return -ENOMEM; +// } +// - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); +// + clear_page(dev_priv->hw_status_page); + + +// script found on KJ: +// grep -e "memset ?\([^,]+, ?, ?0, ?PAGE_SIZE\) "   + +@@ +expression X; +@@ + +- memset(X, 0, PAGE_SIZE) ++ clear_page(X) + diff --git a/demos/janitorings/is_power_of_2.cocci b/demos/janitorings/is_power_of_2.cocci new file mode 100644 index 0000000..7e19e91 --- /dev/null +++ b/demos/janitorings/is_power_of_2.cocci @@ -0,0 +1,93 @@ +// From: vignesh babu +// Subject: [KJ] [PATCH]is_power_of_2-ntfs +// To: aia21@cantab.net +// Cc: linux-ntfs-dev@lists.sourceforge.net, +// Kernel Janitors List , +// linux-kernel +// Date: Thu, 14 Jun 2007 13:39:04 +0530 +// Organization: WIPRO Technologies +// Reply-To: vignesh.babu@wipro.com +// +// +// Replacing (n & (n-1)) in the context of power of 2 checks +// with is_power_of_2 +// +// Signed-off-by: vignesh babu +// --- +// diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c +// index b532a73..8152f79 100644 +// --- a/fs/ntfs/inode.c +// +++ b/fs/ntfs/inode.c +// @@ -27,6 +27,7 @@ +// #include +// #include +// #include +// +#include +// +// #include "aops.h" +// #include "attrib.h" +// @@ -1574,7 +1575,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) +// ntfs_debug("Index collation rule is 0x%x.", +// le32_to_cpu(ir->collation_rule)); +// ni->itype.index.block_size = le32_to_cpu(ir->index_block_size); +// - if (ni->itype.index.block_size & (ni->itype.index.block_size - 1)) { +// + if (!is_power_of_2(ni->itype.index.block_size)) { +// ntfs_error(vi->i_sb, "Index block size (%u) is not a power of " +// "two.", ni->itype.index.block_size); + + +// how deal with extra '()' + +// - while ((big_pow2 & (big_pow2 - 1)) != 0) +// + while (!is_power_of_2(big_pow2)) +// +// +// - if (ubi->min_io_size == 0 || +// - (ubi->min_io_size & (ubi->min_io_size - 1))) { +// + if (!is_power_of_2(ubi->min_io_size)) { +// +// - if ((arg & (arg-1)) != 0 || arg < 1) { +// + if (!is_power_of_2(arg)) { +// +// +// // do something general for those != 0 ? always redundant ? +// - if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0) +// + if (bsize < 512 || bsize > 4096 || !is_power_of_2(bsize)) +// +// - if (!bits || (bits & (bits - 1))) +// + if (!is_power_of_2(bits)) +// +// +// - J_ASSERT ((hash_size & (hash_size-1)) == 0); +// + J_ASSERT (is_power_of_2(hash_size)); +// +// - if ((new_size & (new_size - 1)) != 0) { +// + if (!is_power_of_2(new_size)){ +// +// #include "xfs_quota.h" +// #include "xfs_acl.h" +// +// +#include +// +// +// - return !(size % (PAGE_SIZE >> 9) || (size & (size - 1)) || +// + return !(size % (PAGE_SIZE >> 9) || !is_power_of_2(size) || + + + +// script found on KJ: +// grep -e "([^\(\)]+) ?\& ?\(\1 ?- ?1\)" + + +@ rule1 @ +expression n; +@@ + +- n & (n-1) ++ !is_power_of_2(n) + +@ rule2 depends on rule1 @ +@@ + + #include ++ #include diff --git a/demos/janitorings/kcalloc_un.cocci b/demos/janitorings/kcalloc_un.cocci new file mode 100644 index 0000000..3f25182 --- /dev/null +++ b/demos/janitorings/kcalloc_un.cocci @@ -0,0 +1,9 @@ +// Based on request from Michael D. Day + +@@ +expression X, Y; +@@ + +- kcalloc(1, X, Y) + +//=> kmalloc(x, y) diff --git a/demos/janitorings/kzalloc-fix.cocci b/demos/janitorings/kzalloc-fix.cocci new file mode 100644 index 0000000..fac8e9a --- /dev/null +++ b/demos/janitorings/kzalloc-fix.cocci @@ -0,0 +1,10 @@ +// iso X * Y will handle the variations + +@@ +expression E; +constant c; +type T; +@@ + +- kzalloc(sizeof(T) * c, E) ++ kcalloc(c, sizeof(T), E) diff --git a/demos/janitorings/kzalloc-orig.cocci b/demos/janitorings/kzalloc-orig.cocci new file mode 100644 index 0000000..dfeed13 --- /dev/null +++ b/demos/janitorings/kzalloc-orig.cocci @@ -0,0 +1,239 @@ +// have to duplicate a lot of rules because T E only matches if E has a known +// type, even if T is not used elsewhere. + +// originally, the whens were when != x, but that doesn't work because x +// only binds to the outermost expression, not all possible expressions, and +// the value returned by kmalloc is usually used as a subexpression. +// so we have considered the typical uses that may cause problems; a function +// call or dereference + +//\(x->fld\|f(...,x,...)\|x=E\) + +@@ +type T, T2; +expression x; +identifier f,fld; +expression E; +expression E1,E2; +expression e1,e2,e3,y; +statement S; +@@ + +- x = (T)kmalloc(E1,E2) ++ x = kzalloc(E1,E2) + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,E1); + +@@ +type T, T2; +type T1; +T1 *x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S; +@@ + +- x = (T)kmalloc(sizeof(T1),E2) ++ x = kzalloc(sizeof(T1),E2) + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(*x)); + +@@ +type T, T2; +type T1; +T1 *x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S; +@@ + +- x = (T)kmalloc(sizeof(*x),E2) ++ x = kzalloc(sizeof(*x),E2) + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(T1)); + +// --------------------------------------------------------------------- +// --------------------------------------------------------------------- +@@ +type T, T2; +expression x; +identifier f,fld; +expression E; +expression E1,E2; +expression e1,e2,e3,y; +statement S, S1; +@@ + +- x = (T)kmalloc(E1,E2) ++ x = kzalloc(E1,E2) + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) + if(x != NULL) { + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,E1); + ... + } else S1 + +@@ +type T, T2; +type T1; +T1 *x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S, S1; +@@ + +- x = (T)kmalloc(sizeof(T1),E2) ++ x = kzalloc(sizeof(T1),E2) + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) + if(x != NULL) { + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(*x)); + ... + } else S1 + +@@ +type T, T2; +type T1; +T1 *x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S, S1; +@@ + +- x = (T)kmalloc(sizeof(*x),E2) ++ x = kzalloc(sizeof(*x),E2) + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) + if(x != NULL) { + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(T1)); + ... + } else S1 + +// --------------------------------------------------------------------- +// --------------------------------------------------------------------- +@@ +type T, T2; +type T1; +identifier x; +identifier f,fld; +expression E; +expression E1,E2; +expression e1,e2,e3,y; +statement S; +@@ + +- T1 x = (T)kmalloc(E1,E2); ++ T1 x = kzalloc(E1,E2); + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,E1); + +@@ +type T, T2; +type T1; +identifier x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S; +@@ + +- T1 x = (T)kmalloc(sizeof(T1),E2); ++ T1 x = kzalloc(sizeof(T1),E2); + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(*x)); + +@@ +type T, T2; +type T1; +identifier x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S; +@@ + +- T1 x = (T)kmalloc(sizeof(*x),E2); ++ T1 x = kzalloc(sizeof(*x),E2); + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(T1)); + +// --------------------------------------------------------------------- +// --------------------------------------------------------------------- +@@ +type T, T2; +type T1; +identifier x; +identifier f,fld; +expression E; +expression E1,E2; +expression e1,e2,e3,y; +statement S, S1; +@@ + +- T1 x = (T)kmalloc(E1,E2); ++ T1 x = kzalloc(E1,E2); + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) + if(x != NULL) { + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,E1); + ... + } else S1 + +@@ +type T, T2; +type T1; +identifier x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S, S1; +@@ + +- T1 x = (T)kmalloc(sizeof(T1),E2); ++ T1 x = kzalloc(sizeof(T1),E2); + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) + if(x != NULL) { + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(*x)); + ... + } else S1 + +@@ +type T, T2; +type T1; +identifier x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S, S1; +@@ + +- T1 x = (T)kmalloc(sizeof(*x),E2); ++ T1 x = kzalloc(sizeof(*x),E2); + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) + if(x != NULL) { + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(T1)); + ... + } else S1 + +// --------------------------------------------------------------------- +// --------------------------------------------------------------------- +@@ +expression E1,E2,E3; +@@ + +- kzalloc(E1 * E2,E3) ++ kcalloc(E1,E2,E3) diff --git a/demos/janitorings/kzalloc.cocci b/demos/janitorings/kzalloc.cocci new file mode 100644 index 0000000..46e73d0 --- /dev/null +++ b/demos/janitorings/kzalloc.cocci @@ -0,0 +1,273 @@ +// script on KJ: +// You can probably find examples of that by running: +// +// $ grep -Er -B10 "memset ?\(.*,0 ?," * | less +// +// and searching for the string "kmalloc" in the output. + + + + +// have to duplicate a lot of rules because T E only matches if E has a known +// type, even if T is not used elsewhere. + +// originally, the whens were when != x, but that doesn't work because x +// only binds to the outermost expression, not all possible expressions, and +// the value returned by kmalloc is usually used as a subexpression. +// so we have considered the typical uses that may cause problems; a function +// call or dereference + +//\(x->fld\|f(...,x,...)\|x=E\) + +@@ +type T2; +expression x; +identifier f,fld; +expression E; +expression E1,E2; +expression e1,e2,e3,y; +statement S; +@@ + + x = +- kmalloc ++ kzalloc + (E1,E2) + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,E1); + +@@ +type T, T2; +type T1; +T1 *x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S; +@@ + + x = +- kmalloc ++ kzalloc + (sizeof(T1),E2) + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(*x)); + +@@ +type T, T2; +type T1; +T1 *x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S; +@@ + + x = +- kmalloc ++ kzalloc + (sizeof(*x),E2) + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(T1)); + +// --------------------------------------------------------------------- +// --------------------------------------------------------------------- +@@ +type T, T2; +expression x; +identifier f,fld; +expression E; +expression E1,E2; +expression e1,e2,e3,y; +statement S, S1; +@@ + + x = +- kmalloc ++ kzalloc + (E1,E2) + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) + if(x != NULL) { + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,E1); + ... + } else S1 + +@@ +type T, T2; +type T1; +T1 *x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S, S1; +@@ + + x = +- kmalloc ++ kzalloc + (sizeof(T1),E2) + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) + if(x != NULL) { + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(*x)); + ... + } else S1 + +@@ +type T, T2; +type T1; +T1 *x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S, S1; +@@ + + x = +- kmalloc ++ kzalloc + (sizeof(*x),E2) + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) + if(x != NULL) { + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(T1)); + ... + } else S1 + +// --------------------------------------------------------------------- +// --------------------------------------------------------------------- +@@ +type T, T2; +type T1; +identifier x; +identifier f,fld; +expression E; +expression E1,E2; +expression e1,e2,e3,y; +statement S; +@@ + +T1 x = +- kmalloc ++ kzalloc + (E1,E2); + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,E1); + +@@ +type T, T2; +type T1; +identifier x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S; +@@ + +T1 x = +- kmalloc ++ kzalloc + (sizeof(T1),E2); + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(*x)); + +@@ +type T, T2; +type T1; +identifier x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S; +@@ + +T1 x = +- kmalloc ++ kzalloc + (sizeof(*x),E2); + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(T1)); + +// --------------------------------------------------------------------- +// --------------------------------------------------------------------- +@@ +type T, T2; +type T1; +identifier x; +identifier f,fld; +expression E; +expression E1,E2; +expression e1,e2,e3,y; +statement S, S1; +@@ + +T1 x = +- kmalloc ++ kzalloc + (E1,E2); + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) + if(x != NULL) { + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,E1); + ... + } else S1 + +@@ +type T, T2; +type T1; +identifier x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S, S1; +@@ + +T1 x = +- kmalloc ++ kzalloc + (sizeof(T1),E2); + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) + if(x != NULL) { + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(*x)); + ... + } else S1 + +@@ +type T, T2; +type T1; +identifier x; +identifier f,fld; +expression E; +expression E2; +expression e1,e2,e3,y; +statement S, S1; +@@ + +T1 x = +- kmalloc ++ kzalloc + (sizeof(*x),E2); + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) + if(x != NULL) { + ... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\) +- memset((T2)x,0,sizeof(T1)); + ... + } else S1 + +// --------------------------------------------------------------------- +// --------------------------------------------------------------------- +@@ +expression E1,E2,E3; +@@ + +- kzalloc(E1 * E2,E3) ++ kcalloc(E1,E2,E3) diff --git a/demos/janitorings/list_for_each.c b/demos/janitorings/list_for_each.c new file mode 100644 index 0000000..70ce052 --- /dev/null +++ b/demos/janitorings/list_for_each.c @@ -0,0 +1,9 @@ +void main(int i) +{ + struct list_head *list; + + for (list = ymf_devs.next; list != &ymf_devs; list = list->next) { + printf("cava"); + } + +} diff --git a/demos/janitorings/list_for_each.cocci b/demos/janitorings/list_for_each.cocci new file mode 100644 index 0000000..a850fa3 --- /dev/null +++ b/demos/janitorings/list_for_each.cocci @@ -0,0 +1,43 @@ +@@ +iterator list_for_each; +statement S; +expression head; +struct list_head *pos; +@@ +- for (pos = head.next; pos != &head; pos = pos->next) +- S +//+ list_for_each(pos, &head) + + +@@ +//iterator list_for_each; +statement S; +expression head; +struct list_head *pos; +@@ +- for (pos = head->next; pos != head; pos = pos->next) +- S +//+ list_for_each(pos, head) + + + +// list_add, list_del +// list_move +// list_del_init +// list_add_tail + +// { ... when != +// list_del() \| xxx->next = E \| list_add() \| f(...,xxx,...) +// } + + +// le cas single statement + + + +// in 0c5719c43d34073f6b4b0a2dd99f5317a5f63abd +// +//- struct list_head *walk = &pdev->bus_list; +//+ struct list_head *walk; +// +//- for (walk = walk->next; walk != &pdev->bus_list; walk = walk->next) { diff --git a/demos/janitorings/list_for_each_safe.c b/demos/janitorings/list_for_each_safe.c new file mode 100644 index 0000000..6b729d1 --- /dev/null +++ b/demos/janitorings/list_for_each_safe.c @@ -0,0 +1,10 @@ +void main(int i) +{ + list_for_each_safe(a,b,c) + i++; + + + list_for_each(a,b) + i++; + +} diff --git a/demos/janitorings/list_for_each_safe.sgrep b/demos/janitorings/list_for_each_safe.sgrep new file mode 100644 index 0000000..c6406a1 --- /dev/null +++ b/demos/janitorings/list_for_each_safe.sgrep @@ -0,0 +1,7 @@ +@@ +iterator list_for_each_safe; +statement S; +expression a, b, c; +@@ +- list_for_each_safe(a, b, c) +- S diff --git a/demos/janitorings/netdev_find_allocfunc.c b/demos/janitorings/netdev_find_allocfunc.c new file mode 100644 index 0000000..c523611 --- /dev/null +++ b/demos/janitorings/netdev_find_allocfunc.c @@ -0,0 +1,4 @@ +struct net_device *alloc_etherdev(int sizeof_priv) +{ + return alloc_netdev(sizeof_priv, "eth%d", ether_setup); +} diff --git a/demos/janitorings/netdev_find_allocfunc.sgrep b/demos/janitorings/netdev_find_allocfunc.sgrep new file mode 100644 index 0000000..95ea833 --- /dev/null +++ b/demos/janitorings/netdev_find_allocfunc.sgrep @@ -0,0 +1,15 @@ +@@ +identifier fn; +identifier sizeof_priv; +@@ + +- fn(...,int sizeof_priv, ...) +{ + <... +( + alloc_netdev(sizeof_priv, ...) +| + alloc_netdev_mq(sizeof_priv, ...) +) + ...> + } diff --git a/demos/janitorings/netdev_priv.c b/demos/janitorings/netdev_priv.c new file mode 100644 index 0000000..78ef0b1 --- /dev/null +++ b/demos/janitorings/netdev_priv.c @@ -0,0 +1,14 @@ +void foo(struct net_device *dev) +{ + struct priv *priv = dev->priv; +} + +void main(void) +{ + struct priv *priv; + struct net_device *dev; +// dev = alloc_netdev(sizeof(struct priv), 0); + dev = alloc_netdev(sizeof(*priv), 0); + + +} diff --git a/demos/janitorings/netdev_priv.cocci b/demos/janitorings/netdev_priv.cocci new file mode 100644 index 0000000..9557752 --- /dev/null +++ b/demos/janitorings/netdev_priv.cocci @@ -0,0 +1,106 @@ +// TODO: now that have the assign/affect iso, can perhaps +// deal with the cast pb +// rewriting +// - (T*) dev->priv +// + netdev_priv(dev) +// into +// x = +// - (T*) dev-> priv +// + netdev_priv(dev) + +// and then make another rule for the remaining case + + +@ alloc disable plus_comm @ +type T; +expression E; +@@ + +( +( + alloc_netdev +| + alloc_etherdev +| + alloc_fcdev +| + alloc_fddidev +| + alloc_hippi_dev +| + alloc_trdev +| + alloc_ltalkdev +| + alloc_irdadev +| + alloc_etherdev_mq +) + (sizeof(T), ...) +| +( + alloc_netdev +| + alloc_etherdev +| + alloc_fcdev +| + alloc_fddidev +| + alloc_hippi_dev +| + alloc_trdev +| + alloc_ltalkdev +| + alloc_irdadev +| + alloc_etherdev_mq +) + (sizeof(T) + E, ...) +) + + +// if don't have the iso sizeof(T) => sizeof(E) +// dev = alloc_netdev(sizeof(*x), ...) + +//>>> - alloc_irlandev +// but dont pass the sizeof, so cant get the type T. + +//> alloc_orinocodev + + +@ danger @ +struct net_device *dev; +expression E; +@@ + dev->priv = E +//+ DANGER + + +//@ danger @ +//struct net_device dev; +//expression E; +//@@ +// dev.priv = E + + + +// TODO wrong !!! can have ((T) a)->field, on peut pas remover le cast! +@ rule1 depends on alloc && !danger @ +struct net_device *dev; +type alloc.T; +@@ + +- (T*) dev->priv ++ netdev_priv(dev) + + +// the iso drop_cast is not enough because T* in the previous rule +// can not be dropped. It's not a pure T. +@ rule2 depends on alloc && !danger @ +struct net_device *dev; +@@ + +- dev->priv ++ netdev_priv(dev) diff --git a/demos/janitorings/netdev_priv2.cocci b/demos/janitorings/netdev_priv2.cocci new file mode 100644 index 0000000..5c659f6 --- /dev/null +++ b/demos/janitorings/netdev_priv2.cocci @@ -0,0 +1,7 @@ +@@ +struct net_device *dev; +type T; +@@ + +- (T) dev->priv ++ netdev_priv(dev) diff --git a/demos/janitorings/netdev_priv_dangerous.sgrep b/demos/janitorings/netdev_priv_dangerous.sgrep new file mode 100644 index 0000000..e0057bb --- /dev/null +++ b/demos/janitorings/netdev_priv_dangerous.sgrep @@ -0,0 +1,55 @@ +@ rule1 @ +type T; +struct net_device *dev; +expression E; +@@ + + dev = +( + alloc_netdev +| + alloc_etherdev +| + alloc_fcdev +| + alloc_fddidev +| + alloc_hippi_dev +| + alloc_trdev +| + alloc_ltalkdev +| + alloc_irdadev +| + alloc_etherdev_mq +) + (sizeof(T), ...) + +//sizeof(T) + E + + +@ rule1bis @ +struct net_device *dev; +expression E; +@@ + + dev->priv = E +//+ DANGERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR + + +@ rule2 depends on !rule1 @ +struct net_device *dev; +@@ + +- netdev_priv(dev) ++ no_alloc_xxx + + +@ rule3 depends on rule1bis @ +struct net_device *dev; +@@ + +- netdev_priv(dev) ++ with_danger + diff --git a/demos/janitorings/remove_cast_kmalloc.cocci b/demos/janitorings/remove_cast_kmalloc.cocci new file mode 100644 index 0000000..6c224a8 --- /dev/null +++ b/demos/janitorings/remove_cast_kmalloc.cocci @@ -0,0 +1,26 @@ +// commit 5cbded585d129d0226cb48ac4202b253c781be26 +// Author: Robert P. J. Day +// Date: Wed Dec 13 00:35:56 2006 -0800 +// +// [PATCH] getting rid of all casts of k[cmz]alloc() calls +// +// Run this: +// +// #!/bin/sh +// for f in $(grep -Erl "\([^\)]*\) *k[cmz]alloc" *) ; do +// echo "De-casting $f..." +// perl -pi -e "s/ ?= ?\([^\)]*\) *(k[cmz]alloc) *\(/ = \1\(/" $f +// done +// +// And then go through and reinstate those cases where code is +// casting pointers to non-pointers. +// +// And then drop a few hunks which conflicted with outstanding work. + + +@@ +expression E; type T; +@@ + E = +- (T) + kmalloc(...) diff --git a/demos/janitorings/set_current_state.cocci b/demos/janitorings/set_current_state.cocci new file mode 100644 index 0000000..8f5dd97 --- /dev/null +++ b/demos/janitorings/set_current_state.cocci @@ -0,0 +1,6 @@ +@@ +expression E; +@@ + +- current->state = E; ++ set_current_state(E); \ No newline at end of file diff --git a/demos/janitorings/static_initfunc.c b/demos/janitorings/static_initfunc.c new file mode 100644 index 0000000..45b7890 --- /dev/null +++ b/demos/janitorings/static_initfunc.c @@ -0,0 +1,21 @@ +static int __init foo1(void) +{ +} + + +int __init foo2(void) +{ +} + +static int foo3(void) +{ +} + + +static int foo4(void) +{ +} + + +module_init(foo1); +module_init(foo2); diff --git a/demos/janitorings/static_initfunc.cocci b/demos/janitorings/static_initfunc.cocci new file mode 100644 index 0000000..8bc7dff --- /dev/null +++ b/demos/janitorings/static_initfunc.cocci @@ -0,0 +1,83 @@ +// Thomas Surrel version. Error msg is "not handling multiple minirules" +// @@ +// identifier func; +// @@ +// - int __init func(void) +// { ... } +// + static int __init func(void) +// { ... } + +// cant match on __init in cocci_vs_c +//@@ +//identifier func; +//@@ +// - int __init func(void) +// + static int __init func(void) +// { ... } + + +// cant parse +//@@ +//identifier func; +//@@ +// ( +// static int func(void) +// { ... } +// | +// + static +// int func(void) +// { ... } +// ) + + +// wrong unparsing +//@@ +//identifier initfunc; +//@@ +// +//+ static +// int initfunc(void) +// { ... } + + +@ rule1 @ +identifier initfunc; +@@ + module_init(initfunc); + +@ disable optional_storage @ +identifier rule1.initfunc; +@@ + +- int ++ static int + initfunc(void) + { ... } + + + +// cheat version +// @ rule1 @ +// identifier initfunc; +// @@ +// module_init(initfunc); +// +// @ rule2 @ +// identifier rule1.initfunc; +// @@ +// +// static int initfunc(...) +// { ... } +// +// @ rule3 depends on !rule2 @ +// identifier rule1.initfunc; +// @@ +// +// //- int initfunc(void) +// //+ static int initfunc(void) +// // { ... } +// +// - int +// + static int +// initfunc(...) +// { ... } diff --git a/demos/janitorings/string-array-decl-opti.c b/demos/janitorings/string-array-decl-opti.c new file mode 100644 index 0000000..e3a20a2 --- /dev/null +++ b/demos/janitorings/string-array-decl-opti.c @@ -0,0 +1,17 @@ + +#define MYSTR "toto" +#define MYSTR2 NULL + + +const char *foo = NULL; + +const char *foo = MYSTR; +const char *foo = MYSTR2; + +const char *foo = "blah"; +char *foo = "blah"; + +char *foo = {1,2,3}; + +const char foo[] = "blah"; +char foo[] = "blah"; diff --git a/demos/janitorings/string-array-decl-opti.cocci b/demos/janitorings/string-array-decl-opti.cocci new file mode 100644 index 0000000..d6db414 --- /dev/null +++ b/demos/janitorings/string-array-decl-opti.cocci @@ -0,0 +1,20 @@ +//@@ +//identifier x; +//expression s; +//@@ +// ( +// char *x = NULL; +// | +// - char *x = s; +// + char x[] = s; +// ) + + +@@ +identifier x; +constant char *s; +@@ + + +- char *x = s; ++ char x[] = s; diff --git a/demos/janitorings/useless_cast.c b/demos/janitorings/useless_cast.c new file mode 100644 index 0000000..604c2de --- /dev/null +++ b/demos/janitorings/useless_cast.c @@ -0,0 +1,26 @@ + +// from: http://kernelnewbies.org/KernelJanitors/Todo +struct device { + struct netdev_private *priv; + struct netdev_private2 *priv2; + void *priv3; + +}; + +struct net_device *dev; + +struct netdev_private *np = (struct netdev_private *)dev->priv; +struct netdev_private *np2 = (struct netdev_private *)dev->priv2; +struct netdev_private *np3 = (struct netdev_private *)dev->priv3; + + +struct netdev_private *np4 = (struct netdev_private *) dev; + + +int f(int i) +{ + ssize_t x; + if((ssize_t) x > 0) { + return -1; + } +} diff --git a/demos/janitorings/useless_cast.cocci b/demos/janitorings/useless_cast.cocci new file mode 100644 index 0000000..f0be1bd --- /dev/null +++ b/demos/janitorings/useless_cast.cocci @@ -0,0 +1,36 @@ +@@ +type T; +T E; +@@ + +- (T) + E + +// // special case +//@@ +//type T; +//identifier x; +//T E; +//@@ +// +//T x = +//- (T) +// E; + + +// // kmalloc for instance don't require cast. +//@@ +//type T; +//identifier x; +//void *E; +//@@ +// +//T x = +//- (T) +// E; + + +// kmalloc, etc +// __get_free_page +// get_zeroed_page +// RING_GET_RESPONSE \ No newline at end of file diff --git a/demos/launch.sh b/demos/launch.sh new file mode 100755 index 0000000..3073382 --- /dev/null +++ b/demos/launch.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +ARGS="-no_show_ctl_text -no_show_transinfo -no_parse_error_msg -no_show_misc -no_type_error_msg"; + +for i in *.c +do + ../spatch $ARGS -iso_file ../standard.iso -cocci_file ${i}occi $i +done diff --git a/demos/manual/already_tagged.c b/demos/manual/already_tagged.c new file mode 100644 index 0000000..0b3c379 --- /dev/null +++ b/demos/manual/already_tagged.c @@ -0,0 +1,12 @@ +/* diamond example */ +void main(int i) +{ + + foo(); + if(1) + bar(1); + else + bar(2); + foobar(); + +} diff --git a/demos/manual/already_tagged.cocci b/demos/manual/already_tagged.cocci new file mode 100644 index 0000000..0856695 --- /dev/null +++ b/demos/manual/already_tagged.cocci @@ -0,0 +1,10 @@ +@@ +expression x; +@@ + + foo(); + ... + bar(x); + ... +- foobar(); ++ foobar(x); diff --git a/demos/manual/get_put.c b/demos/manual/get_put.c new file mode 100644 index 0000000..262aa4e --- /dev/null +++ b/demos/manual/get_put.c @@ -0,0 +1,9 @@ +void main(int i) +{ + + get(); + if(1) { + put(); + } + put(); +} diff --git a/demos/manual/get_put.cocci b/demos/manual/get_put.cocci new file mode 100644 index 0000000..c8bd169 --- /dev/null +++ b/demos/manual/get_put.cocci @@ -0,0 +1,8 @@ +@@ +@@ + +get(); +... +-put(); ++putput(); + diff --git a/demos/manual/get_put_full.c b/demos/manual/get_put_full.c new file mode 100644 index 0000000..262aa4e --- /dev/null +++ b/demos/manual/get_put_full.c @@ -0,0 +1,9 @@ +void main(int i) +{ + + get(); + if(1) { + put(); + } + put(); +} diff --git a/demos/manual/get_put_full.cocci b/demos/manual/get_put_full.cocci new file mode 100644 index 0000000..05b95e6 --- /dev/null +++ b/demos/manual/get_put_full.cocci @@ -0,0 +1,13 @@ +@@ +identifier fn; +@@ + +fn(...) { + ... + get(); + ... + put(); + ... +} + + diff --git a/demos/manual/get_put_ver1.c b/demos/manual/get_put_ver1.c new file mode 100644 index 0000000..b79bce7 --- /dev/null +++ b/demos/manual/get_put_ver1.c @@ -0,0 +1,10 @@ +void main(int i) +{ + + get(); + if(1) { + put(); + return 0; + } + put(); +} diff --git a/demos/not.c b/demos/not.c new file mode 100644 index 0000000..1c1ac88 --- /dev/null +++ b/demos/not.c @@ -0,0 +1,9 @@ +int main() { + int x; + this(12,x); + this(foo,x); + bar(12,x); + foo(12,x); + this(12,x); + this(12,x); +} diff --git a/demos/not.cocci b/demos/not.cocci new file mode 100644 index 0000000..da78432 --- /dev/null +++ b/demos/not.cocci @@ -0,0 +1,8 @@ +@@ +expression x != foo; +identifier y != {foo,bar}; +expression a; +@@ + +- y(x,a); ++ f(20); diff --git a/demos/not.res b/demos/not.res new file mode 100644 index 0000000..e503968 --- /dev/null +++ b/demos/not.res @@ -0,0 +1,9 @@ +int main() { + int x; + f(20); + this(foo,x); + bar(12,x); + foo(12,x); + f(20); + f(20); +} diff --git a/demos/posmult.c b/demos/posmult.c new file mode 100644 index 0000000..33eddb8 --- /dev/null +++ b/demos/posmult.c @@ -0,0 +1,8 @@ +int main() { + int *x = NULL; + int *y = NULL; + if (r) x = ALLOC(); + y = ALLOC(); + if (!x) return; + if (!y) return; +} diff --git a/demos/posmult.cocci b/demos/posmult.cocci new file mode 100644 index 0000000..cf1d521 --- /dev/null +++ b/demos/posmult.cocci @@ -0,0 +1,20 @@ +@n@ +position p; +expression E; +statement S,S1; +@@ + +E = NULL +... when != E = ALLOC(...) +if@p (\(E\|!E\)) S else S1 + +@@ +expression E, E1; +statement S,S1; +position p1 != n.p; +@@ + +* E = ALLOC(...) +... when != E = E1 +* if@p1 (\(E\|!E\)) + S else S1 diff --git a/demos/printloc.c b/demos/printloc.c new file mode 100644 index 0000000..b9c2f70 --- /dev/null +++ b/demos/printloc.c @@ -0,0 +1,4 @@ +int main() { + f(12); + x = f(12); +} diff --git a/demos/printloc.cocci b/demos/printloc.cocci new file mode 100644 index 0000000..b8835cb --- /dev/null +++ b/demos/printloc.cocci @@ -0,0 +1,26 @@ +@r@ +position p1, p2; +identifier f; +expression E; +@@ + +f@p1(E@p2) + +@ script:python @ +p1 << r.p1; +p2 << r.p2; +f << r.f; +@@ + +c1 = cocci.combine(f,p1) +c2 = cocci.combine(f,p2) +print "1. function in column %s" % c1.location.column +print "1. argument in column %s" % c2.location.column +c1 = cocci.combine(f,p1) +print "2. function in column %s" % c1.location.column +c2 = cocci.combine(f,p2) +print "2. argument in column %s" % c2.location.column +print "3. function in column %s" % ','.join([p.column for p in p1]) +print "3. argument in column %s" % ','.join([p.column for p in p2]) +print "4. function in column %s" % p1[0].column +print "4. argument in column %s" % p2[0].column diff --git a/demos/proc_info.c b/demos/proc_info.c new file mode 100644 index 0000000..bc56e62 --- /dev/null +++ b/demos/proc_info.c @@ -0,0 +1,139 @@ +void main(int i) { +} + + +static int usb_storage_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +{ + struct us_data *us; + char *pos = buffer; + struct Scsi_Host *hostptr; + unsigned long f; + + /* if someone is sending us data, just throw it away */ + if (inout) + return length; + + /* find our data from the given hostno */ + hostptr = scsi_host_hn_get(hostno); + if (!hostptr) { /* if we couldn't find it, we return an error */ + return -ESRCH; + } + us = (struct us_data*)hostptr->hostdata[0]; + + /* if we couldn't find it, we return an error */ + if (!us) { + scsi_host_put(hostptr); + return -ESRCH; + } + + /* print the controller name */ + SPRINTF(" Host scsi%d: usb-storage\n", hostno); + + SPRINTF(" Transport: %s\n", us->transport_name); + + /* show the device flags */ + if (pos < buffer + length) { + pos += sprintf(pos, " Quirks:"); + f = us->flags; + +#define DO_FLAG(a) if (f & US_FL_##a) pos += sprintf(pos, " " #a) + DO_FLAG(SINGLE_LUN); + DO_FLAG(MODE_XLATE); + DO_FLAG(START_STOP); + DO_FLAG(IGNORE_SER); + DO_FLAG(SCM_MULT_TARG); + DO_FLAG(FIX_INQUIRY); + DO_FLAG(FIX_CAPACITY); +#undef DO_FLAG + + *(pos++) = '\n'; + } + + /* release the reference count on this host */ + scsi_host_put(hostptr); + + /* + * Calculate start of next buffer, and return value. + */ + *start = buffer + offset; + + if ((pos - buffer) < offset) + return (0); + else if ((pos - buffer - offset) < length) + return (pos - buffer - offset); + else + return (length); +} + + + +static int usb_storage_info (int i, struct Scsi_Host *myhostptr) { + + char *buffer; + int hostno = 40; + usb_storage_proc_info(buffer, 0, 0, 100, 40, -1); +} + + +struct SHT usb_stor_host_template = { + /* basic userland interface stuff */ + .name = "usb-storage", + .proc_name = "usb-storage", + .proc_info = usb_storage_proc_info, + .proc_dir = NULL, + .info = usb_storage_info, + .ioctl = NULL, + + /* old-style detect and release */ + .detect = NULL, + .release = NULL, + + /* command interface -- queued only */ + .command = NULL, + .queuecommand = usb_storage_queuecommand, + + /* error and abort handlers */ + .eh_abort_handler = usb_storage_command_abort, + .eh_device_reset_handler = usb_storage_device_reset, + .eh_bus_reset_handler = usb_storage_bus_reset, + .eh_host_reset_handler = NULL, + .eh_strategy_handler = NULL, + + /* queue commands only, only one command per LUN */ + .can_queue = 1, + .cmd_per_lun = 1, + + /* unknown initiator id */ + .this_id = -1, + + /* no limit on commands */ + .max_sectors = 0, + + /* pre- and post- device scan functions */ + .slave_alloc = NULL, + .slave_configure = NULL, + .slave_destroy = NULL, + + /* lots of sg segments can be handled */ + .sg_tablesize = SG_ALL, + + /* use 32-bit address space for DMA */ + .unchecked_isa_dma = FALSE, + .highmem_io = FALSE, + + /* merge commands... this seems to help performance, but + * periodically someone should test to see which setting is more + * optimal. + */ + .use_clustering = TRUE, + + /* emulated HBA */ + .emulated = TRUE, + + /* sorry, no BIOS to help us */ + .bios_param = NULL, + + /* module management */ + .module = THIS_MODULE +}; diff --git a/demos/proc_info.cocci b/demos/proc_info.cocci new file mode 100644 index 0000000..de85bc0 --- /dev/null +++ b/demos/proc_info.cocci @@ -0,0 +1,57 @@ +@ rule1 @ +identifier buffer, start, offset, length, inout, hostno; +identifier hostptr; +identifier proc_info_func; +@@ + proc_info_func ( ++ struct Scsi_Host *hostptr, + char *buffer, char **start, off_t offset, int length, +- int hostno, + int inout) { + ... +- struct Scsi_Host *hostptr; + ... +- hostptr = scsi_host_hn_get(hostno); + ... +?- if (!hostptr) { ... return ...; } + ... +?- scsi_host_put(hostptr); + ... + } + +//alt: +//- proc_info_func(char *buffer, char **start, off_t offset, int length, +//- int hostno, int inout) +//+ proc_info_func(struct Scsi_Host *hostptr, char *buffer, char **start, +//+ off_t offset, int length, int inout) +//{ + + + +@@ +identifier rule1.proc_info_func; +identifier rule1.hostno; +@@ + proc_info_func(...) { + <... +- hostno ++ hostptr->host_no + ...> + } + +@@ +identifier func; +expression buffer, start, offset, length, inout, hostno; +identifier hostptr; +identifier rule1.proc_info_func; +@@ + + func(..., struct Scsi_Host *hostptr, ...) { + <... + proc_info_func( ++ hostptr, + buffer, start, offset, length, +- hostno, + inout) + ...> + } diff --git a/demos/pycocci.c b/demos/pycocci.c new file mode 100644 index 0000000..12009a9 --- /dev/null +++ b/demos/pycocci.c @@ -0,0 +1,22 @@ +#include + +const int qqq = 20; + +void foo() { + int z[10]; + + z[2] = 34; +} + +int main() { + int buf[qqq], foo[30]; + int i; + + for (i = 0; i <= 20; ++i) { + buf[i] = i; + foo[i] = i; + } + + for (i = 0; i <= 20; ++i) + printf("%d: %d\n", i, buf[i]); +} diff --git a/demos/pycocci.cocci b/demos/pycocci.cocci new file mode 100644 index 0000000..f59abbc --- /dev/null +++ b/demos/pycocci.cocci @@ -0,0 +1,15 @@ +@ rule1 @ +type T; identifier I; expression C; expression E; +position p1, p2, p3, p4; +@@ +T I@p2[C@p3]; +<... +I[E@p4] +...> +@ script:python @ +x_mv << rule1.C; xp << rule1.p3; +y_mv << rule1.E; yp << rule1.p4; +@@ +x = cocci.combine(x_mv, xp) +y = cocci.combine(y_mv, yp) +cocci.register_match(True, [(x, 'Array match'), (y, 'Array use')]) diff --git a/demos/sgrep/README b/demos/sgrep/README new file mode 100644 index 0000000..2e17439 --- /dev/null +++ b/demos/sgrep/README @@ -0,0 +1,3 @@ +These are what appear to be the most recent versions of the scripts used in +the PASTE submission. "run" is an example of how to run them, specialized +for the intr example. diff --git a/demos/sgrep/a_and_b.c b/demos/sgrep/a_and_b.c new file mode 100644 index 0000000..ec15421 --- /dev/null +++ b/demos/sgrep/a_and_b.c @@ -0,0 +1,26 @@ +int test1(int i) +{ + foo(); + bar(); +} + + +int test2(int i) +{ + bar(); + foo(); +} + + +int test3(int i) +{ + bar(); +} + + +int test4(int i) +{ + bar(); + foo(); + foo(); +} diff --git a/demos/sgrep/a_and_b.sgrep b/demos/sgrep/a_and_b.sgrep new file mode 100644 index 0000000..341f252 --- /dev/null +++ b/demos/sgrep/a_and_b.sgrep @@ -0,0 +1,19 @@ +@ rule1 @ +identifier fn; +@@ + +fn(...) { + <... +\+ foo(); + ...> +} + +@ rule2 depends on rule1 @ +identifier rule1.fn; +@@ + +- fn(...) { +- <... +-\+ bar(); +- ...> +- } diff --git a/demos/sgrep/dangerous_GFP_KERNEL.sgrep b/demos/sgrep/dangerous_GFP_KERNEL.sgrep new file mode 100644 index 0000000..f3e1549 --- /dev/null +++ b/demos/sgrep/dangerous_GFP_KERNEL.sgrep @@ -0,0 +1,44 @@ + +// note that need -sgrep options otherwise don't detect +// every situation as for instance: + +// static int start_command_port(struct usb_serial *serial) +// { +// spin_lock_irqsave(&command_info->lock, flags); +// if (!command_info->port_running) { +// retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL); +// if (retval) { +// err("%s - failed submitting read urb, error %d", __FUNCTION__, retval); +// goto exit; +// } +// } +// command_info->port_running++; +// +// exit: +// spin_unlock_irqrestore(&command_info->lock, flags); +// return retval; +// } + +// note that better to send a .sgrep than a .cocci, that is +// to not do the fix because sometimes the correct fix is not to replace +// the use of GFP_KERNEL but instead to move the function call outside +// the spin_locked region. + +@@ +//expression E; +identifier fn; +@@ + +( +spin_lock_irqsave(...) +| +spin_lock(...) +) +... when != \(spin_unlock_irqrestore(...)\|spin_unlock(...)\) +//- usb_submit_urb(E, GFP_KERNEL) +fn(..., +- GFP_KERNEL +//+ GFP_ATOMIC + ,... + ) + diff --git a/demos/sgrep/dangerous_GFP_KERNEL2.sgrep b/demos/sgrep/dangerous_GFP_KERNEL2.sgrep new file mode 100644 index 0000000..5a79a0b --- /dev/null +++ b/demos/sgrep/dangerous_GFP_KERNEL2.sgrep @@ -0,0 +1,12 @@ +@@ +identifier fn; +@@ + + spin_lock_irqsave(...) + ... when != spin_unlock_irqrestore(...) + fn(..., +- GFP_KERNEL ++ GFP_ATOMIC + ,... + ) + diff --git a/demos/sgrep/dangerous_arith_pointer_cast.sgrep b/demos/sgrep/dangerous_arith_pointer_cast.sgrep new file mode 100644 index 0000000..9cfebfb --- /dev/null +++ b/demos/sgrep/dangerous_arith_pointer_cast.sgrep @@ -0,0 +1,9 @@ + +@@ +type T; +expression E1, E2; +@@ + +// safer is ((T) E1) + E2 +- (T *) E1 + E2 + diff --git a/demos/sgrep/device_id.sgrep b/demos/sgrep/device_id.sgrep new file mode 100644 index 0000000..32bea6c --- /dev/null +++ b/demos/sgrep/device_id.sgrep @@ -0,0 +1,37 @@ +// from LKN book de greg + +// in fact search more specifically in initializer zone for +// the string 157e for the usb, and for the macro which +// is bound to 0x8139 for the pci + +// could functorize/parametrize this script to be generic +// to handle any kind of device_id number + +--- include/linux/pci_ids.h ++++ include/linux/pci_ids.h + +// would like a $VAL passed to sgrep via a -DVAL=0x8139 +#define V 0x8139 + +--- ++++ + +@@ +identifier X; +@@ + +struct +( +pci_device_id +| +usb_device_id +) + X[] = +- { ... }; + +// would like a +// { +// <... +- V // en fait voudrait toute la ligne + ...> +// } diff --git a/demos/sgrep/double_cast.sgrep b/demos/sgrep/double_cast.sgrep new file mode 100644 index 0000000..df6a337 --- /dev/null +++ b/demos/sgrep/double_cast.sgrep @@ -0,0 +1,9 @@ +@@ +type T1; +type T2; +expression E1,E2; +@@ + +- E1 = (T1) (T2) E2; + + diff --git a/demos/sgrep/free.sgrep b/demos/sgrep/free.sgrep new file mode 100644 index 0000000..db0b4b7 --- /dev/null +++ b/demos/sgrep/free.sgrep @@ -0,0 +1,196 @@ +@@ +identifier x; +expression E,E1; +expression f; +identifier fld; +@@ + +( + free(x); +| + kfree(x); +| + kfree_skb(x); +| + dev_kfree_skb(x); +| + dev_kfree_skb_any(x); +) + ... WHEN != x = E +( + f(...,x,...) +| + *x +| + x[E1] +| + x->fld +) + +@@ +identifier x; +expression E; +@@ + +( + free(x); +| + kfree(x); +| + kfree_skb(x); +| + dev_kfree_skb(x); +| + dev_kfree_skb_any(x); +) + ... WHEN != x = E +return x; + +//------------------------------------------------------------ +@@ +expression x; +expression E,E1,E2; +expression f; +identifier fld; +@@ + +( + free(x[E2]); +| + kfree(x[E2]); +| + kfree_skb(x[E2]); +| + dev_kfree_skb(x[E2]); +| + dev_kfree_skb_any(x[E2]); +) + ... WHEN != \(x = E \| E2 = E\) +( + f(...,x[E2],...) +| + *x[E2] +| + x[E2][E1] +| + x[E2]->fld +) + +@@ +expression x; +expression E; +@@ + +( + free(x[E2]); +| + kfree(x[E2]); +| + kfree_skb(x[E2]); +| + dev_kfree_skb(x[E2]); +| + dev_kfree_skb_any(x[E2]); +) + ... WHEN != \(x = E \| E2 = E\) +return x[E2]; + +//------------------------------------------------------------ +@@ +expression x; +expression E,E1; +expression f; +identifier fld,f1; +@@ + +( + free(x->f1); +| + kfree(x->f1); +| + kfree_skb(x->f1); +| + dev_kfree_skb(x->f1); +| + dev_kfree_skb_any(x->f1); +) + ... WHEN != \(x = E\|x->f1 = E\) +( + f(...,x->f1,...) +| + *x->f1 +| + x->f1[E1] +| + x->f1->fld +) + +@@ +expression x; +expression E; +@@ + +( + free(x->f1); +| + kfree(x->f1); +| + kfree_skb(x->f1); +| + dev_kfree_skb(x->f1); +| + dev_kfree_skb_any(x->f1); +) + ... WHEN != \(x = E\|x->f1 = E\) +return x->f1; + +//------------------------------------------------------------ +@@ +expression x; +expression E,E1; +expression f; +identifier fld; +@@ + +( + free(*x); +| + kfree(*x); +| + kfree_skb(*x); +| + dev_kfree_skb(*x); +| + dev_kfree_skb_any(*x); +) + ... WHEN != \(x = E\|*x = E\) +( + f(...,*x,...) +| + **x +| + *x[E1] +| + *x->fld +) + +@@ +expression x; +expression E; +@@ + +( + free(*x); +| + kfree(*x); +| + kfree_skb(*x); +| + dev_kfree_skb(*x); +| + dev_kfree_skb_any(*x); +) + ... WHEN != \(x = E\|*x = E\) +return *x; + +//------------------------------------------------------------ diff --git a/demos/sgrep/intr4.sgrep b/demos/sgrep/intr4.sgrep new file mode 100644 index 0000000..70acef6 --- /dev/null +++ b/demos/sgrep/intr4.sgrep @@ -0,0 +1,21 @@ +@@ @@ +( + cli(); +| + spin_lock_irqsave(...); +) + ... when != \( sti(); \| restore_flags(...); \| spin_unlock_irqrestore(...); \) +? \( cli(); \| spin_lock_irqsave(...); \) + +@@ @@ +( + sti(); +| + restore_flags(...); +) + ... when != cli(); +( + sti(); +| + restore_flags(...); +) diff --git a/demos/sgrep/null.sgrep b/demos/sgrep/null.sgrep new file mode 100644 index 0000000..75b603d --- /dev/null +++ b/demos/sgrep/null.sgrep @@ -0,0 +1,101 @@ +@@ +expression x; +type T1, T2, T3; +expression e1, e2; +expression f; +identifier fld; +@@ + x = (T1) kmalloc(...) + ... when != x = e1 + if(x == NULL) { + ... when != x = e2 +( + *x +| + *((T2)x) +| + x->fld +| + (x)->fld +| + f(...,x,...) +| + f(...,(T3)x,...) +) + ... + } + +@@ +expression x; +type T1, T2, T3; +expression e1, e2; +expression f; +identifier fld; +statement S; +@@ + x = (T1) kmalloc(...) + ... when != x = e1 + if(x != NULL) S else { + ... when != x = e2 +( + *x +| + *((T2)x) +| + x->fld +| + (x)->fld +| + f(...,x,...) +| + f(...,(T3)x,...) +) + ... + } + +// for some "good" reason, isomorphisms don't apply to whencode +@@ +expression x; +type T1, T2, T3; +expression e; +expression f; +identifier fld; +statement S; +@@ + x = (T1) kmalloc(...); + ... when != \( if(\(x == NULL\|NULL == x\|!x\)) { ... \(return;\|return e;\) } \| if(\(x == NULL\|NULL == x\|!x\)) \(return;\|return e;\) \| if(\(x != NULL\|NULL != x\|x\)) S else { ... \(return;\|return e;\) } \| if(\(x != NULL\|NULL != x\|x\)) S else \(return;\|return e;\) \| x = e; \) +( + *x +| + *((T2)x) +| + x->fld +| + (x)->fld +| + f(...,x,...) +| + f(...,(T3)x,...) +) + +@@ +expression x; +type T1; +expression e1, e2; +@@ + x = (T1) kmalloc(...) + ... when != x = e1 + if(x == NULL) { + ... when != x = e2 + return x; + } + +// for some "good" reason, isomorphisms don't apply to whencode +@@ +expression x; +type T1; +expression e; +@@ + x = (T1) kmalloc(...); + ... when != \( if(\(x == NULL\|NULL == x\|!x\)) { ... \(return;\|return e;\) } \| if(\(x == NULL\|NULL == x\|!x\)) \(return;\|return e;\) \| x = e; \) + return x; diff --git a/demos/sgrep/run.sh b/demos/sgrep/run.sh new file mode 100644 index 0000000..3480e56 --- /dev/null +++ b/demos/sgrep/run.sh @@ -0,0 +1,7 @@ +find linux -name "*\.c" -exec ../../spatch.opt -cocci_file intr4.cocci {} \ +-no_show_ctl_text -no_show_transinfo -no_parse_error_msg -no_show_misc \ +-sgrep -save_output_file \; + +find linux -name "*\.cocci_res" -exec ./doit {} \; -print > err_found + +# doit contains cat -n $1 | grep '/\*<\*/' diff --git a/demos/sgrep/simple.c b/demos/sgrep/simple.c new file mode 100644 index 0000000..9d41fa5 --- /dev/null +++ b/demos/sgrep/simple.c @@ -0,0 +1,18 @@ +void main(int i) +{ + + + foo(f(1),2); + f(2); + g(3); + +} + + +void notmain(int i) +{ + + f(3); + f(4); + +} diff --git a/demos/sgrep/simple.sgrep b/demos/sgrep/simple.sgrep new file mode 100644 index 0000000..59834a0 --- /dev/null +++ b/demos/sgrep/simple.sgrep @@ -0,0 +1,20 @@ +@@ +expression X; +@@ + + void main(...) { + <... +- f(X) + ...> + } + + +@@ +expression X; +@@ + + void main(...) { + <... +- g(X) + ...> + } diff --git a/demos/simple.c b/demos/simple.c new file mode 100644 index 0000000..d2f581e --- /dev/null +++ b/demos/simple.c @@ -0,0 +1,4 @@ +int main(int i) { + f("ca va"); + f(g("ca va pas")); +} diff --git a/demos/simple.cocci b/demos/simple.cocci new file mode 100644 index 0000000..9a531f1 --- /dev/null +++ b/demos/simple.cocci @@ -0,0 +1,5 @@ +@@ expression E; @@ + +- f(E); ++ f(E,3); + diff --git a/demos/type_fields.c b/demos/type_fields.c new file mode 100644 index 0000000..f710520 --- /dev/null +++ b/demos/type_fields.c @@ -0,0 +1,17 @@ +void foo(int i) +{ + struct file_operations myfops; + foo(myfops.ioctl); + +} + + + + +void foo(int i) +{ + struct dir_operations myfops; + foo(myfops.ioctl); + +} + diff --git a/demos/type_fields.cocci b/demos/type_fields.cocci new file mode 100644 index 0000000..0d99d0b --- /dev/null +++ b/demos/type_fields.cocci @@ -0,0 +1,8 @@ +@@ +struct file_operations x; +@@ + + +- x.ioctl ++ x.new_ioctl + diff --git a/demos/unsigned.cocci b/demos/unsigned.cocci new file mode 100644 index 0000000..d4e2ec5 --- /dev/null +++ b/demos/unsigned.cocci @@ -0,0 +1,9 @@ +// This semantic patch does essentially the same as the script in +// unsigned.txt. That one does things with typedefs. Not clear whether the +// semantic patch finds those cases (it didn't but maybe there aren't any). + +@@ +unsigned int i; +@@ + +* i < 0 diff --git a/demos/unsigned.txt b/demos/unsigned.txt new file mode 100644 index 0000000..683a500 --- /dev/null +++ b/demos/unsigned.txt @@ -0,0 +1,129 @@ +From 12o3l@tiscali.nl Fri Apr 18 18:13:39 2008 +Date: Fri, 18 Apr 2008 18:15:06 +0200 +From: Roel Kluin <12o3l@tiscali.nl> +To: kernel-janitors@vger.kernel.org, kernelnewbies-bounce@nl.linux.org +Subject: script to find incorrect tests on unsigneds + +A bash script to find incorrect tests on unsigned values. for instance: + +unsigned int i; +... +i = neg_ret_function(); +... +if (i < 0) ... + +#!/bin/bash +# (c) roel kluin 2008 GPL v2 +# +# TODO: make this working also for +# ... $unsigned_var == $signed_var ... +# ... $unsigned_var == \(-POSITIVE_DEF\|NEGATIVE_DEF\) ... +# ... ( $unsigned_var [+*/%^&~-]?= ... ) < 0 ... + +# a number +int="[0-9]" +hex="[a-f0-9]" +hEx="[A-Fa-f0-9]" +HEX="[A-F0-9]" +upp="[A-Z]" +up_="[A-Z_]" +low="[a-z0-9]" +lo_="[a-z0-9_]" +alp="[A-Za-z]" +al_="[A-Za-z_]" +ALN="[A-Z0-9]" +AN_="[A-Z0-9_]" +aln="[A-Za-z0-9]" +an_="[A-Za-z0-9_]" +# to match something like 1ul, floats or hexes as well: +D="$int*\.\?$int\+x\?$hex*[uUlL]\{0,3\}[fF]\?" + +# more strict and catches it (costs one backreference for (git-)grep) +d="\($int\+[uUlLfF]\?\|$int\+[uU]\?[lL][lL]\?\|0x$hex\+\|0x$HEX\+\|$i\+[lL][lL][uU]\|$i*\.$i\+[fF]\?\)" + +# capital: can be used to catch a definition or config option +K="$UP_\+$AN_*"; + +# can be used for a variable/function name: +V="$an_\+$an_*" + +# works the same as above, but also for members and arrays: one backreference +# is more strict +W="$V\(\[$s$V$s\]\|\[$s$D$s\]\|\.$V\|->$V\)*" +# catches it at once (less strict) +w="\($V\|${V}\[$s$an_*${s}\]\|$V\.\|$V->\)\+" + +# seperators: +s="[[:space:]]*"; +S="[[:space:]]\+" + +# useful to delimit a variable name: +Q="[^[:alnum:]_]" + +# match the end of the line, including comments: one backreference (but at eol) +cendl="$s\(\/[\*\/].*\)\?$" + +# match something that is not comment, string or character: 2 backreferences +ccode="\([^\/\"']*\|\/[^\*\/]\|\/\*\([^\*]*\|\**[^\/\*]\)*\*\+\/\|'[^']*'\|\"[^\"]*\"\)*" + +# resp function open and end (only works when indentation is correct. +fo="^[\{]$cendl" +fe="^[\}]$cendl" +se="^[\}];$cendl" + +# to match nested parentheses +nps="[^()]*" +nstdps="\(($nps\(($nps\(($nps\(($nps\(($nps)$nps\)*)$nps\)*)$nps\)*)$nps\)*)$nps\)*" + + +# first determine unsigned typedefs +arr="\(\[[^\]]*\]$s\)*" +attr="__attribute__$s(([^;]*))" +utype="${s}typedef${S}unsigned$S\($V$S\)*" +uns="unsigned$( +git-grep "^$utype\($V$s$arr\|$attr$S$V$s$arr\|$V$s$arr$S$attr\)$s;$cendl" | sed -n "s/^[^.]*\.[hc]:$utype\(\($V\)$s$arr\|$attr$S\($V\)$s$arr\|\($V\)$s$arr$S$attr\)$s;$cendl/\\\\|\3\5\7/p" | sort | uniq | tr -d "\n")" + +# define left and right operators +# to decrease the number backrefences, these are assigned in loops +opl= +for op in "[;,|^?:(]" "[\!+*/%&|~^-]=" ">>=" "<<=" "\[" "&&" "$an_$s&"; do + opl="$opl$op\|$op$s++\|$op$s--\|" +done +opl="\(${opl%|})" +opr= +for op in "[;,&|^?:)]" "[\!+*/%&|~^<>-]=" ">>=" "<<=" ">[^>]" "<[^<]" "\]"; do + opr="$opr$op\|$op$s++\|$op$s--\|" +done +opr="\(${opr%|})" + +# string catches invalid comparison +q1="$opl$s\($w$s\(>=${s}0\|<${s}0\|[><\!=]=$s-$s$D\|[<>]$s-$s$D\)\|\(0$s>\|0$s<=\|-$s$D${s}[><\!=]=\|-$s$D${s}[<>]\)$s$w\)$s$opr" + +start=0 +end=$(echo $uns | tr -cd "|" | wc -c) + +# main function +while [ $start -lt $end ]; do + # we match 30 typedefs at a time + tuns="$(echo $uns | cut -d "\\" -f$start-$(($start+29)))" + + # catch candidate files + for f in $(git-grep -l "^\(${ccode}[,;]$s\)\?\($tuns\)$S" | grep "[^.]*\.[ch]" | xargs grep -l "$q1"); do + for n in $(sed -n "/^.*$q1/=" $f); do # lines + for v in $(sed -n "${n}s/^.*$q1.*$/\3\6/p" $f); do + # n2 = wine there + head -n$n $f | tac | sed -n "/^[{]/q; /^\(.*$Q\)\?\($tuns\)$S\($V$S\)*$v$Q.*$/=" | while read n2; + do + echo "# --- invalid test on unsigned variable '$v' --- #" + echo "vi $f +$n2 # unsigned declaration" + echo "vi $f +$n # invalid test" + done + done + done + done + start=$(($start+30)) +done | less +-- +To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/demos/usb_submit_urb.c b/demos/usb_submit_urb.c new file mode 100644 index 0000000..60f60b3 --- /dev/null +++ b/demos/usb_submit_urb.c @@ -0,0 +1,194 @@ +// from usbnet.c + +static int gl_interrupt_read (struct usbnet *dev) +{ + struct gl_priv *priv = dev->priv_data; + int retval; + + // issue usb interrupt read + if (priv && priv->irq_urb) { + // submit urb + if ((retval = usb_submit_urb (priv->irq_urb)) != 0) + dbg ("gl_interrupt_read: submit fail - %X...", retval); + else + dbg ("gl_interrupt_read: submit success..."); + } + + return 0; +} + + +static void rx_submit (struct usbnet *dev, struct urb *urb, int flags) +{ + struct sk_buff *skb; + struct skb_data *entry; + int retval = 0; + unsigned long lockflags; + size_t size; + +#ifdef CONFIG_USB_NET1080 + if (dev->driver_info->flags & FLAG_FRAMING_NC) + size = FRAMED_SIZE (dev->net.mtu); + else +#endif +#ifdef CONFIG_USB_GENESYS + if (dev->driver_info->flags & FLAG_FRAMING_GL) + size = GL_RCV_BUF_SIZE; + else +#endif + size = (sizeof (struct ethhdr) + dev->net.mtu); + + if ((skb = alloc_skb (size, flags)) == 0) { + dbg ("no rx skb"); + tasklet_schedule (&dev->bh); + usb_free_urb (urb); + return; + } + + entry = (struct skb_data *) skb->cb; + entry->urb = urb; + entry->dev = dev; + entry->state = rx_start; + entry->length = 0; + + FILL_BULK_URB (urb, dev->udev, + usb_rcvbulkpipe (dev->udev, dev->driver_info->in), + skb->data, size, rx_complete, skb); + urb->transfer_flags |= USB_ASYNC_UNLINK; +#ifdef REALLY_QUEUE + urb->transfer_flags |= USB_QUEUE_BULK; +#endif +#if 0 + // Idle-but-posted reads with UHCI really chew up + // PCI bandwidth unless FSBR is disabled + urb->transfer_flags |= USB_NO_FSBR; +#endif + + spin_lock_irqsave (&dev->rxq.lock, lockflags); + + if (netif_running (&dev->net)) { + if ((retval = usb_submit_urb (urb)) != 0) { + dbg ("%s rx submit, %d", dev->net.name, retval); + tasklet_schedule (&dev->bh); + } else { + __skb_queue_tail (&dev->rxq, skb); + } + } else { + dbg ("rx: stopped"); + retval = -ENOLINK; + } + spin_unlock_irqrestore (&dev->rxq.lock, lockflags); + if (retval) { + dev_kfree_skb_any (skb); + usb_free_urb (urb); + } +} + + + +static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) +{ + struct usbnet *dev = (struct usbnet *) net->priv; + int length = skb->len; + int retval = NET_XMIT_SUCCESS; + struct urb *urb = 0; + struct skb_data *entry; + struct driver_info *info = dev->driver_info; + unsigned long flags; +#ifdef CONFIG_USB_NET1080 + struct nc_header *header = 0; + struct nc_trailer *trailer = 0; +#endif /* CONFIG_USB_NET1080 */ + + flags = in_interrupt () ? GFP_ATOMIC : GFP_NOIO; /* might be used for nfs */ + + // some devices want funky USB-level framing, for + // win32 driver (usually) and/or hardware quirks + if (info->tx_fixup) { + skb = info->tx_fixup (dev, skb, flags); + if (!skb) { + dbg ("can't tx_fixup skb"); + goto drop; + } + } + + if (!(urb = usb_alloc_urb (0))) { + dbg ("no urb"); + goto drop; + } + + entry = (struct skb_data *) skb->cb; + entry->urb = urb; + entry->dev = dev; + entry->state = tx_start; + entry->length = length; + + // FIXME: reorganize a bit, so that fixup() fills out NetChip + // framing too. (Packet ID update needs the spinlock...) + +#ifdef CONFIG_USB_NET1080 + if (info->flags & FLAG_FRAMING_NC) { + header = (struct nc_header *) skb_push (skb, sizeof *header); + header->hdr_len = cpu_to_le16 (sizeof (*header)); + header->packet_len = cpu_to_le16 (length); + if (!((skb->len + sizeof *trailer) & 0x01)) + *skb_put (skb, 1) = PAD_BYTE; + trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer); + } else +#endif /* CONFIG_USB_NET1080 */ + + /* don't assume the hardware handles USB_ZERO_PACKET */ + if ((length % EP_SIZE (dev)) == 0) + skb->len++; + + FILL_BULK_URB (urb, dev->udev, + usb_sndbulkpipe (dev->udev, info->out), + skb->data, skb->len, tx_complete, skb); + urb->transfer_flags |= USB_ASYNC_UNLINK; +#ifdef REALLY_QUEUE + urb->transfer_flags |= USB_QUEUE_BULK; +#endif + // FIXME urb->timeout = ... jiffies ... ; + + spin_lock_irqsave (&dev->txq.lock, flags); + +#ifdef CONFIG_USB_NET1080 + if (info->flags & FLAG_FRAMING_NC) { + header->packet_id = cpu_to_le16 (dev->packet_id++); + put_unaligned (header->packet_id, &trailer->packet_id); +#if 0 + devdbg (dev, "frame >tx h %d p %d id %d", + header->hdr_len, header->packet_len, + header->packet_id); +#endif + } +#endif /* CONFIG_USB_NET1080 */ + + netif_stop_queue (net); + if ((retval = usb_submit_urb (urb)) != 0) { + netif_start_queue (net); + dbg ("%s tx: submit urb err %d", net->name, retval); + } else { + net->trans_start = jiffies; + __skb_queue_tail (&dev->txq, skb); + if (dev->txq.qlen < TX_QLEN) + netif_start_queue (net); + } + spin_unlock_irqrestore (&dev->txq.lock, flags); + + if (retval) { + devdbg (dev, "drop, code %d", retval); +drop: + retval = NET_XMIT_DROP; + dev->stats.tx_dropped++; + if (skb) + dev_kfree_skb_any (skb); + usb_free_urb (urb); +#ifdef VERBOSE + } else { + devdbg (dev, "> tx, len %d, type 0x%x", + length, skb->protocol); +#endif + } + return retval; +} diff --git a/demos/usb_submit_urb.cocci b/demos/usb_submit_urb.cocci new file mode 100644 index 0000000..7f5a2ff --- /dev/null +++ b/demos/usb_submit_urb.cocci @@ -0,0 +1,18 @@ +@@ +expression lock, flags; +expression urb; +@@ + + spin_lock_irqsave(lock, flags); + <... +- usb_submit_urb(urb) ++ usb_submit_urb(urb, GFP_ATOMIC) + ...> + spin_unlock_irqrestore(lock, flags); + +@@ +expression urb; +@@ + +- usb_submit_urb(urb) ++ usb_submit_urb(urb, GFP_KERNEL) diff --git a/demos/video_usercopy.c b/demos/video_usercopy.c new file mode 100644 index 0000000..e01d6a3 --- /dev/null +++ b/demos/video_usercopy.c @@ -0,0 +1,30 @@ +int p20_ioctl(int cmd, void*arg) { + switch(cmd) { + case VIDIOGCTUNER: { + struct video_tuner v; + if(copy_from_user(&v,arg)!=0) + return -EFAULT; + if(v.tuner) + return -EINVAL; + v.rangelow = 87*16000; + v.rangehigh = 108 * 16000; + if(copy_to_user(arg,&v)) + return -EFAULT; + return 0; + } + case AGCTUNER: { + struct video_tuner v; + if(copy_from_user(&v,arg)) + { + return -EFAULT; + } + if(v.tuner) + return -EINVAL; + v.rangelow = 0; + v.rangehigh = 0; + if(copy_to_user(arg,&v)) + return -EFAULT; + return 0; + } + } +} diff --git a/demos/video_usercopy.cocci b/demos/video_usercopy.cocci new file mode 100644 index 0000000..44a79d5 --- /dev/null +++ b/demos/video_usercopy.cocci @@ -0,0 +1,30 @@ +// - if(copy_from_user(&x, arg)) does not work. +// the if-isomorphism does not work :( + +@@ +type T; +identifier x, fld; +function ioctl; // should be caracterised by another rule +@@ + + + ioctl(..., void *arg, ...) { + <... +- T x; ++ T *x = arg; + ... +- if(copy_from_user(&x, arg)!=0) +- { ... return ...; } + <... +( +- x.fld ++ x->fld +| +- &x ++ x +) + ...> +- if(copy_to_user(arg, &x)) +- { ... return ...; } + ...> + } \ No newline at end of file diff --git a/demos/xxx_info.c b/demos/xxx_info.c new file mode 100644 index 0000000..6e198f6 --- /dev/null +++ b/demos/xxx_info.c @@ -0,0 +1,14 @@ +int wd7000_info(int x) { + float z; + scsi *y; + z = x + 1; + y = scsi_get(); + if(!y) { + kprintf("error"); + return -1; + } + kprintf("val = %d", y->field + z); + scsi_put(y); + return 0; +} + diff --git a/demos/xxx_info.cocci b/demos/xxx_info.cocci new file mode 100644 index 0000000..c73c1c7 --- /dev/null +++ b/demos/xxx_info.cocci @@ -0,0 +1,18 @@ +@@ +function xxx_info; +identifier x,y; +@@ + int xxx_info(int x ++ ,scsi *y + ) { + ... +- scsi *y; + ... +- y = scsi_get(); +- if(!y) { ... return -1; } + ... +- scsi_put(y); + ... +} + + diff --git a/docs/SmPL-ver2-tutorial-ols07.pdf b/docs/SmPL-ver2-tutorial-ols07.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1cc81d39e57cb4d13bcc7cf4186857dc9cae1622 GIT binary patch literal 147073 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

QpPr`)up6J7HB_;I$f=i*8MpU9G3St!E>% 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 literal 0 HcmV?d00001 diff --git a/docs/SmPL-with-grammar-ercim-evos06.pdf b/docs/SmPL-with-grammar-ercim-evos06.pdf new file mode 100644 index 0000000000000000000000000000000000000000..78428e646321d7e721da265fc2027d1a1e44e9ed GIT binary patch literal 256889 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%0AC`s@nB(Heo1W=5WJqP!C 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

  • @%d@{+~)Mckd-Gfh}Y&IpcHTEw8 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 literal 0 HcmV?d00001 diff --git a/docs/cocci-python.txt b/docs/cocci-python.txt new file mode 100644 index 0000000..08ca830 --- /dev/null +++ b/docs/cocci-python.txt @@ -0,0 +1,50 @@ +Python extensions for Coccinelle +================================ + +Coccinelle embeds a python interpreter to support processing +matches using the full expressive power of python. + +Scripting with python +--------------------- + +A python script part to a .cocci file must not be the first rule. A typical sample for searching for constantly sized arrays and its uses could be: + +@ rule1 @ type T; identifier I; expression C, E; position p1, p2; @@ +T I[C@p1]; +<+... I[E@p2] ...+> +@ script:python @ x_mv << rule1.C; y_mv << rule1.E; x_pos << rule1.p1; y_pos << rule1.p2; @@ +x = cocci.combine(x_mv, x_pos) +y = cocci.combine(y_mv, y_pos) +print x.location +print y.location + +Here cocci is the interface class for interfacting with Coccinelle's OCaml core. It is part python and part OCaml code. The combine function ensures that the filename, line number and column number of the matches are registered with a meta-variable. + +Controlling environments +------------------------ + +The python script will be called for each environment generated by Coccinelle with matches to the previous rules. By default, the python script drops each environment unless otherwise is indicated in the script using cocci.include_match(True). + +As a short-cut for registering information that "belongs together", the Output class also provides a register_match method that may be overridden in derived classes. This method can be called like: cocci.register_match(True, [(x, 'Array size'), (y, 'Array index size')]). Here the True is automatically passed on to include_match (so one could use False in order to drop the environment, but still print information). In the GTK frontend, this will result in the "Array index size" information being shown as a child node to the "Array size". + +Output methods for the python scripts +------------------------------------- + +By default Coccinelle contains two output modes: a console-based output, and a GTK-based output. Which one is used is specified using the -pyoutput switch to spatch. + +-pyoutput coccilib.output.Console (this is the default) +-pyoutput coccilib.output.Gtk + +The latter depends on pygtk2, and the dependency will not be evaluated until runtime. + +Creating new python output classes +---------------------------------- + +If you have a need to tailor special output based on your python script, e.g. using register_match of existing scripts, you can do this by deriving from coccilib.output.Output and override the implementation of register_match(self, include, messages). The method expects that the first thing you call is "self.include_match(include)", but otherwise the details of the method is left up to you. + +To use your custom output class, just specify it as an argument to -pyoutput. It needs to exist in the default python execution environment or in PYTHON_PATH. + +Running spatch from a different directory than it is stored in +-------------------------------------------------------------- + +In order for spatch to be able to find coccilib, PYTHON_PATH must be set to include the directory in which spatch resides. diff --git a/docs/developer.txt b/docs/developer.txt new file mode 100644 index 0000000..f5b54a5 --- /dev/null +++ b/docs/developer.txt @@ -0,0 +1,134 @@ +-*- org -*- + + +* How to install coccinelle +------------------------------ + +** CVS + +export CVS_RSH=ssh +export CVSROOT=:ext:topps.diku.dk:/var/cvs/cocci + +You must be a member of the cocci group on the topps.diku.dk machine. + +Then +cvs checkout coccinelle. + +** Dependencies + +See install.txt + +** Tools + +OCaml, Emacs. + +** Compile + +make depend +make + + +* How to use coccinelle +------------------------------ + +** Test + +** Tutorial + +I have put demos/examples. + +** spatch, sgrep + +** Emacs coccinelle mode + +See emacs/cocci.el for instructions. + +** Manual + +See docs/manual.tex + +* How to extend coccinelle +------------------------------ + + +Send us a semantic patch :) + + +* Documentation on coccinelle internals +---------------------------------------- +- look at the papers from the coccinelle website: + http://www.emn.fr/x-info/coccinelle +- look in docs from + cvs checkout working-documents +- look at the code :) + + + +** Software architecture + +See docs/graph-module-dependencies.ps + +** coccinelle/ organization + +See authors.txt + +* Being a coccinelle developer +------------------------------ + +** Conventions/advices +Do not use the 'open' OCaml module instruction. +Qualify, like in 'Cocci.full_engine x'. + +Have a makefile in each directory with a clean:, depend:, +and possibly all: and all.opt: targets. + + +* How to contribute to Linux +------------------------------ + +** How to use git +** How to use spatch +** How to prepare a patch for Linus + +* Tools +------------------------------ + +** Emacs + +** debugging: ocamldebug, the ocaml replay debugger + +** profiling: gprof (but can also use the -profile option of spatch) + +** CVS tricks + +*** To remove : + + cvs release -d + +*** To update the code and allow the checkout of new directories but +pruning empty (obsolete but still there because CVS sux) directories: + + cvs update -d -P + +*** To see what has changed since 2 days + + cvs diff -u -D "2 days ago" + +*** To create a new CVS module: + + mkdir nameofdir; + cd nameofdir; + cvs import -m"your commit message" yoyo start + cd ..; + rm -rf nameofdir; + cvs checkout nameofdir + +yoyo is a dummy name + + + + +* Coders +------------------------------ + +See authors.txt diff --git a/docs/graph-module-dependencies.ps b/docs/graph-module-dependencies.ps new file mode 100644 index 0000000..b34ef44 --- /dev/null +++ b/docs/graph-module-dependencies.ps @@ -0,0 +1,6475 @@ +%!PS-Adobe-2.0 +%%Creator: dot version 2.8 (Wed Dec 20 14:50:18 UTC 2006) +%%For: (pad) pad,,, +%%Title: G +%%Pages: (atend) +%%BoundingBox: 36 36 584 196 +%%EndComments +save +%%BeginProlog +/DotDict 200 dict def +DotDict begin + +/setupLatin1 { +mark +/EncodingVector 256 array def + EncodingVector 0 + +ISOLatin1Encoding 0 255 getinterval putinterval +EncodingVector 45 /hyphen put + +% Set up ISO Latin 1 character encoding +/starnetISO { + dup dup findfont dup length dict begin + { 1 index /FID ne { def }{ pop pop } ifelse + } forall + /Encoding EncodingVector def + currentdict end definefont +} def +/Times-Roman starnetISO def +/Times-Italic starnetISO def +/Times-Bold starnetISO def +/Times-BoldItalic starnetISO def +/Helvetica starnetISO def +/Helvetica-Oblique starnetISO def +/Helvetica-Bold starnetISO def +/Helvetica-BoldOblique starnetISO def +/Courier starnetISO def +/Courier-Oblique starnetISO def +/Courier-Bold starnetISO def +/Courier-BoldOblique starnetISO def +cleartomark +} bind def + +%%BeginResource: procset graphviz 0 0 +/coord-font-family /Times-Roman def +/default-font-family /Times-Roman def +/coordfont coord-font-family findfont 8 scalefont def + +/InvScaleFactor 1.0 def +/set_scale { + dup 1 exch div /InvScaleFactor exch def + dup scale +} bind def + +% styles +/solid { [] 0 setdash } bind def +/dashed { [9 InvScaleFactor mul dup ] 0 setdash } bind def +/dotted { [1 InvScaleFactor mul 6 InvScaleFactor mul] 0 setdash } bind def +/invis {/fill {newpath} def /stroke {newpath} def /show {pop newpath} def} bind def +/bold { 2 setlinewidth } bind def +/filled { } bind def +/unfilled { } bind def +/rounded { } bind def +/diagonals { } bind def + +% hooks for setting color +/nodecolor { sethsbcolor } bind def +/edgecolor { sethsbcolor } bind def +/graphcolor { sethsbcolor } bind def +/nopcolor {pop pop pop} bind def + +/beginpage { % i j npages + /npages exch def + /j exch def + /i exch def + /str 10 string def + npages 1 gt { + gsave + coordfont setfont + 0 0 moveto + (\() show i str cvs show (,) show j str cvs show (\)) show + grestore + } if +} bind def + +/set_font { + findfont exch + scalefont setfont +} def + +% draw aligned label in bounding box aligned to current point +/alignedtext { % width adj text + /text exch def + /adj exch def + /width exch def + gsave + width 0 gt { + text stringwidth pop adj mul 0 rmoveto + } if + [] 0 setdash + text show + grestore +} def + +/boxprim { % xcorner ycorner xsize ysize + 4 2 roll + moveto + 2 copy + exch 0 rlineto + 0 exch rlineto + pop neg 0 rlineto + closepath +} bind def + +/ellipse_path { + /ry exch def + /rx exch def + /y exch def + /x exch def + matrix currentmatrix + newpath + x y translate + rx ry scale + 0 0 1 0 360 arc + setmatrix +} bind def + +/endpage { showpage } bind def +/showpage { } def + +/layercolorseq + [ % layer color sequence - darkest to lightest + [0 0 0] + [.2 .8 .8] + [.4 .8 .8] + [.6 .8 .8] + [.8 .8 .8] + ] +def + +/layerlen layercolorseq length def + +/setlayer {/maxlayer exch def /curlayer exch def + layercolorseq curlayer 1 sub layerlen mod get + aload pop sethsbcolor + /nodecolor {nopcolor} def + /edgecolor {nopcolor} def + /graphcolor {nopcolor} def +} bind def + +/onlayer { curlayer ne {invis} if } def + +/onlayers { + /myupper exch def + /mylower exch def + curlayer mylower lt + curlayer myupper gt + or + {invis} if +} def + +/curlayer 0 def + +%%EndResource +%%EndProlog +%%BeginSetup +14 default-font-family set_font +1 setmiterlimit +% /arrowlength 10 def +% /arrowwidth 5 def + +% make sure pdfmark is harmless for PS-interpreters other than Distiller +/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse +% make '<<' and '>>' safe on PS Level 1 devices +/languagelevel where {pop languagelevel}{1} ifelse +2 lt { + userdict (<<) cvn ([) cvn load put + userdict (>>) cvn ([) cvn load put +} if + +%%EndSetup +%%Page: 1 1 +%%PageBoundingBox: 36 36 584 196 +%%PageOrientation: Portrait +gsave +36 36 548 160 boxprim clip newpath +36 36 translate +0 0 1 beginpage +0.1451 set_scale +28 28 translate 0 rotate +0.000 0.000 1.000 graphcolor +0.000 0.000 1.000 graphcolor +newpath -41 -41 moveto +-41 1089 lineto +3762 1089 lineto +3762 -41 lineto +closepath +fill +0.000 0.000 1.000 graphcolor +newpath -41 -41 moveto +-41 1089 lineto +3762 1089 lineto +3762 -41 lineto +closepath +stroke +0.000 0.000 0.000 graphcolor +14.00 /Times-Roman set_font +% Mktex +gsave 10 dict begin +3447 666 32 18 ellipse_path +stroke +gsave 10 dict begin +3428 661 moveto +(Mktex) +[12.48 6.96 3.84 6.24 6.96] +xshow +end grestore +end grestore +% Common +gsave 10 dict begin +1496 90 39 18 ellipse_path +stroke +gsave 10 dict begin +1470 85 moveto +(Common) +[9.36 6.96 10.8 10.8 6.96 6.96] +xshow +end grestore +end grestore +% Mktex->Common +newpath 3428 651 moveto +3367 603 3166 451 2981 360 curveto +2937 338 2912 358 2878 324 curveto +2841 288 2868 257 2840 216 curveto +2812 175 2801 162 2756 144 curveto +2642 99 1764 91 1545 90 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1545 87 moveto +1535 90 lineto +1545 94 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1545 87 moveto +1535 90 lineto +1545 94 lineto +closepath +stroke +end grestore +% Config +gsave 10 dict begin +3159 594 32 18 ellipse_path +stroke +gsave 10 dict begin +3139 589 moveto +(Config) +[9.36 6.96 6.96 4.56 3.84 6.96] +xshow +end grestore +end grestore +% Mktex->Config +newpath 3423 654 moveto +3418 652 3412 649 3406 648 curveto +3319 621 3292 636 3205 612 curveto +3201 611 3198 610 3194 609 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3196 606 moveto +3185 605 lineto +3193 612 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3196 606 moveto +3185 605 lineto +3193 612 lineto +closepath +stroke +end grestore +% Commonop +gsave 10 dict begin +1446 18 46 18 ellipse_path +stroke +gsave 10 dict begin +1413 13 moveto +(Commonop) +[9.36 6.96 10.8 10.8 6.96 6.96 6.96 6.96] +xshow +end grestore +end grestore +% Common->Commonop +newpath 1484 73 moveto +1478 64 1470 53 1464 43 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1467 41 moveto +1458 35 lineto +1461 45 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1467 41 moveto +1458 35 lineto +1461 45 lineto +closepath +stroke +end grestore +% Dumper +gsave 10 dict begin +1546 18 36 18 ellipse_path +stroke +gsave 10 dict begin +1522 13 moveto +(Dumper) +[10.08 6.96 10.8 6.96 6.24 4.56] +xshow +end grestore +end grestore +% Common->Dumper +newpath 1508 73 moveto +1514 64 1522 53 1528 43 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1531 45 moveto +1534 35 lineto +1525 41 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1531 45 moveto +1534 35 lineto +1525 41 lineto +closepath +stroke +end grestore +% Init +gsave 10 dict begin +3298 666 27 18 ellipse_path +stroke +gsave 10 dict begin +3288 661 moveto +(Init) +[4.56 6.96 3.84 3.84] +xshow +end grestore +end grestore +% Init->Config +newpath 3277 655 moveto +3255 643 3218 625 3192 611 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3193 608 moveto +3183 606 lineto +3190 614 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3193 608 moveto +3183 606 lineto +3190 614 lineto +closepath +stroke +end grestore +% Diff +gsave 10 dict begin +3370 666 27 18 ellipse_path +stroke +gsave 10 dict begin +3357 661 moveto +(Diff) +[10.08 3.84 4.56 4.56] +xshow +end grestore +end grestore +% Diff->Config +newpath 3349 654 moveto +3344 652 3339 650 3334 648 curveto +3278 626 3261 630 3205 612 curveto +3202 611 3198 610 3195 609 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3196 605 moveto +3185 605 lineto +3193 612 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3196 605 moveto +3185 605 lineto +3193 612 lineto +closepath +stroke +end grestore +% Ce +gsave 10 dict begin +3154 666 27 18 ellipse_path +stroke +gsave 10 dict begin +3146 661 moveto +(Ce) +[9.36 6.24] +xshow +end grestore +end grestore +% Ce->Config +newpath 3155 648 moveto +3156 640 3156 631 3157 622 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3160 622 moveto +3158 612 lineto +3154 622 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3160 622 moveto +3158 612 lineto +3154 622 lineto +closepath +stroke +end grestore +% Ast0 +gsave 10 dict begin +3226 666 27 18 ellipse_path +stroke +gsave 10 dict begin +3212 661 moveto +(Ast0) +[10.08 5.52 3.84 6.96] +xshow +end grestore +end grestore +% Ast0->Config +newpath 3211 650 moveto +3202 640 3191 628 3181 617 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3184 615 moveto +3174 610 lineto +3179 620 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3184 615 moveto +3174 610 lineto +3179 620 lineto +closepath +stroke +end grestore +% Generate_dependencies +gsave 10 dict begin +2760 738 79 18 ellipse_path +stroke +gsave 10 dict begin +2693 733 moveto +(Generate_dependencies) +[10.08 6.24 6.96 6.24 4.56 6.24 3.84 6.24 6.96 6.96 6.24 6.96 6.24 6.96 6.96 6.24 6.96 6.24 3.84 6.24 5.52] +xshow +end grestore +end grestore +% C_info +gsave 10 dict begin +2852 666 32 18 ellipse_path +stroke +gsave 10 dict begin +2832 661 moveto +(C_info) +[9.36 6.96 3.84 6.96 4.56 6.96] +xshow +end grestore +end grestore +% Generate_dependencies->C_info +newpath 2782 721 moveto +2794 710 2811 697 2825 687 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2827 690 moveto +2833 681 lineto +2823 684 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2827 690 moveto +2833 681 lineto +2823 684 lineto +closepath +stroke +end grestore +% Parse_c +gsave 10 dict begin +2937 666 35 18 ellipse_path +stroke +gsave 10 dict begin +2915 661 moveto +(Parse_c) +[7.68 6.24 4.56 5.52 6.24 6.96 6.24] +xshow +end grestore +end grestore +% Generate_dependencies->Parse_c +newpath 2799 722 moveto +2825 711 2861 697 2893 684 curveto +2895 683 2897 682 2900 681 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2901 684 moveto +2909 677 lineto +2898 678 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2901 684 moveto +2909 677 lineto +2898 678 lineto +closepath +stroke +end grestore +% Visitor_c +gsave 10 dict begin +2986 522 39 18 ellipse_path +stroke +gsave 10 dict begin +2959 517 moveto +(Visitor_c) +[10.08 3.84 5.52 3.84 3.84 6.96 4.56 6.96 6.24] +xshow +end grestore +end grestore +% C_info->Visitor_c +newpath 2867 650 moveto +2891 625 2936 576 2963 546 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2965 549 moveto +2970 539 lineto +2960 544 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2965 549 moveto +2970 539 lineto +2960 544 lineto +closepath +stroke +end grestore +% Flag +gsave 10 dict begin +1829 594 27 18 ellipse_path +stroke +gsave 10 dict begin +1816 589 moveto +(Flag) +[7.68 3.84 6.24 6.96] +xshow +end grestore +end grestore +% C_info->Flag +newpath 2828 654 moveto +2823 651 2817 649 2811 648 curveto +2764 636 2040 603 1866 595 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1866 592 moveto +1856 595 lineto +1866 599 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1866 592 moveto +1856 595 lineto +1866 599 lineto +closepath +stroke +end grestore +% Parse_c->Config +newpath 2967 656 moveto +3007 643 3078 621 3121 606 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3122 609 moveto +3131 603 lineto +3120 603 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3122 609 moveto +3131 603 lineto +3120 603 lineto +closepath +stroke +end grestore +% Parse_c->Visitor_c +newpath 2939 648 moveto +2941 629 2947 600 2956 576 curveto +2960 566 2965 557 2969 548 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2972 549 moveto +2974 539 lineto +2966 546 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2972 549 moveto +2974 539 lineto +2966 546 lineto +closepath +stroke +end grestore +% Lexer_c +gsave 10 dict begin +2765 522 36 18 ellipse_path +stroke +gsave 10 dict begin +2742 517 moveto +(Lexer_c) +[8.64 6.24 6.96 6.24 4.56 6.96 6.24] +xshow +end grestore +end grestore +% Parse_c->Lexer_c +newpath 2910 654 moveto +2905 652 2899 650 2893 648 curveto +2833 628 2794 661 2756 612 curveto +2742 594 2746 568 2753 549 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2756 551 moveto +2757 540 lineto +2750 548 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2756 551 moveto +2757 540 lineto +2750 548 lineto +closepath +stroke +end grestore +% Parsing_hacks +gsave 10 dict begin +2818 594 53 18 ellipse_path +stroke +gsave 10 dict begin +2777 589 moveto +(Parsing_hacks) +[7.68 6.24 4.56 5.52 3.84 6.96 6.96 6.96 6.96 6.24 6.24 6.96 5.52] +xshow +end grestore +end grestore +% Parse_c->Parsing_hacks +newpath 2914 652 moveto +2897 642 2873 627 2853 615 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2854 612 moveto +2844 610 lineto +2851 618 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2854 612 moveto +2844 610 lineto +2851 618 lineto +closepath +stroke +end grestore +% Split_patch +gsave 10 dict begin +414 234 45 18 ellipse_path +stroke +gsave 10 dict begin +382 229 moveto +(Split_patch) +[7.68 6.96 3.84 3.84 3.84 6.96 6.96 6.24 3.84 6.24 6.96] +xshow +end grestore +end grestore +% Classic_patch +gsave 10 dict begin +473 162 52 18 ellipse_path +stroke +gsave 10 dict begin +434 157 moveto +(Classic_patch) +[9.36 3.84 6.24 5.52 5.52 3.84 6.24 6.96 6.96 6.24 3.84 6.24 6.96] +xshow +end grestore +end grestore +% Split_patch->Classic_patch +newpath 428 217 moveto +435 208 444 197 452 187 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 455 189 moveto +459 179 lineto +450 184 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 455 189 moveto +459 179 lineto +450 184 lineto +closepath +stroke +end grestore +% Maintainers +gsave 10 dict begin +356 162 47 18 ellipse_path +stroke +gsave 10 dict begin +322 157 moveto +(Maintainers) +[12.48 6.24 3.84 6.96 3.84 6.24 3.84 6.96 6.24 4.56 5.52] +xshow +end grestore +end grestore +% Split_patch->Maintainers +newpath 400 217 moveto +393 208 384 197 376 187 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 379 185 moveto +370 179 lineto +373 189 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 379 185 moveto +370 179 lineto +373 189 lineto +closepath +stroke +end grestore +% Classic_patch->Common +newpath 511 150 moveto +520 147 530 145 539 144 curveto +716 115 1276 97 1447 91 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1447 95 moveto +1457 91 lineto +1447 88 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1447 95 moveto +1457 91 lineto +1447 88 lineto +closepath +stroke +end grestore +% Maintainers->Common +newpath 390 149 moveto +397 147 405 145 412 144 curveto +614 107 1263 94 1447 91 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1447 95 moveto +1457 91 lineto +1447 88 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1447 95 moveto +1457 91 lineto +1447 88 lineto +closepath +stroke +end grestore +% Extract_c_and_res +gsave 10 dict begin +3388 162 65 18 ellipse_path +stroke +gsave 10 dict begin +3335 157 moveto +(Extract_c_and_res) +[8.64 6.96 3.84 4.56 6.24 6.24 3.84 6.96 6.24 6.96 6.24 6.96 6.96 6.96 4.56 6.24 5.52] +xshow +end grestore +end grestore +% Extract_c_and_res->Common +newpath 3342 149 moveto +3333 147 3323 145 3314 144 curveto +3134 119 1818 96 1545 91 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1545 88 moveto +1535 91 lineto +1545 95 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1545 88 moveto +1535 91 lineto +1545 95 lineto +closepath +stroke +end grestore +% Meta_files +gsave 10 dict begin +114 234 43 18 ellipse_path +stroke +gsave 10 dict begin +83 229 moveto +(Meta_files) +[12.48 6.24 3.84 6.24 6.96 4.56 3.84 3.84 6.24 5.52] +xshow +end grestore +end grestore +% Meta_files->Maintainers +newpath 150 224 moveto +187 213 248 196 300 180 curveto +303 179 307 178 310 177 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 311 180 moveto +320 174 lineto +309 174 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 311 180 moveto +320 174 lineto +309 174 lineto +closepath +stroke +end grestore +% Kbuild +gsave 10 dict begin +114 162 32 18 ellipse_path +stroke +gsave 10 dict begin +94 157 moveto +(Kbuild) +[10.08 6.96 6.96 3.84 3.84 6.96] +xshow +end grestore +end grestore +% Meta_files->Kbuild +newpath 114 216 moveto +114 208 114 199 114 190 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 118 190 moveto +114 180 lineto +111 190 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 118 190 moveto +114 180 lineto +111 190 lineto +closepath +stroke +end grestore +% Kbuild->Common +newpath 141 152 moveto +150 149 161 146 171 144 curveto +423 100 1238 91 1447 90 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1447 94 moveto +1457 90 lineto +1447 87 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1447 94 moveto +1457 90 lineto +1447 87 lineto +closepath +stroke +end grestore +% S +gsave 10 dict begin +1229 738 27 18 ellipse_path +stroke +gsave 10 dict begin +1229 733 moveto 8.0 -0.5 (S) alignedtext +end grestore +end grestore +% Plus +gsave 10 dict begin +1229 666 27 18 ellipse_path +stroke +gsave 10 dict begin +1216 661 moveto +(Plus) +[7.68 3.84 6.96 5.52] +xshow +end grestore +end grestore +% S->Plus +newpath 1229 720 moveto +1229 712 1229 703 1229 694 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1233 694 moveto +1229 684 lineto +1226 694 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1233 694 moveto +1229 684 lineto +1226 694 lineto +closepath +stroke +end grestore +% Visitor_ast +gsave 10 dict begin +1327 594 44 18 ellipse_path +stroke +gsave 10 dict begin +1295 589 moveto +(Visitor_ast) +[10.08 3.84 5.52 3.84 3.84 6.96 4.56 6.96 6.24 5.52 3.84] +xshow +end grestore +end grestore +% Plus->Visitor_ast +newpath 1247 652 moveto +1261 642 1281 628 1298 616 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1300 619 moveto +1306 610 lineto +1296 613 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1300 619 moveto +1306 610 lineto +1296 613 lineto +closepath +stroke +end grestore +% Parse_aux +gsave 10 dict begin +1241 522 42 18 ellipse_path +stroke +gsave 10 dict begin +1212 517 moveto +(Parse_aux) +[7.68 6.24 4.56 5.52 6.24 6.96 6.24 6.96 6.96] +xshow +end grestore +end grestore +% Parse_aux->Common +newpath 1272 509 moveto +1290 500 1312 487 1325 468 curveto +1348 434 1344 418 1344 378 curveto +1344 378 1344 378 1344 234 curveto +1344 190 1350 175 1380 144 curveto +1399 123 1428 110 1451 101 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1452 104 moveto +1461 98 lineto +1450 98 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1452 104 moveto +1461 98 lineto +1450 98 lineto +closepath +stroke +end grestore +% Data +gsave 10 dict begin +1157 450 27 18 ellipse_path +stroke +gsave 10 dict begin +1143 445 moveto +(Data) +[10.08 6.24 3.84 6.24] +xshow +end grestore +end grestore +% Parse_aux->Data +newpath 1222 506 moveto +1210 495 1194 482 1182 471 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1184 468 moveto +1174 464 lineto +1179 473 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1184 468 moveto +1174 464 lineto +1179 473 lineto +closepath +stroke +end grestore +% Semantic_cocci +gsave 10 dict begin +1259 450 57 18 ellipse_path +stroke +gsave 10 dict begin +1214 445 moveto +(Semantic_cocci) +[7.68 6.24 10.8 6.24 6.96 3.84 3.84 6.24 6.96 6.24 6.96 6.24 6.24 3.84] +xshow +end grestore +end grestore +% Parse_aux->Semantic_cocci +newpath 1246 504 moveto +1248 496 1250 487 1252 478 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1255 479 moveto +1255 468 lineto +1249 477 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1255 479 moveto +1255 468 lineto +1249 477 lineto +closepath +stroke +end grestore +% Ast0_cocci +gsave 10 dict begin +1026 378 45 18 ellipse_path +stroke +gsave 10 dict begin +993 373 moveto +(Ast0_cocci) +[10.08 5.52 3.84 6.96 6.96 6.24 6.96 6.24 6.24 3.84] +xshow +end grestore +end grestore +% Data->Ast0_cocci +newpath 1136 438 moveto +1116 427 1086 410 1062 398 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1063 395 moveto +1053 393 lineto +1060 401 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1063 395 moveto +1053 393 lineto +1060 401 lineto +closepath +stroke +end grestore +% Lexer_cocci +gsave 10 dict begin +786 666 48 18 ellipse_path +stroke +gsave 10 dict begin +751 661 moveto +(Lexer_cocci) +[8.64 6.24 6.96 6.24 4.56 6.96 6.24 6.96 6.24 6.24 3.84] +xshow +end grestore +end grestore +% Parser_cocci_menhir +gsave 10 dict begin +1155 594 72 18 ellipse_path +stroke +gsave 10 dict begin +1096 589 moveto +(Parser_cocci_menhir) +[7.68 6.24 4.56 5.52 6.24 4.56 6.96 6.24 6.96 6.24 6.24 3.84 6.96 10.8 6.24 6.96 6.96 3.84 4.56] +xshow +end grestore +end grestore +% Lexer_cocci->Parser_cocci_menhir +newpath 823 654 moveto +831 652 840 650 848 648 curveto +927 629 1019 614 1082 604 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1082 607 moveto +1092 603 lineto +1082 601 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1082 607 moveto +1092 603 lineto +1082 601 lineto +closepath +stroke +end grestore +% Parser_cocci_menhir->Parse_aux +newpath 1176 577 moveto +1187 567 1202 555 1214 545 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1216 548 moveto +1221 538 lineto +1211 543 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1216 548 moveto +1221 538 lineto +1211 543 lineto +closepath +stroke +end grestore +% Top_level +gsave 10 dict begin +1140 522 41 18 ellipse_path +stroke +gsave 10 dict begin +1111 517 moveto +(Top_level) +[8.64 6.96 6.96 6.96 3.84 6.24 6.96 6.24 3.84] +xshow +end grestore +end grestore +% Parser_cocci_menhir->Top_level +newpath 1151 576 moveto +1150 568 1148 559 1146 550 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1149 549 moveto +1144 540 lineto +1143 550 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1149 549 moveto +1144 540 lineto +1143 550 lineto +closepath +stroke +end grestore +% Semantic +gsave 10 dict begin +252 162 39 18 ellipse_path +stroke +gsave 10 dict begin +226 157 moveto +(Semantic) +[7.68 6.24 10.8 6.24 6.96 3.84 3.84 6.24] +xshow +end grestore +end grestore +% Semantic->Common +newpath 280 149 moveto +287 147 293 145 300 144 curveto +524 98 1251 91 1447 90 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1447 94 moveto +1457 90 lineto +1447 87 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1447 94 moveto +1457 90 lineto +1447 87 lineto +closepath +stroke +end grestore +% Semantic_c +gsave 10 dict begin +2785 234 46 18 ellipse_path +stroke +gsave 10 dict begin +2752 229 moveto +(Semantic_c) +[7.68 6.24 10.8 6.24 6.96 3.84 3.84 6.24 6.96 6.24] +xshow +end grestore +end grestore +% Semantic_c->Common +newpath 2779 216 moveto +2770 194 2752 159 2725 144 curveto +2673 114 1767 96 1545 91 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1545 88 moveto +1535 91 lineto +1545 95 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1545 88 moveto +1535 91 lineto +1545 95 lineto +closepath +stroke +end grestore +% Lib_parsing_c +gsave 10 dict begin +3018 594 53 18 ellipse_path +stroke +gsave 10 dict begin +2977 589 moveto +(Lib_parsing_c) +[8.64 3.84 6.96 6.96 6.96 6.24 4.56 5.52 3.84 6.96 6.96 6.96 6.24] +xshow +end grestore +end grestore +% Lib_parsing_c->Visitor_c +newpath 3010 576 moveto +3006 568 3002 558 2998 549 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3001 548 moveto +2994 540 lineto +2995 551 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3001 548 moveto +2994 540 lineto +2995 551 lineto +closepath +stroke +end grestore +% Control_flow_c +gsave 10 dict begin +2472 450 57 18 ellipse_path +stroke +gsave 10 dict begin +2427 445 moveto +(Control_flow_c) +[9.36 6.96 6.96 3.84 4.56 6.96 3.84 6.96 4.56 3.84 6.96 10.08 6.96 6.24] +xshow +end grestore +end grestore +% Visitor_c->Control_flow_c +newpath 2957 510 moveto +2951 508 2944 505 2938 504 curveto +2778 466 2733 490 2572 468 curveto +2558 466 2544 463 2531 461 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2531 458 moveto +2521 459 lineto +2530 464 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2531 458 moveto +2521 459 lineto +2530 464 lineto +closepath +stroke +end grestore +% Ast_c +gsave 10 dict begin +2326 378 30 18 ellipse_path +stroke +gsave 10 dict begin +2309 373 moveto +(Ast_c) +[10.08 5.52 3.84 6.96 6.24] +xshow +end grestore +end grestore +% Ast_c->Common +newpath 2300 369 moveto +2180 327 1684 155 1537 104 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1538 101 moveto +1527 101 lineto +1536 107 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1538 101 moveto +1527 101 lineto +1536 107 lineto +closepath +stroke +end grestore +% Ast_cocci +gsave 10 dict begin +1576 306 42 18 ellipse_path +stroke +gsave 10 dict begin +1547 301 moveto +(Ast_cocci) +[10.08 5.52 3.84 6.96 6.24 6.96 6.24 6.24 3.84] +xshow +end grestore +end grestore +% Ast_c->Ast_cocci +newpath 2296 375 moveto +2183 364 1773 325 1627 311 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1627 308 moveto +1617 310 lineto +1627 314 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1627 308 moveto +1617 310 lineto +1627 314 lineto +closepath +stroke +end grestore +% Type_cocci +gsave 10 dict begin +1576 234 46 18 ellipse_path +stroke +gsave 10 dict begin +1543 229 moveto +(Type_cocci) +[8.64 6.96 6.96 6.24 6.96 6.24 6.96 6.24 6.24 3.84] +xshow +end grestore +end grestore +% Ast_cocci->Type_cocci +newpath 1576 288 moveto +1576 280 1576 271 1576 262 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1580 262 moveto +1576 252 lineto +1573 262 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1580 262 moveto +1576 252 lineto +1573 262 lineto +closepath +stroke +end grestore +% Parser_c +gsave 10 dict begin +2765 450 37 18 ellipse_path +stroke +gsave 10 dict begin +2740 445 moveto +(Parser_c) +[7.68 6.24 4.56 5.52 6.24 4.56 6.96 6.24] +xshow +end grestore +end grestore +% Lexer_c->Parser_c +newpath 2765 504 moveto +2765 496 2765 487 2765 478 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2769 478 moveto +2765 468 lineto +2762 478 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2769 478 moveto +2765 468 lineto +2762 478 lineto +closepath +stroke +end grestore +% Parser_c->Semantic_c +newpath 2773 432 moveto +2778 422 2783 409 2785 396 curveto +2793 349 2791 294 2788 262 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2791 262 moveto +2787 252 lineto +2785 262 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2791 262 moveto +2787 252 lineto +2785 262 lineto +closepath +stroke +end grestore +% Parser_c->Ast_c +newpath 2731 442 moveto +2715 439 2695 435 2678 432 curveto +2543 410 2505 428 2373 396 curveto +2369 395 2365 393 2361 392 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2362 389 moveto +2351 389 lineto +2360 395 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2362 389 moveto +2351 389 lineto +2360 395 lineto +closepath +stroke +end grestore +% Lexer_parser +gsave 10 dict begin +2726 378 50 18 ellipse_path +stroke +gsave 10 dict begin +2689 373 moveto +(Lexer_parser) +[8.64 6.24 6.96 6.24 4.56 6.96 6.96 6.24 4.56 5.52 6.24 4.56] +xshow +end grestore +end grestore +% Parser_c->Lexer_parser +newpath 2756 433 moveto +2752 424 2746 414 2741 405 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2744 403 moveto +2736 396 lineto +2738 406 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2744 403 moveto +2736 396 lineto +2738 406 lineto +closepath +stroke +end grestore +% Sgrep +gsave 10 dict begin +1775 378 29 18 ellipse_path +stroke +gsave 10 dict begin +1758 373 moveto +(Sgrep) +[7.68 6.96 4.56 6.24 6.96] +xshow +end grestore +end grestore +% Sgrep->Common +newpath 1766 361 moveto +1743 319 1679 210 1601 144 curveto +1581 128 1556 115 1535 105 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1537 102 moveto +1526 101 lineto +1534 108 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1537 102 moveto +1526 101 lineto +1534 108 lineto +closepath +stroke +end grestore +% Sgrep->Ast_cocci +newpath 1753 366 moveto +1747 364 1742 362 1737 360 curveto +1698 344 1653 329 1621 319 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1622 316 moveto +1611 316 lineto +1620 322 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1622 316 moveto +1611 316 lineto +1620 322 lineto +closepath +stroke +end grestore +% Lib_engine +gsave 10 dict begin +2298 594 45 18 ellipse_path +stroke +gsave 10 dict begin +2266 589 moveto +(Lib_engine) +[8.64 3.84 6.96 6.96 6.24 6.96 6.96 3.84 6.96 6.24] +xshow +end grestore +end grestore +% Lib_engine->Control_flow_c +newpath 2308 576 moveto +2319 556 2340 525 2365 504 curveto +2382 488 2405 477 2425 468 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2426 471 moveto +2434 464 lineto +2423 465 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2426 471 moveto +2434 464 lineto +2423 465 lineto +closepath +stroke +end grestore +% Wrapper_ctl +gsave 10 dict begin +2625 522 48 18 ellipse_path +stroke +gsave 10 dict begin +2589 517 moveto +(Wrapper_ctl) +[13.2 4.56 6.24 6.96 6.96 6.24 4.56 6.96 6.24 3.84 3.84] +xshow +end grestore +end grestore +% Lib_engine->Wrapper_ctl +newpath 2332 582 moveto +2338 580 2345 578 2352 576 curveto +2446 552 2473 562 2568 540 curveto +2572 539 2575 538 2579 537 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2580 540 moveto +2589 534 lineto +2578 534 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2580 540 moveto +2589 534 lineto +2578 534 lineto +closepath +stroke +end grestore +% Control_flow_c->Ast_c +newpath 2441 435 moveto +2416 423 2383 406 2358 394 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2360 391 moveto +2349 390 lineto +2357 397 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2360 391 moveto +2349 390 lineto +2357 397 lineto +closepath +stroke +end grestore +% Flag_parsing_c +gsave 10 dict begin +2627 306 56 18 ellipse_path +stroke +gsave 10 dict begin +2583 301 moveto +(Flag_parsing_c) +[7.68 3.84 6.24 6.96 6.96 6.96 6.24 4.56 5.52 3.84 6.96 6.96 6.96 6.24] +xshow +end grestore +end grestore +% Control_flow_c->Flag_parsing_c +newpath 2490 433 moveto +2518 407 2570 359 2601 330 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2604 332 moveto +2609 323 lineto +2599 327 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2604 332 moveto +2609 323 lineto +2599 327 lineto +closepath +stroke +end grestore +% Ograph_extended +gsave 10 dict begin +2909 378 63 18 ellipse_path +stroke +gsave 10 dict begin +2859 373 moveto +(Ograph_extended) +[10.08 6.96 4.56 6.24 6.96 6.96 6.96 6.24 6.96 3.84 6.24 6.96 6.96 6.24 6.96] +xshow +end grestore +end grestore +% Control_flow_c->Ograph_extended +newpath 2521 441 moveto +2537 438 2555 435 2572 432 curveto +2666 416 2775 399 2843 388 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2844 391 moveto +2853 386 lineto +2843 385 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2844 391 moveto +2853 386 lineto +2843 385 lineto +closepath +stroke +end grestore +% Ctl_engine +gsave 10 dict begin +2625 450 44 18 ellipse_path +stroke +gsave 10 dict begin +2594 445 moveto +(Ctl_engine) +[9.36 3.84 3.84 6.96 6.24 6.96 6.96 3.84 6.96 6.24] +xshow +end grestore +end grestore +% Wrapper_ctl->Ctl_engine +newpath 2625 504 moveto +2625 496 2625 487 2625 478 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2629 478 moveto +2625 468 lineto +2622 478 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2629 478 moveto +2625 468 lineto +2622 478 lineto +closepath +stroke +end grestore +% Isomorphisms_c_c +gsave 10 dict begin +2232 450 66 18 ellipse_path +stroke +gsave 10 dict begin +2179 445 moveto +(Isomorphisms_c_c) +[4.56 5.52 6.96 10.8 6.96 4.56 6.96 6.96 3.84 5.52 10.8 5.52 6.96 6.24 6.96 6.24] +xshow +end grestore +end grestore +% Isomorphisms_c_c->Ast_c +newpath 2254 433 moveto +2267 423 2285 409 2299 398 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2301 401 moveto +2307 392 lineto +2297 395 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2301 401 moveto +2307 392 lineto +2297 395 lineto +closepath +stroke +end grestore +% Check_exhaustive_pattern +gsave 10 dict begin +2472 522 87 18 ellipse_path +stroke +gsave 10 dict begin +2397 517 moveto +(Check_exhaustive_pattern) +[9.36 6.96 6.24 6.24 6.96 6.96 6.24 6.96 6.96 6.24 6.96 5.52 3.84 3.84 6.96 6.24 6.96 6.96 6.24 3.84 3.84 6.24 4.56 6.96] +xshow +end grestore +end grestore +% Check_exhaustive_pattern->Control_flow_c +newpath 2472 504 moveto +2472 496 2472 487 2472 478 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2476 478 moveto +2472 468 lineto +2469 478 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2476 478 moveto +2472 468 lineto +2469 478 lineto +closepath +stroke +end grestore +% Test_ctl +gsave 10 dict begin +2673 594 36 18 ellipse_path +stroke +gsave 10 dict begin +2650 589 moveto +(Test_ctl) +[8.64 6.24 5.52 3.84 6.96 6.24 3.84 3.84] +xshow +end grestore +end grestore +% Test_ctl->Wrapper_ctl +newpath 2661 577 moveto +2656 568 2649 557 2642 548 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2645 546 moveto +2637 539 lineto +2639 549 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2645 546 moveto +2637 539 lineto +2639 549 lineto +closepath +stroke +end grestore +% Oseth +gsave 10 dict begin +3606 306 29 18 ellipse_path +stroke +gsave 10 dict begin +3589 301 moveto +(Oseth) +[10.08 5.52 6.24 3.84 6.96] +xshow +end grestore +end grestore +% Oset +gsave 10 dict begin +3492 234 27 18 ellipse_path +stroke +gsave 10 dict begin +3479 229 moveto +(Oset) +[10.08 5.52 6.24 3.84] +xshow +end grestore +end grestore +% Oseth->Oset +newpath 3586 293 moveto +3568 282 3541 264 3521 251 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3522 248 moveto +3512 246 lineto +3519 254 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3522 248 moveto +3512 246 lineto +3519 254 lineto +closepath +stroke +end grestore +% Ocollection +gsave 10 dict begin +3113 162 46 18 ellipse_path +stroke +gsave 10 dict begin +3080 157 moveto +(Ocollection) +[10.08 6.24 6.96 3.84 3.84 6.24 6.24 3.84 3.84 6.96 6.96] +xshow +end grestore +end grestore +% Oset->Ocollection +newpath 3465 231 moveto +3409 224 3276 206 3168 180 curveto +3165 179 3161 178 3158 177 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3159 174 moveto +3148 174 lineto +3157 180 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3159 174 moveto +3148 174 lineto +3157 180 lineto +closepath +stroke +end grestore +% Seti +gsave 10 dict begin +3204 162 27 18 ellipse_path +stroke +gsave 10 dict begin +3193 157 moveto +(Seti) +[7.68 6.24 3.84 3.84] +xshow +end grestore +end grestore +% Oset->Seti +newpath 3465 230 moveto +3419 224 3320 207 3240 180 curveto +3238 179 3236 179 3234 178 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3236 175 moveto +3225 174 lineto +3233 181 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3236 175 moveto +3225 174 lineto +3233 181 lineto +closepath +stroke +end grestore +% SetPt +gsave 10 dict begin +3277 162 28 18 ellipse_path +stroke +gsave 10 dict begin +3262 157 moveto +(SetPt) +[7.68 6.24 3.84 7.68 3.84] +xshow +end grestore +end grestore +% Oset->SetPt +newpath 3467 228 moveto +3432 219 3367 201 3314 180 curveto +3312 179 3310 179 3308 178 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3309 175 moveto +3299 173 lineto +3306 181 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3309 175 moveto +3299 173 lineto +3306 181 lineto +closepath +stroke +end grestore +% Setb +gsave 10 dict begin +3498 162 27 18 ellipse_path +stroke +gsave 10 dict begin +3485 157 moveto +(Setb) +[7.68 6.24 3.84 6.96] +xshow +end grestore +end grestore +% Oset->Setb +newpath 3494 216 moveto +3495 208 3495 199 3496 190 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3500 190 moveto +3496 180 lineto +3493 190 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3500 190 moveto +3496 180 lineto +3493 190 lineto +closepath +stroke +end grestore +% Ocollection->Common +newpath 3068 158 moveto +3019 154 2940 148 2873 144 curveto +2353 115 1724 96 1545 91 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1545 88 moveto +1535 91 lineto +1545 95 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1545 88 moveto +1535 91 lineto +1545 95 lineto +closepath +stroke +end grestore +% Oassocid +gsave 10 dict begin +3234 306 39 18 ellipse_path +stroke +gsave 10 dict begin +3208 301 moveto +(Oassocid) +[10.08 6.24 5.52 5.52 6.96 6.24 3.84 6.96] +xshow +end grestore +end grestore +% Oassoc +gsave 10 dict begin +3126 234 33 18 ellipse_path +stroke +gsave 10 dict begin +3105 229 moveto +(Oassoc) +[10.08 6.24 5.52 5.52 6.96 6.24] +xshow +end grestore +end grestore +% Oassocid->Oassoc +newpath 3212 291 moveto +3196 280 3173 266 3155 254 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3157 251 moveto +3147 248 lineto +3153 257 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3157 251 moveto +3147 248 lineto +3153 257 lineto +closepath +stroke +end grestore +% Oassoc->Ocollection +newpath 3123 216 moveto +3122 208 3120 199 3118 190 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3121 189 moveto +3116 180 lineto +3115 190 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3121 189 moveto +3116 180 lineto +3115 190 lineto +closepath +stroke +end grestore +% Oassoch +gsave 10 dict begin +3328 306 37 18 ellipse_path +stroke +gsave 10 dict begin +3304 301 moveto +(Oassoch) +[10.08 6.24 5.52 5.52 6.96 6.24 6.96] +xshow +end grestore +end grestore +% Oassoch->Oassoc +newpath 3299 294 moveto +3293 292 3287 290 3282 288 curveto +3242 273 3196 257 3165 246 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3166 243 moveto +3155 243 lineto +3164 249 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3166 243 moveto +3155 243 lineto +3164 249 lineto +closepath +stroke +end grestore +% Oassocdbm +gsave 10 dict begin +3025 306 46 18 ellipse_path +stroke +gsave 10 dict begin +2992 301 moveto +(Oassocdbm) +[10.08 6.24 5.52 5.52 6.96 6.24 6.96 6.96 10.8] +xshow +end grestore +end grestore +% Oassocdbm->Oassoc +newpath 3047 290 moveto +3062 280 3082 266 3098 255 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3100 258 moveto +3106 249 lineto +3096 252 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3100 258 moveto +3106 249 lineto +3096 252 lineto +closepath +stroke +end grestore +% Oassocb +gsave 10 dict begin +2924 306 37 18 ellipse_path +stroke +gsave 10 dict begin +2900 301 moveto +(Oassocb) +[10.08 6.24 5.52 5.52 6.96 6.24 6.96] +xshow +end grestore +end grestore +% Oassocb->Oassoc +newpath 2952 294 moveto +2958 292 2964 290 2970 288 curveto +3010 273 3056 257 3087 246 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3088 249 moveto +3097 243 lineto +3086 243 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3088 249 moveto +3097 243 lineto +3086 243 lineto +closepath +stroke +end grestore +% Mapb +gsave 10 dict begin +2924 234 30 18 ellipse_path +stroke +gsave 10 dict begin +2907 229 moveto +(Mapb) +[12.48 6.24 6.96 6.96] +xshow +end grestore +end grestore +% Oassocb->Mapb +newpath 2924 288 moveto +2924 280 2924 271 2924 262 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2928 262 moveto +2924 252 lineto +2921 262 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2928 262 moveto +2924 252 lineto +2921 262 lineto +closepath +stroke +end grestore +% Oassoc_buffer +gsave 10 dict begin +3314 378 54 18 ellipse_path +stroke +gsave 10 dict begin +3273 373 moveto +(Oassoc_buffer) +[10.08 6.24 5.52 5.52 6.96 6.24 6.96 6.96 6.96 4.56 4.56 6.24 4.56] +xshow +end grestore +end grestore +% Oassoc_buffer->Oassocb +newpath 3267 369 moveto +3250 366 3231 363 3214 360 curveto +3105 342 3075 352 2970 324 curveto +2967 323 2964 322 2962 321 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2963 318 moveto +2952 318 lineto +2961 324 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2963 318 moveto +2952 318 lineto +2961 324 lineto +closepath +stroke +end grestore +% Osetb +gsave 10 dict begin +3492 306 29 18 ellipse_path +stroke +gsave 10 dict begin +3475 301 moveto +(Osetb) +[10.08 5.52 6.24 3.84 6.96] +xshow +end grestore +end grestore +% Oassoc_buffer->Osetb +newpath 3350 365 moveto +3379 354 3419 339 3454 324 curveto +3456 323 3458 322 3460 321 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3461 324 moveto +3469 317 lineto +3458 318 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3461 324 moveto +3469 317 lineto +3458 318 lineto +closepath +stroke +end grestore +% Osetb->Oset +newpath 3492 288 moveto +3492 280 3492 271 3492 262 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3496 262 moveto +3492 252 lineto +3489 262 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3496 262 moveto +3492 252 lineto +3489 262 lineto +closepath +stroke +end grestore +% Fullcommon +gsave 10 dict begin +3435 450 49 18 ellipse_path +stroke +gsave 10 dict begin +3399 445 moveto +(Fullcommon) +[7.68 6.96 3.84 3.84 6.24 6.96 10.8 10.8 6.96 6.96] +xshow +end grestore +end grestore +% Fullcommon->Oassoch +newpath 3425 432 moveto +3413 414 3395 384 3377 360 curveto +3369 350 3360 339 3351 330 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3353 327 moveto +3344 322 lineto +3348 332 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3353 327 moveto +3344 322 lineto +3348 332 lineto +closepath +stroke +end grestore +% Fullcommon->Oassoc_buffer +newpath 3409 435 moveto +3392 425 3369 411 3350 399 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3351 396 moveto +3341 394 lineto +3348 402 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3351 396 moveto +3341 394 lineto +3348 402 lineto +closepath +stroke +end grestore +% Oarray +gsave 10 dict begin +3173 378 32 18 ellipse_path +stroke +gsave 10 dict begin +3153 373 moveto +(Oarray) +[10.08 6.24 4.56 4.56 6.24 6.96] +xshow +end grestore +end grestore +% Fullcommon->Oarray +newpath 3395 439 moveto +3346 425 3261 402 3212 389 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3213 386 moveto +3202 386 lineto +3211 392 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3213 386 moveto +3202 386 lineto +3211 392 lineto +closepath +stroke +end grestore +% Ograph2way +gsave 10 dict begin +3473 378 49 18 ellipse_path +stroke +gsave 10 dict begin +3436 373 moveto +(Ograph2way) +[10.08 6.96 4.56 6.24 6.96 6.96 6.96 10.08 6.24 6.96] +xshow +end grestore +end grestore +% Fullcommon->Ograph2way +newpath 3444 432 moveto +3448 424 3454 414 3459 405 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3462 406 moveto +3464 396 lineto +3456 403 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3462 406 moveto +3464 396 lineto +3456 403 lineto +closepath +stroke +end grestore +% Oseti +gsave 10 dict begin +3568 378 28 18 ellipse_path +stroke +gsave 10 dict begin +3553 373 moveto +(Oseti) +[10.08 5.52 6.24 3.84 3.84] +xshow +end grestore +end grestore +% Fullcommon->Oseti +newpath 3463 435 moveto +3485 424 3515 407 3537 395 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3539 398 moveto +3546 390 lineto +3536 392 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3539 398 moveto +3546 390 lineto +3536 392 lineto +closepath +stroke +end grestore +% Osequence +gsave 10 dict begin +3133 306 44 18 ellipse_path +stroke +gsave 10 dict begin +3102 301 moveto +(Osequence) +[10.08 5.52 6.24 6.96 6.96 6.24 6.96 6.24 6.24] +xshow +end grestore +end grestore +% Oarray->Osequence +newpath 3163 361 moveto +3159 352 3153 342 3148 333 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3151 331 moveto +3143 324 lineto +3145 334 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3151 331 moveto +3143 324 lineto +3145 334 lineto +closepath +stroke +end grestore +% Ograph2way->Osetb +newpath 3478 360 moveto +3480 352 3482 343 3484 334 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3487 335 moveto +3487 324 lineto +3481 333 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3487 335 moveto +3487 324 lineto +3481 333 lineto +closepath +stroke +end grestore +% Ograph +gsave 10 dict begin +3687 306 34 18 ellipse_path +stroke +gsave 10 dict begin +3666 301 moveto +(Ograph) +[10.08 6.96 4.56 6.24 6.96 6.96] +xshow +end grestore +end grestore +% Ograph2way->Ograph +newpath 3510 366 moveto +3557 352 3631 328 3644 324 curveto +3646 323 3648 322 3651 321 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3652 324 moveto +3660 317 lineto +3649 318 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3652 324 moveto +3660 317 lineto +3649 318 lineto +closepath +stroke +end grestore +% Oseti->Oset +newpath 3562 360 moveto +3555 342 3543 312 3530 288 curveto +3524 278 3517 268 3511 258 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3514 256 moveto +3505 250 lineto +3508 260 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3514 256 moveto +3505 250 lineto +3508 260 lineto +closepath +stroke +end grestore +% Seti->Common +newpath 3184 150 moveto +3179 147 3173 145 3168 144 curveto +3006 103 1805 92 1545 90 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1545 87 moveto +1535 90 lineto +1545 94 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1545 87 moveto +1535 90 lineto +1545 94 lineto +closepath +stroke +end grestore +% Osetpt +gsave 10 dict begin +3414 306 31 18 ellipse_path +stroke +gsave 10 dict begin +3395 301 moveto +(Osetpt) +[10.08 5.52 6.24 3.84 6.96 3.84] +xshow +end grestore +end grestore +% Osetpt->Oset +newpath 3431 291 moveto +3442 281 3456 267 3468 256 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3471 258 moveto +3476 249 lineto +3466 253 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3471 258 moveto +3476 249 lineto +3466 253 lineto +closepath +stroke +end grestore +% Ograph->Oset +newpath 3661 295 moveto +3655 292 3649 290 3644 288 curveto +3604 273 3557 256 3526 245 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3527 242 moveto +3516 242 lineto +3525 248 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3527 242 moveto +3516 242 lineto +3525 248 lineto +closepath +stroke +end grestore +% Ast_popl +gsave 10 dict begin +534 378 39 18 ellipse_path +stroke +gsave 10 dict begin +507 373 moveto +(Ast_popl) +[10.08 5.52 3.84 6.96 6.96 6.96 6.96 3.84] +xshow +end grestore +end grestore +% Ast_popl->Ast_cocci +newpath 573 375 moveto +732 364 1342 322 1524 310 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1524 313 moveto +1534 309 lineto +1524 307 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1524 313 moveto +1534 309 lineto +1524 307 lineto +closepath +stroke +end grestore +% Main +gsave 10 dict begin +1667 1026 28 18 ellipse_path +stroke +gsave 10 dict begin +1651 1021 moveto +(Main) +[12.48 6.24 3.84 6.96] +xshow +end grestore +end grestore +% Main->Kbuild +newpath 1639 1025 moveto +1421 1018 10 967 10 882 curveto +10 882 10 882 10 306 curveto +10 254 56 208 86 182 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 88 185 moveto +94 176 lineto +84 179 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 88 185 moveto +94 176 lineto +84 179 lineto +closepath +stroke +end grestore +% Main->Fullcommon +newpath 1695 1025 moveto +1927 1020 3507 977 3507 882 curveto +3507 882 3507 882 3507 594 curveto +3507 548 3477 502 3456 475 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3459 473 moveto +3450 467 lineto +3453 477 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3459 473 moveto +3450 467 lineto +3453 477 lineto +closepath +stroke +end grestore +% Asttoctl +gsave 10 dict begin +1514 738 36 18 ellipse_path +stroke +gsave 10 dict begin +1491 733 moveto +(Asttoctl) +[10.08 5.52 3.84 3.84 6.96 6.24 3.84 3.84] +xshow +end grestore +end grestore +% Main->Asttoctl +newpath 1658 1009 moveto +1632 961 1559 823 1528 764 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1531 762 moveto +1523 755 lineto +1525 765 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1531 762 moveto +1523 755 lineto +1525 765 lineto +closepath +stroke +end grestore +% Testing +gsave 10 dict begin +1821 954 34 18 ellipse_path +stroke +gsave 10 dict begin +1799 949 moveto +(Testing) +[8.64 6.24 5.52 3.84 3.84 6.96 6.96] +xshow +end grestore +end grestore +% Main->Testing +newpath 1690 1015 moveto +1715 1003 1756 984 1786 970 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1787 973 moveto +1795 966 lineto +1784 967 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1787 973 moveto +1795 966 lineto +1784 967 lineto +closepath +stroke +end grestore +% Unify_ast +gsave 10 dict begin +1515 666 41 18 ellipse_path +stroke +gsave 10 dict begin +1486 661 moveto +(Unify_ast) +[10.08 6.96 3.84 4.56 6.96 6.96 6.24 5.52 3.84] +xshow +end grestore +end grestore +% Asttoctl->Unify_ast +newpath 1514 720 moveto +1515 712 1515 703 1515 694 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1519 694 moveto +1515 684 lineto +1512 694 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1519 694 moveto +1515 684 lineto +1512 694 lineto +closepath +stroke +end grestore +% Free_vars +gsave 10 dict begin +1025 666 41 18 ellipse_path +stroke +gsave 10 dict begin +997 661 moveto +(Free_vars) +[7.68 4.56 6.24 6.24 6.96 6.96 6.24 4.56 5.52] +xshow +end grestore +end grestore +% Asttoctl->Free_vars +newpath 1478 736 moveto +1402 732 1222 719 1075 684 curveto +1072 683 1069 682 1066 681 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1067 678 moveto +1056 678 lineto +1065 684 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1067 678 moveto +1056 678 lineto +1065 684 lineto +closepath +stroke +end grestore +% Pretty_print_engine +gsave 10 dict begin +1966 666 68 18 ellipse_path +stroke +gsave 10 dict begin +1910 661 moveto +(Pretty_print_engine) +[7.68 4.56 6.24 3.84 3.84 6.96 6.96 6.96 4.56 3.84 6.96 3.84 6.96 6.24 6.96 6.96 3.84 6.96 6.24] +xshow +end grestore +end grestore +% Asttoctl->Pretty_print_engine +newpath 1548 733 moveto +1622 721 1799 693 1898 677 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1899 680 moveto +1908 675 lineto +1898 674 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1899 680 moveto +1908 675 lineto +1898 674 lineto +closepath +stroke +end grestore +% Compare_c +gsave 10 dict begin +3036 738 45 18 ellipse_path +stroke +gsave 10 dict begin +3003 733 moveto +(Compare_c) +[9.36 6.96 10.8 6.96 6.24 4.56 6.24 6.96 6.24] +xshow +end grestore +end grestore +% Testing->Compare_c +newpath 1855 952 moveto +1979 944 2419 910 2772 828 curveto +2853 808 2943 774 2995 755 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2996 758 moveto +3004 751 lineto +2993 752 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2996 758 moveto +3004 751 lineto +2993 752 lineto +closepath +stroke +end grestore +% Cocci +gsave 10 dict begin +1821 882 29 18 ellipse_path +stroke +gsave 10 dict begin +1804 877 moveto +(Cocci) +[9.36 6.96 6.24 6.24 3.84] +xshow +end grestore +end grestore +% Testing->Cocci +newpath 1821 936 moveto +1821 928 1821 919 1821 910 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1825 910 moveto +1821 900 lineto +1818 910 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1825 910 moveto +1821 900 lineto +1818 910 lineto +closepath +stroke +end grestore +% Visitor_ast0 +gsave 10 dict begin +1026 450 48 18 ellipse_path +stroke +gsave 10 dict begin +991 445 moveto +(Visitor_ast0) +[10.08 3.84 5.52 3.84 3.84 6.96 4.56 6.96 6.24 5.52 3.84 6.96] +xshow +end grestore +end grestore +% Visitor_ast0->Ast0_cocci +newpath 1026 432 moveto +1026 424 1026 415 1026 406 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1030 406 moveto +1026 396 lineto +1023 406 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1030 406 moveto +1026 396 lineto +1023 406 lineto +closepath +stroke +end grestore +% Ast0_cocci->Ast_cocci +newpath 1069 372 moveto +1170 358 1419 326 1526 312 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1526 315 moveto +1536 311 lineto +1526 309 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1526 315 moveto +1536 311 lineto +1526 309 lineto +closepath +stroke +end grestore +% Unitary_ast0 +gsave 10 dict begin +1134 666 50 18 ellipse_path +stroke +gsave 10 dict begin +1097 661 moveto +(Unitary_ast0) +[10.08 6.96 3.84 3.84 6.24 4.56 6.96 6.96 6.24 5.52 3.84 6.96] +xshow +end grestore +end grestore +% Unitary_ast0->Visitor_ast0 +newpath 1110 650 moveto +1097 641 1082 627 1074 612 curveto +1049 569 1067 550 1052 504 curveto +1049 495 1045 485 1041 477 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1044 475 moveto +1036 468 lineto +1038 478 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1044 475 moveto +1036 468 lineto +1038 478 lineto +closepath +stroke +end grestore +% Unitary_ast0->Flag +newpath 1170 654 moveto +1178 651 1186 649 1193 648 curveto +1417 605 1693 596 1792 594 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1792 598 moveto +1802 594 lineto +1792 591 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1792 598 moveto +1802 594 lineto +1792 591 lineto +closepath +stroke +end grestore +% Top_level->Ast0_cocci +newpath 1131 504 moveto +1120 486 1102 455 1083 432 curveto +1073 421 1063 410 1053 401 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1055 398 moveto +1045 394 lineto +1050 403 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1055 398 moveto +1045 394 lineto +1050 403 lineto +closepath +stroke +end grestore +% Single_statement +gsave 10 dict begin +367 666 61 18 ellipse_path +stroke +gsave 10 dict begin +318 661 moveto +(Single_statement) +[7.68 3.84 6.96 6.96 3.84 6.24 6.96 5.52 3.84 6.24 3.84 6.24 10.8 6.24 6.96 3.84] +xshow +end grestore +end grestore +% Iso_pattern +gsave 10 dict begin +698 594 44 18 ellipse_path +stroke +gsave 10 dict begin +666 589 moveto +(Iso_pattern) +[4.56 5.52 6.96 6.96 6.96 6.24 3.84 3.84 6.24 4.56 6.96] +xshow +end grestore +end grestore +% Single_statement->Iso_pattern +newpath 412 654 moveto +420 652 429 650 437 648 curveto +510 631 596 614 648 604 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 649 607 moveto +658 602 lineto +648 601 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 649 607 moveto +658 602 lineto +648 601 lineto +closepath +stroke +end grestore +% Iso_pattern->Visitor_ast0 +newpath 726 580 moveto +745 570 771 555 793 540 curveto +812 525 812 515 834 504 curveto +888 474 909 485 969 468 curveto +972 467 976 466 979 465 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 980 468 moveto +989 462 lineto +978 462 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 980 468 moveto +989 462 lineto +978 462 lineto +closepath +stroke +end grestore +% Unparse_ast0 +gsave 10 dict begin +908 450 52 18 ellipse_path +stroke +gsave 10 dict begin +869 445 moveto +(Unparse_ast0) +[10.08 6.96 6.96 6.24 4.56 5.52 6.24 6.96 6.24 5.52 3.84 6.96] +xshow +end grestore +end grestore +% Iso_pattern->Unparse_ast0 +newpath 717 577 moveto +744 553 792 510 801 504 curveto +821 490 845 478 866 468 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 867 471 moveto +875 464 lineto +864 465 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 867 471 moveto +875 464 lineto +864 465 lineto +closepath +stroke +end grestore +% Compute_lines +gsave 10 dict begin +707 450 55 18 ellipse_path +stroke +gsave 10 dict begin +664 445 moveto +(Compute_lines) +[9.36 6.96 10.8 6.96 6.96 3.84 6.24 6.96 3.84 3.84 6.96 6.24 5.52] +xshow +end grestore +end grestore +% Iso_pattern->Compute_lines +newpath 675 579 moveto +663 569 649 556 642 540 curveto +635 525 635 518 642 504 curveto +648 491 658 480 670 472 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 672 475 moveto +678 466 lineto +668 469 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 672 475 moveto +678 466 lineto +668 469 lineto +closepath +stroke +end grestore +% Flag_parsing_cocci +gsave 10 dict begin +1774 522 68 18 ellipse_path +stroke +gsave 10 dict begin +1719 517 moveto +(Flag_parsing_cocci) +[7.68 3.84 6.24 6.96 6.96 6.96 6.24 4.56 5.52 3.84 6.96 6.96 6.96 6.24 6.96 6.24 6.24 3.84] +xshow +end grestore +end grestore +% Iso_pattern->Flag_parsing_cocci +newpath 732 582 moveto +742 580 752 577 762 576 curveto +1064 526 1144 556 1450 540 curveto +1534 535 1632 530 1697 526 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1697 530 moveto +1707 526 lineto +1697 523 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1697 530 moveto +1707 526 lineto +1697 523 lineto +closepath +stroke +end grestore +% Visitor_ast->Ast_cocci +newpath 1365 585 moveto +1418 570 1511 535 1553 468 curveto +1578 426 1580 369 1579 334 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1582 334 moveto +1578 324 lineto +1576 334 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1582 334 moveto +1578 324 lineto +1576 334 lineto +closepath +stroke +end grestore +% Merge +gsave 10 dict begin +1011 522 32 18 ellipse_path +stroke +gsave 10 dict begin +992 517 moveto +(Merge) +[12.48 6.24 4.56 6.96 6.24] +xshow +end grestore +end grestore +% Merge->Visitor_ast0 +newpath 1015 504 moveto +1016 496 1018 487 1020 478 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1023 478 moveto +1022 468 lineto +1017 477 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1023 478 moveto +1022 468 lineto +1017 477 lineto +closepath +stroke +end grestore +% Index +gsave 10 dict begin +809 450 29 18 ellipse_path +stroke +gsave 10 dict begin +793 445 moveto +(Index) +[4.56 6.96 6.96 6.24 6.96] +xshow +end grestore +end grestore +% Index->Ast0_cocci +newpath 831 438 moveto +836 436 842 434 847 432 curveto +890 416 941 400 978 390 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 979 393 moveto +988 388 lineto +978 387 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 979 393 moveto +988 388 lineto +978 387 lineto +closepath +stroke +end grestore +% Function_prototypes +gsave 10 dict begin +517 666 71 18 ellipse_path +stroke +gsave 10 dict begin +459 661 moveto +(Function_prototypes) +[7.68 6.96 6.96 6.24 3.84 3.84 6.96 6.96 6.96 6.96 4.56 6.96 3.84 6.96 3.84 6.96 6.96 6.24 5.52] +xshow +end grestore +end grestore +% Function_prototypes->Iso_pattern +newpath 555 651 moveto +586 639 627 623 656 611 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 658 614 moveto +666 607 lineto +655 607 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 658 614 moveto +666 607 lineto +655 607 lineto +closepath +stroke +end grestore +% Insert_plus +gsave 10 dict begin +815 594 44 18 ellipse_path +stroke +gsave 10 dict begin +783 589 moveto +(Insert_plus) +[4.56 6.96 5.52 6.24 4.56 3.84 6.96 6.96 3.84 6.96 5.52] +xshow +end grestore +end grestore +% Function_prototypes->Insert_plus +newpath 571 654 moveto +618 644 689 627 751 612 curveto +757 610 763 609 769 607 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 770 610 moveto +779 604 lineto +768 604 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 770 610 moveto +779 604 lineto +768 604 lineto +closepath +stroke +end grestore +% Ast0toast +gsave 10 dict begin +883 522 40 18 ellipse_path +stroke +gsave 10 dict begin +856 517 moveto +(Ast0toast) +[10.08 5.52 3.84 6.96 3.84 6.96 6.24 5.52 3.84] +xshow +end grestore +end grestore +% Insert_plus->Ast0toast +newpath 831 577 moveto +840 568 850 557 860 547 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 863 549 moveto +867 539 lineto +858 544 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 863 549 moveto +867 539 lineto +858 544 lineto +closepath +stroke +end grestore +% Insert_plus->Flag_parsing_cocci +newpath 851 584 moveto +863 581 876 578 888 576 curveto +927 569 1489 538 1697 527 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1697 530 moveto +1707 526 lineto +1697 524 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1697 530 moveto +1707 526 lineto +1697 524 lineto +closepath +stroke +end grestore +% Context_neg +gsave 10 dict begin +700 522 49 18 ellipse_path +stroke +gsave 10 dict begin +664 517 moveto +(Context_neg) +[9.36 6.96 6.96 3.84 6.24 6.96 3.84 6.96 6.96 6.24 6.96] +xshow +end grestore +end grestore +% Insert_plus->Context_neg +newpath 791 579 moveto +774 569 752 555 734 544 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 735 541 moveto +725 538 lineto +731 546 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 735 541 moveto +725 538 lineto +731 546 lineto +closepath +stroke +end grestore +% Check_meta +gsave 10 dict begin +1496 450 48 18 ellipse_path +stroke +gsave 10 dict begin +1461 445 moveto +(Check_meta) +[9.36 6.96 6.24 6.24 6.96 6.96 10.8 6.24 3.84 6.24] +xshow +end grestore +end grestore +% Check_meta->Common +newpath 1496 432 moveto +1496 404 1496 351 1496 306 curveto +1496 306 1496 306 1496 234 curveto +1496 194 1496 147 1496 118 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1500 118 moveto +1496 108 lineto +1493 118 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1500 118 moveto +1496 108 lineto +1493 118 lineto +closepath +stroke +end grestore +% Check_meta->Ast0_cocci +newpath 1451 443 moveto +1364 430 1172 400 1078 386 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1078 383 moveto +1068 384 lineto +1077 389 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1078 383 moveto +1068 384 lineto +1077 389 lineto +closepath +stroke +end grestore +% Ast0toast->Visitor_ast0 +newpath 910 508 moveto +932 497 963 481 988 469 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 989 472 moveto +997 465 lineto +986 466 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 989 472 moveto +997 465 lineto +986 466 lineto +closepath +stroke +end grestore +% Arity +gsave 10 dict begin +317 594 28 18 ellipse_path +stroke +gsave 10 dict begin +301 589 moveto +(Arity) +[10.08 4.56 3.84 3.84 6.96] +xshow +end grestore +end grestore +% Arity->Ast0_cocci +newpath 326 577 moveto +346 542 396 465 463 432 curveto +508 409 838 388 971 381 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 971 384 moveto +981 380 lineto +971 378 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 971 384 moveto +981 380 lineto +971 378 lineto +closepath +stroke +end grestore +% Unparse_ast0->Ast0_cocci +newpath 934 434 moveto +951 424 974 410 992 398 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 994 401 moveto +1001 393 lineto +991 395 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 994 401 moveto +1001 393 lineto +991 395 lineto +closepath +stroke +end grestore +% Pretty_print_cocci +gsave 10 dict begin +1664 378 64 18 ellipse_path +stroke +gsave 10 dict begin +1612 373 moveto +(Pretty_print_cocci) +[7.68 4.56 6.24 3.84 3.84 6.96 6.96 6.96 4.56 3.84 6.96 3.84 6.96 6.24 6.96 6.24 6.24 3.84] +xshow +end grestore +end grestore +% Unparse_ast0->Pretty_print_cocci +newpath 946 437 moveto +953 435 961 433 969 432 curveto +1086 410 1437 390 1591 382 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1591 385 moveto +1601 381 lineto +1591 379 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1591 385 moveto +1601 381 lineto +1591 379 lineto +closepath +stroke +end grestore +% Pretty_print_cocci->Common +newpath 1664 360 moveto +1662 328 1657 263 1631 216 curveto +1605 171 1559 133 1527 111 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1529 108 moveto +1519 105 lineto +1525 114 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1529 108 moveto +1519 105 lineto +1525 114 lineto +closepath +stroke +end grestore +% Pretty_print_cocci->Ast_cocci +newpath 1643 361 moveto +1631 351 1616 339 1603 328 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1605 325 moveto +1595 322 lineto +1601 331 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1605 325 moveto +1595 322 lineto +1601 331 lineto +closepath +stroke +end grestore +% Unify_ast->Visitor_ast +newpath 1484 654 moveto +1453 642 1403 624 1368 610 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1370 607 moveto +1359 606 lineto +1367 613 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1370 607 moveto +1359 606 lineto +1367 613 lineto +closepath +stroke +end grestore +% Type_infer +gsave 10 dict begin +941 594 44 18 ellipse_path +stroke +gsave 10 dict begin +909 589 moveto +(Type_infer) +[8.64 6.96 6.96 6.24 6.96 3.84 6.96 4.56 6.24 4.56] +xshow +end grestore +end grestore +% Type_infer->Visitor_ast0 +newpath 944 576 moveto +948 557 955 526 970 504 curveto +977 492 987 482 996 473 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 999 475 moveto +1004 466 lineto +994 470 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 999 475 moveto +1004 466 lineto +994 470 lineto +closepath +stroke +end grestore +% Parse_cocci +gsave 10 dict begin +928 738 46 18 ellipse_path +stroke +gsave 10 dict begin +894 733 moveto +(Parse_cocci) +[7.68 6.24 4.56 5.52 6.24 6.96 6.24 6.96 6.24 6.24 3.84] +xshow +end grestore +end grestore +% Parse_cocci->Config +newpath 973 734 moveto +1088 725 1381 701 1422 684 curveto +1444 674 1441 656 1465 648 curveto +1633 584 2901 634 3080 612 curveto +3093 610 3107 607 3120 604 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3121 607 moveto +3130 602 lineto +3120 601 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3121 607 moveto +3130 602 lineto +3120 601 lineto +closepath +stroke +end grestore +% Parse_cocci->Lexer_cocci +newpath 900 724 moveto +878 713 848 697 824 685 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 826 682 moveto +815 681 lineto +823 688 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 826 682 moveto +815 681 lineto +823 688 lineto +closepath +stroke +end grestore +% Parse_cocci->Unitary_ast0 +newpath 962 726 moveto +997 714 1050 695 1089 682 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1090 685 moveto +1098 679 lineto +1087 679 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1090 685 moveto +1098 679 lineto +1087 679 lineto +closepath +stroke +end grestore +% Parse_cocci->Single_statement +newpath 883 735 moveto +795 729 599 713 437 684 curveto +432 683 427 682 421 680 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 421 677 moveto +411 678 lineto +420 683 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 421 677 moveto +411 678 lineto +420 683 lineto +closepath +stroke +end grestore +% Parse_cocci->Function_prototypes +newpath 885 731 moveto +823 722 703 703 602 684 curveto +595 683 589 681 582 680 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 582 677 moveto +572 678 lineto +581 683 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 582 677 moveto +572 678 lineto +581 683 lineto +closepath +stroke +end grestore +% Parse_cocci->Check_meta +newpath 973 734 moveto +1082 726 1352 702 1389 684 curveto +1408 674 1405 661 1422 648 curveto +1446 628 1466 638 1483 612 curveto +1508 570 1506 513 1501 478 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1504 478 moveto +1500 468 lineto +1498 478 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1504 478 moveto +1500 468 lineto +1498 478 lineto +closepath +stroke +end grestore +% Parse_cocci->Arity +newpath 882 738 moveto +743 736 336 726 297 684 curveto +281 666 289 639 300 620 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 303 621 moveto +305 611 lineto +297 618 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 303 621 moveto +305 611 lineto +297 618 lineto +closepath +stroke +end grestore +% Parse_cocci->Type_infer +newpath 882 736 moveto +807 732 666 720 635 684 curveto +624 671 624 660 635 648 curveto +669 608 816 622 868 612 curveto +877 610 885 608 894 606 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 895 609 moveto +904 604 lineto +894 603 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 895 609 moveto +904 604 lineto +894 603 lineto +closepath +stroke +end grestore +% Disjdistr +gsave 10 dict begin +928 666 38 18 ellipse_path +stroke +gsave 10 dict begin +903 661 moveto +(Disjdistr) +[10.08 3.84 5.52 3.84 6.96 3.84 5.52 3.84 4.56] +xshow +end grestore +end grestore +% Parse_cocci->Disjdistr +newpath 928 720 moveto +928 712 928 703 928 694 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 932 694 moveto +928 684 lineto +925 694 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 932 694 moveto +928 684 lineto +925 694 lineto +closepath +stroke +end grestore +% Parse_cocci->Free_vars +newpath 950 722 moveto +963 712 981 699 996 688 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 998 691 moveto +1004 682 lineto +994 685 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 998 691 moveto +1004 682 lineto +994 685 lineto +closepath +stroke +end grestore +% Get_constants +gsave 10 dict begin +1327 666 53 18 ellipse_path +stroke +gsave 10 dict begin +1287 661 moveto +(Get_constants) +[10.08 6.24 3.84 6.96 6.24 6.96 6.96 5.52 3.84 6.24 6.96 3.84 5.52] +xshow +end grestore +end grestore +% Parse_cocci->Get_constants +newpath 972 733 moveto +1037 724 1160 707 1265 684 curveto +1269 683 1273 682 1277 681 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1278 684 moveto +1287 678 lineto +1276 678 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1278 684 moveto +1287 678 lineto +1276 678 lineto +closepath +stroke +end grestore +% Simple_assignments +gsave 10 dict begin +1371 522 70 18 ellipse_path +stroke +gsave 10 dict begin +1313 517 moveto +(Simple_assignments) +[7.68 3.84 10.8 6.96 3.84 6.24 6.96 6.24 5.52 5.52 3.84 6.96 6.96 10.8 6.24 6.96 3.84 5.52] +xshow +end grestore +end grestore +% Parse_cocci->Simple_assignments +newpath 908 721 moveto +888 702 861 670 881 648 curveto +934 589 1163 645 1236 612 curveto +1257 602 1255 589 1274 576 curveto +1290 563 1310 552 1328 543 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1330 546 moveto +1337 538 lineto +1327 540 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1330 546 moveto +1337 538 lineto +1327 540 lineto +closepath +stroke +end grestore +% Disjdistr->Visitor_ast +newpath 956 654 moveto +962 652 969 649 975 648 curveto +1102 616 1140 639 1269 612 curveto +1274 611 1279 610 1283 608 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1284 611 moveto +1293 606 lineto +1283 605 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1284 611 moveto +1293 606 lineto +1283 605 lineto +closepath +stroke +end grestore +% Free_vars->Common +newpath 995 654 moveto +988 652 982 649 975 648 curveto +903 631 698 662 645 612 curveto +620 589 624 448 624 378 curveto +624 378 624 378 624 234 curveto +624 150 1263 104 1447 93 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1447 96 moveto +1457 92 lineto +1447 90 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1447 96 moveto +1457 92 lineto +1447 90 lineto +closepath +stroke +end grestore +% Free_vars->Visitor_ast +newpath 1056 654 moveto +1062 652 1069 650 1075 648 curveto +1159 625 1183 633 1269 612 curveto +1274 611 1278 610 1282 608 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1283 611 moveto +1292 605 lineto +1281 605 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1283 611 moveto +1292 605 lineto +1281 605 lineto +closepath +stroke +end grestore +% Get_constants->Common +newpath 1352 650 moveto +1381 629 1430 588 1450 540 curveto +1456 525 1452 519 1450 504 curveto +1447 487 1443 484 1439 468 curveto +1428 428 1420 418 1420 378 curveto +1420 378 1420 378 1420 234 curveto +1420 187 1451 141 1473 115 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1476 117 moveto +1480 107 lineto +1471 112 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1476 117 moveto +1480 107 lineto +1471 112 lineto +closepath +stroke +end grestore +% Get_constants->Flag +newpath 1374 658 moveto +1392 654 1413 651 1432 648 curveto +1564 627 1722 607 1792 598 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1792 601 moveto +1802 597 lineto +1792 595 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1792 601 moveto +1802 597 lineto +1792 595 lineto +closepath +stroke +end grestore +% Get_constants->Visitor_ast +newpath 1327 648 moveto +1327 640 1327 631 1327 622 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1331 622 moveto +1327 612 lineto +1324 622 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1331 622 moveto +1327 612 lineto +1324 622 lineto +closepath +stroke +end grestore +% Simple_assignments->Common +newpath 1373 504 moveto +1377 476 1382 423 1382 378 curveto +1382 378 1382 378 1382 234 curveto +1382 192 1381 177 1406 144 curveto +1419 127 1438 114 1456 105 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1457 108 moveto +1465 101 lineto +1454 102 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1457 108 moveto +1465 101 lineto +1454 102 lineto +closepath +stroke +end grestore +% Simple_assignments->Visitor_ast0 +newpath 1319 510 moveto +1310 508 1301 506 1292 504 curveto +1218 488 1133 470 1079 460 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1079 457 moveto +1069 458 lineto +1078 463 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1079 457 moveto +1069 458 lineto +1078 463 lineto +closepath +stroke +end grestore +% Compute_lines->Ast0_cocci +newpath 748 438 moveto +756 436 764 434 771 432 curveto +841 414 923 397 975 388 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 976 391 moveto +985 386 lineto +975 385 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 976 391 moveto +985 386 lineto +975 385 lineto +closepath +stroke +end grestore +% Context_neg->Visitor_ast0 +newpath 744 514 moveto +808 501 926 479 969 468 curveto +973 467 976 466 980 465 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 981 468 moveto +990 462 lineto +979 462 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 981 468 moveto +990 462 lineto +979 462 lineto +closepath +stroke +end grestore +% Context_neg->Index +newpath 724 506 moveto +740 495 763 480 781 468 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 782 471 moveto +789 463 lineto +779 465 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 782 471 moveto +789 463 lineto +779 465 lineto +closepath +stroke +end grestore +% Context_neg->Unparse_ast0 +newpath 736 510 moveto +770 498 823 479 861 466 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 862 469 moveto +871 463 lineto +860 463 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 862 469 moveto +871 463 lineto +860 463 lineto +closepath +stroke +end grestore +% Context_neg->Compute_lines +newpath 702 504 moveto +703 496 703 487 704 478 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 707 478 moveto +705 468 lineto +701 478 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 707 478 moveto +705 468 lineto +701 478 lineto +closepath +stroke +end grestore +% Token_helpers +gsave 10 dict begin +2874 522 55 18 ellipse_path +stroke +gsave 10 dict begin +2832 517 moveto +(Token_helpers) +[8.64 6.96 6.96 6.24 6.96 6.96 6.96 6.24 3.84 6.96 6.24 4.56 5.52] +xshow +end grestore +end grestore +% Parsing_hacks->Token_helpers +newpath 2832 577 moveto +2838 568 2847 557 2854 547 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2857 549 moveto +2860 539 lineto +2851 545 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2857 549 moveto +2860 539 lineto +2851 545 lineto +closepath +stroke +end grestore +% Token_helpers->Parser_c +newpath 2850 506 moveto +2834 496 2813 482 2795 471 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2797 468 moveto +2787 465 lineto +2793 474 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2797 468 moveto +2787 465 lineto +2793 474 lineto +closepath +stroke +end grestore +% Lexer_parser->Common +newpath 2724 360 moveto +2722 339 2714 306 2692 288 curveto +2511 140 1747 99 1545 91 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1545 88 moveto +1535 91 lineto +1545 95 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1545 88 moveto +1535 91 lineto +1545 95 lineto +closepath +stroke +end grestore +% Lexer_parser->Flag_parsing_c +newpath 2704 362 moveto +2691 352 2673 339 2658 329 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2660 326 moveto +2650 323 lineto +2656 332 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2660 326 moveto +2650 323 lineto +2656 332 lineto +closepath +stroke +end grestore +% Ograph_extended->Oassocb +newpath 2913 360 moveto +2914 352 2916 343 2918 334 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2921 334 moveto +2920 324 lineto +2915 333 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2921 334 moveto +2920 324 lineto +2915 333 lineto +closepath +stroke +end grestore +% Ograph_extended->Osetb +newpath 2970 373 moveto +3102 362 3408 336 3454 324 curveto +3456 324 3458 323 3461 322 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3462 325 moveto +3470 318 lineto +3459 319 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3462 325 moveto +3470 318 lineto +3459 319 lineto +closepath +stroke +end grestore +% Compare_c->Parse_c +newpath 3014 722 moveto +3000 712 2981 698 2965 687 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2967 684 moveto +2957 681 lineto +2963 690 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2967 684 moveto +2957 681 lineto +2963 690 lineto +closepath +stroke +end grestore +% Compare_c->Lib_parsing_c +newpath 3034 720 moveto +3030 695 3025 651 3021 622 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3024 622 moveto +3020 612 lineto +3018 622 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3024 622 moveto +3020 612 lineto +3018 622 lineto +closepath +stroke +end grestore +% Ast_to_flow +gsave 10 dict begin +2715 810 48 18 ellipse_path +stroke +gsave 10 dict begin +2679 805 moveto +(Ast_to_flow) +[10.08 5.52 3.84 6.96 3.84 6.96 6.96 4.56 3.84 6.96 10.08] +xshow +end grestore +end grestore +% Ast_to_flow->Visitor_c +newpath 2762 807 moveto +2858 799 3068 780 3090 756 curveto +3102 742 3120 641 3080 576 curveto +3068 557 3047 544 3028 536 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3030 533 moveto +3019 532 lineto +3027 539 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3030 533 moveto +3019 532 lineto +3027 539 lineto +closepath +stroke +end grestore +% Type_annoter_c +gsave 10 dict begin +2915 738 58 18 ellipse_path +stroke +gsave 10 dict begin +2869 733 moveto +(Type_annoter_c) +[8.64 6.96 6.96 6.24 6.96 6.24 6.96 6.96 6.96 3.84 6.24 4.56 6.96 6.24] +xshow +end grestore +end grestore +% Type_annoter_c->Parse_c +newpath 2921 720 moveto +2923 712 2926 702 2929 694 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2932 695 moveto +2932 684 lineto +2926 693 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2932 695 moveto +2932 684 lineto +2926 693 lineto +closepath +stroke +end grestore +% Type_annoter_c->Lib_parsing_c +newpath 2940 722 moveto +2954 712 2970 699 2981 684 curveto +2995 665 3004 640 3010 622 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3013 623 moveto +3013 612 lineto +3007 621 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3013 623 moveto +3013 612 lineto +3007 621 lineto +closepath +stroke +end grestore +% Pretty_print_c +gsave 10 dict begin +2566 594 53 18 ellipse_path +stroke +gsave 10 dict begin +2526 589 moveto +(Pretty_print_c) +[7.68 4.56 6.24 3.84 3.84 6.96 6.96 6.96 4.56 3.84 6.96 3.84 6.96 6.24] +xshow +end grestore +end grestore +% Pretty_print_c->Ast_c +newpath 2526 582 moveto +2519 580 2511 578 2504 576 curveto +2447 559 2418 581 2376 540 curveto +2340 504 2330 442 2327 406 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2330 406 moveto +2326 396 lineto +2324 406 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2330 406 moveto +2326 396 lineto +2324 406 lineto +closepath +stroke +end grestore +% Pretty_print_c->Flag_parsing_c +newpath 2603 581 moveto +2634 570 2673 554 2682 540 curveto +2690 526 2682 519 2682 504 curveto +2681 471 2684 463 2678 432 curveto +2673 412 2653 365 2639 333 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2642 332 moveto +2635 324 lineto +2636 335 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2642 332 moveto +2635 324 lineto +2636 335 lineto +closepath +stroke +end grestore +% Unparse_cocci +gsave 10 dict begin +2611 666 55 18 ellipse_path +stroke +gsave 10 dict begin +2568 661 moveto +(Unparse_cocci) +[10.08 6.96 6.96 6.24 4.56 5.52 6.24 6.96 6.24 6.96 6.24 6.24 3.84] +xshow +end grestore +end grestore +% Unparse_cocci->Lib_engine +newpath 2569 654 moveto +2560 652 2551 650 2542 648 curveto +2458 629 2435 633 2352 612 curveto +2348 611 2345 610 2342 609 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2343 606 moveto +2332 606 lineto +2341 612 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2343 606 moveto +2332 606 lineto +2341 612 lineto +closepath +stroke +end grestore +% Unparse_cocci->Pretty_print_c +newpath 2600 648 moveto +2595 640 2588 630 2582 620 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2585 619 moveto +2577 612 lineto +2579 622 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2585 619 moveto +2577 612 lineto +2579 622 lineto +closepath +stroke +end grestore +% Unparse_c +gsave 10 dict begin +2416 738 43 18 ellipse_path +stroke +gsave 10 dict begin +2385 733 moveto +(Unparse_c) +[10.08 6.96 6.96 6.24 4.56 5.52 6.24 6.96 6.24] +xshow +end grestore +end grestore +% Unparse_c->Parse_c +newpath 2448 726 moveto +2454 723 2461 721 2468 720 curveto +2653 680 2708 728 2893 684 curveto +2896 684 2899 683 2901 682 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2903 685 moveto +2911 678 lineto +2900 678 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2903 685 moveto +2911 678 lineto +2900 678 lineto +closepath +stroke +end grestore +% Unparse_c->Unparse_cocci +newpath 2449 726 moveto +2480 714 2529 696 2564 683 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2566 686 moveto +2574 679 lineto +2563 679 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2566 686 moveto +2574 679 lineto +2563 679 lineto +closepath +stroke +end grestore +% Flag_engine +gsave 10 dict begin +2414 666 48 18 ellipse_path +stroke +gsave 10 dict begin +2379 661 moveto +(Flag_engine) +[7.68 3.84 6.24 6.96 6.96 6.24 6.96 6.96 3.84 6.96 6.24] +xshow +end grestore +end grestore +% Unparse_c->Flag_engine +newpath 2415 720 moveto +2415 712 2415 703 2415 694 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2418 694 moveto +2414 684 lineto +2412 694 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2418 694 moveto +2414 684 lineto +2412 694 lineto +closepath +stroke +end grestore +% Transformation3 +gsave 10 dict begin +2118 738 60 18 ellipse_path +stroke +gsave 10 dict begin +2071 733 moveto +(Transformation3) +[8.64 4.56 6.24 6.96 5.52 4.56 6.96 4.56 10.8 6.24 3.84 3.84 6.96 6.96 6.96] +xshow +end grestore +end grestore +% Transformation3->Sgrep +newpath 2122 720 moveto +2128 692 2138 639 2138 594 curveto +2138 594 2138 594 2138 522 curveto +2138 480 2144 459 2114 432 curveto +2070 392 1894 382 1814 379 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1814 376 moveto +1804 379 lineto +1814 383 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1814 376 moveto +1804 379 lineto +1814 383 lineto +closepath +stroke +end grestore +% Transformation3->Lib_engine +newpath 2167 727 moveto +2209 717 2265 701 2281 684 curveto +2295 667 2299 642 2299 622 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2303 622 moveto +2299 612 lineto +2296 622 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2303 622 moveto +2299 612 lineto +2296 622 lineto +closepath +stroke +end grestore +% Transformation3->Pretty_print_cocci +newpath 2114 720 moveto +2109 692 2100 639 2100 594 curveto +2100 594 2100 594 2100 522 curveto +2100 502 1838 426 1720 394 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1721 391 moveto +1710 391 lineto +1719 397 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1721 391 moveto +1710 391 lineto +1719 397 lineto +closepath +stroke +end grestore +% Transformation3->Flag_parsing_cocci +newpath 2106 720 moveto +2093 700 2069 669 2043 648 curveto +1977 596 1886 559 1828 539 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1829 536 moveto +1818 536 lineto +1827 542 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1829 536 moveto +1818 536 lineto +1827 542 lineto +closepath +stroke +end grestore +% Cocci_vs_c_3 +gsave 10 dict begin +2219 666 53 18 ellipse_path +stroke +gsave 10 dict begin +2179 661 moveto +(Cocci_vs_c_3) +[9.36 6.96 6.24 6.24 3.84 6.96 6.96 5.52 6.96 6.24 6.96 6.96] +xshow +end grestore +end grestore +% Transformation3->Cocci_vs_c_3 +newpath 2141 721 moveto +2155 711 2173 699 2188 688 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2190 691 moveto +2196 682 lineto +2186 685 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2190 691 moveto +2196 682 lineto +2186 685 lineto +closepath +stroke +end grestore +% Cocci_vs_c_3->Lib_parsing_c +newpath 2268 659 moveto +2294 655 2327 651 2357 648 curveto +2588 624 2648 635 2880 612 curveto +2905 609 2934 605 2959 602 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2959 605 moveto +2969 601 lineto +2959 599 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2959 605 moveto +2969 601 lineto +2959 599 lineto +closepath +stroke +end grestore +% Cocci_vs_c_3->Flag +newpath 2172 657 moveto +2094 643 1936 614 1865 601 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1865 598 moveto +1855 599 lineto +1864 604 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1865 598 moveto +1855 599 lineto +1864 604 lineto +closepath +stroke +end grestore +% C_vs_c +gsave 10 dict begin +2219 522 34 18 ellipse_path +stroke +gsave 10 dict begin +2197 517 moveto +(C_vs_c) +[9.36 6.96 6.96 5.52 6.96 6.24] +xshow +end grestore +end grestore +% Cocci_vs_c_3->C_vs_c +newpath 2219 648 moveto +2219 623 2219 579 2219 550 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2223 550 moveto +2219 540 lineto +2216 550 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2223 550 moveto +2219 540 lineto +2216 550 lineto +closepath +stroke +end grestore +% Pretty_print_engine->Lib_engine +newpath 2019 655 moveto +2082 641 2186 619 2248 605 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2249 608 moveto +2258 603 lineto +2248 602 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2249 608 moveto +2258 603 lineto +2248 602 lineto +closepath +stroke +end grestore +% Pretty_print_engine->Pretty_print_cocci +newpath 1956 648 moveto +1938 616 1898 549 1851 504 curveto +1806 460 1744 422 1704 399 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1705 396 moveto +1695 394 lineto +1702 402 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1705 396 moveto +1695 394 lineto +1702 402 lineto +closepath +stroke +end grestore +% Pretty_print_engine->Pretty_print_c +newpath 2030 660 moveto +2167 646 2481 616 2504 612 curveto +2508 611 2512 610 2517 609 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2518 612 moveto +2527 606 lineto +2516 606 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2518 612 moveto +2527 606 lineto +2516 606 lineto +closepath +stroke +end grestore +% Ctltotex +gsave 10 dict begin +1730 666 36 18 ellipse_path +stroke +gsave 10 dict begin +1707 661 moveto +(Ctltotex) +[9.36 3.84 3.84 3.84 6.96 3.84 6.24 6.96] +xshow +end grestore +end grestore +% Ctltotex->Lib_engine +newpath 1765 662 moveto +1861 649 2130 615 2245 600 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2245 603 moveto +2255 599 lineto +2245 597 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2245 603 moveto +2255 599 lineto +2245 597 lineto +closepath +stroke +end grestore +% Ctltotex->Pretty_print_cocci +newpath 1725 648 moveto +1718 624 1706 579 1697 540 curveto +1686 493 1675 438 1669 406 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1672 405 moveto +1667 396 lineto +1666 406 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1672 405 moveto +1667 396 lineto +1666 406 lineto +closepath +stroke +end grestore +% Ctlcocci_integration +gsave 10 dict begin +2160 810 70 18 ellipse_path +stroke +gsave 10 dict begin +2103 805 moveto +(Ctlcocci_integration) +[9.36 3.84 3.84 6.24 6.96 6.24 6.24 3.84 6.96 3.84 6.96 3.84 6.24 6.96 4.56 6.24 3.84 3.84 6.96 6.96] +xshow +end grestore +end grestore +% Ctlcocci_integration->Flag_parsing_cocci +newpath 2113 796 moveto +2082 787 2041 773 2006 756 curveto +1950 729 1924 733 1889 684 curveto +1860 643 1893 615 1865 576 curveto +1854 561 1839 550 1823 542 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1824 539 moveto +1814 537 lineto +1821 545 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1824 539 moveto +1814 537 lineto +1821 545 lineto +closepath +stroke +end grestore +% Ctlcocci_integration->Pretty_print_engine +newpath 2121 795 moveto +2099 786 2071 772 2049 756 curveto +2025 738 2001 711 1985 692 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1988 690 moveto +1979 684 lineto +1982 694 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1988 690 moveto +1979 684 lineto +1982 694 lineto +closepath +stroke +end grestore +% Check_reachability +gsave 10 dict begin +2428 594 67 18 ellipse_path +stroke +gsave 10 dict begin +2373 589 moveto +(Check_reachability) +[9.36 6.96 6.24 6.24 6.96 6.96 4.56 6.24 6.24 6.24 6.96 6.24 6.96 3.84 3.84 3.84 3.84 6.96] +xshow +end grestore +end grestore +% Ctlcocci_integration->Check_reachability +newpath 2199 795 moveto +2226 785 2263 770 2295 756 curveto +2326 741 2332 733 2364 720 curveto +2410 700 2441 724 2471 684 curveto +2485 664 2470 638 2454 619 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2457 617 moveto +2447 612 lineto +2452 622 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2457 617 moveto +2447 612 lineto +2452 622 lineto +closepath +stroke +end grestore +% Pattern3 +gsave 10 dict begin +2250 738 36 18 ellipse_path +stroke +gsave 10 dict begin +2226 733 moveto +(Pattern3) +[7.68 6.24 3.84 3.84 6.24 4.56 6.96 6.96] +xshow +end grestore +end grestore +% Ctlcocci_integration->Pattern3 +newpath 2182 793 moveto +2194 783 2210 770 2223 760 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2226 762 moveto +2231 753 lineto +2221 757 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2226 762 moveto +2231 753 lineto +2221 757 lineto +closepath +stroke +end grestore +% Postprocess_transinfo +gsave 10 dict begin +2551 738 74 18 ellipse_path +stroke +gsave 10 dict begin +2489 733 moveto +(Postprocess_transinfo) +[7.68 6.96 5.52 3.84 6.96 4.56 6.96 6.24 6.24 5.52 5.52 6.96 3.84 4.56 6.24 6.96 5.52 3.84 6.96 4.56 6.96] +xshow +end grestore +end grestore +% Ctlcocci_integration->Postprocess_transinfo +newpath 2219 800 moveto +2281 790 2381 772 2468 756 curveto +2474 755 2480 753 2486 752 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2487 755 moveto +2496 750 lineto +2486 749 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2487 755 moveto +2496 750 lineto +2486 749 lineto +closepath +stroke +end grestore +% Check_reachability->Control_flow_c +newpath 2405 577 moveto +2394 567 2382 554 2376 540 curveto +2370 525 2367 517 2376 504 curveto +2385 487 2403 475 2421 466 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2422 469 moveto +2430 462 lineto +2419 463 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2422 469 moveto +2430 462 lineto +2419 463 lineto +closepath +stroke +end grestore +% Check_reachability->Wrapper_ctl +newpath 2468 579 moveto +2501 567 2547 550 2580 538 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2582 541 moveto +2590 534 lineto +2579 534 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2582 541 moveto +2590 534 lineto +2579 534 lineto +closepath +stroke +end grestore +% Pattern3->Lib_engine +newpath 2274 724 moveto +2289 715 2306 701 2314 684 curveto +2323 664 2318 639 2311 621 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2314 620 moveto +2307 612 lineto +2308 623 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2314 620 moveto +2307 612 lineto +2308 623 lineto +closepath +stroke +end grestore +% Pattern3->Flag_engine +newpath 2277 726 moveto +2303 715 2343 697 2374 684 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2375 687 moveto +2383 680 lineto +2372 681 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2375 687 moveto +2383 680 lineto +2372 681 lineto +closepath +stroke +end grestore +% Pattern3->Cocci_vs_c_3 +newpath 2242 720 moveto +2238 712 2234 702 2231 694 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2234 692 moveto +2227 684 lineto +2227 695 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2234 692 moveto +2227 684 lineto +2227 695 lineto +closepath +stroke +end grestore +% Postprocess_transinfo->Parse_c +newpath 2614 728 moveto +2709 714 2879 688 2893 684 curveto +2896 683 2898 682 2901 681 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2902 684 moveto +2910 678 lineto +2899 678 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2902 684 moveto +2910 678 lineto +2899 678 lineto +closepath +stroke +end grestore +% Postprocess_transinfo->Lib_engine +newpath 2540 720 moveto +2526 699 2501 666 2471 648 curveto +2424 618 2404 628 2352 612 curveto +2349 611 2345 610 2342 609 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2343 606 moveto +2332 606 lineto +2341 612 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2343 606 moveto +2332 606 lineto +2341 612 lineto +closepath +stroke +end grestore +% C_vs_c->Ast_c +newpath 2247 512 moveto +2267 503 2292 489 2307 468 curveto +2320 450 2324 425 2325 406 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2328 406 moveto +2326 396 lineto +2322 406 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2328 406 moveto +2326 396 lineto +2322 406 lineto +closepath +stroke +end grestore +% Asttomember +gsave 10 dict begin +1625 666 51 18 ellipse_path +stroke +gsave 10 dict begin +1586 661 moveto +(Asttomember) +[10.08 5.52 3.84 3.84 6.96 10.8 6.24 10.8 6.96 6.24 4.56] +xshow +end grestore +end grestore +% Asttomember->Lib_engine +newpath 1662 653 moveto +1669 651 1677 649 1685 648 curveto +1887 608 2135 598 2243 595 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2243 599 moveto +2253 595 lineto +2243 592 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2243 599 moveto +2253 595 lineto +2243 592 lineto +closepath +stroke +end grestore +% Asttomember->Visitor_ast +newpath 1587 654 moveto +1579 652 1572 650 1565 648 curveto +1501 631 1425 614 1377 604 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1377 601 moveto +1367 602 lineto +1376 607 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1377 601 moveto +1367 602 lineto +1376 607 lineto +closepath +stroke +end grestore +% Asttomember->Pretty_print_cocci +newpath 1627 648 moveto +1634 599 1653 465 1661 406 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1664 406 moveto +1662 396 lineto +1658 406 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1664 406 moveto +1662 396 lineto +1658 406 lineto +closepath +stroke +end grestore +% Asttoctl2 +gsave 10 dict begin +1821 738 39 18 ellipse_path +stroke +gsave 10 dict begin +1794 733 moveto +(Asttoctl2) +[10.08 5.52 3.84 3.84 6.96 6.24 3.84 3.84 6.96] +xshow +end grestore +end grestore +% Asttoctl2->Flag +newpath 1822 720 moveto +1823 695 1825 651 1827 622 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1830 622 moveto +1828 612 lineto +1824 622 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1830 622 moveto +1828 612 lineto +1824 622 lineto +closepath +stroke +end grestore +% Asttoctl2->Unify_ast +newpath 1784 732 moveto +1734 723 1641 705 1565 684 curveto +1562 683 1559 682 1556 681 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1557 678 moveto +1546 678 lineto +1555 684 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1557 678 moveto +1546 678 lineto +1555 684 lineto +closepath +stroke +end grestore +% Asttoctl2->Flag_parsing_cocci +newpath 1817 720 moveto +1811 696 1801 651 1793 612 curveto +1788 591 1783 568 1780 550 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1783 549 moveto +1778 540 lineto +1777 550 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1783 549 moveto +1778 540 lineto +1777 550 lineto +closepath +stroke +end grestore +% Asttoctl2->Pretty_print_engine +newpath 1848 725 moveto +1869 714 1900 699 1925 687 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1927 690 moveto +1934 682 lineto +1924 684 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1927 690 moveto +1934 682 lineto +1924 684 lineto +closepath +stroke +end grestore +% Unparse_c2 +gsave 10 dict begin +2416 810 47 18 ellipse_path +stroke +gsave 10 dict begin +2382 805 moveto +(Unparse_c2) +[10.08 6.96 6.96 6.24 4.56 5.52 6.24 6.96 6.24 6.96] +xshow +end grestore +end grestore +% Unparse_c2->Unparse_c +newpath 2416 792 moveto +2416 784 2416 775 2416 766 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2420 766 moveto +2416 756 lineto +2413 766 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2420 766 moveto +2416 756 lineto +2413 766 lineto +closepath +stroke +end grestore +% Unparse_cocci2 +gsave 10 dict begin +2743 666 59 18 ellipse_path +stroke +gsave 10 dict begin +2697 661 moveto +(Unparse_cocci2) +[10.08 6.96 6.96 6.24 4.56 5.52 6.24 6.96 6.24 6.96 6.24 6.24 3.84 6.96] +xshow +end grestore +end grestore +% Unparse_c2->Unparse_cocci2 +newpath 2458 802 moveto +2513 791 2604 772 2634 756 curveto +2654 744 2654 735 2672 720 curveto +2684 709 2698 698 2711 689 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2713 692 moveto +2719 683 lineto +2709 686 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2713 692 moveto +2719 683 lineto +2709 686 lineto +closepath +stroke +end grestore +% Unparse_cocci2->Lib_engine +newpath 2700 653 moveto +2692 651 2683 649 2675 648 curveto +2533 621 2493 643 2352 612 curveto +2349 611 2345 610 2342 609 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2343 606 moveto +2332 606 lineto +2341 612 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2343 606 moveto +2332 606 lineto +2341 612 lineto +closepath +stroke +end grestore +% Unparse_cocci2->Pretty_print_c +newpath 2707 651 moveto +2679 639 2640 623 2609 612 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2611 609 moveto +2600 608 lineto +2608 615 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2611 609 moveto +2600 608 lineto +2608 615 lineto +closepath +stroke +end grestore +% Pretty_print_ctl +gsave 10 dict begin +2439 378 57 18 ellipse_path +stroke +gsave 10 dict begin +2395 373 moveto +(Pretty_print_ctl) +[7.68 4.56 6.24 3.84 3.84 6.96 6.96 6.96 4.56 3.84 6.96 3.84 6.96 6.24 3.84 3.84] +xshow +end grestore +end grestore +% Pretty_print_ctl->Common +newpath 2401 364 moveto +2294 327 1982 218 1719 144 curveto +1658 126 1587 110 1542 100 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1542 97 moveto +1532 98 lineto +1541 103 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1542 97 moveto +1532 98 lineto +1541 103 lineto +closepath +stroke +end grestore +% Ast_ctl +gsave 10 dict begin +2398 306 34 18 ellipse_path +stroke +gsave 10 dict begin +2377 301 moveto +(Ast_ctl) +[10.08 5.52 3.84 6.96 6.24 3.84 3.84] +xshow +end grestore +end grestore +% Pretty_print_ctl->Ast_ctl +newpath 2429 360 moveto +2425 352 2419 342 2413 333 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2416 331 moveto +2408 324 lineto +2410 334 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2416 331 moveto +2408 324 lineto +2410 334 lineto +closepath +stroke +end grestore +% Flag_ctl +gsave 10 dict begin +2486 306 36 18 ellipse_path +stroke +gsave 10 dict begin +2463 301 moveto +(Flag_ctl) +[7.68 3.84 6.24 6.96 6.96 6.24 3.84 3.84] +xshow +end grestore +end grestore +% Pretty_print_ctl->Flag_ctl +newpath 2451 360 moveto +2456 352 2463 342 2469 332 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2472 334 moveto +2475 324 lineto +2466 330 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2472 334 moveto +2475 324 lineto +2466 330 lineto +closepath +stroke +end grestore +% Ctl_engine->Ograph_extended +newpath 2662 441 moveto +2711 429 2796 407 2852 392 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2853 395 moveto +2862 390 lineto +2852 389 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2853 395 moveto +2862 390 lineto +2852 389 lineto +closepath +stroke +end grestore +% Ctl_engine->Pretty_print_ctl +newpath 2593 438 moveto +2563 426 2518 409 2485 396 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2486 392 moveto +2475 392 lineto +2483 399 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2486 392 moveto +2475 392 lineto +2483 399 lineto +closepath +stroke +end grestore +% Osequence->Oassoc +newpath 3131 288 moveto +3130 280 3130 271 3129 262 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 3132 262 moveto +3128 252 lineto +3126 262 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 3132 262 moveto +3128 252 lineto +3126 262 lineto +closepath +stroke +end grestore +% Pretty_print_popl +gsave 10 dict begin +534 450 62 18 ellipse_path +stroke +gsave 10 dict begin +484 445 moveto +(Pretty_print_popl) +[7.68 4.56 6.24 3.84 3.84 6.96 6.96 6.96 4.56 3.84 6.96 3.84 6.96 6.96 6.96 6.96 3.84] +xshow +end grestore +end grestore +% Pretty_print_popl->Ast_popl +newpath 534 432 moveto +534 424 534 415 534 406 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 538 406 moveto +534 396 lineto +531 406 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 538 406 moveto +534 396 lineto +531 406 lineto +closepath +stroke +end grestore +% Pretty_print_popl->Pretty_print_cocci +newpath 586 440 moveto +604 437 624 434 643 432 curveto +996 393 1421 381 1590 379 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1590 383 moveto +1600 379 lineto +1590 376 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1590 383 moveto +1600 379 lineto +1590 376 lineto +closepath +stroke +end grestore +% Popltoctl +gsave 10 dict begin +682 666 38 18 ellipse_path +stroke +gsave 10 dict begin +656 661 moveto +(Popltoctl) +[7.68 6.96 6.96 3.84 3.84 6.96 6.24 3.84 3.84] +xshow +end grestore +end grestore +% Popltoctl->Lib_engine +newpath 710 653 moveto +716 651 723 649 729 648 curveto +976 598 1612 621 1865 612 curveto +2000 606 2160 600 2243 596 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2243 600 moveto +2253 596 lineto +2243 593 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2243 600 moveto +2253 596 lineto +2243 593 lineto +closepath +stroke +end grestore +% Popltoctl->Ast_popl +newpath 651 655 moveto +627 646 595 631 571 612 curveto +509 561 488 543 463 468 curveto +457 452 455 446 463 432 curveto +470 417 484 405 497 396 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 499 399 moveto +506 391 lineto +496 393 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 499 399 moveto +506 391 lineto +496 393 lineto +closepath +stroke +end grestore +% Popltoctl->Visitor_ast +newpath 710 653 moveto +716 651 723 649 729 648 curveto +949 599 1012 641 1236 612 curveto +1250 610 1264 607 1278 605 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1279 608 moveto +1288 603 lineto +1278 602 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1279 608 moveto +1288 603 lineto +1278 602 lineto +closepath +stroke +end grestore +% Popl +gsave 10 dict begin +240 738 27 18 ellipse_path +stroke +gsave 10 dict begin +227 733 moveto +(Popl) +[7.68 6.96 6.96 3.84] +xshow +end grestore +end grestore +% Popl->Popltoctl +newpath 266 734 moveto +326 726 474 706 597 684 curveto +610 682 624 679 637 676 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 638 679 moveto +647 674 lineto +637 673 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 638 679 moveto +647 674 lineto +637 673 lineto +closepath +stroke +end grestore +% Asttopopl +gsave 10 dict begin +337 450 41 18 ellipse_path +stroke +gsave 10 dict begin +308 445 moveto +(Asttopopl) +[10.08 5.52 3.84 3.84 6.96 6.96 6.96 6.96 3.84] +xshow +end grestore +end grestore +% Popl->Asttopopl +newpath 243 720 moveto +249 689 262 627 280 576 curveto +292 541 310 502 323 477 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 326 478 moveto +328 468 lineto +320 475 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 326 478 moveto +328 468 lineto +320 475 lineto +closepath +stroke +end grestore +% Insert_befaft +gsave 10 dict begin +229 450 49 18 ellipse_path +stroke +gsave 10 dict begin +193 445 moveto +(Insert_befaft) +[4.56 6.96 5.52 6.24 4.56 3.84 6.96 6.96 6.24 4.56 6.24 4.56 3.84] +xshow +end grestore +end grestore +% Popl->Insert_befaft +newpath 234 720 moveto +231 710 228 696 226 684 curveto +217 610 222 523 226 478 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 229 478 moveto +227 468 lineto +223 478 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 229 478 moveto +227 468 lineto +223 478 lineto +closepath +stroke +end grestore +% Insert_quantifiers +gsave 10 dict begin +100 450 62 18 ellipse_path +stroke +gsave 10 dict begin +50 445 moveto +(Insert_quantifiers) +[4.56 6.96 5.52 6.24 4.56 3.84 6.96 6.96 6.96 6.24 6.96 3.84 3.84 4.56 3.84 6.24 4.56 5.52] +xshow +end grestore +end grestore +% Popl->Insert_quantifiers +newpath 232 721 moveto +208 673 142 536 113 477 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 116 476 moveto +109 468 lineto +110 479 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 116 476 moveto +109 468 lineto +110 479 lineto +closepath +stroke +end grestore +% Asttopopl->Ast_popl +newpath 369 438 moveto +403 426 457 406 493 393 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 495 396 moveto +503 389 lineto +492 389 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 495 396 moveto +503 389 lineto +492 389 lineto +closepath +stroke +end grestore +% Asttopopl->Pretty_print_cocci +newpath 375 443 moveto +400 439 433 435 463 432 curveto +683 411 1364 388 1590 380 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1590 384 moveto +1600 380 lineto +1590 377 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1590 384 moveto +1600 380 lineto +1590 377 lineto +closepath +stroke +end grestore +% Insert_befaft->Common +newpath 249 433 moveto +324 371 588 152 610 144 curveto +687 114 1272 96 1447 91 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1447 95 moveto +1457 91 lineto +1447 88 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1447 95 moveto +1457 91 lineto +1447 88 lineto +closepath +stroke +end grestore +% Insert_befaft->Ast_popl +newpath 265 438 moveto +272 436 280 434 287 432 curveto +372 410 396 418 481 396 curveto +485 395 489 393 493 392 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 494 395 moveto +503 389 lineto +492 389 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 494 395 moveto +503 389 lineto +492 389 lineto +closepath +stroke +end grestore +% Insert_quantifiers->Common +newpath 118 433 moveto +143 408 185 358 185 306 curveto +185 306 185 306 185 234 curveto +185 193 173 170 204 144 curveto +251 103 1216 92 1447 90 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1447 94 moveto +1457 90 lineto +1447 87 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1447 94 moveto +1457 90 lineto +1447 87 lineto +closepath +stroke +end grestore +% Insert_quantifiers->Ast_popl +newpath 146 438 moveto +154 436 163 434 171 432 curveto +282 409 416 392 486 383 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 486 386 moveto +496 382 lineto +486 380 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 486 386 moveto +496 382 lineto +486 380 lineto +closepath +stroke +end grestore +% Cocci->Parse_cocci +newpath 1793 878 moveto +1751 872 1673 857 1613 828 curveto +1588 816 1589 801 1565 792 curveto +1538 781 1134 752 983 742 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 983 739 moveto +973 741 lineto +983 745 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 983 739 moveto +973 741 lineto +983 745 lineto +closepath +stroke +end grestore +% Cocci->Ast_to_flow +newpath 1850 880 moveto +1949 874 2281 853 2555 828 curveto +2589 824 2628 820 2659 817 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2659 820 moveto +2669 816 lineto +2659 814 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2659 820 moveto +2669 816 lineto +2659 814 lineto +closepath +stroke +end grestore +% Cocci->Type_annoter_c +newpath 1850 881 moveto +1942 876 2233 860 2472 828 curveto +2555 816 2575 807 2658 792 curveto +2742 775 2764 775 2848 756 curveto +2853 755 2858 754 2862 752 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2863 755 moveto +2872 750 lineto +2862 749 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2863 755 moveto +2872 750 lineto +2862 749 lineto +closepath +stroke +end grestore +% Cocci->Transformation3 +newpath 1844 871 moveto +1894 846 2014 788 2077 757 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2078 760 moveto +2086 753 lineto +2075 754 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2078 760 moveto +2086 753 lineto +2075 754 lineto +closepath +stroke +end grestore +% Cocci->Ctltotex +newpath 1814 864 moveto +1798 827 1761 738 1741 693 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1744 692 moveto +1737 684 lineto +1738 695 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1744 692 moveto +1737 684 lineto +1738 695 lineto +closepath +stroke +end grestore +% Cocci->Ctlcocci_integration +newpath 1848 876 moveto +1902 865 2021 839 2096 823 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2097 826 moveto +2106 821 lineto +2096 820 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2097 826 moveto +2106 821 lineto +2096 820 lineto +closepath +stroke +end grestore +% Cocci->Asttomember +newpath 1793 877 moveto +1748 869 1665 850 1646 828 curveto +1614 790 1615 730 1620 694 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1623 694 moveto +1622 684 lineto +1617 693 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1623 694 moveto +1622 684 lineto +1617 693 lineto +closepath +stroke +end grestore +% Cocci->Asttoctl2 +newpath 1821 864 moveto +1821 839 1821 795 1821 766 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1825 766 moveto +1821 756 lineto +1818 766 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1825 766 moveto +1821 756 lineto +1818 766 lineto +closepath +stroke +end grestore +% Cocci->Unparse_c2 +newpath 1850 879 moveto +1943 867 2238 832 2361 816 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 2361 819 moveto +2371 815 lineto +2361 813 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 2361 819 moveto +2371 815 lineto +2361 813 lineto +closepath +stroke +end grestore +% Cocci->Popl +newpath 1792 879 moveto +1599 862 495 761 277 741 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 277 738 moveto +267 740 lineto +277 744 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 277 738 moveto +267 740 lineto +277 744 lineto +closepath +stroke +end grestore +% Flag_cocci +gsave 10 dict begin +1699 810 44 18 ellipse_path +stroke +gsave 10 dict begin +1668 805 moveto +(Flag_cocci) +[7.68 3.84 6.24 6.96 6.96 6.24 6.96 6.24 6.24 3.84] +xshow +end grestore +end grestore +% Cocci->Flag_cocci +newpath 1800 869 moveto +1782 858 1755 842 1733 830 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1734 827 moveto +1724 825 lineto +1731 833 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1734 827 moveto +1724 825 lineto +1731 833 lineto +closepath +stroke +end grestore +endpage +showpage +grestore +%%PageTrailer +%%EndPage: 1 +%%Trailer +%%Pages: 1 +end +restore +%%EOF diff --git a/docs/manual.tex b/docs/manual.tex new file mode 100644 index 0000000..a4e99aa --- /dev/null +++ b/docs/manual.tex @@ -0,0 +1,257 @@ +\documentclass{report} + + +\usepackage{listing} + +\title{\spatch and \sgrep manual} + +\tableofcontents + +%############################################################################## +\chapter{Introduction} + +%_semantic_ patch and grep +%next-gen + +%semantic patch/match +%SmPL +%%SMPL => semantic match and patch language ? + +%sed on steroids + +%features + +%abstract away +% - +% - +% - +% - +% - + +%submit idea/patch/ or even semantic patch :) to xxx@xxx + +%############################################################################## +\chapter{Building \spatch and \sgrep} + +\section{Requirements} + +\section{Getting} + +\section{Compiling} +%requirements + +\section{Running} + + + + +%############################################################################## +\chapter{Tutorial} + +%toy.c, toy.spatch + +\section{SmPL piece by pieces} + +%very simple ex +%bigger ex, show different C constructs. +%%abstract space +% +%+ +%- +%* (a kind of -) +% +%first run +%first process/workflow ? +% +% +%then metavar +%sed on steroids +%%abstract xxx + +% show vs perl + +%then context!! + +% +%then typed metavar. +% +%then iso +% +% +% +%then '...' and multi usage (in arg, struct, statement) +%%abstract yyy +% +% +% +%then multi rules and multi usage + + + +%############################################################################## +\chapter{Advanced features} + +\subsection{Multi files} + +\subsection{Position} +%src: a mail from julia + +%Tu peux maintenant mettre des positions partout. C'est interdit d'heriter +%une position a travers une regle qui fait une modif. +% +%Tu peux declarer une position avec des contraintes, eg +% +%position p1 != {x.p2, y.p3}; +% +%Entre les premiers @@ d'une regle, tu peux mettre "expression" et avoir +%une meilleure parsing. Ca permet par exemple de faire: +% +%<... f() ...> + <... g() ...> +% +%pour decrire un + qui a f() et g() quelquepart comme arguements. +% +%Pour les }, j'ai mis un champ "is_fake" dans les noeuds, avec is_loop, +%etc. + +\subsection{Embeded Python scripting} + +\subsection{More on ...} + +exists annotation on rule + +'when any' and shortest path + + +when strict + + +%############################################################################## +\chapter{Examples} +%put additionnal commented scripts ? + + + +%############################################################################## +\chapter{Developing a semantic patch} + +%best practices + +\subsection{Emacs mode} + +\subsection{Basic worflow} + +\subsection{Linux workflow and git} + +%git diff +%git revert + +%multi patch ? + +\subsection{Debugging a semantic patch/match} + + +%############################################################################## +\chapter{\spatch/\sgrep command line options} + +%cpp + +%iso +%rules + +%############################################################################## +\chapter{Other tools} + +%partial-match? + +%cocci-ediff ? + +%coccigui + + + +%org-mode ? + +%patchparse + + +%patch handling (splitter, mailer, maintainer) + + + + + +%############################################################################## +\chapter{Reference} +%put grammar ? + + +%context!! + +%well-formedness + +%limitations +% goto +% ... + + +%lexical conventions +% superset of C +%plus +% blanks, column!!! +%comments, c vs cocci comments +%identifiers + + +\section{Toplevel} + +\section{Metavariables} +%typed metavar +%scoped metavar and rules + +\section{Variables} + +\section{Types} + +\section{Expressions} + +%funcall and ... + +%cf also position trick + +\section{Statements} + +%declaration + +%type definition +% struct iso + + + +\section{Rules} + + +\section{Isomorphisms} + +%named iso + + +%iso file +%extra file standard.h + +%implicit iso + + +\section{cpp quircks} + +%declarator +%declarer + +%also extra file standard.h + +%############################################################################## +\appendix + + + +%index (reversed) +%index of concepts ? keywords ? diff --git a/docs/semantic-patches-for-collateral-evolutions.ppt b/docs/semantic-patches-for-collateral-evolutions.ppt new file mode 100644 index 0000000000000000000000000000000000000000..8a58ebbb6cf32f7c207b8f13770b237c21574948 GIT binary patch literal 664576 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.t2y#*8ZR;u>`FyM>G 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

    Egx{WtvM&<)x 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≀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%0A)k2a)i6UD;Q{yB)o_M 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�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

    8JJx=5i_=F7Bn($Q5y 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

    KXWL}6+SZ2+$wDCAuuC~;1q`HaE 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දl>ESvW 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 p5qK?ma;*6m`z6wW$rm+6}aslGx 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%0D!w!IvkyEI>ZC$P=9>B=|KK)AaKBbF$ugm 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 R)Lql(U!y`dBh!}D|9{i`(Psbv literal 0 HcmV?d00001 diff --git a/docs/semantic-patches-talk-ols07.odp b/docs/semantic-patches-talk-ols07.odp new file mode 100644 index 0000000000000000000000000000000000000000..6815d8541ad655350433eda04b2bfe863604a00e GIT binary patch literal 52523 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≷je8 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

    fkFqH
    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

    1lqi}e>5Tq2wG4m>${e%)sbqK(Dx z*{N;4%{5?akp49|0udw2#a0BxWi0aF51NwFgTO@ujon}zf z#tUhNm@pVKkl~`%v@8`%q?h2Bx#mj1$BmIU1FR`&w;-y9P+EL*>~rLj_ZD_VJB{-t zMF|LaF)6yI-%3kC!(=SVZOEL8d^8myqh3j07MjF&n{^{{*juq2k`E>JA{e|Pryg!X z%fZb&!1_klu{pI_toqMB=rv;Qz7U~~HHe?d81zOb5#Pv+dl|G9k_n(E=9m2Ah!`SAlL4KfO0iH;je5AgqaHjp(1N7@BIk)FmD1`_1UG zjp#=&K^pKq0O1Si2dIn#-N{}&=x2g3*-E?78nEirl|B&<`f~Y zML}x^bUi`cfsGt8LzUuMoT{4y=tKw}Py)V^Yyzo?N@YSs!V9Ei7PvleCV~nlGBOVY zaEAzxg+Y+P1V}QHGT|7GSEI}5{A3OS9v_FBDbx+9yTweD?3jc}3 zRwzT6kYKwyr^`1MJQl%!r${TNn>Re^lY@t>rX(tws<}yJg#eCtr5OsL!lQ60>6SV1 zQc}WxMEX64mE75$=pHe55p zNJ|xY#-d(FM;whs<)JnNi-34ol^^cV>mwD+-{QmS4LVn_3ueQ$Y0N0&cK1c&OL!?9 z>=0yes17ZKq9swJP$;*|WMCXPV_~`RM@?>1@W<7>a6@T8#mavRI!qPIfI*YdlY&d! z6Uf&`JKsT9Z5nt0T&}|@pm>HQ2JsT^76k!W6X8C=d~6X|ipoL5_Dhu6PVCoOgvCYdxJs;a@s|R2p#{n(YEch-9HCkRNEVBy z=5)Jc1vV^IjL1I(bOUR#WdaBwuONey>5D-?~O|HOjIy?)tQA*%|oU zU+M$JztJc~q%gWB4Nej+97DK5J+}?2>KASkus@h-0j)qAfpKaDZLU4pTx23(`P8RQ zEQ=~$jSlU!%sJ|15stFh(j>0ri^SKNH>wdRAo0{sBIPe*?|K?NN+5W)4o7K~8DSVG zKMSL0U5Nj`-97T?m4+MDHmx0*>-EfyORZCOQD~trfa?(t{Z6y~+8uk2GplJvzc@2+ zbDKReU2w{>CgVp>R1aGcV05lR&_D&ttyWq=mscx%dE*Rpmd~WPVoU%`7d1TqfIf^^ zkd|D3P#k4|Nw{K~GEgyo-ths0KZj0sY4b%PsnVYFv>|cL3rbl=qMjUbKijW=(eB&_ z(I*uuW!cc4JW&GKYzj-AOuY}Gu(cA9Tn3SQvcSmJ6*c+$?SVNn_+YCy{Yc-d8oT0T zYJm>2&0%Bk2@)d+nj-2n7<-UyFG*S(5of#zGt9GkNo)-*@BRJXvSivJ~uMeRUdqY6!n{fmJ zi)KXf%!PdDD<@s;_!P*qg~rhrl!!dr#ABJ)zmYMKS^TI%tC3+58~`^fovVRW1d3Ad ziTwjNr8-gHplcx6iZnVMLnT(@YW$u~y?#pq0vTXZj_JV^@hJhG=Zi4jI>@*$ybf{9 z;S%}(R{8sfh%*6eGJ$A5Huj5_Bp{GY4ge%B4ra|rq76u)?1-kcdTimuiUf^CH=}~= z2wdb`MMAwDt&6OrMO&%Fq}_d8qgs{umulSQo=9=rxiVhOa}zy5=26xL&<~rIf~H`= z3k7=0YS@;(GuBlZWP+;dP&j)6N@taj7EoI>{nN~!dB(&Itw;}+s1_hQ`r(<2Q z?*+h@mjmIGizb*CkN`&zr(OWZXI@Z`>?ruc+gr!y2|G}e@2*51WZ%7B(6qFJEfc2X z90H4M6=Ns2z%Z~Y2z=s&!~@C!!eDn~TgYDxs4G&~+Yd}O5M2!#lSRx{1=-}Wv4=b& zs-KBefMy_W%(1e}7@nIgNamMF)@XzxfoGEK?gifh2f|(OzX(RUBs8)_#SrSS{qLLW zUXsG%UL2*sfq6)BRs4iWoesJTV9sb4pMLx9Rgc;)sDkVHt>!ZSvI z-T=a(03;a-?Mf#?-catJDO6>LZH7q)Jks9ql!7dDx;<)GPw3y!cOc$aW@8lyAz?lv z^llho$Gtagx)N4HK4u4Zkfy^Z^ZNp9En&9DRKeIH)DsqH4sV^4&RQ@ailfdeK7vWo zw3V^Yg&E<+-1%aV4NegW0q%AD_-OzHXm2>G*HRlJDF->3BIq=dWYlsE8_HKPh*mN( z?`d!G?~%kpj|5Uk(%Cais*CUzNTKi_zzGLcdykc%>0qWI_b8fG}1An(Mac zJ!mn=8we7VZbPC|z>LKC@7&}|A2H{I_Xq@(>Sat|^;i#)L?JGJ3&i~Ns0-u~M04sE z>|+H;QM^?NDP@ttr4SyJ@=g*qr6}Fzs&GS>XGm32(2Kf`9Gp@%b7DlxK=~Nrsmf(GM*$b$imw73V`L)1 z0gPn-i~#WW9-E3ShrU7N(^oy#XXDAlTp*o?VIPmUv4xz}OS5nU%en^G0tsk`yH^18 zLV^smx+)2Lb|jBj(SRr^bJHCQQwbWTKtIXtMu2bie`5#Ipo&>GN;t zz!R~IkV=MdR-?~6d7UsMmB&hmz+K9sNOmw>6#8K3P~;<)@pj<@vMUA+(@9ZWKit7U z)lxru0&s;_@bj2l68~PW_gKEc>(}~4$g`TK4T@_i$Y*NZtK1V(F-dc1viCOau8i6n zXLqDxzEhmpSf#lQGB-(|d;wDhC=GxY#m+0wpm~TrWH^g#xWZk_82(cQt~+(j`(b9# zm@iZzk{RhCCUy#fRt@^Q-bAi7?u06}j$#NmV8qf>l1$5*p;Xg1lW_FlHf7j528L-= zw83v4d#};^uNR>z5FebrpY%LwbC$EtZ;d*yvMo}mEIDfBoe!*1b;!B;pz^BeQ`M4} zen-;exzJiZPZ4;(1m$#kh7$qXSl$7ul2cR^3G;Ul>M(KZt_^5Am_!V7prlg|26^Wd5{W~50yIz<{n*bcr_G=xN5x!55(44Gbz%XI zpJ1t*D9Ll)_>q3vSU>_asaC|dr}r&{2iCS!mijUxJUeoZ=OC4)4ZEygxH)d0PbMVZ z`h1@DQO&&{>4;i$txGg8f?E|*WI-a4zTv}dwxE#)nsSaOm~g&B=pGhwJh*YtCqYt! z(RyV3=|&uu-1S$oNYBLV!zfnSge-B2WRMsmTtSWdTx6s;>;5Gmsn=bKo4OBj8)i^2D=0Bls7T> zKo#Z|bP($FUN=y$V#IPDpFVYiMy^Yu3LD_ho`dJR$N}b(6mYE0*7Bb|lCt=s9neh` zk=?|KkM4ION8p_Bf&?FxWfk`oFL4xV`t%0_K5FQ9k3|?T&$(*Yg#cT$BFE5hPh3i= z(cYcqq5^1%kCAKMs|C5)5zRPP5`rH%e*$&O(%H&*r4S2S2#FwdQKdH;f~+242TngDF4j`9$(818-2OF4CX<;uJL?NgExHe8?Re*Iin&V6+nz+E5T z!0*L_G?oxo7Qcp*g~VPL7C|PV1Y#svu&k;zq5aYfUxl||jZ3|NmRh$|J>e!8# zOVHw5Cx&$>(a>0&$4-CV7wQogaISI<$#e3emf%}^C!`t@-c261X@|D@2K}%rZc9mw z&GfWO5ZBF@ScdhV+&K}y3X5llQZP8o+^D3sM1!i3AUFu#-_4T)TQv$*DlSyPIARo4 z+VCNHt;L`@%!R7xqm(``W?pprEE91j0+;Z&h0jj_6ba8AhxF9`uM{34#8-0p=Du*;o0KnR}6A)syG!`7o6yTub_$D#^JH`vzNH|WU z%Z`BcdP@-lNSczNTuUR7ejaFZ5D z0^W2I3w-IW)LMEvHo=3;R$l4b6tBU>XD|@bo^|q0dFAMnX8aNHMv7n@wmb~WPTXXv zmb6q?$n#6u$V+psSCMy#TE$a>R7Ih~z*cv{ed=k+micPrCJ=Hpx7yqwqTGpUq-6ii zm7`Yg(5MUMzCfd|&o+lA1bV6kQ=J|l!0ZRU=y4v*L-UDTmx761tFQ|`$-%-pE_J

    ZSxm-M#wZ}~O+B51O>o?-ZEB^1!UpozT@NbnQ@Ncj6hxL6L}l^JJK!Ub^#xJQL4 z?ug*)Ff;z0P;SPw`7S+UyMd{}5o4y!ZZUOMNW3j-G;F!`hd=SwuP!G``n!@U0RU`` z{L&33;p}*LYE<<|m``g+H<0u*@-OE|H7hksJbTuhj>I<-%51pIv&rtSzOaV6qzgA7 zH`cft7p50nDaVSFbE@YmW=1}7GmU9>^bf}ups-=m{%Dp;Z(YaW=HeO5tc z5p;XEKksEG_U5gSA*&X|`X=)eQ21bDd$eozD{z<%S!-}le+yqaiIjub|FwFi*5KvP z9tv96_}X)=kRCp$&iGq8!Erme)8z0BF-xC9(rb)Np%063#+OY-Wx1i9b=Eb?)=9X3)l0? z?-ZwQr&UgwtF4kGf>}butJHX`oA3T$!A;{?B+=(h?%rxg)Zi)Q466mXe0e8fINCx3 z7sS+H(sny0>r}LCf@G!Tzs^XQlXLI)6k-3joYo#cw(%%Mt`-sIH9ytox~SkCcS-c} zKEDjmjP@rRAVJBttZg)s;dt%jO-W{UQssyuO={GBE7O_fmSUnSw2cxzfnx_~bld1m zu0<06G)YtV+E_TfCz_ZCQn=903#8Xl=eyEnS@$Vc{x^9BMRfWX1?FW8Un`tb-2Rcz zRdUy`Trq*<^?U;#r_c_Mje=e+V>yr;T&Z|*EXKTH8XId8kBE2^_GuY8m4k-c*KsA@ zXa!41SuSGVyx+T_YnHJyws%*qO7IJBHGdOSlN3o!w!m&{8%L&Oj5Z09 z2G?Henp%C5^`!jVJrY zv@^u8C+~yiMU=G>kZ6)|vVx}aKqfv8f?R_yG8%p{$T8bGpeT84?pO^k=~XFa5y-3sFZlIT#o9qc`yEI>?Hs zhcPogon=|O^g!s#TbjB`gC1j=54x=y#FWo2d1M*Ca(v#g-oO`{-ijf@6j zDPdW}_;!eH>qQ<3&tY{g5VL$cM;)xnC=TiagxYh;TD$_BKSqF#EVRH~o`qFDdCJ(` z8BI&ktr7K=4UwGa&*^g?ah{+&>YG`~c@$fDnvbbtBi|xoE1hXd zXi-)zl5RlEx^izHR5N#8bp%bwc;DvneYH7gE4?X3SMAmr+J7Ewwo18l`KLC78#i&| z9o<_3^|U1dw}cy?r_sWUybI7kHt01|$N+~KW|&_A&A}ALL^dqZd0MRLM1;ByEbw*?T8k4LH zedz}*($e2c2^s)2jTN-7PicF7=^;#6GOq2ih@x9&dDi|IH5#OA&dZk+Z-hdDFv`(# zIK*l_|6(X6q@UJSOFYn(@TmcLB7);mq z;`mjSak3u&-K@t`&qh=kTalv4w{Kn5#_Ioqf%|YIzPztw;C6CY4nCVn)?1{B^8l+4V63yF0^EufWtqZpnxrb>9TR7W#BIYl1J=fiC zEvkr}%#WT%x_5u@RLDVuN;E~TOTVKtVuv68eTwejTslMhDk(w$giWm`8-<~J+$%x- z^n&GwtK~v|ne|6Xq^c^+d60clSLsK`U(G;v;+#U;f1RgaL9H2Mw_g^~r{xemB^B1X z<}?bi+Agx$9wFHYMzk~R&*mkdekKgD=9$5`5<#cs4dKV#Y3`SdKyM+ zobc>ajwwTq;X=Qr6M(voTn55BNX)u7J7oA>Xz^DIJ-o1fExOtEU{XEoeafH2Z-@vr zKN9oz0uM%<-<)wdjRhf*3>h9-PLW|boxj}~I1SJ{CrJEoMc`j9_NU`?t?Loov29&NjAcS?0*+dxqZ$TW9SdNRwLV$~`-{ zB6Wm$D8!}|6)Jp)IK0O0%E0?y@%>2DApL%VDSz>3o5`+>1kV&~L)Ny@NBu{XBr+o4#8&cOoF2`)2PdXJI% z0}$&3oMLrC8C?9l-?>bx@tubzj-Nr>T{Ihix?L(M-Izn2)bqVi+_#4Y;nJRW;#$lz z%t;b&QX=GFZ>}Tkq4UMu2J6&iP=MYxd2At-W^7W3Zae(jiC$tFPJ(dDav_RN<-ZIQ z4{WG`U3NzGMp+nms|?KYZp&z4G_^dQpOX2fZNL3X8c68@wVf=H*Eu1($yhvJXHSUM zp24L8`hX9pKsy`#?5%W*3)@*?*l|W0c%T>gS!G9AN)(OSmW~*K>L#aU(R{LOc+`uy%;}0cEo+qt=NR#}SH7}rfd0i?@pWo2 z(!y4o~(o&Uz zzCO+8Z(w-!l&Jrbn1eIW(M*z$2AT>E0ZR{uGaWobNabSqI+B6CZ**uV(X>dl!%Le1 zysH=4&dVY#`~;9EE&TYfaMbB+*V$&_Y@Z_3A1}W=ObM>H{(%ROKLIJU6b!_Kqi{7BC#WljPGOGDfty8XJAoWkHdhw9{Ae2Rmhd>Mq zVRA`2)E-fzg&mrU#aY`J2WKkm-^{aItShp~+W!t{-N-Li;<&HU%FMIEvGS~+9@s}I z-vpS(^3}~~`bi%XBdB5o))IF|6v1aFXDq8_ z6HF>!E@d)Loq}Z#_6duS-i|9S9*JT4DrY$8y~j<8ZiQNaYYLx@o2QU65eobWXF9Gt$aVaWL{IDpy{zmGQOUtA3^62?2lM4mMdDg5a4XMR* z=o)QG$!w8FJj!_*nyPsegF~#iI1ALLOEgxtBU)D8E4-4bIdAVmwG0wUpgLm8E8Gk(07VM|E>gqU?%=4{4IDa3c`~9Bt>7TJFy)c}_fs?y z0V7}p5;E>rU9yzcrD#}fTA6yfY=bj(+RT{3zgcJNtEdX$%>vWtL@&Yhvk`h?15%W!K4~w-%3TOT8o1X;5ZUPci`ec>!Y% zPhzFYVdN>_2SU~30tSY}U_)aKBU($@;P(uU@9{77R8ve((P4R9GcKyD4JVI7(c1I5m=#)$|ra$Xj(F8^F)+>*VBn!=7BZ6T(uQ zBkG8eo*JLTf3hRo`@?sm!mWUXNJI&1&FH(|D7hqCSb4m|R0b5P*zUA?uc8f2I+8C_ zQk(^jPc)2j9L3^?;!7s%<&S8^ew!Yr4$(_oY3g3_DBqUWM z4#=Dn82N*`$g2uk(di~qlu$=F+RxWf*-|5`aq?=P=&=8Rgz2REI_Z%^#(GsL-e*X- zgme2+?nlN`e^0R?P)6W`xP^YlfS!M_)FwF^{K^_F!U{q|Q8};@pk8|CBq~qu10ko* zOjSL@Ekra*#hx_jb5jLIK_DHn4!oGm z0K72|n<+icBX>i+)E;C%mlcvksn{tlb~@vuTp6`JIM)fCBqp=xrd~-H68t&v0*exlM`xC#}_dV;=y_RGQS)#7q z>w3buvV&-B`C54>tSl{90FHcQk&#t8jKa1AIAaxk`B}(-6k4(1>@Mu3p88U%s{`yL zeHM|!N+qw&(QjAft!5Hb}uXmyLJET{k? zZj)vwIM)B2(cOjF*DWnWooU?MM|Jq=y@w9JFc%v3Okve^#L?>}+FnF?DSnx3O$h#V z)RN~xLdoEWK{$-x;YGV6-C_3=#>=FvxK&9jq3rB~GeF=py5v^HQmqLr4yHX+&6;;Ndi5mPGEvZA3ppbYs)!#(V{B^>6EEpUnNRvF!6mm^j#98T zDw!*u@DnS z+BD*>RWYS1v*L>@`tD$l6Ssk6Y!Q_I2T?$-zcxevq>VgQq)ij-faVZlM-nx#HL1OzTIWErq{m5DAd68MB;6GdD? zRCOt|EG7oa2r5iiD5NGChTGr<%K#vFpHW1X68R#78Y?*fz^GFW;HLQ80vZY+BN{6J zLfi>IZp=z$BMEwHv+NkQ1OTdKynn9bu-6ZQXxg)7hl(8!uYR%&o;0BuJiK^-J*H~U za(9_tO-X?>Ot90%>SPTchaMM|@9%@s>-^VSD3PIS%1Byj7um6SUx)*x6bpA-Hyg<+tettPr5ih8;)n4qmE zg}Ng^yIJXkK`IbXIbiGsQi@D!vR>CiDnr-;%>k)O#XUw!^&T0)vQ=OojAK0K9wBp( zKnINA9h8t(KqC_2wbIiotz9uI;iM61Hq6!rtUEU-&*t0{l!no)P0zOV^0H(9H@V{R zJ_Ark+)^(=Uhs9kMm%`wE^bED|1}Dhn{B)e{IFC3CQ>F}I-6C!YsoejE3pZh7sTd^h zf73S|kp|oIFgETTlVFZJ&EBs?agxd15kn|^&jM>U1tOXewq|`K%<^a;!;eWgiQLt& zqTv?VkE8bB4s7=5*{f61>NPIN8%h)mO6U~5xf2sYxJN|kpOVQ&rw>!RcNW+r3^C^2M0_{fbsey%;jC}7{<_j7p=4nX{yv1%=ADD z<;=qdBo6;-WY9jP!HqL}mj6kU>TzuDC-qvqP71!K%#)NJoJl8Q)uTb)s^}?aQNbe$ zM1(_P*217CHnGqoX#}A|X~1QJU=mj%(K#%n;Pv7LI1+&%#sJ0I=$Wj~Xz|EVtg@K$IjCUQZXrYMG{{b?PcyAGmmo+(SdVO=o5LAaQYt1Ai70mZ|! zgOE%fz3NDjF<>K2*HWCp3U`7L$7j3Ca9$TXZo8=ja@VmStQcHUt>n0`13w;5MVcr` z%Fk+F=XYU(IoSgT;;?v;fN#LzIJFkZ${$*BLx-(OEvT@Qdf7(8@ua%aB$l>y_-cSM3qVV5c95Ws<`fuP!S#)El7$Q}T#uJw z5V|+C7*hWGrMN>9vWCRJw)mzvspxLkc%7A%mL4e*CPH#E@2KI0-frCf)owaP1B`%E z!h-QGnO2Y+z{1yTojXeRnsq2m*M|0;JeAE?RGKkwxB0!v+3UCCWN_5U7IH;gjrPcc z5z5OWNR9E$d>24OjLMV9rRqLt4%`e~YHIf4^d#;WT5J%S2lWpwz&L;drSVtsibO}k zF~pJQa&zHx5uKx4Vk-Uu#ZTqFPrEK7Yo=lHo5_|_!6j(Uyz{HCd0hs=Ig5=xg2M{T zshQhWVTb>k#4sa86uK70oH0OnrA&3`l5{O6H7wxFUvljbLlh+C^XcKo(@;~0Ge+>+ zL1T~9Va(cuw9BWCrpEy4h)fC)XxT%J!B9JUOBzKXkr}6pVS8iM_8d64?1rI_NgBqQ zh62)p!?DYH2?*~2Yv))9br`1ziiL!nBFq|_*Bp%W6(=b9phvK!Wnjs&fSOAbMHEkK ziLytN?vM$J^hg#Dy;ba79uI4QrY-v<(`!WMrxY{^4pBeGU!X`AFl$d2L#{w{J%^uP z*7{)l)sT}8TH8o3IpZ13PV)2lxnWrAQmbapiKCY@Xhj6bh?Rd00MYf2 z1L3x8TKzK_1rTQ>A)gxLtlyF-;W_DGYHubzScjwvk~OE+Aqgloqn2fX0doa8BYou= zUs7y!Do7p`2MefQ-(|d*OH#qwh?LV)60yVWnB zm&Qb9)L8G(lH%>o5>P|~!?-1aksuGMkV)8PNO}rz(Fgz-(@ez_e+Hmr^j;q9T1}vu zH`I#4%%0~)eU@Vcu@nqYR?HTNxMO`W(zpt;(?L8B0|1#;G7@35-5GQrs=c#SBM^@e z$3T8$XOBK--{40m!A{I99rvKZ?ZloTK&(_$0u(h!#*PA%Aqx9|gBICBn<3Bw>S?Hs zTmuz5+oA&}N%WI{mQ{u#WGT0{19&OV0lX9lbKVIoIRx})6Q|KLo_H;CUYV#jy!gH1 z$WH2Ui@2JLhV|P9VBpbu#%Y^kR88Z6P0%_n>UK7KG)st>nq83709hD-wcqcB8C@RG zf!c#-;6G`??<4^s6?WmQ*wGPFV->Zw5mR{2K@hx6VvC#XhHzDG#l21??m`)sR|yso z`_VPRZxcX;VN<#Z`^X2%h(leN)(e3Z>~1sGb(#a2Qb)GzXU^Yi|KxryRK_7!6DNJO zF$^LnjGIK9*CrO0MJgbHHT8lfLB_MSbAu@%!O6swbqPa41)IXMND_jDq^}Ba*BwRJ z#Is-!&Kn41;u7gB6j~CAA5n-YL-C}g&AZI1S6cJ7li1F7cfEPe~ zBew#Y;SOw>&K&av2Fdi)VCb)Cls}gjw!(;r;%$a`mSgu}Jt8^}GRT=&Zw3~y6w`T= z_n!uU07%(l5Wr|%fukfP9f8cKWia{jXLswUk$pM}quLqzguat9Y zSw}XY#Zzrf08ErexBv-#j*u_)1IZ^I{N7oY+k*0VvHx+CHq%|o=Nu!=$zyV#q_7cT z%9&vbUpy5P98B0uyL^O1Es~cpHzlPO@G6%2YIul*kW~SslLiBAn_E;T z3z%Lue1y-#Y&HhIJQ%GwJL-w-P;`SS(8e(}TN#FmdH>X<2M6wocAtq+ZnRzNIso@; zXbtZsmOAA%_sAPGMofZ|fB#vE#U;rGO_gJT#|xF+DB|~SwxFYwgLANy-y$I3dJvm5lK{-wRR2wF<=d1QN$K$h z840k94J90?ECiV*GPAq&+OTt3m}Co5itvk-_%B&lqV z-|5hR#`p)8gcOKWoyIlbP*x)dmyi01Wd>8QXH6JZK{LM7#fYQ_+C*6p<>Ys5dn~h$ zO$=@j&5{o$B(>x~MFnky#flN$(Oa69K8&SOS0(@wu*f$`u~rXAK`Ce2*!bwHk;}w~S@=O1k_APIWFKQ<+?+Nlc$mP%b~s=xc^VyDwRc-0ZtTT$ zQcyAkst+IW7o%94Y(xsRT?KbuU?C{9`^wc3X7~{cM?%4G*@mnOcaeK{LP;PLkWwYT z>K+uO3!c&JJRJ^nbZ2v{OD1_v9LJ~JyAe^0R>q;xccMi2?(2xdK z7!`f*kwN>0M(~zVEIZdZn(mPlKEai44xAZ|Jl^!DO@qJy7wP50SdP7Uib^tV!_9hL zsOMHAL`3Bw1;GvlV)o4(&Dc8Iu&hnKA4(uSPzb9z!zt^aw>L6H6=Mom9n6EPSi*|1 zS|yMdI*?+bj~@4A1r=Vr~gh=SAeBPt&3*~jE%dOe#Z@9&!_AsV@M zbw{AaSHXHYXC849ELqKy#hciQU$BRnwPyB)G#J=|Le_STy_svJpum7r!Z(FxhH;>f z6`oa~#u4odc4IXDZm98jR)g8aDVJb?U%Ze+69oR5(K$E?+O5ZR+Rn1%Dj1M?rtieCR z>nhq6)=7jA$tCgiSjO?x(tQJpO7~{-^mAydRKm<7R*+>GCJq078DY#2Q-Im@ zwm=BesyO-Iovfmhza~Vmk=lKPG#H5D-!k}t}GPA8gG-%TjF zcN|jyhb#dDddhW3GiCR}mM!s;@IqOdm;eEGgIlJE5SEw)RGQ!o4;osNY5HR9h|AO) zx}&xZfj?n_QlbSzz=|g!mg1~H)!OU>7e}ggKH0lsM+Ji&&=IZ~+(Rr4t;%JcU=CyXKw79v4yTA5 zbnq7WIV=stR0^^~{fop9ZtMc*-9n+(7V>gIg4)^(b`O!X3`kWyXv{C~Q3g+d<2&0j^%|ZRE;t7e)iY@&V2mAfV(9^T6|(LrFOZU;|rYfw0k#(Cj2|AzWA-Kv#vh zcUdiS+Gv+ygs7RPHjtDCI^|xv#OZOSyli!T~%F)Y!qiPWi|O` zqd_}B|6*}JP1n~86K8S@j*jIpZXJTlMhKy`ka7LfJr~8)4mpKTK7nK=BZ0rI5Kh@X z?TJZ_Kn_~o>~(?t639WRAZ%9CM}l?ta9ZCZ1(7FMq&_uZF78zHNU|nbmkzSB?tTf3 zjtVGRW|no2j~P*(GEiu?{O5YPd3Zx)?=uY3K=Yf$5L)9&`}y$R2Kf+;@mitK8JA1h zk!oN?iA$pOM{w4_Zmi}eNz#}W$y9E0LQH7=ZFF&$odh~FIrl1+CTTD!XgPO@4;{*G z1%E)Q31rVwqWqcYxaR0_%E{CuQRvC!jByacky*j1H!|%$a33714LuBP?FXY);fXg_ ze5Z^fp+eZ?A>ztaf?)>4+Zda;t|DIAMS_MVd${rYhaawwUwmUF_GjP2H2NO?GKPd1 zGJqPrN6K^H*ga!9*(7HP=Qt#s*fT$Dnkd%C8ufjxvV(H>yecV{KjOo}0_8ZBH00Xle%F)+f>UB6G@5yYHapAM=By6njc zPnt#;c4ghw<4~RLO^O9iz*vW{W5`+K8eDbSHcJ;}2}Dstw9;Kc8=^gx(rQSnfOaA& zFp?p|8H9qPPknG)4n2;O)G8CTFEOVN`T!Sl0vn4j4+Zc zr=XcfGdHfCI>!0(Y6kGViLrI<^Ft-Mo6b@# zhTcO;%%@FEs*(y#E-1}?G`5EVeM_`Lu!<&6w414Nw&Z;%>I_<^M)@)cNyuz=z!NO; z5*s{N2T1kO8qQhyCoCqb?Uci`zsIHdhpe#Vz;zUNv1KDo0nqgG^1C2oC7rCx+cN?1N$*0&R} z0lO;*@ks%XMLFGYuxA0p0%_nZ`I(It`fcK2Spi+A;E+L0n@KBhMbDS+#k6t;_(1pA zd>E40u5A{-gz2RV(Q$*lWk7-zw8`3%7(gXcqsZcy*3oM{MKB-CyTaI1u;S0a3km$6 zCBZyXNNfV4$*G*BG$UZsvi?3`H|5AKMuEy>2}OdHw~^^ix(t=+EN0l7x3gS7;?mHh zwt~?nr&3-$KKY_^vsda?kvF{OqMp|#c=JqkQWJ;Qf?r=i`{(Djo_4MRAn*}#mYr6D zR2v>~%Y!C+H@2D^J>YyQS;87x16D&d%R)|Y|-As9}&>uDQ>)@L-5y=woFJ`v&c|<>vBsa5F`=+l$}hghUDJ(E0~8*Cvu$`rIHH zICsol6%$A;4aeFIe35Cc^r^`R!Y8h>gHlOf2(UKf6DW-u>sJ>2>B}pLRWA!Rz)MIF)#I zGhSB_9={IW3Xo%;7($`Kl_BJmcoC#ODJnd|zPO%6G_^H6=_U996TE|#0HD%<@y>X3 zjB#uQgD?pow{+9fpZO|O7$)$iDE=1WwBh1xKi3QezOo7Wn$)Bc5?M> zl6B;Xq!(fj-HJ_d2cbw9Zu+)H<_9O;_m4NzHB{_><~GV+|HFMM=Jb@{1`H?2;F`AVzo*F^bCKJ9wTVHmIuBri*L}J9ow&snZxT zWtAiUjRH;Q0!Drho{CH;BR=!bXb7)#M_0BL3T}@R0oohh&u+mz(U?zAl*Nz8Gt#Jw zQA2>stnLcV#52UQT-#GYZIJAf3Mw2d`vWsUIgOGCAIIc=2=cQ5{XkfV4TA_i2nEK# z9)ft3Gk#bwZ40qA@CE1CZ>rWD9p<7xaU}phU2`Vnj|-p0tHHMW9d-TcDxlmTVv`}A z3LLSf;@*|6lcxef-XM#hRj-}6^GMln2WBP0Sc`Olhs%LWc1j*X(}A753-k!@#5`XGHFKi6Q8PVh6fM8>)I z4VpNtegWDt%Bx~Q@6tFy>CYi7RPO^w*PBdt>liAS7BZ>M8zRh;BLooJ5rQpbJ_=7j zMC@iQ>tkQ}xcnf($jiQ-hGKz6X%JI9Sl1sS?HHAk+O(=UI+>c8ZEgC8utjj-O$?#K zDHJRf?o2rEg$VN!*mhjKnW=%W32blHC;%vKOwBAd#~l5sjLj@J?DeJZgu1N|;J_;a zI~~D-Ufdo~w`I_ceQ1`E`oMj9HDbvO(tIj%AS7m-V7di8=j%h}ln|sxvi)#tckc8- zAd-@D(SuPc+jtYN=siTnUy|p*71$YGIFY!f+O6anB&f**>!QmyD-TZ#rJ6r3unfON zV-)7qn%Mpo%GntR@T8Hd(h`UE$6*!?XdDt0M{+=DwGFUzaS(r~Sjd6l zh?r5(!n~P8#4!`83O<`og}+p-Efs+Oz~Fm6hfRKu#VnNlPKScsLWK*SUTC=P*e((oub z@ET}$f<-5qj9;0w)&h=Q>Lm3vrtc?PhgaU*jBqCEO7~jVyn_KHY%=3Yglk3)51U2Y zH5+$tVbz2buH}Nwu|axMFO*;8BlUTnUfKqfUaUss zjT9Qj+VfJibiqOsGAe7&rsXAcHRPBKC>3Pqq0uLP$d;D=9M)C(Lvav45jD)>(r?y~ z#TAsgU&gfUC;7J5YBT&WMs86Om5qfEpX8_w8ql6ZCXN35#j}PI#!K3w<&~G6fJ zsFt9)1}!ZxyhfRO??{(%=@hl7MtD52Y~t^X;A|53N7?Et1MC{U8EFv4cLTyLI^g)4!vrAxG zK)8up{Gl+d3d~$=ngCx-Zj}6;MFzDAi_!GD)p7#L#AoQe=c|LgG~>mD-*=05o{2&H zKU*dm=g}HaL{45hA#$i94RUcP*p+@FdyrJ{_*sa9Shfuq=Yn)A*!T*n(cI)8CC{a7 z-2rWr^3Nn?Xyh5k?O2{=(%2=9V97=#x&}K!?Sf4eGZwACq|kF3rHOq+w2IoLt!b!WYpJ5qC&;ypKf`BrGthg_!`B zA$4NZMN>%(S?jwoB9$~6T7Libx;rkPWuThL^SqC1p>5$Upwv`rRch8|Yc%=isLc%- z%%r29lTicP_o@AWQH)Y%!Uk6<^S>@`W^z$lfOooA4=z{oJO8|02! zwL~gFVx{rU?sF1=z^Gpp-$9H8N_HhYBeUIm1Pd+P#99Fe|1iZa6clD`y-8>!D3}}2 z*=xZ_lH%*vat)*nyTo&T64da?)%9%}Lt0-X9tnLLvEc#|48y97fYRdE{!NU#bwf=OIFzetgd z3TB&@L`z|b>jLyLQ|ko5rScSCua+#bO~b*uiF9bYo)PZ?fU3>_S;^0yHBK2S!|QK6 zV6lh`Eui(b6=J^;>{M+$rP$0`5|Y9mCt8KpH)*Y56tV)MM13+vfAP5Y3n<21GA2( z@ZeaiPslI(1}P_)KQ5)V#f}Y5t5Y4o9ILNMqq{as?4Kc<)k_UQ!m-;?{0i$kvvoCJX9J?_(+DEnaf<4QdzkInG#KlwFcO_(p;3N&~rwD`P51o%N z(;vc=d83><9sZQhB6K~G6zZM7OUA2RBfK7BRUkV!M5Q|!TF^n5X|SM5NnJ5SV80q* zh(I45$kc^P0!B-W7l?dWHRJ^TVB@?Bv?3>r1~b>yDe00ZZGH~PNjXAM$t%6EHV+s? z`kvzvw#!-DYvIhj${+t`cNJQQ3kRuMyKR=i653;U7RZ95iA2eZX^b>?K-<(3nIeq> zC7>2Crw}@bWg;PTfUo>%t?cYI%OZe&j^SclrmdJV@8 z?VOnv3X}~+CV{0iUrYX8{d)N|iL~@b%*-*F*J5OvOK{r{Ac42oKdwUR7Mw~RqVhlMv=~O=g zp!@?=wiRGXi7&xWLaVf~^rD3@A`ShbHsMfxQ;ney`9^MVJB1i;*#P?muHdnZGYN^P zM}le$U623s-8b@jB{K?b1bEQjPm)2=V^wqw))kK`%c9 zv6=zcJ(&e@g)8pxs7%hq917z!xmIuP`lA5o4fmD_Bltwrs>-fE1P)gEr7hWZ0>?|)txND~sO7jEj6Q`~*>OBE2r$hJ^*^GVAwxq>j zwqQ26`0d*F)n) zs5l&g2BNwCNs#`ic8`5)WB`rgwwes@V46Ifjc~l!wXwXU#86;7L|)km3AD(AhdFUR z-0eI>00vzLjsqOC<>f)G&H)0jeZgRXA0i)`+kj|N)^Bed0B!zA5UE#mTC(mxK;j=9 zMOB3gD=Qv2r)(oF{zLZ^>z7gP#v&t7=VEGgZeIC_dxH#DQ_u!G!I=-Z)nsW)4kM^5 z-XJ2EFNhKlD_FdX7<>qP-k%0sY1$}?-)_CftvT6a@DOG!?m@@O$Y5yH)H~y8!8%se z>6VCfI75`SS7IXt0EM0fzXlo=woO2|wxC=}W>CMJqYREx;eY0!Tw4hDEYKX;$T4_DxbfIu9h3+{tE9 zRL=sn`{D*f0AaQ@W9~kvKD9{f`<_C5WTO=rYh;dr+yl%_ImjYgXINku{22e-l}?*( za;|i!!<+=-FlHX5bb+0petEB0{jKcxFa}|BG1%HPqeqtdLCoyI>qVx4#Bd2|ETBRq{vkacH$zkSHh8!M`neF zuTqs1#}FRm-h!=fR3x=P4tNX%^jQ4hV|9o3P%&(%N~Qti_UD$iyQlJOu|j~b7(=0B zt9h!t#2Y9oS6>g%+7e{W5`iR$PL_38pj<;*(76#Q(Kf|XI%&4R0P1Yxj+IwjI$~7$ zj)xSOBm_rXFkhkjz)IbJ2eO-WvuyHYwQ4&kPp)q&eI=5s@5%+D8q^t+dC z5PbS_7tUGq0`QEHejOKS0aBBcE#oVj_Qus5;Ck=&HO`}1n`}T+z7#I_Q?&*b<|x~O z4tyNl@HPy;BcNW>WX0h1O`Oe$kLh{Yw%G9_ghhudh0+dbJ}PqKc_SGt8Okc-uF-KF z^6^(8jUpz#UUu%N5u$`tU|>YKUV#ZBmt46A2EC;tL8l)OAv0|h9l&qM20(-BoRp)v zj`|K>RJ{4i*XTBtIZ9e!5D*y^pXor$a4I>@Y%583ETs`rSye*$LO4-*vYN``$oj#7 zH52}6MN11zMch*~n*cs#|NOP^w89Lg^Dh0!*aaVZHO@C}q%)*MohMs?m@Q%4 z!IOQ$u>I@|^xSD8)O%G{V8etqvAwc~0=BN%Yn8#Ct(MN-M}}+rv|8z?6m;MgikG=w ziXIR*Y*UvfTFV8Y+Km!Z_%q~1&TV_|4=>}UQ};?Mxem7%>xiN7abRR7v?->8=6&Q7 z;75vZTJ4?Gr$pn_04}u&cT-(S^3-e5y{RB*XE#b5#_jT=&S~kUj_X+Mr$b)Y4VKiR zsKx_|z<>^o93)uj3vR)_o||;@bSaLXEjcUJ*CvoC#6Tek!v{GK)Hb2-r9_XnVA)6{ z+NVjUwRaKJ;0R6FddCKO$f}5aaVItaW3!pd*#1mR|8#=rj;+xuk##{6q*nwjZCn z;>B7D^UeH21GwwpHMSFyiWZ@nT?|nOH^)SSMwY)FOc%Nob^}>KAaX{mUgcm`Oi=?l z@(U4XfgJ_F2ba>cS|?}_42W+$ul)KSSWhp7+?@BmqQ%y3tkFl+O@bV*rrSqimlrN< z+2%q9&BWOS9zAf{28C_LU3nqAMQ+u6pve6+W$CdremEoG-(8*oxkYd+Cri z-YTLUgUM1D6(X$Sy%oTaQwmaVpe1f6tqYLw;ab}~u9BDHWOQAE87Gq$NKmpB9m^70 z;;o!%;r6w}*&qTpn{NW7$e_L;(SlysNnTg%EEzroC7q1h zLO%K#VwAA!LunQ}`6r8h0^Jr3z|FASDm{rRXW3P_ocjTkXgkJA)MIp^&*Z#668HK8 zx(U-^5E|!wjjJ4LAv_h5={VYva>PtmZ`*B4A_uyihv0 zcQZD-t%|GSP`h_lxFMqndn=4g+Qc{xaUjC2Izl#Surq5FKq}h8tw6`x!tv_TSIG@L zyh;|y>eH;?mpt2kfj0t3G$^3tehUbu2oTngldOis$fiY=^K$Vr1BKx~8-`6hdwV0_ ztdALbNeN)>vz&}VI7|5#=1$v$6oO^Us?`&$Y;eeqH@g7#M$0+zyiaE~b$nBav)BNj zV1J#AvC^~zY&poaZO|Wm4t73lU4P(0ofskrP*Z8fy1uIx5?PRglUz9fI?sH`1N@

    %eQA+^3L5#w8F#ZGB{fPxSmm0q>Q0kJyoBn1;sh=nj$0xkOs=EnC1SZ`QrS*N z>f6V@9h|zNYuN;;DQ0zfVp(-efSu&*1_KHQ71Cw@Z7!gY^XcLtU_t6##=?J=Y2cKJ zPz+iQbD48rDi4#ci(4N(gGzu9dxA#@X^n6tL1c~N{FzdatqKgF5hX(kVyVU!=$mVs zW@yjAXQ%xW$4ts&X)mu{7V35!N#skG1Qe(&lZLN*SPC+bZ|N<02X>SVnBT%tJeM!7FBFV+1f!p00=>ybRM6F@lxaisY^o_f~wkWVqYUQqpC#59=4)8uH za}fDp5YWVl&2h%J$$V^AO9Wg35?xl43(HzchI1otNR*Kmv^DD}Zx8CH9N|m{fhMfc zY$@2OnDQPfCl8J8g2PxLQWAz5`{3I%j`3FaXlmD#nTuCZvkM-fF7d5IsK4ZJn6 zFCCj;49@&vQjB&G@Dl_8GSG=FRU5T&R3luAXwB@Ck&-(^ipCLT1KtI_rnFRev_zbT zX}paRcUD}oB3$SeslW|1SM$ejQLU+%1(L|}qA#&`qbG4qw7-&8xAY;gH!c-X95rHs zNK))Egb7!=EtnE=miJi@pD z+Gg{faF<*-7_LQe<{lBS^ryuJeUPo;N9l2auaq>f((hnGkdsWbA-LrN|S ztXJSlWM$p%CdaNBeTEl~cN)l@|BLCRgOD$zAm^e4LZfK>o8BnU&GIMt2Q#MDAD0Xg%2kTbaiOQczfX#OpNB3N-* z^h=Mo)WT-v*Uk*mv$aDNfrP-o)}pHf$Oizz0m_i$h2)})Uy~u_s+Z131X7Xr99Cs!9XGEw%yTLp2CwA%LNsSct2ExI{)~a%4x8M1e4j zpl0~p0RBm1wFOC%O0!KtVQHWbDg-E$d|c!X8mbs#bD=5uRWl;85_ADg*g3qg8OLxi zUFo4`b3RC)#X@xkWD;ZfnkbZpgr9(CVnVPSd~80eF|*{SAL-%l6`HM12{p+$U?k(d zGzxfb<7svSwY0MqV{}odP*Lm-7wi2Pg93IiQ=S8NbFVv>wfwLTh!L}alL18I$}@`? zGl&Y=#SD3b$}rU^a_EKH9OwP9%n^!NsmWRfa@Ik6o&maqv#57xQao*4Xo(28h=K&@ zCwT6;aChA>dtmV{Ny6b)PMCWj$I=hhK^XASdg%#tdsQmipla8W9>@B+XfJfXd{8Y( z0M(>Kx~C*xeZ?J{2t7=Kx+B3PbC>15UdNzJ)yY_V)c$fEp@5SFv1FU&`O8sB=MzoB z7-TUt3-ma7x5?>^KE(%gM)KB0BaIOg7jC_Ete9L^!hlQshVK`h z=D>3mEm*>Ln`>^tppSw;SFT%|_6-P0p+#*%Blk@$fk~$hr8Gr1s}l@godWdWf`PNJ zI}!Fs>L3g(>H(S&yYx#|hds0atH%RZ_k>hvB#_-hRSy;4iwVpVT|fW@n@i6RXwNY? zMFd4G*$Jedklkz#X|ew>g^9c3V?q=%!zI)K9!@pXF{sa*WxUT*pLGTdjylZ{n3q+O zJ^`#gb$B-|2(3{bU9V_YM;2-juCP=~nE|3_4C)FNh!k+%)a%iu@KbXJ->kRET^7Qh2uU9-BK}NO%+vi>K;E^=XWg16(R~9VZA}4T%Y3 z<6xpnOIg~-c&ypw0mDX$9%Adh74JA{@lT;E8Y?K@bQ&Q5=J( zfPPtDEDM&=eP-{$hGN~1SsW@=oCCR@lM(YUeXqp*#!b)gxF9^5!NL*F5;$g@{benq zd4_z_s*=od(}?H|`8CE4LnZwn#dL?nv;=vinCI+!c9DrC_*YB}(wgJE48ofEg*U)@ zzNh@cWJf&6HPTHSvDQQdt&x(>6o|-Sh^qeSms$i#gR$_Whd82AOK#hXfJjmEyKEVu z7*Q~G@4>Zzx8k89XFdyfV8pP}*+I0wDvJ}FGI<|Z&XPAoU4F2XDN5X6XVG}Ui(*b~ z!9ESxnc9f;ikM>NoGF|qg4H2JeR(m84!jo{z$hl+ z2dIN5d|uqH82@nfFAwLSnEZ_oCz=MuLI_pNciIyFodW_DHIFkN7(Fl|8Z2zV8RTJw z%*uRjOOT>&wU^q}STkG4MFHRv*C8xa^_Zv9<-1$Lp_uib3`oJA2V<34m>l0zHYHp4 zQ2y`3lMV9J!GAU`b^-4g1Bz~k+)J{1dkmDSXs4Hd(M34l8L_l1_^r%TN8ga?-F(tC6ZU-v8 z6Zb0Me;dPlbKM|A5cW&8o40Lo0IHh$KO*OS>Y%$k`6{A3 z@r@#2EErqU?X8dHaY<^z%QhhE{58v&R{`q&{eOknBwwjQFptF72n^^bU;6sACg-mw z`KXq9!1zo>e6<1rfXhj#eLj_3W(jYS?bPcA`=Chla_1ownO_=Apv(&HCe@||dDT!U z6@ZlbMoVDm=pf@DiI8bQ%>h~$zuhj9=byPe=O6kkAm1lBe}5<7-N0Xq0J-f*CGR){ zRDm3!sRHBiER^SdJ88=0#t~IVB28c$=ls3Ot$^*lOa)S-lxdY;W`yV24v<{^h~!Dx zri=*lBna<9okfnS9z!HZsnup>57g?^bPT*%?7H zqxLogA40%H$KrB|MJwI_BCmuszz0YcqppwVNdYQr+J&IdWTgKC?OH(HC7|^kj*QA& zk0_N~o$e#v<;{jPHX{~#7-IV9mVp9YFlN7bEX3UyLc-s{%t_&ZhwD8x3Qm98p_ui@ zPAt=rkUOYf-CMO!4&H&l3*-Tp0U#dYZ-Mm5-@)Ba|NL0aaShcdNe1ew&BDdMTu^Ct z66^vlTmohJnB%RV{E9D78dek#+h-`E@SKE8;t_S$ejXOP|2VK%N6mLr;rxjPe_uSq<=p0D9UkFs_CQ& zsffy}W%~rC6MOSOs<_SR!w|$m98Emgd9fYT$4*87I*(=#MFe7G_`)&m)yppF^T38; zm@p%eDN`=zL!y7x%mi6?6SEyWIc)xorc0C6;*iY7!ZAp#jo`o*E6m z;%3up8U~1xUd;=NRfNG^3%n6WSe8kOk!1XN-| zlY66XL`I#+q8Hn$AD{vCmbD$$n;Nhc6R0=kFm`aj2Sha?agf6Snxk5kQP^Mr;QmQc zZ>NsLCQbvB3!`Dvq_@-wXo|wk%W_4F;MkI3V=gs=>4KDbeuix@az(3!Et=D4LZC9! zHW07@#c1Smjuvla%K_u*=lnp0fzz`ADHD2@{(uzKB@h-kb^>662pc^Mq}-KbO%m(T zF}|UK`vmZ}`=tQx7^4v??3*<$q6MRcd9pKlhBwXQRbN$#V9-KCU*Q@{dx8@Ruz)!U z8=oN!Bt-2>qz-ThIlNnaNUGGh_M-iLL>b!#c?kP%et!1g#*Z@$LpOT(63!;#;C@r3 z&R|?tAqxcgP4G6}@ry{6UA?0Um7GRZH|s7HVI`nsOKwi z^h7wVSPNcPJEMc|4|5aq%P9aqlOqQbZkZTG3A`zl1 z$dO1Qozp(b;w&kg9@uY_B4{tN0>;u6Fl+-VksK|T8}pS`UXC))2Ps!>z1qWfR}b|@ zqOj2Y1|qODifF{C<%SgCr7oT-mbxj6jUt?o5JQ?JKy%opaTZW}6x>t}h9MMy1c4hO zVa`P!Wm@#gJxzvMtw3I}Us{#(e-P}^i5me->x$Q?$S%+Z>t0Z2?szgPU_jBZWHly^ zZwqZsoVw#l^|l5eEwPP=)wM%+&8S-q8A42uj5Lr>TOT)goLwKIC8X25gVY%KN|pm? z%)~o!*QR1FSYuXej~k4)xUmF3iHJSj93UUG;b(Q%+nqo@6B+R@lp?>8%7D(e6|Mmc z2r&EC*g_|AoLxx(F&Yspj%YG8B1w`QOzay5RoCgM68pBaMfIf0u(EjDXuGJ(6O6b9 z{B_R2dsK=Lak=GcaaOk7oLdWg`FA#+v_H1F?79C!lAEFDC)>RHs!U<5;E`klMje#U z7zT!?w;OCw-orO>*BBLjh;A29Cyj0c*WWeG=BXdWppE#{$T(J+MVDyF9yV%`T1qhq zd66oTc+`mCDMLppLols^bgY@$1CFL*kq{B1%9Xt3WL6cr8Ijr&1dwt~EOPQjOnhSh z)DFn#Md~TLMd2(UE>X;$<^x!yl`E$FJfZ5)8XBjTtbPG~I-pfH-^!Fz}6vgcbD3J<)UB8!h1g3fs8aYt!4d$!+(oLdx zu6(uTsSF%Fp?f@TP9-) zLm@qf>Tnyx4q1j?FR*ClApWEbKcGsKT*MD^0!h-Qq&k4s7G!}F7$b~u%~vf$rRDsT zB@%$E$2wgWh+q}aoIPs<4PMB~&%o++2B?t--hK~?9(DjjMX|tO0qL^BS>nXhjl{f? zRkAMv{#sfPT`=XjjaW+0AFvrA6Z$QuGJ8YKzdgWK561@&%vpv^>8$mlA^bQ-&)8xi)yc(HW@XlahXwa+NG zU;*)|${)HGcah-1$A&z$>U%vi8M!TU$^&38?3XM(T#}y~gafrD2ri}qsub55&1q(U zK;OFAJ4Hblt8gm@D_CUfDVXc60rc#l(<3uPWDwxpw`L$8I;BUa;cBf%$gwlrXJtqh zN!_&zyBIyvoprm4cn(W9x8{5XRux%M*J@Q+SR`M?A_MtxyhK0NAZf`8pG#dd6|P?p zB6c(&#yZj(!+Ja~yhzRhg0!)?fFv27x*}#^wS9mjk6-lgzYP=I2fqnZdkVZ8%6 zn)zzXC*P9Bh^HdSp>1u3_;kL^b_4a&0gZ8&MMio>f@`4@_|1+M5vC$bz13rbu7ezz zTHHW09z?u*Z=!VML?(u(FZ4_biaF61@#5>wIBc)?_70Z}*01#btyXd$uhGRA?q0bw z%Z14DwVurdERSnDiC}~{oMgRJPmNJtN!z6_DDl+`R$g zP*F;rQjXY_pDW!M*Jzd6t0?HYGXUj~4pSWmE_9GUJW6y0-x)R{MqIP;Ks)yO3`k|# zqJHG7>kwcliM`th=WKkmIxq9!&|wa9e^$$pb$34F&2C;~uP^nF1jNsvF3%ATB+ zy`u;`r(Rn>@+;n3C+s!Vf$MHP!9aPt2BPv<=+14pUDogJn?4%$Hp5D=Tu4?RAe)qG z;0^sniM0Cx;S4)GmL~+O=nnN`}sd`6gdPmtL44K4bbRs4J zcyJ5g!tE5H5~N(Z25!)mO_d=T&@tDf{JiHaZCWl;eBL&-&?ty^lGtb(ep#n*QY2D&>$L0g-8c^|(71``O zCP`a8c%nWi$jdpI?e##NR12$H#;Vu6ul^)4dZ#d!24~%Zj0n+TlC}K>_+h!GyDMZ?~cd|f^ zurIkKDJVN31#AM7?INehuo$RR)Dj|}c$?@Ll2P}`Ix8uh@XNMFhJ&O?A5hcavQDI( zM1De3=TFj_Cd$rAbIi`LeK+f@FeNXN56}_IqWXLXG8nU3sY`;+n1-BW?k{GtDFXh2 z@u++HgU+fYV9PH-;UW?iszz%q1tWk2GP&yL$|(v1QUz+L*vQ8vm0X!8NIyK4w^Hox z%K<_vOxs^I$v!ozTg26Muns&Ju!VT~CYBYTwZD?1K`=9*^Pa|Oax(Mt2?WxE<+P9n zk>u6_uNaze#mO~vojsPaf1tnm3t(YRupdajM=!NJ2agt5qdL2Wt|p96&>y9^Wui*G zUdKC`YYsycfGEalLrdZo(xcLRj*yTn7!}hlLh5@hYnm{K5#ywAAk1%V%=@=Um9Cf2 zm$&hlSjzF|D2Vht=;m;a&F@;3aY+G)_W@@zkB6_2 zcd7`As1ghDcC#=;1RrS4z~cy~s#3+AR>9)*wMuBaq^4HUc@ZXy4M%*XBV62M zlU3R>M_Ul?jFOr@NyUhpNGXHLZNC%o5m~k|r>N6U_cQ}&o4`}T+3K;xGGdz43UZxw zgrTnZao~VD5Q4BfR&p?qDLDmqik6r35My^4)jzH^>!`AqupKLr%)b&Xhq2hXH(Ii4X?JIGi${i#gQ{izoYrhgq9mh`Q zlo3Ggs_jr^`iwp=21)PxhTDFLyUC;3B6^m$4lKqvDiq}~gE|5^8jf8X@81qBD^xv{ zhZl4e{lX)I|3t#^t;u=h)YM|jnI!AF<%1%!0Bj9Hy=pI_JJ0a-p6mJNeIa7hVO@t$ zE5Xo((-O4y7@5{>C5Peb1%TMc94kGfOaoYnv|BoK^TQWmZ%pxvv%-qS+Di%}PLX)w zwb)Uia^O5$RTh+ z!^mtp|NM^!azG)WC=u=X?h~%nfk3DA6(e1OKy#nKwX2Q zei&jjn-5uVNwhnAR_|aWGZsS~qHRnf1}y0D%Y4HrV&En8=p<{kzhWU0*m!wP1|?;w zydC^?Hq90G<}3wCXCYI;%T&bRZWAaRFog(@W7XZH#1`T#4bXocoRUme6*WRcTA$l) zim^v2K#>bEP4DW?M%Kz2iXyE5$7UDnJYpUPyA1;?#F>Mrxf^NFUPYG8)$*4-}n!orf)E@Z8`3^yKr|gH*IA#_& z-i^G%(TYxL9|9kctTouwIIK5df!?)0jqz@ha9`P$&{v zD^A0M5v=YUn?{!g9}h@j7&>7NBq*uS7K(?XcmhMT$w4!!w95~@55qCSDJlB~5;!Rfl}sR2%&12?5DRzR7zhkd$Z~1rNv>RTGNP$W6sD(x2rVRP5H*Cldn(Ed zAmUJl!-RwnZ4vDek{6&$*dbRLYS8Htt?6K-0lod+S0YH`9e)EMFhHGx2hd3nQ#!&v z3`7Uud|i8}#MZC~z+MiVp3n15PHTUhJbdnw3icyIY_jSd<7J4*g6hJmjg* zsp{1#FaV2aM!6Ln&LHT*Br8oyb>E3a7OJ$hFIH);dn>n+i~;co@WnOWjHqUc$QTsB zc`q^?FboXYOaiu;)QgM~PvoZG+LINl2)?J=tqV}X8i)3RGnk|p10Jro@{$D$NsVsj zqQ25niBt9>U2)_xdx=VJDYPsV`YL8m$vO=qCZ4#lX_VPj(rl8RlyThBPz(epie8{7 z1@Yno=*{$?)W++M5R~FuqB7fEyK?z6DHvHu%6GJp?zS?cjLf89hbH2=V@}S_R&G~y zJE5{A(HRKF>UjiGVFQ2BIxxpKwz$%==@*LuaBtO6E@jQni6s`&H5#Jqz7wNzRLGw< zE-2tudghzvYg5T9m@_%JyKutu?iyzcG$xd7%+fa%D8ksbOP(6j_49#TqY*lRn>KQB zq?pq-cp%cz69VOpPZ|MONihJ>mjUWvh^(lQLBnaefK(i;SOwjW2Owl()WY*&_yRu1 zt71#ffgV{=L@kd6S`+%KwdaU1R5$!Cr$eD8SpM6KPBXHpAK7uAFWnWiI(&~L1Flqw zejVf!qE;fzH}p#l3Rw6{ZraWPZ3kO_`$B39R}%iPW5pL={HA0P-i8fCS%n!|!aT## z7$XPG6=;!Ynuv-i{|>Ekh{(H~Xf;F?nC=9P{d5Y6VG(jiQYqucDuR#ep{}u=K~Y)% zGol)BSQog4-XpjyAh*4uFY0`O?3QiJ#t=!_g{e^Y`2L<|swgc^!`E})2WF}{YZFg7 z#1)Nut_m^@9X4V>>H&)pSw>>J{;|dj>nAzR#cjF~->VM<_TRl!cduQ#4V9I(EKdV& z>Z(o>q1nTW1!vy;DSHOQf-2v%1D<%R1&W?Z!7Je15{Fz}77&6$8u4hbgo~{Vq1BX> z3O%OKOM0@uLM&TARPXI`Pg6riYhDw@kl3q}4U2rK$r_n5VOgf6QXZiAMYb1N6GEt_ z{(N62A*N{3jDo?Hp3IRxH3J3|0Ms+dOU6?_1U#mXEC~ka$beFU;&IriTYjaSOh&8S z-(&z-M1z^7add{H8d>M>5FkF2uzM`113a!V^^t~7f^!iD&n%~y8vFXx7S7trEB(<2 zUpELh9Oab2Z}q^4g3mtv_(?0uTnJmm!qBq?Q2NU<$Vc@p`GbUUWK;fW{ScnN3HQ?( z1l?m19x_8sn4wiOCRY7wzv6&I0JcD037 zw4&olgp@Wp**<8`(Bn-nrXEpHTBM>Q@UKSQq)BC!4nxK4Du(9;Hpru&Qr-)c35Ij( zP$E~C*%OceV6UcvfQ*wCoX^gDNXT+A=Vf^9_=$rANc=^M18g7I9GhTHa4C7=9gc=~bN#3D#aICQy$ zc$7o{bGQ`cBJdp`vha(uM>$ zpaBA`S;DwZFslSldg~N*yy*1-_m9IZyswlq(M%!L^90$ABq;&RnG;2CqbQ89g zly26Mj$fN5Ws0APlrz)-qsuBQu+^p_XdR`9Du>!(Ik{%7$aXDGPTZR_#9Ti@&68bQm?lxBlEQn_^nyYgT^JfMXxoAW#%#mAVpf$QAi$>8G$*dcm zjS&qT(d5EQ&q@}7quVx%k5ej7Z*P!hyhq}x^-e!yH|YLz{ZkJQK?~J`sqj$#8u

      e3K^O|iE3Ks1Lk!py;jKQI$&V#H#QE&h|>YebVKSR zMZITH;HOOWy-ETr_bJfe6aMhGOH>(z46>tP-@Wc=W<*lCwe}K_gm-V}kc)4VwA#_Y zG^Y}xtUG@Mm5jSI+-8d^xsEk5hFO@)vqC-9MZYThf!NBWE!!3HYYJH$JIMVdLX4h8 z04!uh?IA?Y3NT=&0p0Qo9LI}p!- zHm5b=1GB{JW;|wz9AIm(?u0&g0w|ytu929(coXon0aR2oQ%IPJ4-Bu8PH23383U7$ zL&!=A`P&(-pWY4aV;FO0h!$E0`9LM!gHXCA-mc}ruF&P`(8s(g3h!;Hp6{&_KA*ER za-!G9#d1Bf$A;TzaX=Hru{aTmmgQnrC8BDOqw!q0mIOQ~JZ;3Hh}gK6a;Q^}0$Qt> z3L2=eqdM5s;n=SSNTo$Ba7s277s5#wdE6;ecr4W98Uxi(MGlSSi(Hv2B9f|pF*kQZ zB;QgmErvv1yqG|H_9R5fw%ZTk=xRar7LAor3dqY^OXS<%&KPicLriYOcOH-hNOkDKy3vqA4m~H z6elBCAR`_$=2NtEqF!F|brgz5DTDlQ))x=RF!os?eb-7{p6pj|8!)LJ)X~?{#*->mgWsxAHR3LNsqSmcBvQ8* zg92t1Fac~73K346p^cpcGxFuQ0;N;P z19?n|IX=2Df}8kF8&GxAQm9qOo3DKN>$0U&cRB0WSTsl1u)S1LuaWNRqLS2A%64ug zbUl{u1GqWLF<=dFi&z5sboX6JTK9roD_nH&(AgJd!bE=Dg-JOgoQSDlM7H3GUxV+u zD2uhobh)1=y!1hK>+xBd+kG~+i(uheRw~zhe8^jV@(>YMH7zkMG85jVu8Ls5Nu1X1 zga%BIe-G{Q=8?W$YW-E|HHy2>a^}kbX5?ANC?1F(y%p5u0?1L+tgWuCsb}EjgaILCZjk9QMSo_?`Q-m1 zYS~~1LQJoFid9wuiCS_Yj6}!zU)`lByfbe3emXBU5O)7F-`Y~D5KoXV2CLw9TVhGf zOHq*_+>}%quYmZRl@h#TxI2>W4KZI~$y|peZH=U+!Ita~laiuWjCH`ZZh^ZN&DyjV zyQc()N=VJ|efA~EwQXMLoDVw}_{9Xou=MVY?z#FL8~kO^+9A-=h`ZgLcc~M2*sg^@ zc<2vQss_(^BG~x4A5GcCT)y1N0XRpu)yNUHr$Q!@p~B1jd=ws_AI)Ux@FyeeV)D_6 zO$@LD_yReEG$Fw5AiJ8se~8G0B|O|l1Rvk6%KXH8*TAOy3~#%k5_pVaVhQ$zPoh-h zm9zqgCnT&QLBgJiHB=mU;$$A*-Q*GGQ&n6UaWV>A8CGlrF+K?M!Ygy@uys~kh|dXO zl?U^m&u?&gd7d=anis~_KhcOK24)?bk{%IChG|xoA3>pbV|QkUc4+3T4}mAVVABqb zyW@Jp` zP;tUqiQU7l9%=}pTewSs%Zr4?la|_^A>f3qx4x+c

      KXWL}6+SZ2+$wDCAuuC~;1 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දl>ESvWP%U8@wBh>8Ms(PuIqTrlska%871-0M@W+u3`X~CKBdXAA&*vgAT<1+Pek|^- zAGUzlT^kO`L?vf6uP>Ze6wO(RW~{z_X~f3L-Mk$47;xyxA!k^v9AXU~d%xNxTn1Zw z$wYd3Opl{d4irsO-TLPs2-a1`v= znpz(4>-qSdVoOJjw5o4pyhx#uKu8zvq1XIac6VRg?qie}HA-c)9(>((!%Z1U+;yov z$pnd6yLTFt?wwyM9R>~C=%XFA#kk5@6Shjk;r&#>4P2H;+7Y{V8%}P*b~5X+wBIXC z^F+{In~?H1Zl3gIbBH!7AICD%<{yUFF$Qe#!dY{|hLcOOZcHT5OMXpGO;dl!mPA_| z;q(y}LUQ9SqI7ulZ1s-R3sy}wUIAP_0HqUGF!%yEz(bVAXniMc&eQ13#Ulu0dUZ$6 z9K}j9snCVwUBW_P1aLD;c8kMki)f2i)KG#D4-hoHGEyof9AqN4;we#fz$RyC4W z^Vs}Y+1dB92jV5{rn6L?+cPRAWs4FM_Ku&W=W4*-$sxf)+d0&JsgA=2%MPa-`krks z)as~!ObRi%fk?+Ae&h!5X!h9f`~ejtsS;|=-L*av0T18^Y}_IxJbIL-4W7|Ma)W~4EvxBfyYtd4vwSgwnwwz! zNwopUH8&5oIJVCA7nPcnAw*hroT8WvFTVuQH2X=oCYE`#YCUS4l@RGyObEQnZLI+y zJJ_81M&i-pDRq40y-_>}Il)NdbSgk)I_S^$BaOOI22kuYn&o3{z2!k#A9aUSJFr1X zAEW_WM88%JYo)FzCeDCIQKUgFDYVGmCo+hyG5IgZ`6|H<1a4~>0Waj@5kM9K1KcYj z-k0>ISwvZOzIwcbhZ4iaZ7xBgo~Zb_QD-NRQBfl^3B}3CRHlSvTdaz<6q~%=ebP{& zaDwoPVuAJM3=jcnfRV093JGSEAc~$@wrJ(P9i>(7BR1Po#TETFhQ zP|_I_9W;~#2I1+F?z3Th2yBlIjsuY$RF3j0cA0GEu!Ve}G;_X?Ws4k$5S%|UV`e+o zT^(KG-iSk9pa?ZKzrw9RG_HYrGhRb$6Qxm$)Ey;_ZiCGqMvps@uU2CFsQwm9di#|F5J=-s4u_}4rY7DToJDRLCy;rB_6=p&4A3N%B8|q!>P?B zQ`x`}bilPVhfWImfmL4SCVzqcG$CC;ul6&T3Y*QG3KjCUtl6PuGq&8Mcz3qOo;(#W zQ~(1Y-18a`sRM(>o-k$ZBppZ%+4y-1mdtDI5oLv6Hlby`djJ9{V}Uo3(L$W+lSqp+ zR64h!eM_5pH<5|}+Ny{|002iOu}A;{2^pD96C)VxhGBy#`J6*?5Gk=}@YZC+gmRWr z;LO;HnsrSN7KTx#O{PZfgt2shCfeECH>e252eTVQjS-#4CgV~0#e_rkjJ)}tnhfbo zNMC4Nhyfr7Cc2IUK2nyMv`Wc|xM4OIP&6^Fi#gQv{zW4snU4o3)7xiT9*~t@CJ3jN zv2sp*9I8hQ6jyEXdf&Ez5CCN&h#uOtoA6M(Y%li?uctZTLip-8PxYvZv{rGN&+h5~ zNzH$TNCM*Lp5Cw^FrXtZYDNxwlxQ`=Q}>sqmMl@Q4@kU=A~ zSVrppjZL5=fqF<&TH^*b=5moGP)nkqX7{=bn_kX_Ft=39R4Vqs0WDz(SCWt;rOji4 zOgADHR58S@M5zOZ%R?kg%O-tHnCOp_gvS)nR13$;OWHvDb!@{qrnwQEJ_!7@{}PX3 zgxk7&L4kw3?dVg&8hyasj=R-gI+?MPA>7FS+|3hgBq%-dSZXQ`(Dt2qw+!?}q@jV# zR!A9};Ky)_Mo5KU4G2P7RRtlvL1o|b0WxcAA>b$)a8W!nC){hHY`m+we?Ax!pqRsw zobO+T$+ZgH+EzXsg0ofqkmv|C|5QVuZZMe2)44d!WTSAw8TVqJC4@-y6CY?192{Oi zDM`E=Il*bCzzh}XqYPA;ly)cCHw_$NC0mpEN&-7)wWv5@(wGilA9%5S(Gi0JfnHPw z2&I(%+;sfI%^wpuIPX)y+>XG`6`;r4O@_=}gjP<4X&Ev<>*tgyTl<29Xbl({QK>u` z&#Z8pfl`ICT>Em7G5;&e@m{%TaPaa#Z%OR!S_{NBRNe@5lIIx$Q(}Q=h|K86-dErr zfUWREFZ0s#j!=fLNHtDQFp)XBNZm&X-%I=9#h=zmOi=! zRkDk6^DrKv8GLNKWWa}I2KpXcx(0xyFrG2bPLZV~01+4~bTO$?TL|Uz=R;bgc+=t_ z&xM2}!4?R>22UISu8Wq~E}eSOy-1jbfOuSH;2?{tadWo{ zIbLn=xGXlLTTXs-yDYgxxL>(4Se?Z*usiaE3yNvU8S_;n1ZLqRJZqCMipmu^`9(;d zVf242?(wPQ(g>tW5MjAQCz<7f*;_5eWDnph5PvgI-BKN)OsfEwlTNC0lYuyk-JYtr z6a{L!G2)wDPFbSD923MH;aF~I%f66HM&w;$G8|cC2Yv#FhskrysXVrlVV1CM*1a@|#MlEchNd!M)}NA{fP4mF%-kp_a*rnNr1-7YzuGA-Jnm zy&Rp`l8`(hWAY^ef+3nkJQP-s6IblMjwG5BV}>rmznSl?gcBhb2bi9>_2QzC0PSH& zN&AikmlB8KY$k2Yy>bSW3Fcfx&Ro7rWqb!%Xv#b^c`&gs0K?Sm+z0v%*?XiO2pI#w zzVj6}+6&=wyOBCjUMyB%8=M*DGecX1;E04{w?Q zkS$R+?jWg~UK~y~cGByKWsN>2{b2{4)^sC5@#qpL==oB!EB}|yjX94ZsdZ2c)Z|&0 znG+ZJpk7%35in(Y=3cW~s77{SOby_srDD14Xaeu`hkBE`>v(8GU@VkWM>5K@jgu}W z=mwrG$koC)NJ+f3wr2sN*W%V@{2TIGp>4zgfd)}ZjWB3Ol)S(~RR~q{-jBo~5vWxJ z--ob(=h8=UnSOpusS_HI6uVU})=;HCP8bscFY{(o<`;(7+2H#BPTF@#Fl8Viy9pj1 zwRwmYfPMx=vO~qombxIf4bz7wuC{PgM!c3*C;nf##(i6lWfKER=D22eSo{t%fc zZjb>To+zdcP*C2>IK`X2*bW&Gb0%?niXe_dZy^ggS~tG&=WL9^UHpUjVf>c)qxJ#orl;n1Cm0LKrccM z6{xg8B)oQNt3h-elL>E_d~cDQfRCf#7YiX>B7~3)*&(;-N^0Y<_yY=4H_bGn%{Elq zILsz%G&20uF(ZstCGU~L63+K&;y;MI5UTED!l=n^_?H*^wjF7rfb$yt7qm% zPfz!=r0%QHB{q)q7T#eev7{zZgKK^6SSj64aI31Yz9p&S>`$r)h0!R`($>6XMre>N z3EfR}0BQQA3cRPN*pEzz^QI}xdR){fVdhTgn)=(my5$xHt#T)q=l!v*vYDIwA~?pN zG#Zateab4Xi&9^qqA*a0i91>;nU$EZn$Y_WM>N*rOv00)TIl3LS~3a<3f{o^Qn zsR`l{%_FoxaF&cn9puva{3Q*pj&TlU7eFQo2cSG$U+`nY`jrdWGSa+PtYvQ0YBL&Y zM1%V6tA!{&nCV+D4;uFli`(F`dVE@i14EZRma9~ANEj=|Z!-{zi~=PwgPqV!)nPa0 zvS{G#eF%>nHvZ5!F(b#MIXxJCLPob_#8Su?y5!^>2Mj{9XR`om&I9;((T$Zz^Y#jw zvZ~Va)MDtD=$C$}@V05db(3iKb1W_l&|jP84lDC{M-khd(3$Si)i|h$Pf_u<9V|8b zGN;Lj=bF)kQ#F)E^w1!<=qP~e?C7G$VrFu({a7XFMndMq%d){u`iGMQlg@4gG05%0 zZPd~1Y%)An)uP@K7iK@2Hl3uz*=~J_#7r}e8}qhs1EzV7K}=GmnHh&I4|q0t{P*rG zjPv`upZniLd9FL>%as*y8BpQ+Pq1?KJMzB!t9Mzx%gvbL+!Hq2!zLUJglARJ5^Bdm z3(plV<3M0@|AEKhspzY>>C zX5yQ?T9<)0qVB$Gzoa^{ikK|7nTu9_jBd)vLrae2a;4FU=HdiT)m37dY>Cd`15C92 z*0P!VbmRYS{l=ndx_*JzW$fyqztV7tVv{Pe1g<)sb8G$L>C+aX@e-qkT20TU%5A6s zp_P!mVazfRtV5?PYrw$(Byu4az>qNSz>t@)_d3&bQ`&Fzll8JJlwM+CgIJ0Rr=958 zC8f9raI5%SR8eFqTRq|E&aULmPcaRYQPF5A?h}5U+NIOT4!`6ua0@D1O@bl)VK-F` z>-jsO^s#PuvyfEOYGFAb&;Vd5D9BXs!;GmPH&`q^@>A8F z1;gYROTQMZ4B7H+ty-26P7+Q;O1>MQEkB9&8&AVn zqKEemr!8L7JUDvGi#?3Gp~x4PiuW)<4eBksj1;!-Ifs7)=wm}4pAv3WzXCOA;tQTm zqO}&m>dG}|VkzRk7)Qa_^)v55&e1K%Q|$j#T#6f0vw&obj0;&DA)1Rjma)-B29M%L z!!aC)VN$DHjjTU}x<9%$0Etr)f)mF7ARSvShB^96(#9Z@Aw2up=t2Ho(8g@aQXC*T zhP2^oxA)0#!OfJ?G0AZ?jTWmq-7{YXIk+};V<4*^F?kpF9Zk8`L6Yq!PNa^k@eUe0 z70BwLk4uD$#&e=)iLHK$P9}eUaQ@na1!B+*sTYFmIDxC@JTvQXqQ+P^BeMzaB1Ky0 zao$O#g(Hr(Lf_T%T2rMQ@yI&2B1zd0rYfB%YYXX7#4A!+3quhU$`^YTB>k9h9p||6BK+ZoD4Sj8VNg zD#j)!-sSc9@P2(uwy8@Z<|)cd8!$jHfv-Ti3gnNGcP}5dj4TbqP}v@aYgC4Z26I8v zw3V1pX`S-dP#l(|MWp?%N%j&qNxf35*rr0~-(Gb7?VC0V?QZ+8-M~W4Lc=(>KU3CthY~!C^qf{oXM_r;S(TgY3EaDP!k7n zw6$neLQ?IJ{{(3>$tX1;M!<9|kX+RK3!+M?Ek5?<_CPyDpZS8Si#j&ti8G3R_bd_> zn!@@=_zc9!oe{lC+dlcNCrd*n$PTi60sg6W@u^~! zs3i=DaUgn@?9(U@3SCa`{1)xExPVYrbvS+NUZTXlp;vJp*h{(hPP5YpIlXVR81aVJ zDOG)lq>nIpXj{g$8fd+0uW^}8f|+^Im@de(?){$WZHHHqe_wLmf^-C096Ia<{lFIKy*mb0)mhiL2@0OoXkRLpf64j)6Gv*vJV~31m;cB60#{ zY4SlkMeU}&7LkEpT%pE`ttizephw|$rQWg-=qT1T%hbK$;WF&f4U_SN93&*4;5; zVP_#UT$GphJQ6K_)E711iQBKtfwr~SiWhof8<8YH#_0+BL@i0s$|OAEyF8yyA#tLJ zD%)mc#xJ0#h4F8C`=V720?cL*hen=iE^COfg_vQvTU=D$=6B23Z<7QtNk$Gpu4V|L zP;RfzaxMg?BfdV^;Q6g+p=463;2N$>bC^$I0UxxDoIcfpvVd?p(Ji|2Lm8fZwFogg z@p`Eq;^H&4K&zQ-B9z_wfsIiyGUeWMNEis9DuWjt5FX)9pw$W>8p7 zJ8yRo-sr=AEN#xiNZGjS!g@v|!S@z$M5=gVCMglV*(%9M@>fz0Egl+_m7*j=uvg_m z?U-{{B)ZaR1Fm!!`r#t2yhK#Y6 zK{{FcAPnTEdR8$299H;v)WdYA0a~N0F*6(+UFyN-s8n0ia>m2<7hy)5C>-hP=d#U) z3C+44-JfjDDdxR-8xfGaR9@pcFem*7OZcg>YY)Ip1}l2{g|Uc3EB&`y5vX!zr^3=; zJJ7T3dwN4UYl1md;v3M)I+QN1Ru+NGcrL$Jh^JNjX%OGCw4lw=xYt6 zo2c#%<-RRg5+x}x)#M$lK}dwu7?&iQ1R^avu28PCk%Zw%e@pXF! zRF5l;!GdwLAdwf@pN`QNh(RSfFp`7mDaMt1!!{nYZ^_bC6#XaPc)>}eg;`f?w$SbH0W<0F?4f0>^3aXxv<|W}paq#+GDlb)R>^Tt{hnK(Catum zr-ek57UzDiL1&h4L%!oXM4XO5rKb)M0G+-pA)gm&De;>SY0$)JvN&GE6UQplK~>bs zgEFWH_{70Ek>}BXzm)DKJ*B70{$bfOmQ{CrZyI^%`;*elmuw-GMln7{JI;mifu@k1 zMBcqb{+E%Qns~WJ1}P%aai&^H{L5gls(MhSp>B4NB)M^<@8H?1#0myjxMrYl75Wdv znul&nP&_R1q3So6B83-y&CX*>%RrTBolBCWj=DM-)B)42&S2T3)>*CuXpv3ZOi68z z??2f5i<{0*up-s6i9qs(XGE-iiVA_@D5{hDwQC4}-}r;dqEvDh%-@=6%GC0{_kPol zzHwRzz4RA5flN@bfs0dAyp{r(n2%&O3QNwTnL<`UbX&_5BfVqE@QvvR63<659fR? zgbFok0y5)Aa=OK${-Ie7Bs+MmZc9Hh8+M}{=Q5pjBx@xY)Z2Y)%gg{>m2QkaBumVa z(=ji7iQKkKMql?T0rHgPH=~zQG(%$K$;T#Xu+yY;kkI;2a{Y*2RdmGoOpzqxHl!*T zpmG&hZc5*e#7^*Yf4Ial!H*bk85J*=aq_j>e#q(BME{e3ni0e!D&ypi8i$fvkSNJiLYCu z3}ckM0?l9k&d4&=PWH>)Wjm513trO30>wrJ9cdQXi=?AS;V<6EU{!6}{)k;+u`x7) z1Z)|EW2FR{_}lZKO!1~B?F>xxNRrmbsUmQb1C_E$?`M&WQ{Ossq7A_2JL|CT~s?1B8)t}tf^M{Cy$dn7G*}?cG4e~ zTtlo*_8<%>{r-+4P73uF6CUSIq*2a0o$D|E4TbF3NLwBZ#_W^j3fG79Ng*At2qpL9 z_V3VF-eKee|BP$G^l&pHb8~rkQMgIqv9Y*dcpr<4Oy$W4Jb&C*)jVM~_?*rIfYfvT z%m|TZ8V?f~`)_6m@%&O=Zs1f6_r25%zB!#Z=etv<; z$pMV%>}TF59(ci9fy{+HR-rhiHw#X1$Y6ySYY5E9WJKD50BP5Gf-BxQ;bFqY83EPN z&1(~S$GQPcxaC__0vh#wXS6XaOafGUtjVc>pk#%$x9)Uaq(5?p>K5_T9^;)Lb*6p2U^RdUA`VgGiWg z19`d?o0xT!8`zhLV<=5V!(cQZ*6{MW!3XWZ;+pB?g(Der_`T#F-Ct$i7;-oHeg2CT zCW8C9_lZ!6(DsBVYR_qsJ-I!FIO0EF_*=t|ouLINPpM;81|d?|<=K-)wr4ShR-YRS z-hebjzD#{wW|H_O9TkKv&u7_(cq{6k2bm4vp5<5itAN$=QM$0txtsXCut8npxd#anS~4CkCa?D%0fW4Fi`Y0sV!#{~FB-z4(ua-L&AEZ{r$A*UMv4pK%ov`5O6Rx5_$EVcVMdAX zH1mdYg063qEfFnbv)xFBeonq^ZVSQYX{M~nU=c>x4z~~{AW&hlTpxWtf#+|UFAX`w zoO^c624a!@SJRV%AD>^8$<-=oo_wacu)J8!`+)Fk5N$~+hF-&Lv2M3um(a}eHrQs!!SJYHG^l#;(rO4A7^6paG2sRxkkV-q`h)yjfwS}}%F z{i&pI$eV+Qz-f1HYB3mmS;(@UX68c75{u28V;*bwqHFBd>9^kaerK|2Z54G#YM})s zojlROj}Ye>RlYVIJp7aKFQeRn**EGl34JHJ6yjJVmKl>vTVrSFknBqLf2BCoDDo$| z)YTzirp0*7__e=|@0pjU3JTqpYsgVEjsDCXXxM7v@5MD;dw%gcq8lKV7$|4sU>DPHUD0o2^L|vp|woe-GOm zoP5fa$ysFr{osV~a3^!^Cx%~-xd!-{1fygF0j=~MN zLvHB$Mia2sjLtW#Em+;SBuW*b!`lML=_;hFPC23D=~cvB8$Dd6ThVr0q1==t9PRpN zj4iW+cyVX+q|9tcZ-F$kd`8-&dB&7`Gd8eBiQ05qba8>sZVTy@F!E96Tp`Tio-`Cs znMSuTEBr1t*N)H_PN95xr9v>*Xh>Jz#Q(wQ--XETY`^CD6s6hhxX&pJ()AB3j^`=l zKru;1G0D^UG)ED+wI#S3i0AgKmgUhpWbXw^!%56UyNgWHb~;Rk$8l^VJJMrX{$xE{ zmg8o?6I>!F8%Pb-hb#lB&~q50n6^q~mTbAHvy=q8CBPi1GHJ^fOvXLRNQ1NbQ2TsS{=tH4}F8;6f+HNb&Ih{I;#0hy{(}TQp;4Lbc$m z=Bg1uDlw$W!%&8-7H~mp4in7k(lr*hY9ea!uGq`BMW^gP2dHc;uvytONQvuFks8P0 z#6}q(X3D15+pp94ZlZuP%yBM57F55H1|{Ii8KU=}M?%}mohSkjmI^$EN6H4djMKNNrocA*pGgzOIY;o;5oWU0vzWEf)7Z!U1Zw13wZha*uaEcw(O zq;a)+$9B3yTt;eL!8_*8gKd9ELsxe_?&>jq`dzz{{5;{z+0;9kO~n|;J57(c|Ggg+ zd);ob4=#@UC>{VsqF%io#VQ)o;b!}Isu1+?0QW!oW_vj=G0;$hkgldv>AiX z$>KOTVZF>=)6oT(8yCxZt!QI;;mE}b$L&bH*2;m9G0wR*u)1{#+PM@t&AF_9{9z&O zHm3lw3!XE{%k<}hN>tx^gRn0;yPMQSMlixAQHk*Cy@1=AnN*4pmJ$HVKMxeBOxdJl zRZQhDt8Rho)8G{L zRse+-u4Ld6&&+%QDQko=&u-y`j0->g8>*-T{RZ^kHyW)Bnb7QlytIVp)OWi_+`(jn zI_2vqFe0}Uf9oV6ybx|@Et%DuG15;{tIJ&|4hl{nzsYo-7e1bC9=FjvOAyzlXziel z3t5eWiCM8-zNQ;j(TIk;ZZSmv>(8&cXqK1lGd(s;$Q$b&`KQKdq!8)r!gH<}pUUsdhaJEc_;a+OnfnY<#xyEL;PA@x8 zh=(*eIyl*S#&n!_vJoCy%6J4_Qrq)cH{R;K8hSb?(O%P7=II8pZtN< z^JDn3BDa4!;(ZGg`Pa4dfes1NRP?eg1k0;ki((03nuuSAvqNSn_}0612oHm{(U6D% z8`H^-?Kf7QAG|)7BBx{6<)I~pkGp>F#2`yP-nbNa`-vv zcEDNFZCUHj?y#RHyIpP=nZ5t2WX2^@5_7=dEvh@y-xWgy?n5K=K-l(+>#1KYm)ejB zmj!eTVTN^8k`*0zRoexsaR{_*k4sZu6N-n8ocHtiOi;wF-^!`<*J7KCSX>a$=G3+nBCQ71^L`_O=KXS? zg|VjOR3tfah_5kLv-e~?HKbFuG*9O3V3pW`_hS!-9ow^lHSQUzL750Gm6^T~#xG4W zn10S<@K#oyj;qis4Nauz*W_9z+&ZB4RMPpjf6uEz6*+Zgc`E=btkIygeh%eP8W3 zk)|!?YChKLs!|+HbV3F2i~ag_Q4M>WwdIQW-I*CbuB(yDZ=XU2H3xwG@_ZR*&d~3l z8iPDPJ#sWfi{N}e6>y&fwXWMnv5YE63+hUfQu6evo_pc(D%DQKp(BQJ%3m3l`&6%nq(H9g%qUJuFq`eM-8oK3I6f zSW3u7oLY5>5CTfH?Wi+3cZ#HdIF>%L-s=qw0U^$j8Z}RnGKyT|)7;9LUkWH`YW^U6 zW=+dj6u+vzwcQx?B2gPO#;MSe@s@r$Um*52@RsQ7*S~=+Simw97&4FpiF1)aMU)yL z4*}=SOt}<8ix{u6D5FVsJ#6f~8X2Y)yWF~X!;~i!sjzsn$Wp{%@=;b@3&nJnfG?Bj2 zcANa1S?WVCL8AsH?yByLLkxt#XT^B+sw8ldSdR!iN@7s9Wl~^iz@U+JLc{vQYdw?O z>%go7u15ZtYXk*Hpl&2mr`wdJv8UlF9_**o_c&0jWB)sc?>wKaai_+)( z_B#xtqMgJD0<8&vu^+&0!92InI$kke>mJ{3FG~m;!n8-vU zGD~J%XE7ZPj4(5E@wQ(x3LR~!WTUE9htcxVP;*S{$)qC5Gz_NN%LN~-v3<Xh1%louWQjzM zS#yC%5_{ebdD9wsT3=a4qE;xt&E2%AIU4go|UG*2LNf%X5rtn5fBvM9`dgACmXX4hyjca~TETniAnVHsqQ(m3X7$SPKzmZSQn` zUV24>v-2}zm}0oO6mPRn6Oy*vR~(8{2k7Iy8$&+nR%@!CD!NYzt979)A6{PZg~DGL zh{=P_V9sx!FFcYD_=Dk50H10(HY5@}gpWMAA||knUC*VM?rphH$%&Z4%)=}O3QlRT zLb?dx+25DA`U&O(mx5}!7fz6VHIqyq^gfB&8)$r@s<-EJGWq9b7|y$jW7Kp{&SQj z(**u}M19xrjZ9SZ84@JlUzt{@+&wxV{Fu_meURA0VRRJ`6^CVD#+lD3j{}1D-GEN* zzVNGYoQZlprO3OS%gp^dn)SwH`5? zux^9C@Fl%X+@>@2c^Y9Og3;tF0^r7%vkjH2Qlk=4GM^h(`o;7+ZiWyH7a>;Mv4YCQ z-~M<5ta#HAV8fLz2aSPwC0(a0F8#izcOG;^iMC8kSt;<8r6U}Y0We=OcDiLs^qHX- zDo;f*`?Yd|l|RV66B9Yp(zX|Ea~<~|E7FaIEKu|x=?RLH9HBEKJ38Ir>C6w!IOeiV z%;T9qFWJGEq(Y&%XQG(e(*6Z|@RHDpaq|XIC+Wt)2V0tU>ndJN`38F|KlFj&*kE zTY0gh)^ypL*y(Ml8pXm*)eW4{!Y!8d|NvI%rzaIG4>mq2tf7U$XECK$~@<^<7y0z19t?L$RZMzIV|e zLQ#9}lwsZ=DSQ>K;YK%{h*Qx~eUg3TnOy}(O7QG6?r)&{ZUD5LILjL+-N=s^tpQK8 zLF>Oy5WBpjmsjb*dEm3cn|>?>=XVJsLY!hfRF~D?(q8h`lv?wAe1O$m-E+M2BzR6~*Zkc#h{ zgq%3f)vYNRG&j)t{nw_i6C|sPfVrT)zYt)lbP9PK?xXgr{$gf3VuduvLJGwor;A@%u3}A%Do73A9 zVOsF1D3Q2_0H!FuqajM!_X?~zGn#>^Er47c^M4x4@F%9n6myN4rKlg$HuK4|JDZvV zyH*JPz$k-~;{8%uYb0%~Y>7e{VE-xdY<80$3#zlU;!fs}(X77Jmk;+D{v4FFGB*lv zF%oO6XYL~}WGNIM*Q^DLSsg2b%V(W6pX{vhuGU~;hBmIq+p0wf^*8-!6QELGK$-!f z8#&u|uT$uioP`*5946P7EWdCM3Pegsu)~$RBA%6epwfd_0G+6xn~eZk02_cKzzSgg zUv&L!BLOG^)IQPi)6}cc|Cf0s-Xm^jpabA0ky!qN|0$?|RX9ihETqVPxx@iq0qy{o zPbQ1cngpQqiJqU={hx9H0I;ko|K(EuWO4ZPcm4l(NC2vz{0;z<|D(7*xzLRN%VqZI zW&RnNBfuKK3Sjw+=>M9F3;^gtWf27c{$utc0089Y0sYAYi3syq|Gy;(;y;#{6k)0LIVz`xW5viM)VM zMWs)V{~eE*nzYK%e**pg6(~S91%QPVARG)J&qA9$kC`yu(3-TC_Y4eh73^k5o3jnp zx4x=fyp5WwABagNUp9f7-f}+pc=l6+bdB1=t$_J?fWje7E5$yf@cR4fcLgcM%kwKP zC=$Wm>ADB@OR(E?Ug?bWiZQH-Eh~pKo=01ARpYt*^*TKB3{pP-t4&{*Z@f%BYwKtOjy7-0VXV^% zx2A54tbJHCP``g!wF!#sH!0hBGTMLqE7DgNp_5Q-R<(kOCw}D9-LL`z@K0g@#?RDJ z%sEB6q&^sSdH}}fzul915exNHU|9Il$6**`AbMJF;c~qQ{?!_~{&Ap391~M#&zD!; zp`)C#b!KBcSrptu86w43;PY7z{RQx9YLCp&5AM}uyMoU`PM1$H-wyQp%0$UydFwWmTe1Z z=1$~9X3nTq#$-p|APQhGh|Tx`;cgaE00eN<2fgK>|9kKIv&*)Yh1idbuwN>7_s=Z| z4P;zK)BalcG${8zKE`@cM9-q)1V_TW7etlIxTvzDlgbX6`76oB_7-ZW3k@7?bnPO2 zIU#c>9uE5QXH5khMwN@7p!78%6Uz04PR0SK&Wb%gxM0x+{sTS|4ckA)Vkwzu9}8hv zBG<9VVq?@w2p{EzSkTovkv%yUbh^OjvB9Vl@=E4bcR( zh1EJmNr?1`TXpf^=Ii^Qp^4IritNWDhd4u?=q;aW5{b5}whnuUVp6uRv%T|?+C9F7 z-5P_pHVPDpcg?r+FGWeQ;I0no-4Q^ar)b~=Te35(C6N3D_!gAC(c5DNz)srEZGyjb z@=}els#c)2Eyqq(fm2XO!Nfy`dEhE2?`(4@o}I#Gh~qh#UVo@NMlsRbR1BeYFzU}E zaQy11leTbdl((S*NCvGys~HML&9EnDxlsK`5|Cg$gGdgqZhreqdM{AjP=nRexzzk$K}vH@%MFY>r#UkltTxkeH*KQebs^ zaML_446)^tX@&Tv&}&S4bNRjIYu-g%PmgrI+CItgP=)c0INY+oev%!P2(m?R5VBj^{wK5IbvJ_FtQmI0xyMJ z<~da!kwz{v(bgYp7pq%aNEb&=CIEAq3V7#23yKD}4x`XK z`~-|VlOqCoDolX467A4FdPEL}d3O*~XZ?oFX4QFBAa~A^1&m{Iu-5579Dt-=^K;e) zua52EtY%aw=_wR?-VHX}hM3LEB?BvJz*n0`fSR%A%8lhn+^TjFpR0dP5B`;T-pm;!)o6ue$saMV8|=Av(ID z4ftkGp)cegpA8BizX%QgM);g80d66%DkbIo(N_|d6rj9PxhG^iafT2XWfAKWw52K? zlmq89(vPw@G5P#&gRO-S$nv7^^LnbF-nR4#@d*2)9KDO42cfkJeU$<;(xf1s4*Wt~ zDGJ+(Fuejp@JnN{e$O*V;inAc4HCr3)(@?MOsGozA-Y>9(Yye$p*@1(pnWTL3V^vo zNHX4L2e&052~!^O*GO2i#{=$N(p6LuR$Fv^ne(p3Rv}VHi>}n$T3R2`RHQpp) z%}vh^vaXb24F%KEr@fYFl?EZ&5!s<_u70-{I^+HC#N#reAd+BUDpy_tNB_K!@T|#E zq1cVCc}MjKb5h!>Xq4VTkLds?{0OUjL&5bxl{))}SPA^`kHJ6Hb(y!g;vu0y8}9-^ zC@Q`tISu1cnW;$R(@5p1^in|RWPYC`H(KlaohT0|i*zLU$Pzgb=f9e7Z~%H2XM|8B z%8Ty@nh5`bI5>vMp+n7y)o~KD7d?c;wf5z%DImKIp^SnDXac7`R;DRoi-`zyrXnM9 za0qU`4Ay2iRB%L>Q{O)e_cce194Q|BkJN|ki#0AI+Vds2ghHbcp2hOejf0>lKPXGRc%32CPowmHIQ zB#iS9Xyi}+qImn6?Uw#@v;9VsxuKtLdMS{3krmHFLk|aes6IGh;KGUn=Fw@=(rBu2 zzR-$jwuMyV;EX6j2?&RtAO{|WxHj~TXAOZp@tirCWU`Q*c`(k%rx$Ch|$xx@lb!p;p~?AxmwW7e2u1`E@Ka!%p<-# z-qJ;XzuG?Qew#V?k&}+E27R-!2f>@v`36t2m9|Efh0m>ljQx|!d1_=i3n!4LJK#5G ziKvr4WvDlXh7Ix-Nl@B$Gy|U`mq7^7IU-1uchc3(qYZFkzFTTVonzLsrCub!lTr_O z>}t3^PS!ATaWXwrz&BAGfq)4-AM!08H%+@gRSB|UpicSs;?}oH!sQ0){z&Y-!nw7k z!ANtF8=s>*P7sga3uX199uU$P5mr0l#Do;VMC*G@L{|Gkl|8a8y1)6gD``=QskXhP zo#uOXKmKkdSjl{6~249e^GEIBMwuZ7)oqE<%5|;H-7I(3xPZ;gn>&LBv ziW(bbtP4KzVSR;Rl|&Pr0%4BTBe6#+QZIOeG@h(x{Z8%_Wtb<8MOMnh{x%-Lc@i`1 zl4Ge3PJq2Zg{8&l)khejg~~Y3!o@|#S&Va`=1*Di>W`u57G%DMOkPxg{TB&$_rs{M z%pDSEV&zc(`y5O^a{`is{J{+}j1y~zstDE4Hlpv-LI>Tl3pqfozB<7kKW6YtP}KQ^ zF*NQrnVuJ-0J#QO#DcQm$M<5#dG%c2L*@g!%WY5Fu{`B!<2RF+H|{Y4R{e+|WX@sv z${tt;A#Vqq_Vk#KHFVBeg(&nR&xAWrt609bbjgE-=mLDG=?Ypz%`kGCAeCeh^d4t^ z*fGZ53nT^F1C-4N>oOF1N#~GSGy6D=!kjpSsC%ea84jsFNn1?tzeNRA>M?&nqcV4l zV&=hf6N>S7#y6doQPc9Vy{%N?4T&E*Qb?*b?C`zS@41(4M6KMn3;jA)#^1f?F|$q7 ziw!Z>k=PgY>S?Ojs&*KXSNL%~9;&ZqX-*7Q>*5$s250xCVUV2 z3lU7IstY|f>M4QKQDd+7bTIWq@w?nLWTxXXk>x}rT0gQ3m%{QCq~j$5Bp=d5xeUJR z;Pi|B6R#X&N^&y0>9^l$lMyp{ir5^r^sYVf+lkMPqdu9=Yq# zokFfUcSS$pd%SW55i{6Pq&bU*P$F-5=k!1Ul>}_JB&;3kH z3IbD}pn$Gj%!6*1O)jc|D(CNw>>+%tT$(6_VmN%EN2gk-?;@`d*)G0=k`0*(QaS~* zN4!YK6e6)UeuB^}T+0?O6hXirePg2n!W*iuEueo7^P~BZ$B$L$F5S%**cqMTHAaZ2 zJNt7lhU?=gTd_l>D;;)$V5L^*bQh`43xrga<}xTijABa^4OARfv`+q)2h~^Az19Qg z1_l2-ud;qxG<$Ax(;EX}?K$1iQ>`{ps(w4l zoG}S8^B>uo0-A5BLiwmz<4=dgILfS-RnUKFo+zu=46ya5<81X7@rog{@$`e-sO<0V z$zn1Y0a@Ogk;OIOxv-|J$?~l;>hSIi)C7nU0CAJ~#}35K<%bnhWcS~N*)aAy>cPqG z?=JYy5MwY-V(BSK8ac*-O+k&nD1_g2g%6obkiMDJM}G+|e2P(epVohbQ^3P3l0u+3 zfI4-1vI-L+@po{g@u8BDVSIx|{k`4==_Zd?o{bPKLot*U{1*ART83FDgOXjsDRSDP zr&>cHp=^TU_L+P#=5Ns+A_FX7mSY%%xs>dDF91=x$w_|1*ox{zzlpajK_O~uj4GIc ziU`m^AtLA`o5o=sq&r=hz@>^rC~_*)W=3m{^@IiKcB)WBCCjvmjqm+k z6^;kS<(%{!{ya6tkNBl89%5-6)690nVGkcapE_8N7^69rBH8rd3gzWyMB&90rP9XN z&4M9`WH$@Qq2sV$z8-@%#J_%kro?a&haE$HLWNK8q#`!?9ezPOdtgpJMlL0m)ML!Bqw$!e74evB(@r8 z3X1AkTh8as6JAG*1OlcaCXZYTHg=k^j3+&X_YlBZ@)m@jPtahiDb?deTNngwjgAb? zzy1vV<#o(7%{Fy{lTH#}+9kCiXc;h4G0zARGSDQvM2>pjp-Tb=73rn_JFe$u1d$mW!2A$$t;M#}xA zl{R$`v!tERm4s6Q1TTUJHwsP9i=`f4uUbjt=L=O(ClgX4j%ho4bk;O;nfv$k!^V5T z&Qy#miE0XtqLk^;C53S-e&P~E8!su}KG=2dBEi%w^0J%Ky9Hz0Y&+H~UPI$w^L5 zl9S}*`Qsb7(Cf?&Xp@DZ#Fm|{$L194dfx^xv^gkj+>C-9}xT&s+n?KjhS>3do z!W1|+s5>`^!8i5WrT5MXdEZZdn!CiV>sX;dN$*(0G_B06=WVQ251K3|AD>)TJ8&dJ z47*&{sF8Cu^6O&X-D%;k1eS|99&$@@&S>40OM6>%wr=s(sB-}qGdr6%OcKF$Y+O8w zVlGsBHLsFub@(v$^V8ijk{-U55h}q`XV<)$xKu1md{ETPZoP;8;>MH!jS%k{(WyRb zDFJ$W5@zX|t5mO1QpFrEoDp9v5PCOxV4qw3kxz&Dq~71XAH6ExG-t~44@p@!l&3Tn zceQuNe%=|ilqG(3k6}QI)U8#=YggU6`9@Cc>2ZzmaZT&4BxM{wZ6x-j@UAa#5mdjY;tFe5Pbl zBorQHrd?v#qNSe{wW9<7W>u1x@guX6kve73(!v+Z&aUEFeN43ZXver~^3$WUMrg;>bS3Ho20tVZQDVam9H_iO-ZSJ-3FA@u;aIlKTdv}kP-ZPuHeqe zhMpdlSqyWVzMTu~Qnlg~@2J%qKdY{JmsfvLZhL@nO{`FVvt+$ekm1;)1#vvCZu4Da zYj?iYSf+I@>3h(`Nt$k6PS4Dlp);IL79IR}xnsuFpbx%dAOCESQZ!37T;uhM=TN19 z+nmtzuhRPsqJookSlw8H)XdYq_BxuAsnIqkBo!Lw&DxddUNhnD=lzwFuW!g6HKjM7 zKf7j0*B0!>M&;2T3iX`pE{>8Cuid&cS7|isJa57NA7^H$wV}UCl3HdY@^pX3B83HuA`96P4(o_Luz8nn+Vo2RzFs!3a^V;;H zlqM_ZrZH^`*YEGpYULRa4Lo8s(bDkIsnboi?w5kwUaM^{&|Pa%>+YClla|)jr>5fi zK-@4RWD4aLMcz0)nUDAR)x%c@=Q8Zkx#1A=_oAvmG zix^mx+owF+yUkgk*WlpB0K=L|mFkQrPkn<#?+(w+E%RqA$+gHdr)c(UoI8onme2a! zehOby<9wR=I+ujO(t-m)NdqO7xz{&XQ{@MZD>Fkx1?2W=e;G2qKWFz{73aE6T28ro z@D;}foh^H6moFamdAIwD`4W+%M!#6D+8;ChSarWS^;y@r&ZOOmq0t-P@XdQ1>U;QB z_06K=>zl>BbIPlgb{{efr(HK+Id<1u>zjcyaj_|*9MW4qEbBeJd80%+_3{18Dt>0e z%WYqaRTMvl6?rL|2u1VNv`&rCcza&CZXU-MZ^B(x^FUjO3f z_VeGqZMGaNP!H+fq+eB?qp_HO(@aW#%Tv?rw6)7x4`m!2LsuBM!|b%aw#9x1UvB=_ zL$N8#`o~GO_G$56q|7^1|Hg6h{_2xXHU}PJLeEXaatfLbpRana7{3TFQh2t{6e~@5 zr?7JS8I!DJ(wTYHg+!aV&YH}zsdA)Js21T zotQd{z$QBRY2%v*1_;YR+oiT6NyBlcE!4HPy$g{>VGn=zd7&HD!CttPoy1 z6~X2hjiiy|ZB4Zs^nV=s!p~x;g#YG2#x_BhHRC%6 zk39{QKBaG5w96#4u_O1+7>$0ZYo8iVEiA%>E^b<$`Bg5`yvZ-fN;v#mUewja^A-i9 z_ATf?+mii7L+`>m-3!mumh8Ire3_BN78~KQR4)_WN$*FmJ<@kAw6Fi_ZOl|)-=S;; zd*)=9mm)Q7JEKo;Z!5KprHa#cysFfyk;p%heb69b!HVE<3)EHoZ4INXs}$5Wuv*U_ z->CoPenkb{Am{Y_4ZZ8%nHJpAjByBUnV^~4>1UZUJ#(J?$L7jsvY5En_(V}(>rR&< zn|3dCt2gudobTlFoUuPQxMNJh2|g#o%_46{y;)}D`%akF*E7Gi!2iOVA97iT>6@D# zY+SK(+1fXZabE=atZv|ad0lDyqIVpatzfdrX2JUyoxKwdo2yU1^hv_{wPu$D|IIgB zcuPV)q!-Otp(A&5+mzeNl&zP2MVLJspY5s_N;#c!y_G57()-b*MSIs{h9hMs}-;86FHO6U0pEBL}DpsFLcS=oKG_@tx|q+!=>d$>ar6;C)~1CK6}JE zO*C6<-Q9gBLyP)DTm`yM?lV9CHCERt*r-}_`&0Ld^l)4Iow#`XQPI3AHI=rpb_Ua$ zd8ZB3y_bD9Q~q4uhX-L*Kk9^6r7t^hK2T$O`pq26%QI5Xq>IbYnc)}E%X^6j^d7`j ze0gPl{h|WRpYDCA22Wg5pEX59TbO55_9Wp2D+}+M*{5H6U4z9cjdSrAJ3B5Qb7A^6 zf#+L#=c!y0>{fsB$#jCUmHnuRaupkFV)GWPd1c!ZHTC_ncJm#Q#f3Coeu~gwP1nBW zZh=dUH_tSRe=WPQUvA)%){M=uN%lvq#D%4VY9~#SwO%~!`}qaOH$@MexMeXpntJKM z?3(ij?rut%re)r=PGp{~$T_<^R&w|%{at*Y3NFtZyN}nyY3kMuS;bNh23vBCZq(!j z`^ukw^01Q9qvr5_a@*sS*v!hs>2)VITIv@T?w&VLaQ=Xf5iUwsd}bvm>|Eb=B({d< z`-v-dEnm9p-3xe1KmK$X(iO8fQM$?R$dc3dH)Z6mHCSowa_P-+Y&+S>iq( z2j9l6JolLAVb4I|Rp$d<8qS*z3^|9Xdq<`mnb%vc6VgApdHWd6rCQ1ttzU(0P&)C_ zbk5~%50$2i$5m5Xj}%sX#9w7Oh#*6s^^NfwbG z@0&=Ln8vLT@3Z;&xZvrS1hMup!j!fvGqo*^1TW`FT~Ml59(ycBaB!#OG3L|~X8BF+ z-N&rz6*7IK14H}yYt^M*-^Y*tNIeqjcc(W(BxT#UmE)(CPz??)JF;2Qp&}N2nW)44 z%sM^`Z>z68ndiP-Wj#sW=P|#Mf9j#}PrOa{A32Skwpr%ej+yTmtFg_zcex+08|QX4G`6{7~zYs;v{yh;;iSPnU8PR@?r;5TR7>WDW6=4%YGDqH-q`?@8vIb z7&!R&oxbbQqyqW+;+(BhZ*^pbpVu$AWf5yKc~aGwyVuMetUZ%TDVI+c46Mw{H0K{Q z$osCeG)Fk#dsKPst{n$>4ovJSUpU+FRjKh}$)?WE%AQ8UO<(h+Oeka26iu9pi^$jX&JJ#h#HB{NGx*uRZwQk!1n~WOo33r3NV|ki$`xM2_w(ncz zu(mb-=*cfV$9vaF%F0ZUytB%4zJE%ph=bvUKDznyw?-b6IlWWNDFq(FGY0yu+Dl?9 zR09L@I=@W5F6On%=IiPiB3e=($DeOo>ecIgMt}4(S+l#N4wiO38EDJ-I1s15+No~g z^)fMau}dY}f0VvA*KKtk=zaBaTVjN8Y1YfMG|{==9?aEG8~w8~*uhyzbj#k7DU%*t zkmOh4)o{kGZ!egwA3iH|iSFDfWweg++RFNMd=Ko(STC9;nyTf_PVy_5`nU(BU zv;E{6+qtIasFQ9hSuzc~-i8*ADsq`Dx9`bznK7#it<)3*7+-c8rNy5Uo;YAIi*z;5aAbk}4H?@8s_ zdIh`MHkhRGp1nO|^7=Qk(zh(I$~X`pSthx*u*OBE*zL{em_NM5uv#E9TXgg3LtodV%Dhgwcic5k=3CGcwU~fJxmlfGHcPxI zrfUdpPU@)Ok6@0SKULTLON{moD}%MB6--{1z42$KUSTt)_6w$! zYR~(hxhqrJvFk^lvQ~%4E1%6>^!3uzS^j6b_5F1;J3dT$JYj&AXO_7_Q`b*I$bqtI ztNXXdH+!lx)!HfhRL5wzRDM=`wOb%z|LT_~EYkL!dpNVI+h03ky`bP7d+Odgo{wpr z+1ZNIyXP)1b-0#Kzl3k2QB{rCA2|HeL1*)V`A#|uYg7xBiaVyw{y|w)Wo|g8AZ|*z z^+1gDft!1@(l^5-Yd6jdKfjXgzCUHnq|{#)y>LSFOvXcb0H zs@e|i3`vEuysbV0>Z(`bYlV;AYE(4ct>{s8-e>XFbwX#Hwlz$~6^djuccX zJJL0~m#bZQH8EnguKPmXNRJt>wO^E9AH9F<8JX3M$_76t*FRFLyh~r^V{#$z^ZNOD zW?V-&d!paC-+zQ z%zRoLIFThVpHJB(#yi+P;?2k4gbjW|=3~02I#_+B)u!9*-LBp%q;a&@FrnY%mA%N` z8IAp}%cJn_x34?rtSK-oyWDnNn{R*mt+38u?YmQhl25uxTZL}ZC=e`J>f~r^KTsL; z61yN#>*TcH_VP(*{0gUCSiQYEV86tyc{gT{pN9V7!FiMB=*{DF&pw#-&~W^m>~tgB zrPu^ZS*;hrNMF8WQ9(ls#c1aB(k>7V03fw2i;A$d<~6yxSTop@jc^LPq*-FtK3i&yiYr4xBdiEdCcK> z+k=70_{5%2nIfj5(~E4OkMd>3osu>^l9OW3nH;|y^Qe8ClD|XtnDuz&Ipqnj3O`?^ zw(XWXv^i}2W0kdwsh?<>Z?5(^$0XN?lnaQfXFDEGSLz=hM$;L{$v7J&xohRUWsuNp-5WTleyry=cK+S=TOj{3E#_rb=&8Z&;Ff`pMEa3i?NVO!IELCm)}< z@tRr%t?$07fJWMinw*ECUVcI;_@q^9Q zYvZ3J7Fn5F@&z2ZYOwk&b=&CRua9oexVSQt_g&=2%Y{znKAsmMjdz_m=&f&?I+3pN zbGQ5tWlu@R;6cMF(I1l9bb175|5T6X|HwOmIja6`_>FAeLIa1!0-o$MU5ih;Er_Lx z>{4Cy(ckLl3YTKjD|v=Wc5;tG1@BCb5sIkXJ5i&0+Vf{>@-ykQg15^prx|W(t!~HK zuXLC>+I=l{8UIEh#3n?>rY)mbQaP$i0n0yWJ8jK-ZwubEpN8IRk}j@#XyoD`TdBLa zZrYG*ark$>W%qSY%5>zo7>!C=vqmg2SZc|Ix$507ScPL(9e8fACBT1FfX{>rjO+c6 z2bT-%D2e-7v*<&Is_Ddg#=VB-^UR-K_tX&hT(YlYY1{Tat0LwYYUKK^-McwoZ3Csa zbH)s#g~p>*6uY86udR|<>3+zv$j0i$X-VHYT~T?Zr}T*|N828`(rJRD<#t^cN?jqH zHgBI%mgM00y~52EHx=K8H1*9iYuprZW5tyhb$VwMJhRr?E)-AOk-(@pHcGp2uZF5p z^H(ahPxHtA)U27}vmI=<8C&0t|1oyPX0K!Glq_Fek6U`2b$hgQL7%YKZ>u)=1FI!pF4e+tF~ zdo8%wTqlq>zIOJeMe5nU;Rb^limM`d_Ig{rQxJbqhdyNQU2vmJ6K-I^Ze zmjW{!vh>bh*JUZDW#*1nY3kc&JtZ~c`gZLFewo5iRv-J~!)|9poDp=1v!B1F^=wsZ zec-Lf&zMn@8YYJx4xLxb)2YXpKi7WVDDCyU_EUVa;(cb}RCk7olKF0D+g9r6G z--~$Hbf$`9=VWc&F?8Dtt9h0jFQ46UY}pHHQAD&EWxb%4l*gA<=g-<-x_^}K;cgR) zZ!3N1HqV4VnpaJX|9DAar+Vv}A(24Eew&~do7-n}?2I{cyC+M5%JU@e%opiO*hLH{eI#)?{Ba8a_?KJ_PGsvM|)C_9#W^!1G*fr+{*F*kFvIx zEA(}?Stjuxx64uDIeB$mgIdp-0o%H9b3UzK!57m!eur-LcnyYrL1>QN$zlVGb(CYv z0)+R8RO^T>OEPS!?i|RPGIVL9)pf@+GuItAyFWG4K=Q)v!$F1NYbRLqeA!;E);epP zLd48qmAh*a_Ux~rNefReDKn~xqG0`$hF;GdY9;bk*sU}V ztskGZe4dcc*u*ufrf5osY(AL0SH0!h?jXl?v8Rjz9qeq!^Q_;>r`?d{`FWg++!ofU z#wHPqAOq)P+06CXJ%Q%g8#fs~t~kG2RPG^j&g$%l`jizzlUx%mg=1-t1nc^IrYq>Y z|86mMqwK(%qyw_b(wh$F;Qbblb(NRqJlO<9(bL0OfoXGQ17 z=dYzljq8_a-!}dwEhE!+qU3Q;zAW)w`u6;tyzgT*m3J(880B*Lvu94=$AX{}k+$Eg z3OBDA<@Y|bCtEvqZc_inR)gjDH?~Wia(j6$y3S06T6XZ*Oy11PDoaAP-Mc;+i!-L( zKeB(6aFsU$&BONFzrPcn^=76+xA7p~;DlSZSym!FycKm#VS=rz1vp$_@aNyYVlU1Il*Bqs|dR}o~9C|4C%JQ(!F*DDe zqL`&fe+ejRcw3(#cB6jnVTqOtxa_r}ucJym<{oOh|4=(KZ~OS-^I3UbI0g#l+L~UO%eV&t(aOo-bTiXM9g_pUC4?JIwFLI?&JV+vQhGuMyLZ zT!#LFM1HTwLDBcm*GNl??>O=Nnw*=)g?bUS8`JzlE8GTkAB>Odkjj3mQo^{FJAcyC zE3Al7V&~+XDpf6%^C%e;_a1+1vU{KO^(zCHRIiCHSaRXiv2=-fCDbpkWU}**7LOCf zm|uh29_W7Fb@q(%F3Xl~RY9$1=637m&?5Mrs;7p&YdL?;VMTyEu6oFLa%Wnnkbjyo z&(Cp@e0{PHhXy;<4{Dxylm0brXS_)oCAGmHeRX1u;=?6p=G`~GvsC=8%9@@AagR^D zee3nb7uZJR-IM6OU+v@;d)#l%G|6?BlGQp+JvvpBoflC2-ub%Q;xFYhN3G0YDEQ1z z$Z71O|0qp1)@vEH;l8fjotLjSv04f?#|YmNcEF2XU3*k$ z*NV)J+^H?Kt);JSt^OvPIy z3-=7|u#i(KJEn~1+uuumn&dsW7X4}TmU{2Py*v8NpFdc?xrSdREnIw;L6o58ZQ75H zna!q3>u;15hSl!v?7jK*?aNcQ;t#o>KyTrS2+fe{QcSP05)ivKZR?qsEs_J-XZN3< z>nSy5llQIV)n-L=x}AlV{A{b!m0c$`tEjJGzfiuS;n10anIiUwg!d%R>o)iq>AL1i zP}xjJ*BN@cV^%oa5~BK!qc@(!Fp(-9+4J1vPu^N05` zbth=e@2Ps5CwyT=W_RK$-VILzKM3*F1r9zsbZw*i+e@tCwN#TTrwd*Z${q(qKTBV^ z#P8DEm1~k=o)ER!m)4^reRHRV+#-SI51-7k3vNXyo*I}W`(-T76BOm6y)V6G($F5c zJvzsq>)Xe#jJ;uI;GwZlG2+&em5+OQD=zM*GIg$19G+b7pQ6pv(%dO|IOeIhC$}Tu^J7e;T4d;+z0mkOvH{;|A&FDH zPW|vI@lbMD8N5Sxe$8^~3bl#X7dU9edn|b7Bi3CfG4GPGX;6{S0p;X#%Czuta%V+M z2jq1Xvz64#oeNCqmrs{z9?UpfGjt*Bj5?O3f0O@gaE6F5UvwN#Ovtr)LSq+f=$duW z>{VY$&gvzhf?gIk6h5|FI0fdVmMItC&dr*3d)#WR-e>Oxx>~$qBcFCo=Mzd8os)3N z!!3Slmg}*@E@v9G*T?U@SsP~ee5PcVM_KQ9%NcgJ>(nt*UavK!SEfYIZPiGT$a@jG z+YwC%10iPSJ6KUJS|7G<^G@AexbSuaV{Gw-w$I;XCD(8E+}---`J^Idbl8Jz9m`fn zE9IZlBj(lA3+G0O6g1Q?d09GC@^MFi!itawZ#!Sj@*0z;m*rpPqinwESkN}+ z>9f}p&NcVczw*|fyM4jzo7?GYjkg(P#Jpc{!#HlG^EBC%ULC*jB1ZPwblKhe!#lSy ziY8?EVA38}H{2^bW%so5VRLb6gZ$48>%`6O372<=-N~W3e;a%Hd5iW8#nt^kK91?P z)*i}1{|Dl}#GU`r1xLTCUEPQ72S=+09PatPU9hoRn`f2P*C#)}#b37hB6KVDL;8}K zJ6fX;SvUB+HKb4RvE7jvKvB*!H{##AOMT|7>^F^rng{l~O&W8>CuE+SO0{e2?imgf zLS}o&-&|01Tv6D%Vqxw^zQIqrAH+o@!;FudtZSHV^VVzQwbM4MvN!p~&bH$XII(@| zZ3BkG*!GUPF+vL@g2l(X=Uv!)#cy?p;R5WM^Yo*O{Ws)%ywrHl*#7J+wR}}s2aV%4 z9@Ca+sx3d3`ARg_P2dXu{KB^IlV=@6rA8Sm7Gc>~GI0z2HPoD3BGvO>35R?xG4a~BHCn@j?=D~Z?OC}!M+Ik2*}Rl5 zKXv+`$?d@1A~{1lBvx)vZH|szNW;g=`0ff>aW**Wu7$MmXipQN^>wE<@KxJyz16&Y zeCuuL(r481bE<0>i?^f;hV$+Ut<_xJqc1A(_jnZIy6Zkn||!F+8nD#IoL=SfO!yv9AMVQbJjG?e!_5bWi!wtC@CrNYR>jH(?R~nN6JHHcX+E*Pjz;9 zdw*wNn~Uo_iI!z|o>*y0PBam)Oy?i7O+VH3b+2xhk45nE=`*#@=-N%~6g{&d|C!#^ zJDa9ickPz-`#^srR`=YsPljiY+K(K9R`^|OR&Oc{;uHE;P|Lzrmz1x(x-zn&y zDG?vzGDl!>`4$8rrsH6JGFbmQKc^vii=(I_qPg8FnhS6|D3d1%g5ImwpjGyDSpCziHSxh zj+EIMe0~#|+~+xI+Zz0dEC2V3B^vrBZqIh?YPa^kV>0UVz=51A8|`B7R(jgOw5^NN zW=H!!8)M>jh~HgNMOpBgsMhl5frbX(g1@e`{O%+6@JqpxH)WBPUsoOM?{zDk>F%QM zIOS37l8mfc_nw~dcjTBBxNl`O7Wdy)O*A&F(ws8_Q7B zuFx_iH}(x2*!pf$)a{L#yju2=YEu0N7R$OlopbTSgyQ)kp{Ztl!EX1H2K2PAo(iP0 zHfT=|RgLTVaQc{zivQ8t?NY9oZPpr3L?-xbs;ra>Zjx0=zLGpt)F3(jQr-Y|w5R68zza#Na| z@P#hVEMuFUdE;iQuU^_=Y~|59=_xHl+sQr6-LmTQxqMSYE44u8l+1yo2E(6+&?0Fi zhnZcFx7uf>*;4O1t;WCoohg>5%$L@(S96(n|1qEAO#RK3WnWfLix;SSdG^(^|OV+wtD%&DDSf~F@Do5+vWCWcc|x_ohh)&x1qy%Kwx3|l0fGk{gq$F`#n}Y zkgXHhs9RlKulahGk+fI1Sf6Cf*WBOS zfl2%2_;x82E_^5MHs5Vd{94&&Ny+?)K0a|b#%4ZfcTzI!3l)#c@UA~F({!oJy`4#G z)b=X;9NW+P*y`ha$EH%nfOV6*()$K)OB;qCojEV#_WDgBO}u9mC4I*n8Ed_@`pqp~ zDPE}~?aR=o$R0eWQKUESiOdfv*;R94;r;xI7ORja81Jfn_pyDw^*bCl4e5NzzJKOP z&;*5+trlyJ9ACmPY#yC$T{I?2LFQ!Co6WnkmXC`pnO?g6fsSA5$)3x8ag#H2m%Yf? zzw2$tgFEjBHzOV3rM2IT@3_vKIm>Y9Z?pW&6lWc^30dD!X9pfLz^z)ZP--SF5j2c0 z^Eb0lnBTNgs=Dc1Y2C9j)>^F!$J8F7>u)Rk-Tm?wt#)}>a|t_D%n~&Y>*%zRdpD(J zg^i)2nHzJaR&hYzWX7zCh3onHZe5OQk~GGBO3Hkj_-1_<)6r*kwclaMqQeA=T!6RH zv=CXlh7GfhI=k(&wzH%wWZ87tQcTmHt~$K+Nw>w>o%c7=Uo{tPkSI*Qeto)5P4ltA zQ3b_?!B*axj=WQb&N}P~Ui-<^{r)QHAm5i)nP#($Qod6n%9xX<9TaU&0d;Z6Zx?uGw%U&+9bv8#R?-^K|O*&`ZHmqZQj{(6>gEti86u zFzcpV)^U-*)XYS>QsJe8xRaODL1!xihWfal^7})(OHEJ8Z*Umw5qu!6toX9|RiI|+ zm4Gx8-*MNH6^&SBYNOsMZIx$;21U>EirZ%*ruA_``psKE+hXUgU`|W1__TC(XZX5V z!7C{@4a62rFU26Jss4<%hpa>qqJGXHRZkRvV#etR{MpAV#)`u zXcx`!HEYur?^0Ixp!f5qTJZ0`+wL{7!DpwDo^^oDj^=X{+5=s*183G{u6^>djP(7vEi!oKu^Ab&4QC0wZ+wz!?{!_>dg)`e*qg69Gb$t29Iy@8 z`nvUzRM1s^3#Eta4^WL)FV)Ym>C~Q^6ligH>8%v}Na+@tk4ve?Dn!i1o_EQlj=jlx zWb-nMqIq^z<iF=^WAfCcul+}V zmMY4>Yi0cX3a{(6ldkW?4>sg4#7e%VtXuWaxOiMeLMW#N&*1>pRYaV(II= z6gOwTp6XgP)`9;p9}i2h@#Mawhbg7<>#{G`e-k<&FxvWLa;}i5p0x#13GZi}@ojd0fW%M=2#L!Bs30S>%FzMAt-kKlZbB?B%FYo$!Y)X7U){UA6V)0K*x_|bHxH4ot^K}!0D2hspq0qDw0oRxAh`F~mA)bR_O$7g^%$jcmyXcI z?(@>C?ILZV$RuME$7=C?lJ%}~UNYVO;nK=-%Py;3+P34B)B@W1x+{$4<_kuH z0y{;@?`ZWzR`Tx=Jw`cHdhPL!D^t&vM4#RxB3JY@^Kna_h-yLghjOh?^EFj_Uj!eG zv%A17wJ5p%&}y#p>>GufA2IvuVIZrO+KfM)}%qyPy z&8>FrZnMaq?6$Av!Rr>kW4w)cq|!V4XL8Qh_+Shxmk>kW9!SM(kxRjbh7^!rA)!Qk zkKl;5J|>9m!g%3H0K>GfH|QCzY6%hKLYM~=M0e!3ir{KhQ8X#=NL*{^R0B-<6282`jQc;=kg$q%> z<3iwLZw?|K5&1?4!TFZ*V8!T343#$qb*CJ>;IIPrvGQfwdMAuYrM%Hi=) zXNVI;H>87>L(PIw(GA~tfD4}C0=OjGhi8a~dP4ic_c;)mm@K--qFWB#7U-5oH%); zi0vD*edLXx?|=1qIvXFfA(RIkIK2MW>}MO~L;C`+1KbYX(4Y3~X9u=FgY6@41fKuq z8QKLtH3IzOf$rh-phx1_3;Dnca6#Mnp!@f9z;koa4Sfw4z~{4l&NIhfhyuW4{^*8u z0q6!gXy}G|2BI6{gV;Xu2tEY=_i{PUzUN&ymOncoh2?d4J%6^5OcM zAA{nB2`Cp1<;0N;@|-|e7y$zBy>YNC8Hb0&0=)J*js{b7{^P|4egSG zZosn~-HX)v;7The808I&QDaQ-jXLsq z`9@j(REjkoy>FA6WuW=w#bQHP9h#6R2*$a1g+$-Lgr9~P(kWOvR&)@ei#O|!>}_L52~XWWe_zz6%gX$gqunrPop5Zgwj!%f@M(9l#i_-!Yhe1nbv?| zRU^1r5QAkC?rOr#A>1{Dn@hNPgu9k-$*=n46X62FT~D|h2zMjlZX(>mM!;M|gf|oJ z7Q)?1xZ5bG(pG0EVrWKgpr9zBM&wYivjny0APwF`q-?eZJS~mjwh}RIgnOQFFA(lU zim3*MwWF{Qc8Q4TAl%E1kn08oElk)DMF6-Hf*6Gdc|trq7cXAKcp(PoLoNm5=P^Tr zRe*5O$DGh5M7Y8PRD=kN5-zND6pTuQ#R*q}2Ss3#L|BS&Es@KMr4r#Zo;P0vuuLMnisutTkOg7<3=akMZvzqENVsQtf)U^x5pE*fX2NYD+*ZPE zBi!?Zdx6I=9>Xs3bV|!$?L3ArUkqL1vGU5sI(V>D47-fnp`lKcGI{6hn zu&X@o=P<0Bz;KO6ay*7z=ZQg#e}m`1w4tG!MEorx{x%Um#3PTXV0^sL+}6BR+7!$N zbu60mdBL;eU3!{=*%L9#kt>0%Ai^sNHZ^Ww63nCZ$&tknVZ(s(oa#-EZ6POh?_ASgvXfzAKNI+x@ zLEEZeZzRl6JchmJl|?R82f>L86_!edNEj5(fgzuONno9V{3w$OCd)^z5OREg=M+9D zj9u6=^=E0M8Ti1^64+PXMFhg1L|XuNU_W>#BG(4p!NYtM#Ksi77ae4OQVgEqdiG;z zsQV`xy=d8r!M^cwCcPLG;5-9XD-% z4+;xO4vSud)1rfMT6`QMiWY|+MQs_8k+e8ElNO2FCom%8xE zGgRM@y|xNqI79%;qKgOZI$%vFQ()L`31|XnKv)@({D3G2xsOaO$tD|SH4Lkg*o)k` z3|e$FqB%H>5lN@TQ|*J0j|U_AUBjZ08%)P%p?c9-y0`sW|qDK?;bB>P;qv0;JL|SAdu4U&m(_0s}qen;4m=W648DWu;fHxj_OkC?9 zOVXxN<3j1UEh8uhk$@88F-%4{Jt&R}&EtcJ-URd$*C@jMii79_Td`nx7SQ5$6d~$B zB#0-_OtKi6M*s-#~ik04U81RTb4QFp?f+j_UkZrr1sJyBbQ(rG`TTXKH{ELd@&P=kO;HMCGWU zfLlBhkD`S|<8d_RB6^%T>e+;_Ak@{&umn02aUNL+j*@Z<;cyH|f3d`BG^$*Y#2k&J zNgRFMFANJr-}i%W{K0nIQ3?gFVP+0)c9hM>xVTG?NY9UAvN;#62WFjq#_@ZMpq6czn;@W7)b7>DEsHdZn z<9^XSyi^uZCg2VsD8W%V41|l0u-FZ&Ay5I|b&Mcrg}UNs#Nn7J8nGJ4XQ2EzDkGGD zyC7WAi1s8DN7Bb+*OH5!OC!+3Ky=2V{9z~*P1G4$KN#hQ9FgcpLr`cp8Vchm^k*I_ znqrL+J%;}P#|f%%ltv$$^sDXQ3zj&-8iIawR2t9#U)#jdZl1&iEfa}gEFurkK}9ri zdLE{AG93%00~%QfPDK+w4b>lN17E}hJ|f%bZzHV&nYC+LRndXoIJ2>Eg7NAek`C0Qe4p_Y&rdYjBowmp;uzaZ3? zkP~nL&qB&Lbd&u7CDXB3loKcf{(+Q`cVs@GC=R7!A~^5|m&a-Bx&n=W8%7c2g+7QF zhEEd>)e;FI3WjN;F^ev=>dixZ2U89Og~ibmOd04RAO;*M z$q(Xz8bUcGrhw=`7YON+vLq!iOUn|mvM5$o7Fz=;h%l^tF2 zMaL)MG$xvC8PRk+noeUzCZowXIvy>P$>uoKE-WM@EGRxQj_MT_MaP4XBoH5kgaoQR zlZk`~v^+%9sjyIlhAj$3Sy6%@vRq=-4Gv?)F~b7m$SVPH@(M(T| zWW+=vIssP@oy9_>N1(MhEDlGoXgra@WYG~Ju3@bB=wP%Q#35+~5x~N!Zt-z|Ef~ov zcnm4p=mG&Dkzqj~$Z#U59Jwbhlop3ag`qNn7)W|xg(2Yq*9xQu(c)Q9`9xHKu;@4@ zBRD5QY{!B~kGamo6)a6^831mxTApH4*jBQZlu8{)%4 zw8kZ))Q|vY(h-M7<9bF@@nygA022S0_&BX(ltGxpvkXT=uS7x%wM0457Mz&}+K7UL zJql_qSz>&Gkk3mz@sEJPSm(mzM!=wfxiFY1xj09{pkMw8h6JKvFxWX!P_vVip$7rP z6T{#m@j_p6@sjh*@VsPdL3Ygm8(G@$G{AXW9GuRF_TqLvX9jdeu^j$V1?0pvlE0vh z?304%%ot+W6C)lE35%q2P{U-+MLm+QiY25`i{tE{9ug=f5(33!6f@!1lNnml^-v7C z(Beo@8H`OPLP^fN3P_au#p2LeMze3T1P#jpWuUi8=&Dv(vww2l4-CA{;RlawfyS zO^5$_LgeNgIVp1D+0$Ylq8%wo(8ZY+M@}_RbMEx^uck#9(cFH3#^vUNrSP9%u#o)| z40g`{1k?E!FeGOV%g59?>ZU|emK71;{VUN zWCD93WPASsm*}CS!xl`kPa*R6MHAxw)w0RW`G2^CE%yJNOMnC50#QKmAGib-V$Udd zm)|)AX|kdh#nToMiyugRz;0Yd0n{YMkt|az;e!%dW3UjwRKAGVCBqYF3SiGp?h@e% z_L`vSfSn}lU16sO`#pewW&w7guw=kKITTI1u=j_lHW*>!?41AHhm#ry_(uyCfoXVZ zj;4X6jB&;QAhW1ie&H@w7lThG;|MNu=R(fq9W=T2nzYRKfnZgbZ+f* zke(q3#R4vJ{~R=I;n)8yHK{Wo^(UZ-06gT5p4$SRsHNO77leY0gA+>U(&L*0mk1T5uf`RUb)MqddE^e&@i4g!4X%RdL zniCQOlmImRnHKbQPN+UmBhWHI3ZNH82dABW$EJYmBi_=-6mh^$>Jy=Uz}JA!4TXV| zK&Qejad@9V%Wz5{$1b!V=x2b2Kj{xcP-rPAAqL@w=O}c8$O@V(I-+I~x?wzUM89ML zN>k;;BqO15I{HTxZ^Xeazri@MkOK07D0Pqm|9wMTgk}dF1j0N-gpm(VC=B|ab;J`1 zX@_`rDslVdo1=I@)HS5O|<5AvHT7T9F}GDme?g0%2D`#>4c=jVDDBa-Txr z5*#iNC=in|nUAEG2PxwxKoRUcGcm^w+iNcz2J?e3aYiVMS{TBpG$GhqV}d{(2L^j3 zObB5@nk5oyIt&T|N2-jl3hi(wFII9UPEc;O;8P5@L79luCz%k~4eiM43T|qMx zf=*R%7Uv9#*tUUm1C38MJqi%$iKZp+j$E{=B%YxntZ-(0B;5$N!l_876dx3adpdgI zA&eN-R4S68&;eIS7&^QGEfS$Nm`b&>q7rcZUvX&r|0_I|N+nSm<5t5F5T$Ulj6fb3 z9}+@m>f%TV#f;NM;yF_L=;EOaR$Me=L_&y)iDQy9aLdHCsBFQEQw2~iIHJV34m*o3 z6^U1H1%=X>xDKa8@=1qXFjbFC1N#HAblqQy5QrlPBXuCdq%n4@{ZS<7LAc4-bZ|5! z@aP{JO=wKWq6obSncfo75f*}Ljbmr}O_73>C8Q>Wo0<>_37nu(;bh}dfFsQdOeB$r zyPgw_#o0r^0|iY06vD&?6C{QL5_v$OK@1te-%|`9_+rF_z)^sR!J$8KzQ&mt#0Ylg z>@LKJX@CoZA^5NI4&TxIo|jaNaOozgM8lAv8wL@#RG2ilrH;f(;^E}`y{><@23dP< zx&N*Xu507i#uTd4F%)k(ftPJhJ`3{EgeA=s|!ihg4}1 z{3JkP8`dHMBl`!I5-w#>8n^GDHMy{nWs{0A4qiCvB{6Zzh8Qx(@HE5KX=23D1s6Xt zwWIP#o+5Y6!}E@;8{i*VH;93SluJMGCAWP5{wEGtI7X)VPwFwU9J1B^HLZWvXCw|V zL>NiOpS1qjo+JAbRwNi9Fz3M7f{QfY@gX0G837c&ewYs7jR@>vy$3x;9K2ctPCq2-Yh%Tz+y$5>+Xsjd5!NGI zz^9EU{2MmdGQt)MHjY3&hi+X&^#tOm-IDDZvVC`?jG2KB0{v0DIiYQlJ%JrspcwsN zn+c{BuyqB64QvNtBMYqx+gMTo^Y1p-unE>hsX?KTi24OKkDRzaH`6c-9TBs@tV>>C z#!MlCbh7Xx)!vKTLlQi1;lOb67cS{5y7v@nC3-|mFc$8cL5Ria! zSy|&(ddS6%pZY5vO5?_J=IbyN3#<wYY%v?2r78y@xsZ!BQ581$03K5G!(JW-k2X=c5bW|P+wr+UTu!`Yf zEF7I}2csncp+V>0(KuQw=u}%22&9uBR9+M#fm}SOp2z|qC=_iV5H>KkgYz}2D;%!t z;(=k&!MfZ+sa~Ao5l%Qc4}lYVW^!C8oV_EOz}Ao`i3l6~q85)r_5@+*oEVQoHU%sy zA@FZOjZNszMnI2<1hYA^lYs5W1$kr~2TGpDf(`-JV@zj#F~JTMYTqMl$jjGi04#2 zfkkkCFdOXj_f{bJh{LA8P=>@uBU2Al7QsW%O!ep{FETW|_n>lrYbMUr5sl!`doZz> zkqJ>~c<&VxQ==!EKDl;Oq>hoJPvvM}6_6bEH(ej->EOSHjnN{)=~|fT$cqedy4Day zl2QUd<s<==NXr?wyfLu~;I|Nq9?8vlp21&Ivm&#fbeQh;#!Mc}WL zR!P7nz=_2`^IS}57%OU+=nJ_)KYTt_9-nk@{V7AHdNB0pF6_b&ggG zhBRk`|Np%Hb~s%y9yp4D-}T0@sB&RYC$5%`Q~~_GJ}9B!zpEj+pTf9hNph^P9 zsVnS>=}9y&Stiy_kP6`DN(G!X8-^Yf2+)yhDre1hLlDlIt?^r-kQa2dV9Yb3P;)#1 z9bGc~(H5N<#E3!bK3N1;Ljs~chX@kuzanBGDu6?T{{LG6M znv~-HNsi=j+%%LME?{#|Fp<|tNfm|(7#Svnv4%A($ld?ctW^>h5iU5lj|>ZB(wOiz z2vXCd8xGg$OxWUseh2hVbk5tMI4zRJz!O1xL23y`9{1x~p6=S9eTu^q(VLbWGz1Rx zQYYtS(_iRVR7X@igAsugBX|fMH4yohg)XNEPj_9M784U0MzotQGTaX#UI|4njRev_ z-G#JaA#{3hAT1~Y4`DK*(EAz4(h|Ka3Mx0GWy9&wi%<@P1-;#Y^1|CLNREyUW}z2Z zSh%MC*=nd*wq_57nDiJ1dIN=ldH}U8(Rd@@iyZOJNd%pVUP#4*kV=N=3sCNH zUpA>k9o|l|2-+LWL%MCaKzj@8FQ~p?q+tS5;1cmL(fx`SB%nmR{P1`I1L6trknF_4 z14j!a9&(Gvi7)#V4~+Q>zW{6?$@H9&57cs5l*95QeUK9AjsFG9!+}_2{C~>w#S*)b z-~k)-KVMq3N6JTt=f3DjZiGn#ItYWx08FgFR17xY9K%7Ir3}(V!$jf9{J>}fPdf6 zgYN&&8vpHOM=GKcR3QK?4Zg1)#IQfb&TTtKsCqM57ax*f8;q0M;${WS_BOGASIOfpZ6aa`MII| z?6%fI4u45l2E8j4R>Y3phawK`~%}O12$o0t!#0YKyE9 zw{3>^KkyB_SPBX(XlcN}Es;F=Bg+AG8EN1MIY7MyrowRU2Fj*(e(+k3Whdb}VtQ>;~;Ldw=6hl%3E;pVtAEu&MxL`g6B_?@|6akj=B>@VkIdt?MW_)BYk_jT{c=9l8)LHPRek9u%9k;~27z{WRAl?GB zMCVn1S>1oV4oL$e1NgiEGSg!MTHKQAgkFb0t04mqi$XxOQWJI+mQ;JToDS8qG`blhJFZ>JlcZZCpiNJuqVITo#aM{ zgMQ%l1$yBbJ&UvR09QgD=w$_D{EjZd6m<-t45gqj1${yWIDj+~+ z*ybe}kcWL)k_pihY4xIkLY$q1>@V1G&idOvWaLhzO5!bI@c-6s(;v=s{+;nAJJEk+ z!O2cL%tn-BRLQocWQ2sU=>HRQP6G4)T{fMF3V(R9k)-AS+ZLYeelx+5G4HT``OWn9 z&yIrx#`>fg>Ii#VF5oX#w*($7WQ@wOh@A#+@#^6?+jf?)$z_|O>RAxRsnHB70>ewe z7AUZcV=6rHza^O9Wt>V+ieaKx+hLpVzr=gUo*4}es0!F1lSa^gnDgoa*<@9TilTb_ zGI}PPf@6eC)E_mNE>T&i@ZYIJ#>LQDaFK1#%|KcjLw>TYP*cJ34AT@0esrM?hdXB) zLSb?A^p1e=5MKi#_qvewUrkjog~D_M*Q8(55jj;wp*YS|HTf6pzniN5HkomzLT#c{ za*>t$D}K@d&<*VhndEX6LMOg;Kq!@9rvnGmWX|7bNGk-f3uA?|&#|eq=!*zr4ys!W zd9Dp-JXG{YS7EX7u*GFjy^>>oGZEnInXD16KV<}RuSb%v@Gr<8p^kx7*47>n|7-GX zP?6rOKz~+zU{qL~e>^h~*Fs;9KwH*GG_G0NR8M(J16Hc4_U7bf_A&n=UhG_+e)t)e;iAHvutpAI>FM*Gv zxbp6v8A+pKG-F#b=58({*|L$3fWaK{1vcR@u^>PITb4$ah%5<7zBqymPDn6e%?H_p z1c*5{cnOQz-g%pa;C3pMzWdniKr5Vr9Fu(9)-Th{h;_pF3W(QYje0)~TKuItOJ zZsN#9lZW95u=!#jNZKz&-t?2MU&cw1RmPg0INFxf6Y|83QxW(Md*av@^*EcIWqoXi zdP+R`q}f2mIxF}xAI<#gag=%)H%Ud{o7=DDBjY}&e&X91mon~fEzao|8Rv*y*nr|G zQwsJn^PZkKI-aR#FHhXDDgxh*El$=al?a)@plK6*f?$MGbP`7Txw z_;&nrW!$A&oU`^W0G7F4N+?;`|0Jt|<-Y+hQJ$8y|ZSpEyc?$Sz-Tj6 zRxVXom9eUEnUN~9?4LXd_HY08Z;jvl<~KOYaEmcx#xusw#fy!dzc3Azj%oPpv(G+= zzh0zcJVTk@n{MgSr6T>?Z@+B}4h|Y8pM0{hef#!wI+!qd?l{t1hwo>MY1i&Fu19G* zQ8s?2)2VuA%$R|+?Z#uh-!(pe%00$o>wjUazHgB)9oun!(`w`8zkkGdecLt0UC&-- z-2V>?ed!3(X-h9MzW>w<0LHja~R=B!q|l@v$P2T;wAhDD#c<-blkEM0|%DiDgBjc;Ww2> zhD~Q!*>fT0ry7|~SCR@ZL+$jKOs9(^N(Lj$U}ZfWo{Lm`Sf<`Gbvk?%gGo%N-xAQs z_a*^_d|xJNm+ylSS?gld`UM$en3%+>MIi{lxB6|dTtKaUOBk@UZl`CPC>5&TvgBnb znNW$$On|2sVeCBsX+Mq`Na9K~4{^kiC|10WMd|XP-|1k6Qj{l?%;}UeRx2f;m6Cw} zYgOcVSj^)_DD^M+?lqz*jzUT|G1%baMmV)X#79zf2s4fH6hvy@6EZ49K6JilSKNrC z9z&|Jc6bQkbk(}ms7#T@F2#QYZ8+z__bb1OcJiEP;%L1ItVFkA2VTOEXDjbSa1`7D zX`+!Zu`v$k?NSQCxw=9OPl%eAnq}tRp({giBbGW55z2!~;_T+Qg%H^bjcB06jWl}< z0y~2Uk!B2vZ%ij8FCvR=c?BV=En&MYze8J^5w6-YbGy4OgC@(6ExMdVMmOT~2RpAa z+wfzXS%coqw~Zf}PZX_t{$h&?(_fvTV?z_e#cJcfYW-DexA6tgOq|v#cE&%YD_%mZrys5Tq2lzaMWk!9+vr<`GI*~k=jCrqDEHK?x}fZWs35e z>ZvDRaJOX};^GFSs!~HyCR>+@GWSWJL@!T@m)ugG;Vw^OS7)6Q1M)O;4G$rn2Q0bh zpF@^;UTwTcc=%7$uJBN9!#5oCZQsg65XZ|A7$67J!Km5jqR7M#fjHwZgMSFD)6$h zr5~7y%}=gc+xaF==In-70}jbH-%EATN7T)auAi760_}iSC}Qt zhOrs9DHw2ir%{r?@t0w+zvY|!#5wH3@#~|w%*8a)Fv^!->wp-! zAMZXucobJz&;WN_m||_hR-K{mAuL!W=A8ty5YPJrNTa+@fFn}BPe9#Cz;O6bPeq3s z-S0kbZr^)DsfF}ZaOPrlojwFyF^?PXgkMKLDfOPc8jeWy9uzc)pLnVoseGJ+4Lq*itCT9U;GZz3QlM=3^O3qKKe5b7YlNLN8M z#l@s`AL8euwl&DrgF(TXIuNF4BVwU+U`^46Ta7}7KtaemY0CN(t@@ zdL8J(i|I1E<(V;!j?NR)3i1SL1dw|%9kuJrhH2KitC)U`nAR{zI4%T8io(imIF!fs2!4d3JdZ1HUf zQZ24TeU||v;~<>3BV2EBF$D6=qPQH7PY_hVNN!bc!@5I*wF&6H?*mCahX^CLA_uQr&oE!Xdo6(QN-v!qF~iYF$+J?NnSC!dB4-EhA&2M zDqj}1#=REvHkK3)oqM2L~nmCg0J3c3PYJ%z5S3vwEDHgrdofi*|*VSws(RXQn0-Z-*^0uKM+|s`bX(m+@A{frrT{`MyECZ-Z*EKNJb{ zuRU=G*;bTI2n8G0md!Q2oRQ%b_PFTg58J@t=L$85lcRvC*WrpMt z`Yhqc1zTj}BFZ-%8*aXsFE-jxvcg8h#zreB<6wkeYDCP4Dc4vo1+XR*$1yOp>@=gW zr5zWND#!DRA1r-H!;e8hrXmbt48_acZ2aO1;G5r`hV`h zu|8!_FP2HiY7QLkSa;8Q`BHb4h7s~m@;xs`)_zy7K5 zA$1PlV6^GKADsE zX^)x#q99Oa$bFt14o0dq3W?Yl@p6+{+k!DtX#UC`Rs40hbmHc(!@){I!wSb>CLa4> z7CIR|RxGbU--6cK1{|^5|w;-gNVj`f-u&YHh~@1I2E@&d8Qku(oAPr~b^ zXz!pAnZvXt50AxXsmXV4dE_0T(~MbI8eNJI1;y>*XUBZA_M2#bB()Hss!b5yv(Tcx zNVMy7{xztIi$veRceX{MP7&`c5*fb}8xSYU{^n)e^LI%9`a^eEBCXJy?Kk!H<1jrH ziJQ1_%no{^HJNjFkgn)oM`E3fFMPif-W#Ec$P)~-A1dRGz^fv1UY$)MpF~K?q?;Sr zZuB``S07G2f(%4(9m3RVj$KsxORX^&$fJmy*8tyACA*qsv8(SwSIBI?} z{TB8{_K7&28PL;*t1-E25+{7Nb@8N6aYd#)asjzI+qw_M=CZy{oO&S6I_Sp!MJIiO z+z-h+Jb5oTqU2EnxLTXX6`a2cz^H37*I>IR4hijMel*A4!3lWU#fHiDPF&H+Te>?} zbj#d;s=ae9wie;ePL|f6#0{aH12{0WzaKj)r&{8?Nw(5L*(+Ocgf)(j?q0#O9ndm3 ze#}|C2uDApPc*;@2VJa=)!XMD*as>g2*?u$o-z{o&;p#EfV(%vp`>z8=<>c~%a^BG za{vnpZA*6H=xo`T9&B+2&NCBYwa2aS4M>@#10kKFUaJ>ds zp{|&^`2p^QvaBiA2{_8c`g~tcOUIOj*qMS|F%8zKCoQq2H#QzV6=Ue;_#h}{42j;j z*WyA5Zwbc(4U^jhLihy-S2#j)jD;|A%4HjBjfbG95nK09M3!@(jC&VxlF zk7AKrZkt;wS!5jHWRYPkv0aStOVM#rW5L562tNK{&djGh+>X!FAI67qhWPyA!_)?7 zw@QGGzVx4WL5oemdQ}qIf^8$E;`2Co2#1VqAnvF!_-GB%(?2+B?1jJ7PQy6wc*96l ztSsgKbtPBD_-`2BYUck{i{3k#|9?DX@d^B2*8GJr%Mf$k@i!sednfZ>#W`g#j%mIy zW-pmP3ZO?(S1ov$D__Tpo;mGdAU8vg<^SqkD=F^Sj{L_t=Nv9j986}fWGoEVZ{|)s|H4ip34ddt4@L#@1 zG0us5_y%e?XJ{1p4Py}a;ZCI%yz}>Icz+6EH`L4Dj8~7sF~9jQar!(cYC8U}UThds zn*2CrZi&&uE1Jy{ODQ+TQgWA*uJ_*@KM*N_P&{5nEJGbuNqvQ3lHs9i@pu{Dd?ZkP zRx=X`&}Z*M1R+yb<7>3Hyd!{^l)d$0_?YM!V}Dpm`giFpz@-I}%B-_2OL{d2;nQlD znau|^mO*nMG^~GL^jTV*wENN#C!bm8h?Ade`a1Za?)%H}qx=5mDo!?)G*#X_rXB5% zrEVl39&wTqJTJ~z-qKgc@3r+8QJMg+0;A#MCE`kisdMw}Yr!zta1hBYDoz|mQ#vJO z1-S&yQYFFjG&(=QAFUy&+(yz1Ab3JFXf*VlUZp%Yz%z|v$loWJKPnv%2-`{kJqTk< z7O11jV&xDjThfP{5p!oE9%B^GeHL5l$YDZR%7{;x^DMA^S z8HXPtMiE+t4~Lrvi;ctkBIifXt^9EbiLR4idT_}8hX&At^ZJQ0a!fgQdWlVj5*al} zBMFFM*$C)#jeshBjX(IBVmH2|>`=2jwxXPk{};gOZT#mDG7l%K;gY$Q&MxQyIIj)* zN32{s-X=|8LThQo(RAGd0#(h(OjP)(i%9g3R+&~((;gy)LromX6cm-@>lI{AWY1 zJ{?ut$Q_-I@(~_>S^7YX!b3Q9K881^g;~J4vP!H6@oob9co@9#aj*hqmDm@!rXQ=C z)>Tt|w=4B@MEC2MZU7lj3H=7Rgy&x(Q{yKu1Vbr(x z^wdqO$L9B&pJyWl+QlK^;;6YppmYdUfm@Vq?xG5`~8c~lE!?5Ne#+7 zA(SJ=gt?XS1}`3!GKTuCOCUN|V_Dg_8j4HLm*aeRsoCz}r4R%n@zP&Oyz~p#vq8X@ z2`?lJ{wur?w9I%R7InO!LHJGHo(~>qFi>(snGX*$pL7J&!qG=4LIJf-$O`KLwHFUc zKqY->0xG#jW&xE58j5=iC4|0@G87_eZA3UMb>QDJa}V%rI4u{#2)sYEmgyDmi@ka) z0E-tXhz&fj$Mi^4U1u)Nv4 zB+^_F#4yPLq(C%HHop-8QsBF3$xS z(?=E=6MV?n@TX!Ux`uK*M{5PNaq&bB4uaz)ZIc&&yJj;V4e;QfWvO17%93{YfGG?L{8B{ zc;gJ6O?Xo?at)B6&rCrx^iblQj;4KlXd0-MT!?7?;sC>Hm_%Rb8;6+kj(ds|IuK!UO zZx$jvxPA%~Pn)#&@5GkJ;X?7Fc>P#E6bFtd6q_r56hD5vERkr zBL|Nt6hE%|QT(CAkA;e=)5Rep3dN#o;$l&?7Z($AhJs9FSE=)O&_(^&<9&2-=!in` ztf0x_H$`7xg0wMY|Xy?Y=QGX+)t|EvR#~piZvnD8YNO4TYm~Y}h07 z6jwM!?8jBdL@$s18W@SCHi2Jzbq=bSo$W$TpHYt!VX1mh49KjIazfV?QqDTg?;tUN zWo47cbsRPLaP-k3nQ>GIF+eKq566h3|BL?0iX%z@pBavHUOQz(sku5qURy2Jnsq3q z<_tw4B!SoCgyMA}UF%RBHlk4M#K?XqvC}v2H0BINA?BS1;Nqb~gTRHpC^XH6!r?DQ z%s+Mt>)3W+>2>2?sQsf@SnI?%_wpBx`;(F@aBa>}%BqoB!;qm=vT^Sz>}}(jI<}8m!Upw-Y^Y^5SqhXfGsI|cU*k@>u~Uli8CI&&89tOc@kF^Bvq?r zJG{mW8R~8|!?LydzqMA=(T8>tC5{gokIivf?PZa>+Uhq&s~^Kz8nM(0RP1dv4OlJh zxIsxZI=cZ&@9LopSPM~f+KZNr#>90wbP(E!xKzQtk*MBt)Jkq%w1svN>w`!4vIkE6 z5}+!ci`XSl!Ic*++aKdXA0F7w2g3+ZE@Ic=onEw8;k(h4UbM8YM^0jRICZdy&(Vt( zdDzDkyV1w#4hbRL0z6C5A^Ra*xoS6m0knwn9VhYJ9WKrgHgxndo-9t{0W~))@zyNP z^0Hk$E(|xD*VS@Lb8nagsBp;e*UWIX*+qn?d3PqlE4i&;{ogzTD2qpgZ-A15h>+)B zD1!|Cp_hTg+BC7 z0+{D<>omNjTjb3+;%1%JRV(4_Abh)9Rt@yv{Qabr(KCWG2mSA0Xv5>3E~T@LwDwDZ z!Et;bO{kRsZ`>YQoLVwr4cVqy*I*}}!Hag+8K)(M!@WvwrsPz-!JdSJQqW+>e)RNU ze*uW%jPo?UEqlh{iefE9Mx36%=J73dP%%&F0&&=Cp}PK~XWHP*hYC7ym63 z(L1zp5e5{bNX4j>B=+^I&ZrvX5V2Qvzcz>Ol+Adg1SK>x%*km9j_RfacazEOT;CU; zo0-qL`C;bxfe2ClO107T=Cs&JWAdHCP6mW(3ahg5b{AyFxu^jf?Y@T515Q&|MfF99 zDh;)_3ytmPY>~%fh0U|@G+DOm4&d%tlrn(3m694zt2YK{hb2A$92>vm9)mXAy-&tA==U~bS=i^`W zg@DYNjro=-d`>#t?_$jT4)2BKD%lvDsD1~cYDS(xCS~_;$02~ zuUxdNQ^nyGt%+O5-V1B|m{fzPuO@M@fO>~GTo$iok@@(vA7V$gl&28IQs;kM_Qx=0>^rJCG}saJ^v2MD zd!{oqOyl!FrHql4NUs`(I7I0uIr_~iM2_<#@@@x_S3O8X?w#7Xv+yK$ZS0yveEiph zA`wJ#*iDpvaOH&yk(4XEh};VyHX@UKeYkm3T)oaqy?ITw!sXr~XC_?A7#)`k$%e}X z8ZK*nxV-xz2bXgmAug|jmQZ+HmXxiJ$HyN6Nhdd=Eb-uy^Q{+`Z29rLV7#jbL}{&V z5xa2HOj{vSZo$liOc|pilOfrVc|YQRY2V~A9>^T5aCF3o@yM}b?b|!lG+Ssc_;UHT zO5TsQ!rdzvjXD=Bb)nH?Xdy8`Wl$o`dNP4LtbL~%C8;K4fdV4#9f{yga6S7sEstWp zuzwS;VldmkfjWZ(na=^uM+p_@%5l^2oo(;^SP?Jx-qT>y_)m{)M+Tw8J^JW-G48!D z6(0SE?ywNS2Xc((8Dj4}3wfBWFq}g8OEOcw;rZ4$aoG?#o^Jy`F=iNZcGTdLne>c= z<~ZY!9S!)#;rctMf-;`cg?i$~(K|##4O6s?@uz0UBVe>MWy-^b{JUtryCKZt#R}_S zLm0O|>XOV|!pAW6P|Rhymle2Nmd|pp5y;9N-Z{vZJ~@GTHyQRZ3jDEI{lL4iRsCR0 zqdIMYG1(d{#c!<<%f>ffDx$ciSVX~4p`HM3Rw4_FCyA zefW+Wne$N_7*0Miq~YWv{bkShPIxN>=%B?GTDsKA>Jw46E0o%X@1_#DvPxNd>|(jH zda8)eaj^w?pb4V9NNNMiurS?HCjBCT2(9%B>7duhv4zmL@ia zyDb@9DkPUn86TMw!m}c0qTWbK$3dA72OWPZJ`Sw%KUI9TIMAuFJS#O8dg<*WEc7gi zU!L~vR-BX8Vb zuwY1e6e}N?X5fk?FPXXj6ZZn3yo%^+4uU97yV^yE?m*Q*bCFs!O(!#nL(E>x9yG63ypDD3^k2 zZ1Wr0t+0`lk};Dt^Ean>GF=rXO?5I(v1QiaX3I2_LY4qqCgGE`6v>(FD9q!-HPFUk zpha=8BBjbKd_x@M&%jIJhkJ70k{yqmTmN;=7g4k@L$VGk@C7~G^ip6gNN$S&PfBk4 zTi}y&+tv7PvYljT|J-*m!^5flM0~Dto8u(omX(Z*vXWt)Ic!bJ`Y z#U`x0xS^;XQ7A62JRM-+ z-D2K|++-YC+939CtOP9H*^i4)bcso>ZCTmd1w)NI*o$hL-#t@?awegLUJCdO%QlmI z4wz5~*vCeIGv#kO46Lf)Q~sM}H&qXge^PAtx`z$%xDhNt$U->bV1|~nHJopNgT5qg zMec)34h}S40hb%^)PG!TQMa{*#|zsDR&v3-3+EKCYFUxAj#J2M7FBu=l9QoC9@nZQ z@)(v4dG2W#iT?_wVXkvpUAO!Xpe^1s+zwBWplR6Brr~MOHaQK~Q|q+NCkebJnxy%p z6MGjqOzRM)PV>U6>rn?nU>;AKPu3!ZVmBd#ThNhP!EO#lIDG_og#PvuGfl%%+*WKQ z`=OM6wnD(XtUrwUgQvklPsX80=E*pc6^fCXj7zdYF;bIp>4-uRG#QtTC=@}HaTHKw znvB<;Jo1zAH?+B^+{TVG7oBu&G3KH-VCX!r;xXZuT8{d?bI~CPQJ$onSEOU=Y%3;J z(DqJfnQI%?%?6{oIer5YPh=TB`x{j^<*8X?JafJADeH1h)S?m?7JtqGY@Cbui+V}6 zytLstd1(!F%GGNjW0mt7VRX-HLtFhSnot%%aipWv7m6(%(F#2^eBf?l`K#KBX7Kzq?|UIJx*H#L#^*sIdcd#|OtSJv5~G&xYVVb|wp{XGI*uN*C_Y#jV9 z?c2NQA`VPWd?%QDJx=Gqht4U6b6_YkuX=9nN>D?vSDWr=$?-$_$L37o+k1g{cYCa2 z*c$NNZh==|XUp=gq&N?jQUV8r*M*x7zcQRf)3PJc$T0VCDn$r~ytLM|Yv_yl(6{gs z2YsKvjOeRAs2J!wyyD~PD{8sBGB@;j{Zu!jJ#OOLEIfJ#j1D7dSjGfvs=>cKEel8I z_adwhSM&_voko$H<5cy=u?UZ2Jh3WmViK#8gz4;FV+h|nkgtwymXQtHGc;^h`>@^c z6$jhD`Vq1H$uElG75r(nRla|sLnx#TfH-dW9np1S4WW$y9FHW{Ov)f9iIqKVuwEwn z(uB&{ArnevxEpm0%Z9o)5r2!icfv-U!|%6z+duwIY)k1_bfb#Ru2lN=a@K6 z-`(mhaWb0u$yOM^VdBOGLrSCNpdzcPC89D6Dj7}+a5P$mWut(Fh*ye}NsR1*M!OV- zWm*)J=P$`y%pSI9FJ~^n4(;C@_+r4?zsVHhgu(tzxY zTZ+5FmKuxk*NnTv8WFy6+&v=R@dVa2NUwY-bTs#8r#l`dLJY zuyYns_%XIO&$Eb-M+j)J&bt=95l(CS5|{_}10I#Nef~obrUA=v90Y^y?0U^?MW&kf z+2*ZTKL#ch-fE_5kIsAHa3R{37L-x*t_aHc2(;G-+RX1-*|Tvx$>5RW9zfROE&0?! zR}Wh9nXVCG19U7d`5cVzLHk-+%EaZkRGCEhAhg_^mwb>%5uxsRz_O^zJqjXZM-|uq z;r8&y#&5-)$DW}8C^8YG^@5imb3dLW$Dt5V^GCj#^`Q`otT)G21|7@guNgQNJ@qN9 zU1}&qY|LK{%u}=C@Gmh2jf8ntPHX#W;Vl&TUghBU**MxFmb!`7G}{uuIt^n>{9e2? zS$(Uzk~6F(moc7U)22F>dfiaZxam`Ih{Hg4&+N<*y#sx-V@*xCA~sz_-PEa5aWt#A zHTGz{$EH}8B@2m7wqKEL%CQVv+T9}(BHgigxg;i`oS6rdTyDSuLvn2|&ZX$5Q`_=Y z?d{1v+><+iYib*C=Wfp`d}U|{gH#J*;-Crw&y0PmS_iBpJTPM+(pZ!1lnqw8aiVEx zj?-?@I)sRtP;7%}83Q~335=+O-91h^0ckz6Nqk%q6YC^*MhxQ~(UrKC6eiWhm=?r? zU+P_t!JVZ@L01N&jJ!gvhR6`+)l<-}pjJStT&pKlzLl3M!9OyUN4rS`b?PfK;=arR zmQBJ|D>sEMn|KN;o0f}UjJaFPjinAY(Q)|2l?3AEunTHGmGzXNE*0WVgAAqaGzUFl?!Mwz^q9%8{z3YHg!g0sRn;#_)zsKDW(^}~Cgu7H4-<>!& zrMRJ`LCv8Q{K!BBGKZojrjfZ6wz#kogbjE3q(nKIbV_uW&ou7xDLXjjvo@z~k|Rl~ z=0Xp#!dXX#^OKmt1LS#KKFUT^{w>S)l;ft`iA&)r$SRaaQf?wJ+j! zC69YDq1Xj0asDxwEjIcvX+8L|^ew2o0;hna)5{}m*pAykR2&Y)u3K8vKgmdsadfF$SJIkY|RauOeZkB_Q z-q5Dn#aN7XyIC?t+&C-HIe8)CRsAOF-<=8KDfp>x`gz^U0J(Ss@jXlgiXhn6`tiYB zz*GeB6QK=-Qg`5cldUar4ypY}62x2)pQD2u@+gAPwI!A{a@x|lk;aPn_%}g9ZV&02 z5r*O!FO$0SXQdulXXer*~N7uCoOX3%%yjfSR}bhgVzFb+#)b&lp=oJKO`3 zG*xW`>ueJtmZ$+)W@Fx~vwd`2emdKgk*O7fqG!jX=A(XY6yc&j*WYI1o9l0!WA*j7 zBk_CVxbciM?i8_jA;+^H>VFrC-*P3G?V|p73qGent#Fi;)(&hCngqq90f%Mrb&}MU z(z=NSy=lN!ny5oz7ZLTSdZFbw<>;ysl_X77O6x#}j{mCqw*c+%07;cS{-KZYe|Dt;n3l-3q25{U{l)S`eDMO_cP= zU)f`l*2t%x!K-qTkJ_WTM$k7<&Uf1M7N|{g!<= zHFx&m#7$gHYE5mmaQxlWj(TZ1I1sJI!I5}e{`+Nhb|^Im>FvN?WJ=kK{=)-5L7eK- za=T9*UzZ7U&noiHkEW87%a>IAgV_1e3s{teONwKgnzJ|t>WZaJQ4K|;KD&7>aoC&5>fvGotiq!hxkrKrOv{^S9uOuVmS3p5uc-oiaeP_ zRF*YzBIs6i=ktr`WSwLSSK>tp$`Kp$UP1Z6!Tbbe(%0>Kyd+rvBv#~E z+&C5?O<2{?Rshb#f&f+}rdTVJEBliJb!Rp-Hdu@2oUmZ&l0|1PpbXpEm2Bx-+KZiT zb!XOd+MuoAI2JA@110RxkWL}dDC3l(gdZ8gQR{>_#z`sA>A9qVE@4kVdOU?WX6I|RCf*(Y|OVu4mA_eF9^re@8;Gc z3uarCS*&K+GnTc$I>r*pMqP8g#U&5x%PS$q^t6igBld`ek`F=4WZS9@p7N`!1+qs9 z+e2)O)2H}RrVH{3Z9zouMF~mnz3iqX_Ohe{RRaCE9Vi%2>QI8Xx<))#3V0lO)tD>` zpnzH5&5r_3#v<;KwQs0~qu&NKXlBrW?!{Y>i@>K#sj}K8Mu0Ih4!jD5Mksc~y zBEvYRs0)sXnVB9L4i6TLpiCDIt2MDfPVv<)KM6G}sJNl>@`!%54x4XYPNqS5y=@@L zE1|;+u}rHV*2PxQe%I=?43VYj)=mllPWiM@I*@@cYH?(HPMo`LU08A~wvMIM5wBF; z43W7M{O)V-CiwQuD8QokHnfD zFZ)|B!`~iv8M>?x1gjqocV8;IFvo}(CW3Xs3pi~0BV?%6vE3*v|edDrX?KFpb z7vNd(kBvW!T?gmYSn4)lTM4a#<6@O$Izn8#Tdg*=j|^UA&>4B;8BDdfyQsS#90>MX zc*v0-Fel|Fzs+%~2qi5|5R*4W1AAXFx>s(9WlkyNmJ3k4H{j@Y$C!<`&(`i(ofQf+ z!qsED>ML=Dusfa~^4T2;#cnK#(pMri2=~1PI-W5WQg;{@IRVQR?1^OU6LrEv%rzPlIXHO zdgZ}FFG`mO)O_&&cx%=r(fx%adM%D0%TE&Rz&KNqXenx@4&aqUpNXHHrz7zzxI2>9 zT*XpR!HnFJ=zgFm>7qN$g2_z@Z3~;N_MYB;moTb{sB{o!yyIsK?y1GwUcb{VmyGLi zO7uUPqMuVBU|zUu7t^(ol#myt~7q*k0z0njhlGVpu6e z7wPT}o8y~N>nS)(WB})iG#D1HIqET1igQQ$j8)>sBFkt)SU1ie89;oicptzCB%KJe zkdLR4bR%CoV)~GmXOnb_RF-(>XBYlr#ypYI!nr0bxCM!4oAB-wn{GRav?L>?t3 zZqPbp0>Xn0mVbEfw?(+2VSk*BwV{$Ge)nw=dwvG6OfPFT*Hpd=AMAsdEw#VT)cOm+0pHUS=A*ks=P@o#F5gQ9$QFh>j{6yKq(Bn;& zCGecZJ+*>s=%VcA_;%F2+^~#e@ZS#x$jjT78Y=|5sx#`1*k-2q))iK9D7TH}FVp;kjV1)ZxWW&pm>sX}dL`hwOJx)gG zg?4QY6un^511N{}5)OCGjUtRSlZBp-&ldcHDcZs&g+)h%lhz$wNSU2I9%Dq$uZs?} zj7ggXYjkWDq@G`yP9K&8^kL+H{Q7VKsB>`@sWX-uK>5mIBVJ*#`2j+fD_byaz_8VJ zw$~l7yj~f3r%an2>xb7~Ye(H$xht`?1(#BvG3_X;bMoZb(uz!D@ACTDDo-a($THdV zqpb6TlAX_FZOQhQRb2x|;nh_Zf7^EE#@R7xHNFAR-p)qk+*7nGW$DS%{fCI(cZhhN zZ{(D(`j#-d`}Ra|0yREM1NwIH+4=P?x!{wPKNqUz+rGZt96uUi91*#VP^RPnwlWLYy68ya32&RSNz#WU#;!r-9QdWv}{H*c%{zs~8l3Nf4 zH$|;Q$n=Q3|2%3_)LpiZ@D-@R5t`o}Gw6~BhHwA9Jb}OKlevtE;hF;`<>?tn-SwJ;udb zJ~0u-S-YNCITNWk6JmtGdhK|8^QcTehjXv)`Ql4;c}H?EjwwQt+nAcI;j!9>$GWc; z2agluv&Kq1^4tT*o6q13sCV?`EwBSi1GYX}}i@*_)+1Qf4*&yy4 zkjt(q_JF*k^eZ)k<8KtILoWe#9jv(}P9{CjxiU%OI}q=jRQ>E(h7wC8Ajz7gXwK9_ z;Xr522_Fv5xwF_fcmtrGZk7nI+udV=8so!4bZfD(&E>BZvA zy7gmc*A{8k^$8~SQ9i|+b$_mr)gC?+cD-8+6uw;kVdWLIdx&kDC$o<|q=YHfnA5eU zWnI73(~bKE>7NH#5F0YvoB#-dR&TP;A+y+$b=?CkYq5)y2SN4Y{G|aWvL8#)*k`cD z>TiL6y6w&b26uCO6Dnhc{>2CZnU7vMVyT;Pg4er?)4fqf>zs<^yAq*9Z0T`YtSnvX zaR|13vmL>K8X$dyWID_?nl8<-Y@*ac#4F2<$xa31QI^&9%pASkgrE|=*1Y=r8;$GC zSAW(4ZF?;8>_lwTh=d9Iabb?iVxKMY3H)UiKX@W{2^4Q3qyq~}u7wcEb*N$wmY~UM zA>`i4WK?3iYThf{M7%3~n}d4ObL>i!A7Rfimf@L+@g&i5a789sK^ zjq0Q5_bTJ#JH^?J4FVef8T*kYMA#1rkQ9Q&qDC5czk)Xf`IxMb7y6c_!y;G58fw1@ zdEC8VQkE5p;#~FJ7-cfrK^1bh={9L`Ce!3!qKQKC}TOKdDS z=BtEpPFh*#;NE6B$M5^iXWK&Di?A~^9!m73;RJTUZJ+{Yd`*0+vuw_a-(*zB={y;H zA4X(8^T}r~7xlzaTSc(0-fxbdh_F+!Xd>^!n1Z!v3(F#0Mqx-RmNmH0B5%g%7hx;K z>NQuQdy$fZwunzy(ma?WJUM^=PjkUm@G?vFO zv6N>pZ?8iozVc)Ar|39?jc_QCc8?iHAg$k&uIieFSa)4C zWV2USsWf5BGL-?FwcC^ez1V*= zzy^dV-Z(ZZR~r7UZ3h_#?x5O0ZnDhS7B()!pMBEQmDnTud<`%Aar5bMMS^7~V7?=8XHtoi1!R+X1P2+-wnM^(odm&*Gul3X(Q3 zuB!(L%6qI26{UEUmTVNr-U^^jaYT!XQ&h$pvQgOwh*vnR@!|BzPm8Vi?H~S0q`d4n zq4;$OZ0NjbOPsivCoTzByjZrzi!&MO=EV%l)^^<{SnF&1!p36L)BfQ%V^55eZO>#A z4uL2)#8r3@w}NeU2~k_(L>%;LxxkhkailegxZIGYQ`^A-NSkm* zv5~g5>XrCIiGLD%406%^sy#>xqBddl&5PPFN92Y$o!SlwK-_gpi;cL|)oW_bs=XAB zwz*MTjR$c-)HbU))TSeCVgS+-oyA7lgvzxwXV)G89XU6oO~?^xhZi4dhXx>RLSM0w zwz`@_G&vQi)cJ6A(L1qXc(c|!eO*3J}UJCP9++_;Otn?---XF8?*tt2&Bjqkk zMp93qF4e9nXjc>36-K+3A>7@roj}h*bNcyg*GXT_)UHCc=%KOyH;)!odRoMuT5k8$ z)T}*qY9m_|`M1C9Tx3S?{Zo;9YD?wGiG9c3p7XR6^R!Fvsl(8&?SVbD*Du(v1yc?5 z)Z^`!3X_eS0t?eqH&*^^Y){RWoN2Gh(<1g%$nL4etUdLr`7tj4<+WgoOuiR)Og$1i zIdO7gr8t}=7jZT2X%~A+QQ$PYU75$!zt^*;j7#77^CI)RUwA)5y9(1&ld9gVd8;OO z+S?;Ti&Rfd&)OpE!9S*ZitqlODol$WiM?6#W=-yWRO@LGY3~a*?ae@o$oDey^ZTwy zp+(>MTnR=K-~BBrBtLJ7-fy=<1)*$;L>gVw3y!XbQ1M(-%5_KB=u+l5>2W-tcZeI80!A~#OzIx{`@uk`%W}C& zajg~OtA7-4%}!%Y0Kt zT^r-GJ@5}2Fa4dfpp3pK$bxcvj0?(N%XyC9(*4Yu7PZhpMtP`tf_`&$p3vU zxdB;jWwz|i%xdd07b90;j~$nmFTh(;?BC;ZCO12GAlyQEa#6WX)aEtf%TTxZnPE12 zAg9Q|n;z)JBbf`StQKQHs2@Dp9^>eSB2?Tp(m#8c-;wdgE!IXB_RHl={5!3B z?&Id>iyk64!jo&k8f!0JUS0`l8xZfX_=QK|Q~u)TkHge42siI=hFhLsFZ8+dd~2MzznBEzD@0;&&W;*HGLxQ>&>UwRvO_e)sN2DoGM*KyCvF@q7U2;i zTE_TOGvr~S|Y{5FiEc94BAp8pAB?hbn6gjd6LiTm@H3#Tt;oV23{5#V}a z6ezwZg7C4waqN!C;>X+_2jM&1j|qL9$UGG%k*LBth4&a^Sme<=xE5^~f1X6XjB7>fc|gn7;2)U9kUyb80x(Fbj&FC;t z3*^%mqch0}P4UzK^XZsThNUqpz7~*SQA^LKFGdH+2n`aNIr8b4(LqwYK|)j2XkY9e zvpUUwqkXY^^aV|{`Siu;k#?$#poazp+UlhoP0WFbdVHp zkZ>_ApS~C!BqKCPxRRMq$BYh=;tdk6DCg4`ql09G1__t^^XZt;K~lUyLbr{4`eJmD zjL;yVUrjz8Gdf6$H%RFFluuub4w4ZXBy>(2?U>zgk)1xeqaCvwc1%eg9fON@Ccgxq zpSTg7Oeab>Dos{Shy2B|;HHfoqvax;K2*v#it$1D=s%VzAM@}D%EyJ!O!-(RpP+nP z8yZeNngxfGkMiws@{yYjCm$^{!^uYxV>tP!U55d>VIW95FA2~6O+;&K9UW5-8uj_Whm z8=uM?+||Jl!mKV*oB&d0Y859LvbSs}HMTTnOwDrfl+th2Da~DzJ5JWby&)0QE^}9j z+?S`rWd6$$FVpb1+Gj7@VPaQwUA2g@MG9eTX+^CjT+r15rN(q?zWYDwqsm_s<<8F8~Dz) z9ivmkJKHgg?QhVPx_Afceh(hqL5%)LP>o{rKLPQQ(cgjZW%dn&cs2H^lQ#^`74bPT zdgM`zegn!-9kK_)gLg9(htXXbSy_2^?a`o9_aU|8v%*rG+YYx^H=7$Ps(rB3eg?4o zsGP9yN@+J(oV+5TLLye7r)^hPS+;O71s5`b8CTC$|41a0WGMBX;{08|7hqCB~qUIOyEG zE-^n0ExWLscYVfE-$D6m#t^T#TMJUFQG`p(#ToMBQOW77GJVG%caN#F--Yb!xg=Vb zKdOcNK{%CEP>s3Vkw2=+Or&xe}B;?sRiVb;NtE-O-2lfnga zI1(0d@F_wR4oU-XaMj`Y;ecHCJi&Eishd!~7YB^m+gI-SPq(m3HS2PX;(40U7Sd4wn|L<6w!+EMvo z;d#u1zb%Uk+3^CD@5RDF2;qI99XwbR>$v>&GaPswDq#A#Vm=Q?+`Tj}1$b+8t1l#|!A;%&Bd35k2^)R^e;tB{Y%kJIBM z7sI#~s(2MnHV@-Iaw5tBj3i1Si`f`;ZUXpV;ki|p8I6++V}tnICUULkff}yUZ2h+a_z%v=rsZD{eX{bm zwG{GVsRzjSJO`|vg%IfU1M7N|R`YDD*;;^$dfSrS1D)-ixVdF@gVo;EHan(S0Ty7~ zA;*HLhyY*0PYXtXW@|N>l$8!`ur3h?bo0>uvstfkFZ$cL1Mu@k4bZJRLY;Vv=4)L; zou9Y#_3Wuj&&PmHAWP>NAFTMNl?C{HHVGQtsDPA>&CHmH{J#DXf8?^G#;qVm(4UyI8jcx1A7x;hde&U6*Sbk$%@;*6xtSz^LU&rs~U1=FS+i%@pp z9Vh@NW#Jj#bmSgK{!aBXNoC@eof;IcI#rHr)#<9!*zDXojW=bfu{Xgt_U`<4vB%#2 z;j3dm8Y^#OSSRr89(z<*!5zEXTKd|o&i}1KF_On~mS%;b(39vti%In4FmbUKn3*1t$McriP$>26 z3V}0uyzP4P-7$kM|DjxLikZzHFNWV8_sg0If=_aRND0?byMD*MdDVNx7N~w$I%nLx z+NXu8*b7(`XCw8Iv+;YNb7hiz<3PM~uJfzyGSsbLNcv@JQXXj+k0{pbbaN^aC>)gg za8UI@v2pNh<)P+VHI2f;{-^-ct!;e~VJCF;EN|(u`d2OQALtwqx4m0+Eml{Hb=Zn} zaRc|7P8_%0mh9?W**O3wo&Hv=8^w9g8bb#+-QGURXT5vNTPtuTw=xz8e^ZWmSv zqpZ#jb)%KQ$e}zGT3^!8THzt>L8C2vUfP!ly^^=NJTqxu8F{Jd*)fyEM0utF(~ZjW z06h$Pu!*PVvl!+kE7sE53ja7Yk1>c(Y-JBFIbWv*`xC;d-iZs+`+8c%$|ebQD{5Ja ze-J8UILBIU8g*jHLovu|T=42J>1ul#RAvL6-OA+*vUw-3Ki+Li^2fW)5@gJ3f*{+L zdO0zaTmO#L`nS?IY>qBDFQXe|;rjZ*@Q%s_<66XZnO_6cUe>V}LgsWkH`804-QrUF zw!Y5QNyvwiq0qlAQ$NXYdh;pFu)N$bLt$TufK@hTydvOpd!3h;*Ttghqe`wx(Ellx zdW9f+mfTyRmk8#Qjg0+gA{$Mbs{rVY~)um&X8aO1oTxQBLi$hoikbnu_9!om;w0 zYL{gqK1b~md6afZNkw%?2;mm`q!otbgAqQ#FE;eh&^8@%(J|B63m%-sGsetx?5*k z`l9smRqgG`z6LJ5^$j$DU-zuSR|W-@K}t1^LBQ#5rB=#}(&eVLzjNtAq_HO1DI2(G zC$(0gvtn*f&)9WBZRK>Y5(|};0Um$^YgGxmd+4hp9|5UwYe6+obT5%E4!vNZ_mY0n zTvq(xX--gj<$ER-7_1KC86=kGl2tAhxXPyjSGiPRnV;n=E?ebNfvb$dmQBi4l0>1) zmQoB$k6;RL!>y~pnQ%r9=)k3`z*RyMQ1e}tPX(4C`V1(_cd5WKgi@4K4t}^)V2O8E z{BG2*Y@dT4iA^be4oz=#*mCl^`^AkDum4AtP{xAt4%Me_m?sGAE12E1GR_s}rUf^= zoFZL)l%bzx4k-=Eo|m~)-ISn%+T<>uj!AOFNOOy%HFx<;<1U}muv5NnX5p=KeB=mG z(kiD8o5LWEn85?&`3x}jRQBj+>M}>+ge)#I6ac%RE_2TtT*Y`%7+@9xEoxdf2?aV= zP3!B4!06>Ba38(ay!!hajqA);f7Ssr%vj{viP)$S36rvp3sX}l_C}MRVHM-KTenX^ zg~eONC z62zS~c@PBhD1z94GSmpIMtCrvD9&!5Uq!xU{By_1*E zvAGtv00oDLcX8|DtG$CG_x&WnO4tYJ3uP*e*zI@B#jpKMv28xLhbKkWmp&nEJ{^EX zDNK?vY!SOD=UMHYT}fr%ku#t7W-%GcxtkJ%+&RE78D1`m^O}iuQ+bK6?HxB1yY2gj zXT;*;q*G2Wo9=M}=CE9nT-gGz-&SjJ%Rnm-ByC)Ak=ly`8S2IX!*azzg%1Z?e^_iB za1>luRbN6YSSB2B0%~evyC>p}vZQ~pK!#G1149zcmHp3fciV~4kMN%|J~AhSXGP9L zy^&N3A!-a%+Bi^4HiJgjJs5YGK)K8gGAfW=`>@E}HG|_n+jjrE*6u1_y9a+(jCS9L zy=LcE{95$)*{I)5^OCwbCwbN`O6$*_f||cmKK=Ej+B` zTgDNU7mCH7`2s3^#bR^(A&_)u`sT#xxD9S8e)m8m8o>2Rb?LZPW2Mn%G#C~xVCq3= zn=uLZEcO{IjCz>Wco*XugbpBI2Xe{O^$5R6#99bx5jQnj#u>&UV?O>*HBK<*8O_*l zcZ#vV_yQa*oz#{naRBA75|FS~)|o`zOHs=zK%7J@!)K$0a=dloen{5bgBu{%Ayqr# zdjR!Pq~;xweTbci^bKja4=|2FdkH`D%fCLPWchul!7|2K3ykB9Ie_sbKt zr&a!%$Ll|(oaw}qKe+4P(-p7VHY9wUGoAc$4NjGhs4~tnPW)8yOU1K(sURu%^({-X zd^h|`T3H5cx@Rle6o?&pk_6YF-U~~|f`rY>eg`$G87T&hrsv7aD370Dwm-FV=R)%U zRJLAdy4%dc`3pW@{ZOJ>NUdX1?5DU@PR`fWxGb9@h%OMh| z`5@|>52~t{7h$HqGBU36irO!UC4q0S>pfClInZPAu{V2ZZd+>`gwwp$+0#1EB@E)L zdpg^!NiBUV8kG6l_SkB+*3O36yV;tw78|~hU^Z;oNCOKuHf*-`^sZal-q*8oDbD-o ztDCsCfl2D?Y5&$Y^)ZLs)h9i{>MUs?U(5Yt(yG2z`0U3nwqvY`Yi(=$+L&W6cPbs| zkyR4piEHcYnax`xw-E|6yYwb&0z!xs!??SVRtoMM!~+pP2?6&Yyu=r-hNRqzt$rnJ zcEnq|Bf`wi(nvJ?EeF37H%W_=j6=rJd`AMK63cveN;y1LIiJ(wm{u|kS%-Xg%7OX8 zRgMl1O;4&0$7JZ#DdCmn%6*MaxiYVeQ%t1-c+55+xX!4UN~w>j)V=R8m3{6cQ~Bhe zVlb6W6`v#?tF6OIVK7sH1e1Qe7uK&4F>aNA`BM*CO_%DE4JWE9q-{vI`#Q8LLqm&q6%YYfRobvo8)ks~j2h}1cI9R)>`o9v{v8GcU*_BRpBaO9%z^bx6n#3Bo@o-lMmg4sG#q3aH58(*G zb_phG|K?;b_<{YKj9y4?_HR;$pm+N>ClvN%KC2EJ0Y8tox}390mfOZ#Mf}@SS*H*} z40+VmnJ_p%_tJy?2o?tC1CILWD&Ac^j`Y0h@XFi)Z-mM<%CxrA)==J64{?V7`T^jP8D@K|B;*?c-? zj$n#~AK`Baepk41M@M*4@YoT%&z=){K7=$nRZwshRKL}jyF>iouSV1UAu0Hf9bBg~ zjJh3AhI|j_Fs{>hg$GWT`kc#xY0Xn}Zrqr*V>5o^Fo7MkoH3sN2|z+`u`rF={rF!F z^X~`~5+%EQ2x;`r2B=MVW(W$Q+^RnXyh52Gc&;4-cZkXKj|n>2ozo8f@;-r{TxK}= zD1QtmAKN^fd?e!R`Q8bKVX;^KMjU*)dkK|R$d`|O_n%L6_AKS2G;>|SDH!ErKqbI$T2Z!FqfoJ>l6ZNKWIVz+&Fb22IO;b7(| z#m2#5kyzyqcOxg0sEq^1$;3F5=DPpiolMGo?cThi80{WeCzEq9@hI+A;cMaijm2o8 z?qu?ckd5@!kInJ3!Qua!olGXdZA7|RNGA#9kYOQI{^>3x?l9?gu^Q`x$L^xL2usM< zVZ@y$Uzd@g+BWhoAO4=OFq_{Tp9>13G*^5F5U%989XMF6E2Nax8&^n~P&^@PN+%OU zXGkMgc$K4u+tI`CNaCy2-uR=};j6XG?QD`u8B%f8O2v{MTc_a6r3|?ite3Hes|s;}L!g&y^sx4}XRq6!*!N}~Y8%05Cow~~AvCd-GGZ&J_Qu-e$=a=2dk)_5r=hXeE z7<103BMW_JMjcrMOQmxPmlTz=3SLWTnG@y#ILM5&BMTjd6oaVsF^COcbr{6RII_f2 zpRrR)L_^4UA3~14!a>N$IHhDhUU6g`O#TGIRK&4|4;PES;^1Or985;uSwzPG?Q3pl zk(obtFfcOCA|sChm*WR90Pa;t#}C1DG{+Ay<}}9-A+>0ZAA%0;-;^5JEBQEn+=x7M z{P-5WvpIgO67fSjelQuAU5*jyodrvMxkW@7LpXlWM9ze97rmxG%n6vv(TOcVx_3X$rmv@@meeVB{e}y{2H6HPWWwl_eJ#H&>hw-(UAm!?LWf z6xtO0-I7l#4jC_RH*@VY1Qav{FM${Ne!!SA1)uaP*a48`HU+C~xP>qRN9^`HM&OTL zE4~qMApCU6sbc3*2U_d(b)@&zi0m}+c=9uDuk1gS51!7A)paL3aJK9hgD^rxSU%X7MtE&WL+6Enygb%gW1 z^x8ib^=B-8wnf{^7J$7K|L~Bv+#d2Y1u9EH4Y?hDNh?5&@O_WE;`epMQ>1r?Ai9*t zf;c5&sZJ}A@iIi}^EJj^u6UNHGj9cv+A~k<0_7M57q`vZrs&~aDc)ftt zODeQ5H8m0Y6Y(ZzMehb&8A^Q9Wt`2;ZzHOXgSZa|Gbgkbd7bRTl9HNRYd>2YJOv~w zHj(hLiM#hK2Ag;i)AYuQ9|$&aqUc1oHGL{NUv1{=fZs@~@nvjsq%C#@!h5ixunt=w zJMp&`n;mCiD_?zj8>WSrKE!mx7X4+U+sER@NN$wu!?wYFt$MN9&@%Yvw(fE(+PB8J2VT&Y*OmSxVJQ!utn4&DU z-RSEl7DMP6)s51#<6o0*ROK5Y zGuw(iM0PjbDCWb#rtae7;Ir3_-qv&@3IUwB9X2u8Qw%nt>qh5i(2bhXy3ql7$mwJyJg{7qI51Rmqxi)t26dV0!>aI+M1< zqx&6A1V1wP^6aW^be*U}=}x{wXY9po6)(?z&~-1j?j-GSDn3|uVvBRuojBtEx9d)S z56r6-B_a;0lz70I2B!&RR^gnPs>o`vCF)My_+C~f&#ol*D*L_Eok&4BuP7mp(w+46 zlTw6JQ&{3zKNgISILYi@+7B^+l_{7g%aTXYjQ7gfkXkcr_`+*10q;eqA)8GsyVSx*% zn{9A3j11-QJRGs|<`WuWP5jGGIm{%4-jg6*CJN$qgofG6AW51iUJw)OPsPc+OJUMm ziqqs512a5h%rG{NyGz8&9sBcnX7I7#?$CF` z?Tr9s?E5a>Ibr=Dd^bh32`eEdtVtq1$J4iwM@?9|X)AZsCjoL!j11fZYJ)y@rcii2#*UOLd(AO zio!{_L*9Co7ZD;)Mj}LbCQ>-(=U!4MI1vWaJo8y^&3+=JJIgL`Le#uF6X6s8^n}^8 zX54{ACBkoj(A1PJC|<$*C!V^d(yv9!~LI z!JIn;c~pn!6GRB%nYhB*-*aqI;@c@cGZpu$i75!y49o?CF*nX*=e=9JhwFFc5S3~0i-C= zN?!x1n&rPl65h7rY3*p~vnHu(<*!NhrIqpoYzvoH4%jzWHdrbj!{k+w)H8^xxqbr2>nfLabT3_z9H`@acTc^O{k(fEu@#dKZCumb-<84#01l)N*G;a;zX$HJiYzGbIj$%otAWp z2Bhjf?#cEm@=iHcV57T7H3_$H@)}MF@DSIM`blbcxtml#mZr?1E+|#BrwC8rf?XVN zKk3&nt3Dy-VH3QtI(;XpfnUM*la`9fSihf?Az+H&g`Cd$%YEk~LnwC1`wRJttX8@P z=8~68J18%~ck0EDGIA@YYQO8H)^U7ciS8n+05m0x^pN46Ry^m%qy{|m+x*H)3D7>8KgXi9x|69*PIl7m?oEY zxa)BaZ%{4w!|HF3yNt0p!0N}R8)t4fP@s0xEg>6$uLIU?PD5_dWVj8=YDl_cQ=o4x63~xeO5fx4KtJ;4cBg3k;keie&y!H zZW@)NS@Ds~{p{vfOylMO?(*HUsJr~ke9B$EpC7vUxpPPjX_?AD`|DrOg;Lv~uJaXy zC|#!vx(-=Lu{AGwdF&gJUzXleHZMvjJ^>WUlcL;)!ttcIvpiYkZB~mbzZhB<`E@0= zvR=TVv@+5WwK9Isn{&n-lRq9uLeZvCU7?9v)Gw*W*F&iHfW}f$Rmn zt9fk6&eAK&KEz(sNb1i3PtilA4TV?tee;{S>b|n4|F){xJhAjXasS@;1Ont{E{T^d zagM>JCJXv2ZYk;>z-G?&uAY_wBKssn$+co8u7==2baD{#qB1;X?hqvcxYCr$ib5iX zbVQNEo&~tOg(wIkNTHxA00p;Qn;#1Hiyc++Qq?yE3T|b!_LWl-vMq7?(`q#(9i6>P2ZTncP(gkwLC%B`K5EYX8WQe>2U7><+OIk;_^shXut7io?++#r>2c^Ti zI=fe`RWTOvbRO~_iT_|c$@xIXlOt!_WF<&O5m6B4q}5B+&Lm@KgjeQehDdB=K02&Q!%f_Wo9NvRZk||9+|2k= zF>upVLfkAC+lwz`<6OAeOoJe{hW273Chv#b*Rt@&O`}PK%X{!RhBD(s#^^XrNDz1EB%O*c%hV& z880$M#|uNU;e}2%3NN%)Q$BIV(cKR@c=>80@$%S)V&LVa((^$pZ{pa$m{@uA;)Q&9 zAB*>{a#L{dVQeAd)%0Z&V<0^> zgRf_y(aXghl-HV9e}AKKo%!m|I*e`RSmfa`)6jXs)JBfOENEh@b4jWRzx4Z*1UJ); z)e$3DJ61l`K)MM9}V z@%@_a=p2=cE!)r`oLuWrhFUbitLssVCI<3QtYrGbA?m1(jUb#uL3ONJmPnZGIW9{` z(d@-=Tj-67Pla6auR?xxi)NpqU8Bnp7G$yit;-Q)>UTh8By#}0Lg=OuTN*5Q;U0(( zqz`JuI~~j`LMop>Fe(x@lmCRJIpxJ+CwtJN0_u^46>O2?Yhx z4o9pQv|{#Hq|F{B0kg;2+I(k^uT-t6Ss+enc`L*0@ieL*UCy*ut#ey5#}Yp7#}zkA z2QOJS&?q2RY{g~MSblV`^XI&rsqTzc>%9#_t!Mrgl=qaNDm4{I5({3>ltc`A%z2V1 zG=t4np3cB@W|@uoW-D)38MCzE3u8>i85TDV0BuOj6FRLeEpvJkII9Wgnf?1G*-68d3p>l+^c|?^5%rdlaUA!o{0!+I*Lw&0X0A9tGVDrh?;k2BIMr6#+zGS{LF}Oj{qWk zO`neM9|k8xo{U6@@JvKFYoO>v7*KO!6>FxAUu~T!I1!@e-I)kE9XC$=f9;(IU=!v0 z$6uCh1hg(xLZJV05EK%!1R75~TtEjm5!aYzF2VxXl z;6kg#g{!C_h?@WBdG9X0Bv)udq2c$>rJvk;@4e%>=f3ZoTYc}9kvma@<@K6z3|2>N zs3(Wt1ULq4tOr9`NLc+83cHO3u*b#?r8U3(AZ_I&t%G)jtwYADBm^~+}ywrZ(o){@E1?IVb{YLQT} zIwEaogv=V)>e|@wl{zo(ea3;2b+Pd%N9t-^-jc9&yA5YD86!ALnr)nrU{&Sf`*cbU zH@>dxwy@G0Uy&yy#l^)GsML$4Whyn5U(b>fRT7YWHFLjC#LJK&+<#=Me8>>}yoxf0 z49Vjkd*}S}=23gAaE;I+9W|ot|McBG291!%Q6t3Hv_^(SYs9R@StI}S9~QGlq^_7X zf>rUX5kDGHQ#vn<)JWY*G_uI9k%=*AgglNKA$}KV#H__xBkM|QNh4Sl&l;JHM$(_X zdP}56(dWJ?_6shT$Dk4NIBJCWn%0Pn7!q;rYu4hdk?yZYj!shbb6;b0 zk{Hi@v1)hJh;ffBS|e`z?TO_vXoNhD8X>->HR5nQV%FlU5w)_Gjz_R6o;5O>i*x0@ zUKkj8ULzN_oqlUp*){TK3>qPiqeh6YX^nWI`w_DiXN}b7-`~Qo*HyhAk-B33t--2z z*GOspt5F&;-hLF_kCfUqvN;BgkjGIY#MiV&v) z!K&R+BgU=pXpNNHHS$jk8X=FPMu^`98Zm2e)=23EwWJZO+8s4wjB*#Pkrex#YA&M4 zo$6}cuOW}4Mu^`98Zm2e*2r^1YDptlwL5C0X(h)a?d=-j{~fEX5%M@{g!r1)h{OFF zvleHKjJl$huCroQJZmIFZYWQ2t%y8kHO3T=?nlPiHNrtlwKYN>M~x6)(;9I&_cd#A z*2wh5wRG-_Rq?EmTr`sY-_6%VYQ%UdDq17?c8!pz+8QB`qeh6YX^l7>vzoOyYh;$M zmVRrnYIo5{YaV&9o*!}Berx2#L-PE{BIYR#Y|oGMGBnajudm|sBjm9(lEtB#^<+m~ z;zc8od(Zj#k?_}UZu=<`<0{E~TV3_cx(axT~N&$Q1v#7P}iEjv*c*b~pX7{;5E)0aKlRDNsh zx;PTEopkZIT^Bhq=z=_sx*)#hbTM9E841&cS$?E0QcfHn^K~<+CFbj9*b~pX7>+LH zG=AuJ|DT}+Qb7vyo&1@Sef3*!hiOc!SPk-BJoR4pBwVoyBlVwAjTy}|K} z${yZdw5~)KZu14``hS=BVUc6gYW8V$cYA z95q6GO>4wB5)J!b2(y+*jdc9f=}5FX8rh-aQLKt*jZ}6#+TNxS`}u2k+n8GQzKG%X zg*=uibueskB<3DA>jz`V%EBYy;2Wi`{mi|Wud*WFaofy<@&X=ldVo*1(}lx%idlZ7E{5FZ^vhDU>l!=sn}R*@tcw?Au)n7Lw?^th z2CH?tu2F8+MI&PjzG|JPkjGIM#MhiI9L`hB@*{PTe{?OKr(jP!>tZXqXn#)c>mqfL zT8S=HvhBJ#7s#r8{z@K4T@b%hbzzntsf*&twWJH|*&TJ!u@YUR*mbdg47wnXqb`WA zIbDp5K7TdKkJLp@6+ze+7JpTA;H-0LFHH>$rlp%PuV?YcN923?THQ5VGTR9%?m zN9tlqw_4H#_Uw+jFkYw_ecajJt_x0btNlAd9!FgeUvs)Jo;nUYA2G|1)J6V^T6*3X zd*WReDNhcL>MxA3pQClr-L4CEWVLlc9!FgeUvs)Jp4tf0g;{>2E>@jcOV4Y_#x|-L z>-rM<=ZZnhYkw>UIqr1QMW;%BNAm5u=o*7A$m6IB;%iP94#yW}`H{K^Y^tT-5$uU) zU8FwuR-MwH&wMQMe57+Fx+u2mqI(RwAdjOih_5+a82>35)?b+AN9tnT+oNMX?%bjO zk;I<3*TsA3QM%|-i7ra*x)>gVF397k3*u`|7Y_H+%!iqx}TQfvR%K(GIY^audm|$H1b%w2)my~yy&80zwP+_G(#O> z_e#uKBJY*-n&PC6>f9^Yp?j`a70()}>>5{Bn?~lC8j;5e+S@gf6GPuY9!n!(_ezMb zxxT~U+NW85g$9j#CF`E7rE6T+6VJL>PTw)^?EUVFJk~g+5?yq+>mok}U69977sS_` zE*$QanB_<6BIV0kx>tfdaj%Qz2Sn-O)Jk+Q&aR8;G3bIkj=CVe=5*0C`r4;iexxqi z?$W1V(N`460r7V4-{PO5oz+TVMqaeF4IZ(Ag((+@~e zefDyx3!5dWU)m(8b5mUE(qTy|B|S;qH#JG!ygo_o*)>`1qsA%E2gz#ozAm+Rf0tU_ z#HIc|$fXWD#H9{aZq@Tpms)sJk~&hgSL)Mb_3R!l^=de0hp>VqR)yudMEZEEFGHw;QrO^EPm}Whp9mQnEUW`FkB*YKZEt);yZ5zB`fp_a>=Pg~@6J`Ty(WQcX^F zsWGe%+?1?-c`;eF>*i8}PIaj)<*u{hh$JbD-rg?ta$mOpbeH<|OqbeY06s`}smW~HiGy5fzz~;Oa89zC zuI4E3Fqis$agzEoJ6T;c+@;okl&tO?=~6F@aw*@MWc9%qc|pU*y_@kZeR#SarPSph^Tf0>Jn&zT|KhGg3yzq?CVq6%$(?vH!$jTQcs3|>J)2P%FXpfROQs($_YDmgh>HEPsI?X%B5 zs!5Y3s#&vUs%6WTs!f|VYUt3Rs(=6fs%Ouhs&nVgDmcAZ1=G{jYIVH|{2Wxjt$tH| z|NUz9$OCg!D)o6mMopLfB@wCMg%Sur5F}A5c%cLW5Cq96gT{J|fn(*ZXetO&SSoly zMw1OdP?phO2?T%?`s3xh1OgBQF(4JZPyzu6f*6$wUMPV81VIc<1uv990D>UKr-Bzs zAOJx~WrMs>0s#mDg;TRve@gfcKoDf3Q^5-*5P%?vBT~T&B@h5{Oe%Px1OgBQaaJmn zKmdXu&P#<72tbe;1AObzcX6nE0^(fp49ldX?h;ZEhqF_`E9saAAV@fsk$b%|dM^YZ z2(m*`!K>>ho^a6INvZ58FX0mA0SKBq4$o*05UW43gHzd=UMPV81VMIgDtM{Cgn0mh zgk^`Pf)`3406`EDq=FYpAOJz&3ttdV{Uyu;5R^D-7tdgs7E@{}djv`#06`EzrGl5b zOPB{BNSK1Kfp{o^00e=;v4MCffdB*{HAozFmM{-MQ1-3t7x3ybWqnZHqgtr3W5=q= zlP9YgGiIm-3l^w%-g!qYUc6YXS+hp1UAtD5m6fUW>({Fd8#buTn>VZA)^fFI(cLuT zV%ZY5mp?N=O@#G=8bc4Tzq(ZS79Hso>XS5y-bVV69u3`iV~ScN`PHhrOQpk6tzi*J zcUVXF!321HuJcq(Pr@3k&@;XXhI*Fr757%VXDOZ@RO#tK`jyox_;WzLx%xM?`up$I zoChAEBBND_f^oaCD6Lpp4~k+p09(!?yA=qCdSvh6ah*+Cv9usjvM5OJK`D-SX+@%B zQ4o7jS`@n&L^%|#KeRFm5+%{jQ8Dp+NsE?NC8`!xX_K%)TC}t*QMIT_n~4q5s-<;_ zszp`Wbm>X3L0XrnT2v)Hi?nKKS)ypID%m`0M@M{&mL;mzn~W{evq(#p)+OrJZeXSK zEYh+>+1f4GAw7$nYblip2QlPH?D#79~p?xP;#!!mYB?@B7& zs-=}_S5vq2bkeg(tCrR#y{hzR(z8g5mKLRVhpwA==|!ktT9oV}=~<<>lb%Idv~E>W zpWYMnc!b0<*}c-cORp-uoAfNwvh}VNJMe+@Zql>p)-Ai6OwzMT4<|i~v}`Q_Y?0no zdN}D>q-FC5l*2xe9!`1|Y2EA@*#ol0)Q4oSL3(xRMWttxo<++E8>DBKUQK!x-Mfgy zut9ou>0za3lb(g5fp~0?9#(ob=~?90MfdR3FTI-dCepJ=Zz8=+kY(v*TF|#tw`VEe z8dP^LTBLgxYS(`hCLxe=nagrwN_ZgQfrJMlJx`kFl(3E*E-0D2_Nt! zAwB5@Sq!a~m6FDa(Se=sIkP%3Pos@6jWsONHpyyZm65?ry-Vyf9Hwg&TZ~2d)|TmS z!*fQIw$xa?^UagWtXib{=*gBKa-~!9$TT~?yq#LMVc(9|ohTvUfrJMV9!Pi~;eq(} zKuw<58Yj>Cyjh<$a|&&oM;j;6<~g-KrM4&1YpvMOnYWpzM(vZ6dOfjEOk;JFEa|g- z9jTWj!b((;#HX?Lp6V$XGVN&9%A&iZ)V9GP8tjSrfgE zY`PF#tzIye#XgzB)*9x! zXE8FGxh1vE!k1~JwP??*jkiZ6!U+#l-ve4ubx1pnC0`;> z!UH?a1G`L-TKz^VrJ2evm+|wbL)I^>5i9H2U?YuACt>}O_?-Q+ zb=0o)hBVRek71<|C#xi+Ewz&EN&_w5NoQtZ7^Bx{`^4|u^ubP{aNWN1&5YKAq#FW;l(}-y|FI%=#oe*Q; zVxQ{N>Dy_`mc&@XPRq6=xFn6&FYrmzFq0{_;*(1_G|kHmedZAgO)t$0eUb=8O~IEO zKS5#*WCJA}HDMsr{7!0Xr)ksTZTFhS&7VI%PW2}S&R;Trep!6#Pw(3KW%J9*EdSMN z1BveA@E%iHS>L$OUzB}%*Ya3=-@f;y-S_mOPS%?K`_Ay66v9+dyxl$>w${nqNFB;!dbz?R zGp$jY@oi-?>e1g@wkYLx+akh(75TtpiU|emx$I%3wruHJCJMxha>7^1lvWXM+dzu9YOv-N=?EE-WC-_3 zD3cC2=Cq1&D?Hby4AYoz!#*p0_?)7*S$btFD~k^=U6y3WZYdKFY8~Rh%6%A}d*{cv zF;J;8RVIeI-Oa0O-nO>Jc2ZvD4YB8u-HClf^~HmIr5(GsTTp~S4vQ60)z%BON91ug z7r$-kgOPohH?NX?l%b7~jg|7Oxgic?l~g6E^g1b30@jzTBdk*pFAF-o%q3)-a3Fpw zBM}~~n*WS)r3@*Wk6FH1xL!2U=oPl0P9e*ofX;2?H_DQg_6g022T@=jF)(7SJ*5$r zvZN$!MaV*<)KJY*y_H5MG?pup>jXLl1zAOf@`Tmuri+n2kTxu*Wnt?a7D5{!0bR7r zOvFr`z?w?|5}~oy*fLtFr67AA$!AT?b>G*gER7fWrB&TNE4yv3>(I;E6x*7p$jAhh z87CR_58D>Z!+()w#>KL7H+Ki|T@~C{8}@2no0kM?qy8$@sph2xw=2FXl~l`#%!3hq zNMalx$TtTl#?hN`#9&5gQ}w}sPGB6aNIHqL(&&=5yHSx1s7UaMVKjd@*Vx!Zds8DShk|9c_?B>jd9A)Mu+NgTu-Du zfh~C`Iuvj!AP(Z<-M%<*QNo0T2NE7gcp%|{ga;BHNO&OOfrJMV9!Pkg8XnMt<;nHy z|M%0j#(%B*@w*={Y<@4tltV+<3{tifz8^Cg7q*GSF_&>-4`SYk`FjkzErX`6 zqcUrJ*d8)+>%@!+9(Sobr`3;{{){}mPSVTxu0oJGBC z&A&UKp|($!#ZH+b=Z9hVam34Z_wZ+D(ePz%yApVMunar$Cn6gUFDl9haG#Rg^dJ`1ZP_o;jYptOACI zwhfM(ZVZm=c6)t(cR{`LY-6DlY> z%afrFF>98EF7D76!KNE@J%e-8`$evD_shteP=r|2K@=cc=q<|0aTkP*F>DMwOm266 zwudblKh+2*H+j;0d6|Asp$A!IdE7_28FDz=%kC?1w?6*34l>;LHq&&FG-7;zPhrNS z4D^D33-oR(#2SAQ8`@S@7v&UY(nxG^8inQ7*=4Ju}%L<1L^Pc zd)%HW8KQ*(y}!a@y0|B?Ykgyj3OxQyU;fl8q|gI8+e_`@X1wUk^Tzr;6Og&u-g?=( z(|nWNSw6g&UFe?d^PlHFRkwH1@1*PkDMgyUXdtIZFG}w;f(DGMv-4!Vbcgn~l-eOW zDm6N)V|3IBT89IXh2Je&c6&V;g++e6CBtHec}rSKT5sKs(=+^qbV4*qM$1+Qka9@I z6knb%cd8`nt(8X7M)X?JV@ZRQ5xUcTIW*b=H$6g5cEOKSBK@ND;gUj%>F>+>A%|uy z%13DV(sk%W^vybvZc*8V7)TYp8Bl4oHxsPdxr9>srsD)wPVyXp9!Pi~;emt)5*|o+ zAmM?82NE7gcp%|{ga;BHh}i>j+eYrC%Y7cXch9YLeMd;{`N+Ay+^?5=^>V{Y?xp|7 zQx?}4NiwM;7sTT{b2wMgmgFy2Ekw$0z+XKoDIWa z1dN1pU=)moF)$X!K?aP6OvnNccwqueglsq$&VwAtg*@;Up)Z@`=I7A%LiVFkPc0eBbQgO#uf-iHt1L-+_j zhSjhJK7mi+Gx!|7fVJ=?d;wD4ejx8}J^-4)fgsQ891Kn25Rmse9}0&-b8tfoXbFeI5pX0N1+Abpw1K1H7-$Q} zLOVDP+QaeC0aBqOoB$`nNze&8Ll-z1xdB60cS!# z=nn&6Af&@tFbD?25Eu%>;A|KUBVZ()1EXLxjDfK*4l-aoWI`5rzzY*#B4oq4a3179 zF64m^^5J~&Lje>*5ln)~Fa@Td7FYzJPXgk^Y8+^2rt1Bco|-SrSK}e2Fu`ecmv*qw_rKE z4J+Us2*A7W9;}2_@IHJ1AHqlQF|39)@CkehpTXzw1+0ZH;VUSGui+aggLUvNd5DFW4JWU?12Q_JjT50B8aS!a;B_G=)Q;85|0SL340J3up<4 z!x3;K90jeQHMD`F;TUKO$3i2L;|3H_iy41j@<4rjq27z{&TC=7$MVK|I{k#G)-g3&Mr#=ORLOn`}y4d=pnkOR4p2R_J$^T7`VPzXgZ2`0l7m&xE|)i4X^-igqxrQZiZW6A>0bL!R@dJ z?tnYtF1Q=+fqUUTxE~&X2jL-j7#@K~;W2m|o`A*hBs>LA!!z(KJO|Ii3-BVm1WVv$ zcm~;wD4ey~3r08QXPI0z1g zrf>)}gG1pkXbx^@0WINhI0BA@qo5VEhBk0C90P6PSZD{wL3=nJIzTFPgcIOII0-sI zXXpYaLs#eqr@*Pu9eO}dNP}L`8~Q+BI1NsRGvG|<2mN6H41{zz3kJbp7y?6K7@Q5m zVFZkXb6^yVhA}V}#z6**hfK%<4|rh$OoVJW7tVtm$b~%cK|Y)hekg!KD1u2a8K%Hg zmMf{URTE`dwoGPoSBfEjQl%!I4pYPbew!L=|Ou7f!+7v{nBFduG!1#lzW z1SN1Y+yV>XR=5prhedD)+zEHV-Ea@w3-`hO@Blmr55dFm2s{dp!Q=1*EQTlHDR>&5 zfoI`4cphGW7vUvX0x!cWuoPZ}*I*gE4sXDl@D?nGw_ydm0|9s!-h-8}3f_kg;6wNb zK8Dq>20npL;WPLgzJRsxC42>?@HKn`Wv~vuh40{d_yK-|_3#t?48Opy@EerF2KXKR zfInd)Y=XaFGi-ssVJrLt|H6L|1XZ8*4|Sm))Q1MJ2P8o;-#63hV>> z!hWzn8~{z=KsX2vhNf@`G=oFoFlY{LXaOzZa5w^vgrlGpw1zftG#mqM;aF$~$3c5I z9y&lObc7S&L^ugLL1*X!Cqq~02B*NO&>ea}Pe_Aa&>Q+dUpNg;hcnE{JVHlhZ!(jxBgmYjNjD|5V7REsajE79f0uOj$0!)N#I2X=?9LR+{@IgMD z4}K_sLMVbsFd3%6RG0=Az;w6}E`p1p7%qWJ;WD@!u7DYECCr4Y;A*%AX2G>E8?J*n zFc;>*^)Mf9fCX?P+yo_XGu#3T;a0c}Zihv12iysF!QF5V+za=?{qO)h2oJ%-@CZB# zkHO>c1T2Op;VF0;o`GlKId~pkfEVE)>1X4!(yU;71T! ze`5YK`~ttiZ%_^!K-T}k{7={jo8T|l3|m0f|62|AXkg?aOJe#T_rM^oB>K2==;q32 z9&>rpt2$E?)u4{$BKb*4x%QH*TL!M&XU2Li+dbb#E@4GYqDLz-ohzJ~)LTT&9(@(l zT2r<8zN&7hezBu!x#%knGE%1Lnx$^pdN(-G|Y0C#y$@n{M()dR= zes8&QT*Ot~TxC3EcRF@>*&}`(Q;2tb`g(6=<+i4NIh3c#Y8xs`XODk{`u`bX#H3UH zWWB`_$~L{wi*Tm4%kYamcX(Lpx3;~i{%=eX5AvL$Obt|IUDfkPC+Zh>S~loHxAV2$ Z=Kt*^t +;; Padioleau Yoann (modifying the ediff layout) +;; Version: 0.1 +;; Keywords: coccinelle patch refactoring program transformation +;; URL: http://www.emn.fr/x-info/coccinelle/ + + +;;; Ediff and dired support + +;; You must modify the variables `cocci-spatch-path', +;; `cocci-isofile-path', and `cocci-spatch-args' according to your setup. + +;; Once it is installed you use it by loading a .cocci file (called the +;; SP), e.g., 'coccinelle/tests/rule17.cocci'. From the buffer containing +;; the SP you then press `C-cd' (or `M-x cocci-directory') and specify +;; the directory where your target C files are located, e.g., +;; 'coccinelle/tests/rule17/', pick one of the listed C files (place the +;; cursor on it) and press `E' (or `M-x cocci-ediff-merge'). This will +;; then run spatch and apply the SP to the chosen C file; when spatch +;; finishes Ediff will start in a merge session, displaying the original +;; C file, the spatch'ed file and the result of merging those two. You +;; can now use Ediff for merging as usual. When you quit Ediff you will +;; be asked whether or not to replace the original file with the result +;; of the merge. + + +(require 'dired) +(require 'dired-x) +(require 'ediff) + +(require 'cocci-mode) + +;-------------------------------------------------- +; Defaults +;-------------------------------------------------- + +(defvar cocci-spatch-path "~/coccinelle/spatch") +(defvar cocci-isofile-path "~/coccinelle/standard.iso") +(defvar cocci-spatch-args + "-no_show_ctl_text -no_show_transinfo -no_parse_error_msg -no_show_misc") +(defvar cocci-spatch-default-output "/tmp/output.c") +(defvar cocci-save-merge-result nil + "Determines if the result of merging files should be saved.") + + +;-------------------------------------------------- +; Key map for Dired under Cocci +;-------------------------------------------------- +(defvar cocci-dired-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "N" 'dired-next-marked-file) + (define-key map "P" 'dired-prev-marked-file) + (define-key map "c" 'cocci-dired-compile-makeok) + (define-key map "\C-c" 'cocci-dired-compile-makeok) + (define-key map "\C-r" 'cocci-dired-run-spatch) + (define-key map "r" 'cocci-dired-compile-spatch) + (define-key map "v" 'cocci-dired-view-file) + (define-key map "V" 'cocci-dired-view-corresponding-file) + (define-key map [(control return)] 'cocci-dired-view-corresponding-file) + (define-key map "*c" 'cocci-dired-mark-c-files) + (define-key map "*C" 'cocci-dired-mark-cocci-files) + (define-key map "*o" 'cocci-dired-mark-ok-files) + (define-key map "*r" 'cocci-dired-mark-expected-files) + (define-key map "*f" 'cocci-dired-mark-failed-files) + (define-key map "T" 'cocci-dired-toggle-terse-mode) + (define-key map "E" 'cocci-ediff-merge) + (define-key map "D" 'cocci-ediff-diff) + map) + "Keymap used for cocci bindings in `dired-mode'.") + + +;-------------------------------------------------- +; Internal Variables +;-------------------------------------------------- + +(defvar cocci-current-cocci nil + "The current cocci-file") + +(defvar cocci-spatch-output nil + "The buffer for spatch output") + +(defvar cocci-current-cocci-buffer nil + "The current cocci-filebuffer") + +;-------------------------------------------------- +; Misc helpers +;-------------------------------------------------- + +(defun get-spatch-output-buffer () + (if (buffer-live-p cocci-spatch-output) + cocci-spatch-output + (setq cocci-spatch-output (generate-new-buffer "*Spatch Output*")))) + + +;-------------------------------------------------- +; Shell Commands +;-------------------------------------------------- +(defun cocci-spatch-cmd (sp) + "Assembles command line for spatch" + (concat cocci-spatch-path + " -iso_file " cocci-isofile-path +; " -compare_with_expected" + " -cocci_file " sp + " " cocci-spatch-args)) + +(defun cocci-makeok-cmd (sp) + "Assembles command line for make ok" + (concat "make " + " ISOFILE=\"-iso_file " cocci-isofile-path "\"" + " SP=" sp + " ARGS=\"" cocci-spatch-args "\"")) + + +;-------------------------------------------------- +; Misc. +;-------------------------------------------------- +(defun cocci-convert-ends (from to files) + "Convert files (in files) from ending in from to ending to" + (mapcar (lambda (f) + (if (string-match (concat from "$") f) + (replace-match to t t f) + f)) + files)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cocci-ediff-windows) +(defvar cocci-ediff-result) +(defvar ediff-buffer-A) +(defvar ediff-buffer-B) +(defvar ediff-buffer-C) + +(defvar ediff-show-sp t) + +(defun cocci-merge-files (orig-file new-file &optional name-A name-B) + "Invoke ediff to review application of SP and manually perform merge." + (interactive) + (let* ((found nil)) + (save-excursion + + ;; Set-up + (let ((config (current-window-configuration)) + (ediff-default-variant 'default-B) + (ediff-keep-variants t)) + + ;; Fire up ediff. + + (set-buffer (ediff-merge-files orig-file new-file)) + + + ;; Ediff is now set up, and we are in the control buffer. + ;; Do a few further adjustments and take precautions for exit. + + (make-local-variable 'cocci-ediff-orig) + (setq cocci-ediff-orig orig-file) + + (make-local-variable 'cocci-ediff-windows) + (setq cocci-ediff-windows config) +; (make-local-variable 'cocci-ediff-result) +; (setq cocci-ediff-result result-buffer) + (make-local-variable 'ediff-quit-hook) + (setq ediff-quit-hook + (lambda () + (let ((buffer-A ediff-buffer-A) + (buffer-B ediff-buffer-B) + (buffer-C ediff-buffer-C) +; (result cocci-ediff-result) + (windows cocci-ediff-windows) + (original cocci-ediff-orig)) + (ediff-cleanup-mess) +; (ediff-janitor) +; (set-buffer result) +; (erase-buffer) +; (insert-buffer buffer-C) + (kill-buffer buffer-A) + (kill-buffer buffer-B) + (when cocci-save-merge-result + (switch-to-buffer buffer-C) + (delete-other-windows) + (ediff-write-merge-buffer-and-maybe-kill buffer-C original)) +; (kill-buffer buffer-C) + (set-window-configuration windows) + (message "Merge resolved; you may save the buffer")))) + (message "Please resolve merge now; exit ediff when done") + nil)))) + + +; pad's code +; merge between ediff-setup-windows-plain-compare and +; ediff-setup-windows-plain from 'ediff-wind.el' +(defun cocci-ediff-setup-windows-plain (buf-A buf-B buf-C control-buffer) + (ediff-with-current-buffer control-buffer + (setq ediff-multiframe nil)) + + (ediff-destroy-control-frame control-buffer) + (let ((window-min-height 1) + split-window-function wind-width-or-height + three-way-comparison + wind-A-start wind-B-start wind-A wind-B wind-C) + (ediff-with-current-buffer control-buffer + (setq wind-A-start (ediff-overlay-start + (ediff-get-value-according-to-buffer-type + 'A ediff-narrow-bounds)) + wind-B-start (ediff-overlay-start + (ediff-get-value-according-to-buffer-type + 'B ediff-narrow-bounds)) + ;; this lets us have local versions of ediff-split-window-function + split-window-function ediff-split-window-function + three-way-comparison ediff-3way-comparison-job)) + (delete-other-windows) + (split-window-vertically) + (ediff-select-lowest-window) + + ;NEW + (setq lowest-wind (selected-window)) + + (ediff-setup-control-buffer control-buffer) + + ;; go to the upper window and split it betw A, B, and possibly C + (other-window 1) + + ;NEW + (split-window-vertically) + (setq this-wind (selected-window)) + (other-window 1) + (switch-to-buffer cocci-current-cocci-buffer) + (select-window this-wind) + + (switch-to-buffer buf-A) + (setq wind-A (selected-window)) + + (if three-way-comparison + (setq wind-width-or-height + (/ (if (eq split-window-function 'split-window-vertically) + (window-height wind-A) + (window-width wind-A)) + 3))) + + ;; XEmacs used to have a lot of trouble with display + ;; It did't set things right unless we told it to sit still + ;; 19.12 seems ok. + ;;(if ediff-xemacs-p (sit-for 0)) + +; (funcall split-window-function wind-width-or-height) + (split-window-horizontally) + + (if (eq (selected-window) wind-A) + (other-window 1)) + (switch-to-buffer buf-B) + (setq wind-B (selected-window)) + + (if three-way-comparison + (progn + (funcall split-window-function) ; equally + (if (eq (selected-window) wind-B) + (other-window 1)) + (switch-to-buffer buf-C) + (setq wind-C (selected-window)))) + + (ediff-with-current-buffer control-buffer + (setq ediff-window-A wind-A + ediff-window-B wind-B + ediff-window-C wind-C)) + + ;; It is unlikely that we will want to implement 3way window comparison. + ;; So, only buffers A and B are used here. + (if ediff-windows-job + (progn + (set-window-start wind-A wind-A-start) + (set-window-start wind-B wind-B-start))) + + (ediff-select-lowest-window) + (ediff-setup-control-buffer control-buffer) + )) + + + +(defvar old-ediff-setup-function ediff-window-setup-function) + +; pad's code, almost copy paste of rene's cocci-merge-files +(defun cocci-diff-files (orig-file new-file &optional name-A name-B) + "Invoke ediff to review application of SP and manually perform merge." + (interactive) + (let* ((found nil)) + (save-excursion + + ;; Set-up + (let ((config (current-window-configuration)) + (ediff-default-variant 'default-B) + (ediff-keep-variants t) + ) + + ;; Fire up ediff. + + + + ;NEW, use ediff-files + (setq ediff-window-setup-function 'cocci-ediff-setup-windows-plain) + + (set-buffer (ediff-files orig-file new-file)) + + + ;; Ediff is now set up, and we are in the control buffer. + ;; Do a few further adjustments and take precautions for exit. + + (make-local-variable 'cocci-ediff-orig) + (setq cocci-ediff-orig orig-file) + + (make-local-variable 'cocci-ediff-windows) + (setq cocci-ediff-windows config) +; (make-local-variable 'cocci-ediff-result) +; (setq cocci-ediff-result result-buffer) + (make-local-variable 'ediff-quit-hook) + (setq ediff-quit-hook + (lambda () + (let ((buffer-A ediff-buffer-A) + (buffer-B ediff-buffer-B) + (buffer-C ediff-buffer-C) +; (result cocci-ediff-result) + (windows cocci-ediff-windows) + (original cocci-ediff-orig)) + (ediff-cleanup-mess) +; (ediff-janitor) +; (set-buffer result) +; (erase-buffer) +; (insert-buffer buffer-C) + (kill-buffer buffer-A) + (kill-buffer buffer-B) + + (setq ediff-window-setup-function old-ediff-setup-function) + + (when cocci-save-merge-result + (switch-to-buffer buffer-C) + (delete-other-windows) + (ediff-write-merge-buffer-and-maybe-kill buffer-C original)) +; (kill-buffer buffer-C) + (set-window-configuration windows) + (message "Merge resolved; you may save the buffer")))) + (message "Please resolve merge now; exit ediff when done") + nil)))) + + +;---------------------------------------------------------------------- +; Executing "make" and "spatch" commands +;---------------------------------------------------------------------- + +(defun cocci-dired-compile-makeok (arg) + "Compiles the marked files in cocci/dired mode. With prefix arg no file +names are substituted (useful for Makefiles)." + (interactive "P") + (if arg + (compile (read-from-minibuffer "Compile command: " + (eval compile-command) nil nil + '(compile-history . 1))) + (let* ((file-list (cocci-convert-ends ".c" ".ok" (dired-get-marked-files t))) + (command (dired-mark-read-string + "Make targets %s with: " + (cocci-makeok-cmd cocci-current-cocci) + 'compile nil file-list))) + (compile (concat command " " (mapconcat 'identity file-list " ")))))) + +(defun cocci-dired-compile-spatch (&optional arg) + "Runs spatch on current file. Non-nil optional arg to specify command." + (interactive "P") + (if arg + (compile (read-from-minibuffer "Command: " + (eval compile-command) nil nil + '(compile-history . 1))) + (let ((file (dired-get-filename t)) + (command (cocci-spatch-cmd cocci-current-cocci))) + (compile (concat command " " file))))) + +(defun cocci-apply-spatch (file &optional sp-file out-buf) + "Applies the current SP to FILE." + (interactive) + (let ((cmd (concat (cocci-spatch-cmd (or sp-file cocci-current-cocci))))) + (shell-command (concat cmd " " file) out-buf))) + +(defun cocci-ediff-merge (&optional res-file) + "Use EDiff to review and apply semantic patch." + (interactive) + (let ((file (dired-get-filename t)) + (out-buf (get-spatch-output-buffer))) + (message "Applying SP '%s' to file '%s'..." + (file-name-nondirectory cocci-current-cocci) + (file-name-nondirectory file)) + (cocci-apply-spatch file cocci-current-cocci out-buf) + (message "Applying SP '%s' to file '%s'... done." + (file-name-nondirectory cocci-current-cocci) + (file-name-nondirectory file)) +; (ediff-merge-files file (or res-file cocci-spatch-default-output)) + (cocci-merge-files file (or res-file cocci-spatch-default-output)))) + + +(defun cocci-ediff-diff (&optional res-file) + "Use EDiff to review and apply semantic patch." + (interactive) + (let ((file (dired-get-filename t)) + (out-buf (get-spatch-output-buffer))) + (message "Applying SP '%s' to file '%s'..." + (file-name-nondirectory cocci-current-cocci) + (file-name-nondirectory file)) + (cocci-apply-spatch file cocci-current-cocci out-buf) + (message "Applying SP '%s' to file '%s'... done." + (file-name-nondirectory cocci-current-cocci) + (file-name-nondirectory file)) +; (ediff-merge-files file (or res-file cocci-spatch-default-output)) + (cocci-diff-files file (or res-file cocci-spatch-default-output)))) + +(defun cocci-dired-view-file () + "In cocci dired, visit the file or directory named on this line +using diff-mode." + (interactive) + (let ((file-name (file-name-sans-versions (dired-get-filename) t)) + ;; bind it so that the command works on directories too, + ;; independent of the user's setting + (find-file-run-dired t)) + (if (file-exists-p file-name) + (progn + (find-file file-name) + (diff-mode)) + (if (file-symlink-p file-name) + (error "File is a symlink to a nonexistent target") + (error "File no longer exists; type `g' to update Dired buffer"))))) + +(defun cocci-dired-view-corresponding-file () + "In cocci dired, visit the file or directory named on this line +using diff-mode." + (interactive) + (let* ((file-name + (cocci-corresponding-file + (file-name-sans-versions (dired-get-filename) t))) + (find-file-run-dired t)) + (if (file-exists-p file-name) + (progn + (find-file file-name) + (diff-mode)) + (if (file-symlink-p file-name) + (error "File is a symlink to a nonexistent target") + (error "File no longer exists; type `g' to update Dired buffer"))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cocci-dired-run-spatch (&optional spfile) + "In a dired buffer, runs spatch on marked files with source buffer as SP file" + (interactive) + (when (not spfile) (setq spfile cocci-current-cocci)) + (dired-do-shell-command (concat (cocci-spatch-cmd spfile) " ?") + current-prefix-arg + (dired-get-marked-files t current-prefix-arg))) + +(defun cocci-dired-run-makeok (spfile) + "In a dired buffer, runs 'make ok' on marked files with +source buffer as SP file" + (interactive) + (let ((files (dired-get-marked-files t current-prefix-arg))) + (dired-do-shell-command (concat (cocci-makeok-cmd spfile) " ?") + current-prefix-arg + (cocci-convert-ends ".c" ".ok" files)))) + +(defun cocci-run-makeok (spfile) + "Run 'make ok' in current directory with source buffer as SP file" + (interactive) + (compile (cocci-makeok-cmd (buffer-file-name)))) + + + +;-------------------------------------------------- +; Marking files in Dired under Cocci +;-------------------------------------------------- + +(defun cocci-dired-mark-c-files () + (interactive) + (dired-mark-extension ".c")) + +(defun cocci-dired-mark-cocci-files () + (interactive) + (dired-mark-extension ".cocci")) + +(defun cocci-dired-mark-ok-files () + "Mark all .ok files. In terse mode mark all .c files that have a +corresponding .ok file" + (interactive) + (if (not cocci-dired-terse-mode) + (dired-mark-extension ".ok") + (dired-mark-if (let ((f (dired-get-filename nil t))) + (and f + (file-exists-p (cocci-file f 'ok)) + (not (file-directory-p f)))) + "source file(s) with OK result file"))) + +(defun cocci-dired-mark-failed-files () + "Mark all .failed files. In terse mode mark all .c files that have a +corresponding .failed file" + (interactive) + (if (not cocci-dired-terse-mode) + (dired-mark-extension ".failed") + (dired-mark-if (let ((f (dired-get-filename nil t))) + (and f + (file-exists-p (cocci-file f 'fail)) + (not (file-directory-p f)))) + "source file(s) with FAILED result file"))) + +(defun cocci-dired-mark-expected-files () + "Mark all .res files. In terse mode mark all .c files that have a +corresponding .res file" + (interactive) + (if (not cocci-dired-terse-mode) + (dired-mark-extension ".res") + (dired-mark-if (let ((f (dired-get-filename nil t))) + (and f + (file-exists-p (cocci-file f 'expected)) + (not (file-directory-p f)))) + "source file(s) with EXPECTED result file"))) + + +;;; One shot - for counting in README's +;;; FIXME: remove +(defun cocci-count-status () + (interactive) + (let (res) + (save-excursion + (beginning-of-buffer) + (let ((ok (count-matches "\\[status\\] ok")) + (sok (count-matches "\\[status\\] spatch-ok")) + (fail (count-matches "\\[status\\] fail")) + (wrong (count-matches "\\[status\\] wrong"))) + (setq res (replace-regexp-in-string + " occurrences" + "" + (concat "[ok: " ok "; spatch-ok: " sok + "; fail: " fail "; wrong: " wrong "]"))))) + (insert res))) + + +;---------------------------------------------------------------------- +; Cocci Dired - Adapted from VC Dired +;---------------------------------------------------------------------- + +(defvar cocci-dired-listing-switches "-al" + "*Switches passed to `ls' for vc-dired. MUST contain the `l' option.") + +(defvar cocci-dired-terse-display t + "*If non-nil, show only source (.c) files in Cocci Dired.") + +(defvar cocci-dired-recurse t + "*If non-nil, show directory trees recursively in VC Dired.") + +(defvar cocci-directory-exclusion-list '("SCCS" "RCS" "CVS") + "*List of directory names to be ignored when walking directory trees.") + +(defvar cocci-dired-switches) +(defvar cocci-dired-terse-mode) +(defvar cocci-dired-mode nil) +(make-variable-buffer-local 'cocci-dired-mode) + +;;; based on vc-dired-mode +(define-derived-mode cocci-dired-mode dired-mode "Dired under Cocci" + "The major mode used in Cocci directory buffers. + +It works like Dired, with the current Cocci state of each file being +indicated in the place of the file's link count, owner, group and size. +Subdirectories are also listed, and you may insert them into the buffer +as desired, like in Dired." + ;; define-derived-mode does it for us in Emacs-21, but not in Emacs-20. + ;; We do it here because dired might not be loaded yet + ;; when vc-dired-mode-map is initialized. + (set-keymap-parent cocci-dired-mode-map dired-mode-map) + (make-local-hook 'dired-after-readin-hook) + (add-hook 'dired-after-readin-hook 'cocci-dired-hook nil t) + ;; The following is slightly modified from dired.el, + ;; because file lines look a bit different in vc-dired-mode. + (set (make-local-variable 'dired-move-to-filename-regexp) + (let* ((l "\\([A-Za-z]\\|[^\0-\177]\\)") + ;; In some locales, month abbreviations are as short as 2 letters, + ;; and they can be followed by ".". + (month (concat l l "+\\.?")) + (s " ") + (yyyy "[0-9][0-9][0-9][0-9]") + (dd "[ 0-3][0-9]") + (HH:MM "[ 0-2][0-9]:[0-5][0-9]") + (seconds "[0-6][0-9]\\([.,][0-9]+\\)?") + (zone "[-+][0-2][0-9][0-5][0-9]") + (iso-mm-dd "[01][0-9]-[0-3][0-9]") + (iso-time (concat HH:MM "\\(:" seconds "\\( ?" zone "\\)?\\)?")) + (iso (concat "\\(\\(" yyyy "-\\)?" iso-mm-dd "[ T]" iso-time + "\\|" yyyy "-" iso-mm-dd "\\)")) + (western (concat "\\(" month s "+" dd "\\|" dd "\\.?" s month "\\)" + s "+" + "\\(" HH:MM "\\|" yyyy "\\)")) + (western-comma (concat month s "+" dd "," s "+" yyyy)) + ;; Japanese MS-Windows ls-lisp has one-digit months, and + ;; omits the Kanji characters after month and day-of-month. + (mm "[ 0-1]?[0-9]") + (japanese + (concat mm l "?" s dd l "?" s "+" + "\\(" HH:MM "\\|" yyyy l "?" "\\)"))) + ;; the .* below ensures that we find the last match on a line + (concat ".*" s + "\\(" western "\\|" western-comma "\\|" japanese "\\|" iso "\\)" + s "+"))) + (and (boundp 'cocci-dired-switches) + cocci-dired-switches + (set (make-local-variable 'dired-actual-switches) + cocci-dired-switches)) + (set (make-local-variable 'cocci-dired-terse-mode) cocci-dired-terse-display) + (setq cocci-dired-mode t)) + +(defun cocci-dired-toggle-terse-mode () + "Toggle terse display in Cocci Dired." + (interactive) + (if (not cocci-dired-mode) + nil + (setq cocci-dired-terse-mode (not cocci-dired-terse-mode)) + (if cocci-dired-terse-mode + (cocci-dired-hook) + (revert-buffer)))) + +(defun cocci-convert-file-ext (file ext) + (concat (file-name-sans-extension file) ext)) + +(defvar cocci-file-types + '((cocci . ".cocci") (source . ".c") (ok . ".ok") + (fail . ".failed") (expected . ".res")) +"Alist of file name extensions used by Cocci.") + +(defun cocci-file (file type) + (let ((ext (cdr (assq type cocci-file-types)))) + (if ext + (cocci-convert-file-ext file ext) + (error "cocci-file: requested unknown file type (%s)" type)))) + +(defun cocci-file-type (file) + (car (rassoc (file-name-extension file t) cocci-file-types))) + +(defun cocci-result-type-p (type) (or (eq type 'ok) (eq type 'fail))) + +(defun cocci-corresponding-file (file) + (let ((ftype (cocci-file-type file))) + (cond + ((or (eq ftype 'ok) (eq ftype 'fail)) (cocci-file file 'source)) + ((eq ftype 'source) + (let ((status (cocci-result-status file))) + (cond + ((eq status 'cocci-ok) (cocci-file file 'ok)) + ((eq status 'cocci-fail) (cocci-file file 'fail)) + (t (error "No corresponding result file for %s" file))))) + (t (error "No corresponding file for %s" file))))) + +(defun cocci-result-status (file) + "For a source file return the Coccinelle result status (if any)." + (let ((ok (file-exists-p (cocci-file file 'ok))) + (fail (file-exists-p (cocci-file file 'fail))) + (res (file-exists-p (cocci-file file 'expected)))) + (cond + ((and ok fail) 'cocci-conflict) ; old .ok/.failed files lying around? + (ok 'cocci-ok) ; found a .ok file + (fail 'cocci-fail) ; found a .fail file + (res 'cocci-update) ; found an expected result but no result + (t 'cocci-unknown)))) ; file is not under cocci "control" + +(defun cocci-stale-result-file (file &optional src-file) + (when (not src-file) (setq src-file (cocci-file file 'source))) + (and (file-exists-p file) + (or (file-newer-than-file-p cocci-current-cocci file) + (file-newer-than-file-p src-file file)))) + +;; Trying to abstract away from files +(defun cocci-stale-result (file &optional result) + "Determine if the result is stale." + (let ((src-file (cocci-file file 'source))) + (if result + (cocci-stale-result-file (cocci-file file result) src-file) + (or (cocci-stale-result-file (cocci-file file 'ok) src-file) + (cocci-stale-result-file (cocci-file file 'fail) src-file))))) + +(defun cocci-dired-state-info (file) + (cond + ; a source (.c) file + ((eq (cocci-file-type file) 'source) + (let ((result) + (status (cocci-result-status file))) + (setq result + (cond + ((eq status 'cocci-ok) + (if (cocci-stale-result file 'ok) + "(ok?)" + "(ok)")) + ((eq status 'cocci-fail) + (if (cocci-stale-result file 'fail) + "(fail?)" + "(fail)")) + ((eq status 'cocci-conflict) "(ok/fail)") + ((eq status 'cocci-update) "(update)") + ((eq status 'cocci-unknown) "(unknown)") + (t nil))) + (substring (concat result " ") 0 10))) + )) + +(defun cocci-dired-reformat-line (x) + "Reformat a directory-listing line. +Replace various columns with version control information. +This code, like dired, assumes UNIX -l format." + (beginning-of-line) + (let ((pos (point)) limit perm date-and-file) + (end-of-line) + (setq limit (point)) + (goto-char pos) + (when + (or + (re-search-forward ;; owner and group + "^\\(..[drwxlts-]+ \\) *[0-9]+ [^ ]+ +[^ ]+ +[0-9]+\\( .*\\)" + limit t) + (re-search-forward ;; only owner displayed + "^\\(..[drwxlts-]+ \\) *[0-9]+ [^ ]+ +[0-9]+\\( .*\\)" + limit t) + (re-search-forward ;; OS/2 -l format, no links, owner, group + "^\\(..[drwxlts-]+ \\) *[0-9]+\\( .*\\)" + limit t)) + (setq perm (match-string 1) + date-and-file (match-string 2)) + (setq x (substring (concat x " ") 0 10)) + (replace-match (concat perm x date-and-file))))) + +(defun cocci-dired-hook () + "Reformat the listing according to version control. +Called by dired after any portion of a cocci-dired buffer has been read in." + (message "Getting status information... ") + (let (subdir filename (buffer-read-only nil) cvs-dir) + (goto-char (point-min)) + (while (not (eobp)) + (cond + ;; subdir header line + ((setq subdir (dired-get-subdir)) + ;; if the backend supports it, get the state + ;; of all files in this directory at once +; (let ((backend (vc-responsible-backend subdir))) +; (if (vc-find-backend-function backend 'dir-state) +; (vc-call-backend backend 'dir-state subdir))) + (forward-line 1) + ;; erase (but don't remove) the "total" line + (delete-region (point) (line-end-position)) + ;; Ugly hack to display the current cocci file. + ;; Needed because of hardcoded dired regexps + (when cocci-current-cocci + (insert + (concat + (propertize " " 'display '((margin nil) " Current cocci file: ")) + (propertize " " + 'display + `((margin nil) + ,(file-name-nondirectory cocci-current-cocci)))))) + (beginning-of-line) + (forward-line 1)) + ;; file line + ((setq filename (dired-get-filename nil t)) + (cond + ;; subdir + ((file-directory-p filename) + (cond + ((member (file-name-nondirectory filename) + cocci-directory-exclusion-list) + (let ((pos (point))) + (dired-kill-tree filename) + (goto-char pos) + (dired-kill-line))) + (cocci-dired-terse-mode + ;; Don't show directories in terse mode. Don't use + ;; dired-kill-line to remove it, because in recursive listings, + ;; that would remove the directory contents as well. + (delete-region (line-beginning-position) + (progn (forward-line 1) (point)))) + ((string-match "\\`\\.\\.?\\'" (file-name-nondirectory filename)) + (dired-kill-line)) + (t + (cocci-dired-reformat-line nil) + (forward-line 1)))) + ;; ordinary file + ;; show only .c in terse mode + ((or (and (eq (cocci-file-type filename) 'source) + (equal (file-name-sans-versions filename) filename)) + (not (and cocci-dired-terse-mode))) + (cocci-dired-reformat-line (cocci-dired-state-info filename)) + (forward-line 1)) + (t + (dired-kill-line)))) + ;; any other line + (t (forward-line 1)))) + (cocci-dired-purge)) + (message "Getting status information... done")) + +(defun cocci-dired-purge () + "Remove empty subdirs." + (let (subdir) + (goto-char (point-min)) + (while (setq subdir (dired-get-subdir)) + (forward-line 2) + (if (dired-get-filename nil t) + (if (not (dired-next-subdir 1 t)) + (goto-char (point-max))) + (forward-line -2) + (if (not (string= (dired-current-directory) default-directory)) + (dired-do-kill-lines t "") + ;; We cannot remove the top level directory. + ;; Just make it look a little nicer. + (forward-line 1) + (kill-line) + (if (not (dired-next-subdir 1 t)) + (goto-char (point-max)))))) + (goto-char (point-min)))) + +(defun cocci-dired-buffers-for-dir (dir) + "Return a list of all cocci-dired buffers that currently display DIR." + (let (result) + ;; Check whether dired is loaded. + (when (fboundp 'dired-buffers-for-dir) + (mapcar (lambda (buffer) + (with-current-buffer buffer + (if cocci-dired-mode + (setq result (append result (list buffer)))))) + (dired-buffers-for-dir dir))) + result)) + +(defun cocci-dired-resynch-file (file) + "Update the entries for FILE in any Cocci Dired buffers that list it." + (let ((buffers (cocci-dired-buffers-for-dir (file-name-directory file)))) + (when buffers + (mapcar (lambda (buffer) + (with-current-buffer buffer + (if (dired-goto-file file) + ;; bind vc-dired-terse-mode to nil so that + ;; files won't vanish when they are checked in + (let ((cocci-dired-terse-mode nil)) + (dired-do-redisplay 1))))) + buffers)))) + +(defun cocci-directory (dir read-switches) + "Create a buffer in Cocci Dired Mode for directory DIR. + +With prefix arg READ-SWITCHES, specify a value to override +`dired-listing-switches' when generating the listing." + (interactive "DDired under Cocci (directory): \nP") + (let ((cocci-dired-switches (concat cocci-dired-listing-switches + (if cocci-dired-recurse "R" "")))) + (if read-switches + (setq cocci-dired-switches + (read-string "Dired listing switches: " + cocci-dired-switches))) + (require 'dired) + (require 'dired-aux) + (switch-to-buffer + (dired-internal-noselect (expand-file-name (file-name-as-directory dir)) + cocci-dired-switches + 'cocci-dired-mode)))) + + + +;-------------------------------------------------- +; Hook +;-------------------------------------------------- + +(define-key cocci-mode-map "\C-cd" 'cocci-directory) + +(add-hook 'cocci-mode-hook + (lambda () + (setq cocci-current-cocci (buffer-file-name)) + (setq cocci-current-cocci-buffer (current-buffer)) + (setq compile-command (cocci-makeok-cmd cocci-current-cocci)))) + + +(provide 'cocci-ediff) \ No newline at end of file diff --git a/emacs/cocci.el b/emacs/cocci.el new file mode 100644 index 0000000..58fc80a --- /dev/null +++ b/emacs/cocci.el @@ -0,0 +1,363 @@ +;;; cocci.el --- a major mode for editing semantic patches + +;; Copyright (C) 2006-2007 Yoann Padioleau + +;; Please imagine a long and boring gnu-style copyright notice +;; appearing just here. + + +;; Emacs Lisp Archive Entry +;; Author: Padioleau Yoann , +;; Version: 0.2 +;; Keywords: coccinelle patch refactoring program transformation +;; URL: http://www.emn.fr/x-info/coccinelle/ + + +;;; Usage + +;; Add the following lines to your ~/.emacs or equivalent: +;; (setq auto-mode-alist +;; (cons '("\\.cocci$" . cocci-mode) auto-mode-alist)) +;; (autoload 'cocci-mode "cocci" +;; "Major mode for editing cocci code." t) +;; +;; You can also use cocci-mode to edit the files containing the +;; isomorphisms with: +;; (setq auto-mode-alist +;; (cons '("\\.iso$" . cocci-mode) auto-mode-alist)) +;; + +;;; History + +;; Some cleanups done by Rene Rydhof Hansen + +;;; Utilities + +(defun join-sep (sep xs) + (mapconcat 'identity xs sep)) + + +;;; Variables + +(defvar cocci-menu) + + +;; new (color) faces + +(defface cocci-number-face + '((((background light)) (:foreground "black")) + (((background dark)) (:foreground "yellow3"))) + "Used for Cocci numbers") + +(defface cocci-punctuation-face + '((((background light)) (:foreground "black")) + (((background dark)) (:foreground "cyan"))) + "Used for punctuation") + +(defface cocci-problem-face + '((((background light)) (:background "deep pink")) + (((background dark)) (:background "deep pink"))) + "Highlighting potential problems") + +(defface cocci-special-face + '((((background light)) (:foreground "blue")) + (((background dark)) (:foreground "red"))) + "") + +(defface cocci-rulename-face + '((((background light)) (:foreground "DarkSlateGray")) + (((background dark)) (:foreground "DarkSlateGray4"))) + "Highlighting the rule names") + +(defface cocci-minus-face + '((((background light)) (:foreground "dark green")) + (((background dark)) (:foreground "SeaGreen3"))) + "Highlighting lines to be removed") + +(defface cocci-plus-face + '((((background light)) (:foreground "red")) + (((background dark)) (:foreground "salmon"))) + "Highlighting lines to be added") + +(defface cocci-match-face + '((((background light)) (:foreground "violet red")) + (((background dark)) (:foreground "purple"))) + "Highlighting lines to be matched (sgrep)") + + +;; can look in lexer_cocci.mll for new identifiers + +(defconst cocci-c-keywords-list + '("if" "else" "while" "do" "for" "return" + "sizeof" + "struct" "union" + "static" "const" "volatile" + "break" "continue" + "switch" "case" + )) + +(defconst cocci-declaration-keywords-list + '("identifier" "type" "parameter" "constant" "expression" "statement" + "function" "local" "list" + "fresh" + "position" + "idexpression" + + "typedef" + "declarer" "iterator" + "pure" + ;"error" "words" + + "char" "short" "int" "float" "double" "long" + "void" + "signed" "unsigned" + )) + +(defconst cocci-iso-keywords-list + '("Expression" "Statement" "Type" + "Declaration" "TopLevel" "ArgExpression" + )) + + + +(defconst c-preprocessor-directives-list + '("define" "undef" + "if" "ifdef" "elif" "else" "endif" "ifndef" + "include" + "error" "pragma" + "file" "line" + )) + + +(setq cocci-font-lock-keywords + `( + + ; blink possible errors, when - or + is not in first column + ("^[ \t]+[-+]" . 'cocci-problem-face) + + ; modifiers + ("^\\??\\+.*" . 'cocci-plus-face) + ("^\\??-.*" . 'cocci-minus-face) + + ("^\\*.*" . 'cocci-match-face) + ;("^\\??\\+.*?//" . 'cocci-plus-face) + ; ! \\+ + + ; --- +++ + + ; #cpp + ("#\\(include\\) *\\(.*\\)" + (1 'font-lock-builtin-face) + (2 'font-lock-string-face) + ) + + ; comments + ("//.*" . 'font-lock-comment-face) + + ; strings + ("\"[^\"]*\"" . 'font-lock-string-face) + + ; rule header + ("@[ \t]*@" . 'cocci-special-face) + ; this rule may seems redundant with the following one, but + ; without it, @@ int x; @@ would color the int x with rulename-face. + ; by using this rule, we color the @@ and so prevent the + ; next rule to be applied (cf font-lock semantic when have not the + ; OVERRIDE flag). + + ("\\(@\\)\\(.*\\)\\(@\\)" + (1 'cocci-special-face) + (2 'cocci-rulename-face) + (3 'cocci-special-face) + ) + + ("@.*\\b\\(extends\\|\\(depends[ \t]*on\\)\\)\\b.*@" + (1 'cocci-special-face t)) + + ;old: does not work, not easy to handle the rule1, rule2, rule3 list. + ; ("@[ \t]*\\(\\(\\w+\\)[ \t,]*\\)*[ \t]*@" + ; ("\\(@\\)[ \t]*\\(\\w+\\)[ \t]*\\(@\\)" + ; ("\\(@\\)[ \t]*\\(\\w+\\)[ \t]+\\(extends\\)[ \t]+\\(\\w+\\)[ \t]*\\(@\\)" + ; ("\\(@\\)[ \t]*\\(\\w+\\)[ \t]+\\(depends\\)[ \t]+\\(on\\)[ \t]+\\(\\(\\w+\\)[ ,\t]*\\)+\\(@\\)" + + + ; inherited variable, fontifying rulename + (,(concat "^" + "\\b\\(" (regexp-opt cocci-declaration-keywords-list) "\\)\\b" + ".*?\\(\\w+\\)\\.") + (2 'cocci-rulename-face)) + + ;rule1.T *a; + ("^\\(\\w+\\)\\." + (1 'cocci-rulename-face)) + + + ; just for pad, metavariables in maj + ("\\b[A-Z][0-9]?\\b" . font-lock-variable-name-face) + + ; todo: do also for other variable, do as in font-lock.el + ; with font-lock-match-c-style-declaration-item-and-skip-to-next + + ; special cocci operators + ("\\.\\.\\." . 'font-lock-keyword-face) + ("^[()|]" . 'font-lock-keyword-face) + + ; escaped version of cocci operators + ("\\\\[()|]" . 'font-lock-keyword-face) + + ("\\bwhen[ \t]+!=" . 'font-lock-keyword-face) + ("\\bWHEN[ \t]+!=" . 'font-lock-keyword-face) + ("\\bwhen[ \t]+=" . 'font-lock-keyword-face) + ("\\bWHEN[ \t]+=" . 'font-lock-keyword-face) + + ; used in iso files + ("<=>" . 'font-lock-keyword-face) + ("=>" . 'font-lock-keyword-face) + + (,(concat "\\b\\(" (regexp-opt cocci-iso-keywords-list) "\\)\\b") . + 'cocci-special-face) + + ("\\<[0-9]+\\>" . 'cocci-number-face) + + (,(join-sep "\\|" + (list "(" ")" ";" "," "{" "}" "\\[" "\\]")) . 'cocci-punctuation-face) + ; . -> * + etc + + ; c keywords + (,(concat "\\b\\(" (regexp-opt cocci-c-keywords-list) "\\)\\b") . + 'font-lock-keyword-face) + + ; cocci declaration keywords + (,(concat "\\b\\(" (regexp-opt cocci-declaration-keywords-list) "\\)\\b") . + 'font-lock-type-face) + + ; cpp directives + (,(concat "^#[ \t]*\\(" (regexp-opt c-preprocessor-directives-list) + "\\)\\>[ \t!]*\\(\\sw+\\)?") + (1 'font-lock-builtin-face)) + + )) +; "Expressions to highlight in cocci-mode.") + + + +;; define a mode-specific abbrev table for those who use such things +(defvar cocci-mode-abbrev-table nil + "Abbrev table used while in cocci mode.") +(define-abbrev-table 'cocci-mode-abbrev-table nil) + + +(defvar cocci-mode-map nil + "Keymap used in `cocci-mode'.") +(unless cocci-mode-map + (setq cocci-mode-map (make-sparse-keymap)) + (define-key cocci-mode-map [(meta control *)] 'switch-between-cocci-c) + (define-key cocci-mode-map "%" 'cocci-replace-modifiers) + + ;(define-key cocci-mode-map "\C-c" 'compile) + ) + + +(defvar cocci-mode-syntax-table nil + "Syntax table used while in cocci mode.") +(unless cocci-mode-syntax-table + (setq cocci-mode-syntax-table (make-syntax-table)) + + ; _ is part of a word. + (modify-syntax-entry ?\_ "w" cocci-mode-syntax-table) + + ; change mode for ", bad interaction with font-lock + (modify-syntax-entry ?\" "w" cocci-mode-syntax-table) + ) + + +;;; Code + +;; helper functions for the cocci programmer + +(defun cocci-replace-modifiers (beg end str) + "TODO" + (interactive + (let ((str (read-string "New modifier string (+, -, space): " + nil 'my-history))) + (list (region-beginning) (region-end) str))) + + ;(interactive "rsNew modifier string (+, -, space): ") + (replace-regexp "^[-+]?" str nil beg end) + ) + +;Used internally while developping coccinelle. +;Allow to switch between the corresponding SP and C file. +;todo: handle the _verxxx naming convention. +(defun switch-between-cocci-c () + (interactive) + (let ((target + (cond ((string-match ".c$" (buffer-name)) + (replace-match ".cocci" t t (buffer-name))) + ((string-match ".cocci$" (buffer-name)) + (replace-match ".c" t t (buffer-name))) + (t + "none")))) + (if (get-buffer target) + (switch-to-buffer target) + (find-file + (read-file-name "file: " nil nil t target))))) + +(eval-after-load "cc-mode" + '(progn + (define-key c-mode-map [(meta control *)] 'switch-between-cocci-c)) + ) + + + + +(defvar cocci-mode-hook nil + "Hook called by `cocci-mode'") + +;;;###autoload +(defun cocci-mode () + "Major mode for editing cocci code. +Special commands: \\{cocci-mode-map} +Turning on cocci-mode runs the hook `cocci-mode-hook'." + (interactive) + (kill-all-local-variables) + (make-local-variable 'font-lock-defaults) + (make-local-variable 'comment-start) + (make-local-variable 'comment-end) + (make-local-variable 'compile-command) + + (use-local-map cocci-mode-map) + (set-syntax-table cocci-mode-syntax-table) + (setq mode-name "cocci" + major-mode 'cocci-mode + local-abbrev-table cocci-mode-abbrev-table + font-lock-defaults '(cocci-font-lock-keywords) + comment-start "//" + comment-end "" + ) + (easy-menu-add cocci-menu) + + (run-hooks 'cocci-mode-hook) +) + + +;; Menu + +(easy-menu-define cocci-menu cocci-mode-map "Cocci menu" + '("Cocci" + ["Switch to corresponding C file" switch-between-cocci-c t] + ["Replace modifiers" cocci-replace-modifiers t] + )) + + + +; put cursor before a parse error coccinelle message and it will +; open the corresponding file and go to corresponding line. +(fset 'cocci-goto-next-error + [?\C-s ?F ?i ?l ?e right right ?\C- ?\C-s ?" left ?\M-w ?\C-x ?\C-f S-insert return ?\C-\M-l C-right right C-S-right C-insert ?\C-\M-l ?\M-g S-insert return]) +;" + +;; Provide +(provide 'cocci-mode) + +;;; cocci.el ends here diff --git a/empty.h b/empty.h new file mode 100644 index 0000000..e69de29 diff --git a/empty.iso b/empty.iso new file mode 100644 index 0000000..e69de29 diff --git a/engine/.depend b/engine/.depend new file mode 100644 index 0000000..301f8e4 --- /dev/null +++ b/engine/.depend @@ -0,0 +1,141 @@ +asttoctl.cmi: ../ctl/wrapper_ctl.cmi lib_engine.cmo ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi +asttoctl2.cmi: ../ctl/wrapper_ctl.cmi lib_engine.cmo ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi +asttomember.cmi: lib_engine.cmo ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi +c_vs_c.cmi: ../parsing_c/ast_c.cmo +check_reachability.cmi: ../ctl/wrapper_ctl.cmi ../commons/ograph_extended.cmi \ + ../parsing_c/control_flow_c.cmi ../ctl/ast_ctl.cmo +cocci_vs_c_3.cmi: ../parsing_c/control_flow_c.cmi ../commons/common.cmi \ + ../parsing_cocci/ast_cocci.cmi ../parsing_c/ast_c.cmo +ctlcocci_integration.cmi: ../commons/ograph_extended.cmi lib_engine.cmo \ + ../parsing_c/control_flow_c.cmi ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi +ctltotex.cmi: ../ctl/wrapper_ctl.cmi lib_engine.cmo ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi +pattern3.cmi: lib_engine.cmo ../parsing_c/control_flow_c.cmi \ + ../parsing_cocci/ast_cocci.cmi +postprocess_transinfo.cmi: ../commons/ograph_extended.cmi lib_engine.cmo \ + ../parsing_cocci/ast_cocci.cmi +pretty_print_engine.cmi: lib_engine.cmo ../ctl/ast_ctl.cmo \ + ../parsing_c/ast_c.cmo +transformation3.cmi: lib_engine.cmo ../parsing_c/control_flow_c.cmi +asttoctl.cmo: ../ctl/wrapper_ctl.cmi ../parsing_cocci/visitor_ast.cmi \ + ../parsing_cocci/unify_ast.cmi pretty_print_engine.cmi lib_engine.cmo \ + ../parsing_cocci/free_vars.cmi ../commons/common.cmi ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi asttoctl.cmi +asttoctl.cmx: ../ctl/wrapper_ctl.cmx ../parsing_cocci/visitor_ast.cmx \ + ../parsing_cocci/unify_ast.cmx pretty_print_engine.cmx lib_engine.cmx \ + ../parsing_cocci/free_vars.cmx ../commons/common.cmx ../ctl/ast_ctl.cmx \ + ../parsing_cocci/ast_cocci.cmx asttoctl.cmi +asttoctl2.cmo: ../ctl/wrapper_ctl.cmi ../parsing_cocci/visitor_ast.cmi \ + ../parsing_cocci/unify_ast.cmi ../parsing_cocci/type_cocci.cmi \ + pretty_print_engine.cmi ../ctl/pretty_print_ctl.cmi \ + ../parsing_cocci/pretty_print_cocci.cmi lib_engine.cmo flag_engine.cmo \ + ../globals/flag.cmo ../commons/common.cmi ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi asttoctl2.cmi +asttoctl2.cmx: ../ctl/wrapper_ctl.cmx ../parsing_cocci/visitor_ast.cmx \ + ../parsing_cocci/unify_ast.cmx ../parsing_cocci/type_cocci.cmx \ + pretty_print_engine.cmx ../ctl/pretty_print_ctl.cmx \ + ../parsing_cocci/pretty_print_cocci.cmx lib_engine.cmx flag_engine.cmx \ + ../globals/flag.cmx ../commons/common.cmx ../ctl/ast_ctl.cmx \ + ../parsing_cocci/ast_cocci.cmx asttoctl2.cmi +asttomember.cmo: ../parsing_cocci/visitor_ast.cmi \ + ../parsing_cocci/pretty_print_cocci.cmi lib_engine.cmo \ + ../commons/common.cmi ../ctl/ast_ctl.cmo ../parsing_cocci/ast_cocci.cmi \ + asttomember.cmi +asttomember.cmx: ../parsing_cocci/visitor_ast.cmx \ + ../parsing_cocci/pretty_print_cocci.cmx lib_engine.cmx \ + ../commons/common.cmx ../ctl/ast_ctl.cmx ../parsing_cocci/ast_cocci.cmx \ + asttomember.cmi +c_vs_c.cmo: ../parsing_c/lib_parsing_c.cmo ../commons/common.cmi \ + ../parsing_c/ast_c.cmo c_vs_c.cmi +c_vs_c.cmx: ../parsing_c/lib_parsing_c.cmx ../commons/common.cmx \ + ../parsing_c/ast_c.cmx c_vs_c.cmi +check_exhaustive_pattern.cmo: ../parsing_c/control_flow_c.cmi \ + ../parsing_cocci/ast_cocci.cmi ../parsing_c/ast_c.cmo +check_exhaustive_pattern.cmx: ../parsing_c/control_flow_c.cmx \ + ../parsing_cocci/ast_cocci.cmx ../parsing_c/ast_c.cmx +check_reachability.cmo: ../ctl/wrapper_ctl.cmi ../commons/ograph_extended.cmi \ + ../ctl/flag_ctl.cmo ../ctl/ctl_engine.cmi ../parsing_c/control_flow_c.cmi \ + ../ctl/ast_ctl.cmo check_reachability.cmi +check_reachability.cmx: ../ctl/wrapper_ctl.cmx ../commons/ograph_extended.cmx \ + ../ctl/flag_ctl.cmx ../ctl/ctl_engine.cmx ../parsing_c/control_flow_c.cmx \ + ../ctl/ast_ctl.cmx check_reachability.cmi +cocci_vs_c_3.cmo: ../parsing_cocci/type_cocci.cmi \ + ../parsing_c/lib_parsing_c.cmo ../globals/flag.cmo \ + ../parsing_c/control_flow_c.cmi ../commons/common.cmi c_vs_c.cmi \ + ../parsing_cocci/ast_cocci.cmi ../parsing_c/ast_c.cmo cocci_vs_c_3.cmi +cocci_vs_c_3.cmx: ../parsing_cocci/type_cocci.cmx \ + ../parsing_c/lib_parsing_c.cmx ../globals/flag.cmx \ + ../parsing_c/control_flow_c.cmx ../commons/common.cmx c_vs_c.cmx \ + ../parsing_cocci/ast_cocci.cmx ../parsing_c/ast_c.cmx cocci_vs_c_3.cmi +ctlcocci_integration.cmo: ../ctl/wrapper_ctl.cmi pretty_print_engine.cmi \ + ../parsing_cocci/pretty_print_cocci.cmi postprocess_transinfo.cmi \ + pattern3.cmi ../commons/ograph_extended.cmi lib_engine.cmo \ + ../parsing_cocci/flag_parsing_cocci.cmo flag_engine.cmo \ + ../globals/flag.cmo ../parsing_c/control_flow_c.cmi ../commons/common.cmi \ + check_reachability.cmi c_vs_c.cmi ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi ../parsing_c/ast_c.cmo \ + ctlcocci_integration.cmi +ctlcocci_integration.cmx: ../ctl/wrapper_ctl.cmx pretty_print_engine.cmx \ + ../parsing_cocci/pretty_print_cocci.cmx postprocess_transinfo.cmx \ + pattern3.cmx ../commons/ograph_extended.cmx lib_engine.cmx \ + ../parsing_cocci/flag_parsing_cocci.cmx flag_engine.cmx \ + ../globals/flag.cmx ../parsing_c/control_flow_c.cmx ../commons/common.cmx \ + check_reachability.cmx c_vs_c.cmx ../ctl/ast_ctl.cmx \ + ../parsing_cocci/ast_cocci.cmx ../parsing_c/ast_c.cmx \ + ctlcocci_integration.cmi +ctltotex.cmo: ../parsing_cocci/pretty_print_cocci.cmi lib_engine.cmo \ + ../ctl/ast_ctl.cmo ctltotex.cmi +ctltotex.cmx: ../parsing_cocci/pretty_print_cocci.cmx lib_engine.cmx \ + ../ctl/ast_ctl.cmx ctltotex.cmi +isomorphisms_c_c.cmo: ../commons/common.cmi ../parsing_c/ast_c.cmo +isomorphisms_c_c.cmx: ../commons/common.cmx ../parsing_c/ast_c.cmx +lib_engine.cmo: ../ctl/wrapper_ctl.cmi ../commons/ograph_extended.cmi \ + ../parsing_c/control_flow_c.cmi ../commons/common.cmi ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi ../parsing_c/ast_c.cmo +lib_engine.cmx: ../ctl/wrapper_ctl.cmx ../commons/ograph_extended.cmx \ + ../parsing_c/control_flow_c.cmx ../commons/common.cmx ../ctl/ast_ctl.cmx \ + ../parsing_cocci/ast_cocci.cmx ../parsing_c/ast_c.cmx +main.cmo: ../parsing_cocci/parse_cocci.cmi ctltotex.cmi asttoctl.cmi +main.cmx: ../parsing_cocci/parse_cocci.cmx ctltotex.cmx asttoctl.cmx +pattern3.cmo: ../parsing_c/visitor_c.cmi ../parsing_c/lib_parsing_c.cmo \ + lib_engine.cmo flag_engine.cmo ../commons/common.cmi cocci_vs_c_3.cmi \ + ../parsing_cocci/ast_cocci.cmi ../parsing_c/ast_c.cmo pattern3.cmi +pattern3.cmx: ../parsing_c/visitor_c.cmx ../parsing_c/lib_parsing_c.cmx \ + lib_engine.cmx flag_engine.cmx ../commons/common.cmx cocci_vs_c_3.cmx \ + ../parsing_cocci/ast_cocci.cmx ../parsing_c/ast_c.cmx pattern3.cmi +postprocess_transinfo.cmo: ../parsing_c/parser_c.cmi ../parsing_c/parse_c.cmi \ + lib_engine.cmo ../commons/common.cmi ../parsing_cocci/ast_cocci.cmi \ + ../parsing_c/ast_c.cmo postprocess_transinfo.cmi +postprocess_transinfo.cmx: ../parsing_c/parser_c.cmx ../parsing_c/parse_c.cmx \ + lib_engine.cmx ../commons/common.cmx ../parsing_cocci/ast_cocci.cmx \ + ../parsing_c/ast_c.cmx postprocess_transinfo.cmi +pretty_print_engine.cmo: ../ctl/pretty_print_ctl.cmi \ + ../parsing_cocci/pretty_print_cocci.cmi ../parsing_c/pretty_print_c.cmi \ + lib_engine.cmo ../commons/common.cmi ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi ../parsing_c/ast_c.cmo \ + pretty_print_engine.cmi +pretty_print_engine.cmx: ../ctl/pretty_print_ctl.cmx \ + ../parsing_cocci/pretty_print_cocci.cmx ../parsing_c/pretty_print_c.cmx \ + lib_engine.cmx ../commons/common.cmx ../ctl/ast_ctl.cmx \ + ../parsing_cocci/ast_cocci.cmx ../parsing_c/ast_c.cmx \ + pretty_print_engine.cmi +sgrep.cmo: ../parsing_cocci/ast_cocci.cmi ../parsing_c/ast_c.cmo +sgrep.cmx: ../parsing_cocci/ast_cocci.cmx ../parsing_c/ast_c.cmx +transformation3.cmo: ../parsing_c/visitor_c.cmi \ + ../parsing_cocci/type_cocci.cmi sgrep.cmo \ + ../parsing_cocci/pretty_print_cocci.cmi ../parsing_c/lib_parsing_c.cmo \ + lib_engine.cmo ../parsing_cocci/flag_parsing_cocci.cmo \ + ../globals/flag.cmo ../parsing_c/control_flow_c.cmi ../commons/common.cmi \ + cocci_vs_c_3.cmi ../parsing_cocci/ast_cocci.cmi ../parsing_c/ast_c.cmo \ + transformation3.cmi +transformation3.cmx: ../parsing_c/visitor_c.cmx \ + ../parsing_cocci/type_cocci.cmx sgrep.cmx \ + ../parsing_cocci/pretty_print_cocci.cmx ../parsing_c/lib_parsing_c.cmx \ + lib_engine.cmx ../parsing_cocci/flag_parsing_cocci.cmx \ + ../globals/flag.cmx ../parsing_c/control_flow_c.cmx ../commons/common.cmx \ + cocci_vs_c_3.cmx ../parsing_cocci/ast_cocci.cmx ../parsing_c/ast_c.cmx \ + transformation3.cmi diff --git a/engine/Makefile b/engine/Makefile new file mode 100644 index 0000000..044cc14 --- /dev/null +++ b/engine/Makefile @@ -0,0 +1,123 @@ +# Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +# Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +# This file is part of Coccinelle. +# +# Coccinelle is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, according to version 2 of the License. +# +# Coccinelle is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Coccinelle. If not, see . +# +# The authors reserve the right to distribute this or future versions of +# Coccinelle under other licenses. + + +TARGET=cocciengine +CTLTARGET=engine + +SOURCES = flag_engine.ml lib_engine.ml pretty_print_engine.ml \ + check_exhaustive_pattern.ml \ + check_reachability.ml \ + c_vs_c.ml isomorphisms_c_c.ml \ + cocci_vs_c_3.ml pattern3.ml sgrep.ml transformation3.ml \ + asttomember.ml asttoctl2.ml ctltotex.ml \ + postprocess_transinfo.ml ctlcocci_integration.ml + +# just to test asttoctl +# CTLSOURCES = lib_engine.ml pretty_print_engine.ml asttoctl.ml ctltotex.ml \ +# main.ml + +INCLUDES = -I ../commons -I ../commons/ocamlextra -I ../globals \ + -I ../ctl -I ../parsing_c -I ../parsing_cocci + +SYSLIBS = str.cma unix.cma +LIBS=../commons/commons.cma ../globals/globals.cma \ + ../ctl/ctl.cma ../parsing_c/c_parser.cma ../parsing_cocci/cocci_parser.cma + + +# The Caml compilers. +OCAMLCFLAGS ?= -g -dtypes +OCAMLC =ocamlc$(OPTBIN) $(OCAMLCFLAGS) $(INCLUDES) +OCAMLOPT = ocamlopt$(OPTBIN) $(OPTFLAGS) $(INCLUDES) +OCAMLDEP = ocamldep$(OPTBIN) $(INCLUDES) + +EXEC=$(TARGET).byte +LIB=$(TARGET).cma +OPTLIB=$(LIB:.cma=.cmxa) + +CTLEXEC=$(CTLTARGET) + +OBJS = $(SOURCES:.ml=.cmo) +OPTOBJS = $(OBJS:.cmo=.cmx) + +CTLOBJS = $(CTLSOURCES:.ml=.cmo) +CTLOPTOBJS = $(CTLOBJS:.cmo=.cmx) + + +#all: $(EXEC) $(LIB) +all: $(LIB) + +all.opt: $(OPTLIB) + +ctl: $(CTLEXEC) + + +$(LIB): $(OBJS) + $(OCAMLC) -a -o $(LIB) $(OBJS) + +# clean rule for LIB +clean:: + rm -f $(LIB) + + +$(OPTLIB): $(OPTOBJS) + $(OCAMLOPT) -a -o $(OPTLIB) $(OPTOBJS) + + +$(EXEC): $(OBJS) main.cmo $(LIBS) + $(OCAMLC) -o $(EXEC) $(SYSLIBS) $(LIBS) $(OBJS) main.cmo + +$(CTLEXEC): $(CTLOBJS) $(LIBS) + $(OCAMLC) -o $(CTLEXEC) $(SYSLIBS) $(LIBS) $(CTLOBJS) + + +# clean rule for LIB.opt +clean:: + rm -f $(OPTLIB) $(LIB:.cma=.a) + rm -f $(TARGET) rm -f $(TARGET).byte + rm -f $(CTLTARGET) + + +.SUFFIXES: +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) -c $< + +.mli.cmi: + $(OCAMLC) -c $< + +.ml.cmx: + $(OCAMLOPT) -c $< + + +# clean rule for others files +clean:: + rm -f *.cm[iox] *.o *.annot + rm -f *~ .*~ #*# + +beforedepend: + +depend: beforedepend + $(OCAMLDEP) *.mli *.ml > .depend + +.depend: + $(OCAMLDEP) *.mli *.ml > .depend + +-include .depend diff --git a/engine/asttoctl.ml b/engine/asttoctl.ml new file mode 100644 index 0000000..05e445f --- /dev/null +++ b/engine/asttoctl.ml @@ -0,0 +1,1462 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* true = don't see all matched nodes, only modified ones *) +let onlyModif = ref true(*false*) +(* set to true for line numbers in the output of ctl_engine *) +let line_numbers = ref false +(* if true, only eg if header is included in not for ...s *) +let simple_get_end = ref false(*true*) + +(* Question: where do we put the existential quantifier for or. At the +moment, let it float inwards. *) + +(* nest shouldn't overlap with what comes after. not checked for. *) + +module Ast = Ast_cocci +module V = Visitor_ast +module CTL = Ast_ctl +module FV = Free_vars + +let warning s = Printf.fprintf stderr "warning: %s\n" s + +type cocci_predicate = Lib_engine.predicate * string Ast_ctl.modif +type formula = + (cocci_predicate,string, Wrapper_ctl.info) Ast_ctl.generic_ctl + + +let aftpred = (Lib_engine.After,CTL.Control) +let retpred = (Lib_engine.Return,CTL.Control) +let exitpred = (Lib_engine.ErrorExit,CTL.Control) + +let intersect l1 l2 = List.filter (function x -> List.mem x l2) l1 +let subset l1 l2 = List.for_all (function x -> List.mem x l2) l1 + +(* --------------------------------------------------------------------- *) + +let rec drop_vs f = + CTL.rewrap f + (match CTL.unwrap f with + CTL.False as x -> x + | CTL.True as x -> x + | CTL.Pred(p) as x -> x + | CTL.Not(phi) -> CTL.Not(drop_vs phi) + | CTL.Exists(v,phi) -> + (match CTL.unwrap phi with + CTL.Pred((x,CTL.Modif v1)) when v = v1 -> CTL.Pred((x,CTL.Control)) + | _ -> CTL.Exists(v,drop_vs phi)) + | CTL.And(phi1,phi2) -> CTL.And(drop_vs phi1,drop_vs phi2) + | CTL.Or(phi1,phi2) -> CTL.Or(drop_vs phi1,drop_vs phi2) + | CTL.SeqOr(phi1,phi2) -> CTL.SeqOr(drop_vs phi1,drop_vs phi2) + | CTL.Implies(phi1,phi2) -> CTL.Implies(drop_vs phi1,drop_vs phi2) + | CTL.AF(dir,phi1,phi2) -> CTL.AF(dir,drop_vs phi1,drop_vs phi2) + | CTL.AX(dir,phi) -> CTL.AX(dir,drop_vs phi) + | CTL.AG(dir,phi) -> CTL.AG(dir,drop_vs phi) + | CTL.AU(dir,phi1,phi2,phi3,phi4) -> + CTL.AU(dir,drop_vs phi1,drop_vs phi2,drop_vs phi3,drop_vs phi4) + | CTL.EF(dir,phi) -> CTL.EF(dir,drop_vs phi) + | CTL.EX(dir,phi) -> CTL.EX(dir,drop_vs phi) + | CTL.EG(dir,phi) -> CTL.EG(dir,drop_vs phi) + | CTL.EU(dir,phi1,phi2) -> CTL.EU(dir,drop_vs phi1,drop_vs phi2) + | CTL.Ref(v) as x -> x + | CTL.Let(v,term1,body) -> CTL.Let(v,drop_vs term1,drop_vs body)) + +(* --------------------------------------------------------------------- *) + +let wrap n ctl = (ctl,n) + +let aftret = + wrap 0 (CTL.Or(wrap 0 (CTL.Pred aftpred),wrap 0 (CTL.Pred exitpred))) + +let wrapImplies n (x,y) = wrap n (CTL.Implies(x,y)) +let wrapExists n (x,y) = wrap n (CTL.Exists(x,y)) +let wrapAnd n (x,y) = wrap n (CTL.And(x,y)) +let wrapOr n (x,y) = wrap n (CTL.Or(x,y)) +let wrapSeqOr n (x,y) = wrap n (CTL.SeqOr(x,y)) +let wrapAU n (x,y) = wrap n (CTL.AU(CTL.FORWARD,x,y,drop_vs x,drop_vs y)) +let wrapEU n (x,y) = wrap n (CTL.EU(CTL.FORWARD,x,y)) +let wrapAX n (x) = wrap n (CTL.AX(CTL.FORWARD,x)) +let wrapBackAX n (x) = wrap n (CTL.AX(CTL.BACKWARD,x)) +let wrapEX n (x) = wrap n (CTL.EX(CTL.FORWARD,x)) +let wrapBackEX n (x) = wrap n (CTL.EX(CTL.BACKWARD,x)) +let wrapAG n (x) = wrap n (CTL.AG(CTL.FORWARD,x)) +let wrapEG n (x) = wrap n (CTL.EG(CTL.FORWARD,x)) +let wrapAF n (x) = wrap n (CTL.AF(CTL.FORWARD,x,drop_vs x)) +let wrapEF n (x) = wrap n (CTL.EF(CTL.FORWARD,x)) +let wrapNot n (x) = wrap n (CTL.Not(x)) +let wrapPred n (x) = wrap n (CTL.Pred(x)) +let wrapLet n (x,y,z) = wrap n (CTL.Let(x,y,z)) +let wrapRef n (x) = wrap n (CTL.Ref(x)) + +(* --------------------------------------------------------------------- *) + +let get_option fn = function + None -> None + | Some x -> Some (fn x) + +let get_list_option fn = function + None -> [] + | Some x -> fn x + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Eliminate OptStm *) + +(* for optional thing with nothing after, should check that the optional thing +never occurs. otherwise the matching stops before it occurs *) +let elim_opt = + let mcode x = x in + let donothing r k e = k e in + + let fvlist l = + List.fold_left Common.union_set [] (List.map Ast.get_fvs l) in + + let rec dots_list unwrapped wrapped = + match (unwrapped,wrapped) with + ([],_) -> [] + + | (Ast.Dots(_,_,_)::Ast.OptStm(stm)::(Ast.Dots(_,_,_) as u)::urest, + d0::_::d1::rest) + | (Ast.Nest(_,_,_)::Ast.OptStm(stm)::(Ast.Dots(_,_,_) as u)::urest, + d0::_::d1::rest) -> + let l = Ast.get_line stm in + let new_rest1 = stm :: (dots_list (u::urest) (d1::rest)) in + let new_rest2 = dots_list urest rest in + let fv_rest1 = fvlist new_rest1 in + let fv_rest2 = fvlist new_rest2 in + [d0;(Ast.Disj[(Ast.DOTS(new_rest1),l,fv_rest1,Ast.NoDots); + (Ast.DOTS(new_rest2),l,fv_rest2,Ast.NoDots)], + l,fv_rest1,Ast.NoDots)] + + | (Ast.OptStm(stm)::urest,_::rest) -> + let l = Ast.get_line stm in + let new_rest1 = dots_list urest rest in + let new_rest2 = stm::new_rest1 in + let fv_rest1 = fvlist new_rest1 in + let fv_rest2 = fvlist new_rest2 in + [(Ast.Disj[(Ast.DOTS(new_rest2),l,fv_rest2,Ast.NoDots); + (Ast.DOTS(new_rest1),l,fv_rest1,Ast.NoDots)], + l,fv_rest2,Ast.NoDots)] + + | ([Ast.Dots(_,_,_);Ast.OptStm(stm)],[d1;_]) -> + let l = Ast.get_line stm in + let fv_stm = Ast.get_fvs stm in + let fv_d1 = Ast.get_fvs d1 in + let fv_both = Common.union_set fv_stm fv_d1 in + [d1;(Ast.Disj[(Ast.DOTS([stm]),l,fv_stm,Ast.NoDots); + (Ast.DOTS([d1]),l,fv_d1,Ast.NoDots)], + l,fv_both,Ast.NoDots)] + + | ([Ast.Nest(_,_,_);Ast.OptStm(stm)],[d1;_]) -> + let l = Ast.get_line stm in + let rw = Ast.rewrap stm in + let rwd = Ast.rewrap stm in + let dots = + Ast.Dots(("...",{ Ast.line = 0; Ast.column = 0 }, + Ast.CONTEXT(Ast.NOTHING)), + Ast.NoWhen,[]) in + [d1;rw(Ast.Disj[rwd(Ast.DOTS([stm])); + (Ast.DOTS([rw dots]),l,[],Ast.NoDots)])] + + | (_::urest,stm::rest) -> stm :: (dots_list urest rest) + | _ -> failwith "not possible" in + + let stmtdotsfn r k d = + let d = k d in + Ast.rewrap d + (match Ast.unwrap d with + Ast.DOTS(l) -> Ast.DOTS(dots_list (List.map Ast.unwrap l) l) + | Ast.CIRCLES(l) -> failwith "elimopt: not supported" + | Ast.STARS(l) -> failwith "elimopt: not supported") in + + V.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + donothing donothing stmtdotsfn + donothing donothing donothing donothing donothing donothing donothing + donothing donothing donothing + +(* --------------------------------------------------------------------- *) +(* Count depth of braces. The translation of a closed brace appears deeply +nested within the translation of the sequence term, so the name of the +paren var has to take into account the names of the nested braces. On the +other hand the close brace does not escape, so we don't have to take into +account other paren variable names. *) + +(* called repetitively, which is inefficient, but less trouble than adding a +new field to Seq and FunDecl *) +let count_nested_braces s = + let bind x y = max x y in + let option_default = 0 in + let stmt_count r k s = + match Ast.unwrap s with + Ast.Seq(_,_,_,_,_) | Ast.FunDecl(_,_,_,_,_,_) -> (k s) + 1 + | _ -> k s in + let donothing r k e = k e in + let mcode r x = 0 in + let recursor = V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + donothing donothing donothing + donothing donothing donothing donothing donothing donothing + donothing stmt_count donothing donothing in + "p"^(string_of_int (recursor.V.combiner_statement s)) + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +let ctr = ref 0 +let fresh_var _ = + let c = !ctr in + (*ctr := !ctr + 1;*) + Printf.sprintf "v%d" c + +let labctr = ref 0 +let fresh_label_var s = + let c = !labctr in + labctr := !labctr + 1; + Printf.sprintf "%s%d" s c + +let lctr = ref 0 +let fresh_let_var _ = + let c = !lctr in + lctr := !lctr + 1; + Printf.sprintf "l%d" c + +let sctr = ref 0 +let fresh_metavar _ = + let c = !sctr in +(*sctr := !sctr + 1;*) + Printf.sprintf "_S%d" c + +let get_unquantified quantified vars = + List.filter (function x -> not (List.mem x quantified)) vars + +type after = After of formula | Guard of formula | Tail + +let make_seq n l = + let rec loop = function + [] -> failwith "not possible" + | [x] -> x + | x::xs -> wrapAnd n (x,wrapAX n (loop xs)) in + loop l + +let make_seq_after2 n first = function + After rest -> wrapAnd n (first,wrapAX n (wrapAX n rest)) + | _ -> first + +let make_seq_after n first = function + After rest -> make_seq n [first;rest] + | _ -> first + +let a2n = function After f -> Guard f | x -> x + +let and_opt n first = function + After rest -> wrapAnd n (first,rest) + | _ -> first + +let contains_modif = + let bind x y = x or y in + let option_default = false in + let mcode r (_,_,kind) = + match kind with + Ast.MINUS(_) -> true + | Ast.PLUS -> failwith "not possible" + | Ast.CONTEXT(info) -> not (info = Ast.NOTHING) in + let do_nothing r k e = k e in + let recursor = + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing do_nothing in + recursor.V.combiner_rule_elem + +let make_match n guard used_after code = + if guard + then wrapPred n (Lib_engine.Match(code),CTL.Control) + else + let v = fresh_var() in + if contains_modif code + then wrapExists n (v,wrapPred n (Lib_engine.Match(code),CTL.Modif v)) + else + let any_used_after = + List.exists (function x -> List.mem x used_after) (Ast.get_fvs code) in + if !onlyModif && not any_used_after + then wrapPred n (Lib_engine.Match(code),CTL.Control) + else wrapExists n (v,wrapPred n (Lib_engine.Match(code),CTL.UnModif v)) + +let make_raw_match n code = wrapPred n (Lib_engine.Match(code),CTL.Control) + +let rec seq_fvs quantified = function + [] -> [] + | fv1::fvs -> + let t1fvs = get_unquantified quantified fv1 in + let termfvs = + List.fold_left Common.union_set [] + (List.map (get_unquantified quantified) fvs) in + let bothfvs = Common.inter_set t1fvs termfvs in + let t1onlyfvs = Common.minus_set t1fvs bothfvs in + let new_quantified = Common.union_set bothfvs quantified in + (t1onlyfvs,bothfvs)::(seq_fvs new_quantified fvs) + +let seq_fvs2 quantified fv1 fv2 = + match seq_fvs quantified [fv1;fv2] with + [(t1fvs,bfvs);(t2fvs,[])] -> (t1fvs,bfvs,t2fvs) + | _ -> failwith "impossible" + +let seq_fvs3 quantified fv1 fv2 fv3 = + match seq_fvs quantified [fv1;fv2;fv3] with + [(t1fvs,b12fvs);(t2fvs,b23fvs);(t3fvs,[])] -> + (t1fvs,b12fvs,t2fvs,b23fvs,t3fvs) + | _ -> failwith "impossible" + +let seq_fvs4 quantified fv1 fv2 fv3 fv4 = + match seq_fvs quantified [fv1;fv2;fv3;fv4] with + [(t1fvs,b12fvs);(t2fvs,b23fvs);(t3fvs,b34fvs);(t4fvs,[])] -> + (t1fvs,b12fvs,t2fvs,b23fvs,t3fvs,b34fvs,t4fvs) + | _ -> failwith "impossible" + +let seq_fvs5 quantified fv1 fv2 fv3 fv4 fv5 = + match seq_fvs quantified [fv1;fv2;fv3;fv4;fv5] with + [(t1fvs,b12fvs);(t2fvs,b23fvs);(t3fvs,b34fvs);(t4fvs,b45fvs);(t5fvs,[])] -> + (t1fvs,b12fvs,t2fvs,b23fvs,t3fvs,b34fvs,t4fvs,b45fvs,t5fvs) + | _ -> failwith "impossible" + +let quantify n = + List.fold_right (function cur -> function code -> wrapExists n (cur,code)) + +let intersectll lst nested_list = + List.filter (function x -> List.exists (List.mem x) nested_list) lst + +(* --------------------------------------------------------------------- *) +(* annotate dots with before and after neighbors *) + +let rec get_before sl a = + match Ast.unwrap sl with + Ast.DOTS(x) -> + let rec loop sl a = + match sl with + [] -> ([],a) + | e::sl -> + let (e,ea) = get_before_e e a in + let (sl,sla) = loop sl ea in + (e::sl,sla) in + let (l,a) = loop x a in + (Ast.rewrap sl (Ast.DOTS(l)),a) + | Ast.CIRCLES(x) -> failwith "not supported" + | Ast.STARS(x) -> failwith "not supported" + +and get_before_e s a = + match Ast.unwrap s with + Ast.Dots(d,Ast.NoWhen,t) -> + (Ast.rewrap s (Ast.Dots(d,Ast.NoWhen,a@t)),a) + | Ast.Dots(d,Ast.WhenNot w,t) -> + let (w,_) = get_before w [] in + (Ast.rewrap s (Ast.Dots(d,Ast.WhenNot w,a@t)),a) + | Ast.Dots(d,Ast.WhenAlways w,t) -> + let (w,_) = get_before_e w [] in + (Ast.rewrap s (Ast.Dots(d,Ast.WhenAlways w,a@t)),a) + | Ast.Nest(stmt_dots,w,t) -> + let (w,_) = List.split (List.map (function s -> get_before s []) w) in + let (sd,_) = get_before stmt_dots a in + let a = + List.filter + (function + Ast.Other a -> + let unifies = + Unify_ast.unify_statement_dots + (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in + (match unifies with + Unify_ast.MAYBE -> false + | _ -> true) + | Ast.Other_dots a -> + let unifies = Unify_ast.unify_statement_dots a stmt_dots in + (match unifies with + Unify_ast.MAYBE -> false + | _ -> true) + | _ -> true) + a in + (Ast.rewrap s (Ast.Nest(sd,w,a@t)),[Ast.Other_dots stmt_dots]) + | Ast.Disj(stmt_dots_list) -> + let (dsl,dsla) = + List.split (List.map (function e -> get_before e a) stmt_dots_list) in + (Ast.rewrap s (Ast.Disj(dsl)),List.fold_left Common.union_set [] dsla) + | Ast.Atomic(ast) -> + (match Ast.unwrap ast with + Ast.MetaStmt(_,_,_) -> (s,[]) + | _ -> (s,[Ast.Other s])) + | Ast.Seq(lbrace,decls,dots,body,rbrace) -> + let index = count_nested_braces s in + let (de,dea) = get_before decls [Ast.WParen(lbrace,index)] in + let (bd,_) = get_before body dea in + (Ast.rewrap s (Ast.Seq(lbrace,de,dots,bd,rbrace)), + [Ast.WParen(rbrace,index)]) + | Ast.IfThen(ifheader,branch,aft) -> + let (br,_) = get_before_e branch [] in + (Ast.rewrap s (Ast.IfThen(ifheader,br,aft)), [Ast.Other s]) + | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) -> + let (br1,_) = get_before_e branch1 [] in + let (br2,_) = get_before_e branch2 [] in + (Ast.rewrap s (Ast.IfThenElse(ifheader,br1,els,br2,aft)),[Ast.Other s]) + | Ast.While(header,body,aft) -> + let (bd,_) = get_before_e body [] in + (Ast.rewrap s (Ast.While(header,bd,aft)),[Ast.Other s]) + | Ast.For(header,body,aft) -> + let (bd,_) = get_before_e body [] in + (Ast.rewrap s (Ast.For(header,bd,aft)),[Ast.Other s]) + | Ast.FunDecl(header,lbrace,decls,dots,body,rbrace) -> + let index = count_nested_braces s in + let (de,dea) = get_before decls [Ast.WParen(lbrace,index)] in + let (bd,_) = get_before body dea in + (Ast.rewrap s (Ast.FunDecl(header,lbrace,de,dots,bd,rbrace)),[]) + | _ -> failwith "not supported" + +let rec get_after sl a = + match Ast.unwrap sl with + Ast.DOTS(x) -> + let rec loop sl = + match sl with + [] -> ([],a) + | e::sl -> + let (sl,sla) = loop sl in + let (e,ea) = get_after_e e sla in + (e::sl,ea) in + let (l,a) = loop x in + (Ast.rewrap sl (Ast.DOTS(l)),a) + | Ast.CIRCLES(x) -> failwith "not supported" + | Ast.STARS(x) -> failwith "not supported" + +and get_after_e s a = + match Ast.unwrap s with + Ast.Dots(d,Ast.NoWhen,t) -> + (Ast.rewrap s (Ast.Dots(d,Ast.NoWhen,a@t)),a) + | Ast.Dots(d,Ast.WhenNot w,t) -> + let (w,_) = get_after w [] in + (Ast.rewrap s (Ast.Dots(d,Ast.WhenNot w,a@t)),a) + | Ast.Dots(d,Ast.WhenAlways w,t) -> + let (w,_) = get_after_e w [] in + (Ast.rewrap s (Ast.Dots(d,Ast.WhenAlways w,a@t)),a) + | Ast.Nest(stmt_dots,w,t) -> + let (w,_) = List.split (List.map (function s -> get_after s []) w) in + let (sd,_) = get_after stmt_dots a in + let a = + List.filter + (function + Ast.Other a -> + let unifies = + Unify_ast.unify_statement_dots + (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in + (match unifies with + Unify_ast.MAYBE -> false + | _ -> true) + | Ast.Other_dots a -> + let unifies = Unify_ast.unify_statement_dots a stmt_dots in + (match unifies with + Unify_ast.MAYBE -> false + | _ -> true) + | _ -> true) + a in + (Ast.rewrap s (Ast.Nest(sd,w,a@t)),[Ast.Other_dots stmt_dots]) + | Ast.Disj(stmt_dots_list) -> + let (dsl,dsla) = + List.split (List.map (function e -> get_after e a) stmt_dots_list) in + (Ast.rewrap s (Ast.Disj(dsl)),List.fold_left Common.union_set [] dsla) + | Ast.Atomic(ast) -> + (match Ast.unwrap ast with + Ast.MetaStmt(nm,Ast.SequencibleAfterDots _,i) -> + (* check after information for metavar optimization *) + (* if the error is not desired, could just return [], then + the optimization (check for EF) won't take place *) + List.iter + (function + Ast.Other x -> + (match Ast.unwrap x with + Ast.Dots(_,_,_) | Ast.Nest(_,_,_) -> + failwith + "dots/nest not allowed before and after stmt metavar" + | _ -> ()) + | Ast.Other_dots x -> + (match Ast.undots x with + x::_ -> + (match Ast.unwrap x with + Ast.Dots(_,_,_) | Ast.Nest(_,_,_) -> + failwith + ("dots/nest not allowed before and after stmt "^ + "metavar") + | _ -> ()) + | _ -> ()) + | _ -> ()) + a; + (Ast.rewrap s + (Ast.Atomic + (Ast.rewrap s + (Ast.MetaStmt(nm,Ast.SequencibleAfterDots a,i)))),[]) + | Ast.MetaStmt(_,_,_) -> (s,[]) + | _ -> (s,[Ast.Other s])) + | Ast.Seq(lbrace,decls,dots,body,rbrace) -> + let index = count_nested_braces s in + let (bd,bda) = get_after body [Ast.WParen(rbrace,index)] in + let (de,_) = get_after decls bda in + (Ast.rewrap s (Ast.Seq(lbrace,de,dots,bd,rbrace)), + [Ast.WParen(lbrace,index)]) + | Ast.IfThen(ifheader,branch,aft) -> + let (br,_) = get_after_e branch a in + (Ast.rewrap s (Ast.IfThen(ifheader,br,aft)),[Ast.Other s]) + | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) -> + let (br1,_) = get_after_e branch1 a in + let (br2,_) = get_after_e branch2 a in + (Ast.rewrap s (Ast.IfThenElse(ifheader,br1,els,br2,aft)),[Ast.Other s]) + | Ast.While(header,body,aft) -> + let (bd,_) = get_after_e body a in + (Ast.rewrap s (Ast.While(header,bd,aft)),[Ast.Other s]) + | Ast.For(header,body,aft) -> + let (bd,_) = get_after_e body a in + (Ast.rewrap s (Ast.For(header,bd,aft)),[Ast.Other s]) + | Ast.FunDecl(header,lbrace,decls,dots,body,rbrace) -> + let index = count_nested_braces s in + let (bd,bda) = get_after body [Ast.WParen(rbrace,index)] in + let (de,_) = get_after decls bda in + (Ast.rewrap s (Ast.FunDecl(header,lbrace,de,dots,bd,rbrace)),[]) + | _ -> failwith "not supported" + + +let preprocess_dots sl = + let (sl,_) = get_before sl [] in + let (sl,_) = get_after sl [] in + sl + +let preprocess_dots_e sl = + let (sl,_) = get_before_e sl [] in + let (sl,_) = get_after_e sl [] in + sl + +(* --------------------------------------------------------------------- *) +(* the main translation loop *) + +let decl_to_not_decl n dots stmt make_match f = + if dots + then f + else + let de = + let md = Ast.make_meta_decl "_d" (Ast.CONTEXT(Ast.NOTHING)) in + Ast.rewrap md (Ast.Decl md) in + wrapAU n (make_match de, + wrap n (CTL.And(wrap n (CTL.Not (make_match de)), f))) + +let rec statement_list stmt_list used_after after quantified guard = + let n = if !line_numbers then Ast.get_line stmt_list else 0 in + match Ast.unwrap stmt_list with + Ast.DOTS(x) -> + let rec loop quantified = function + ([],_) -> (match after with After f -> f | _ -> wrap n CTL.True) + | ([e],_) -> statement e used_after after quantified guard + | (e::sl,fv::fvs) -> + let shared = intersectll fv fvs in + let unqshared = get_unquantified quantified shared in + let new_quantified = Common.union_set unqshared quantified in + quantify n unqshared + (statement e used_after (After(loop new_quantified (sl,fvs))) + new_quantified guard) + | _ -> failwith "not possible" in + loop quantified (x,List.map Ast.get_fvs x) + | Ast.CIRCLES(x) -> failwith "not supported" + | Ast.STARS(x) -> failwith "not supported" + +and statement stmt used_after after quantified guard = + + let n = if !line_numbers then Ast.get_line stmt else 0 in + let wrapExists = wrapExists n in + let wrapAnd = wrapAnd n in + let wrapOr = wrapOr n in + let wrapSeqOr = wrapSeqOr n in + let wrapAU = wrapAU n in + let wrapAX = wrapAX n in + let wrapBackAX = wrapBackAX n in + let wrapEX = wrapEX n in + let wrapBackEX = wrapBackEX n in + let wrapAG = wrapAG n in + let wrapAF = wrapAF n in + let wrapEF = wrapEF n in + let wrapNot = wrapNot n in + let wrapPred = wrapPred n in + let make_seq = make_seq n in + let make_seq_after2 = make_seq_after2 n in + let make_seq_after = make_seq_after n in + let and_opt = and_opt n in + let quantify = quantify n in + let make_match = make_match n guard used_after in + let make_raw_match = make_raw_match n in + + let make_meta_rule_elem d = + let nm = fresh_metavar() in + Ast.make_meta_rule_elem nm d in + + match Ast.unwrap stmt with + Ast.Atomic(ast) -> + (match Ast.unwrap ast with + Ast.MetaStmt((s,i,(Ast.CONTEXT(Ast.BEFOREAFTER(_,_)) as d)),seqible,_) + | Ast.MetaStmt((s,i,(Ast.CONTEXT(Ast.AFTER(_)) as d)),seqible,_) -> + let label_var = (*fresh_label_var*) "_lab" in + let label_pred = wrapPred(Lib_engine.Label(label_var),CTL.Control) in + let prelabel_pred = + wrapPred(Lib_engine.PrefixLabel(label_var),CTL.Control) in + let matcher d = make_match (make_meta_rule_elem d) in + let full_metamatch = matcher d in + let first_metamatch = + matcher + (match d with + Ast.CONTEXT(Ast.BEFOREAFTER(bef,_)) -> + Ast.CONTEXT(Ast.BEFORE(bef)) + | Ast.CONTEXT(_) -> Ast.CONTEXT(Ast.NOTHING) + | Ast.MINUS(_) | Ast.PLUS -> failwith "not possible") in + let middle_metamatch = + matcher + (match d with + Ast.CONTEXT(_) -> Ast.CONTEXT(Ast.NOTHING) + | Ast.MINUS(_) | Ast.PLUS -> failwith "not possible") in + let last_metamatch = + matcher + (match d with + Ast.CONTEXT(Ast.BEFOREAFTER(_,aft)) -> + Ast.CONTEXT(Ast.AFTER(aft)) + | Ast.CONTEXT(_) -> d + | Ast.MINUS(_) | Ast.PLUS -> failwith "not possible") in + + let left_or = + make_seq + [full_metamatch; and_opt (wrapNot(prelabel_pred)) after] in + let right_or = + make_seq + [first_metamatch; + wrapAU(middle_metamatch, + make_seq + [wrapAnd(last_metamatch,label_pred); + and_opt (wrapNot(prelabel_pred)) after])] in + let body f = + wrapAnd(label_pred, + f (wrapAnd(make_raw_match ast, + wrapOr(left_or,right_or)))) in + let id x = x in + (match seqible with + Ast.Sequencible | Ast.SequencibleAfterDots [] -> + quantify (label_var::get_unquantified quantified [s]) + (body + (function x -> + (wrapAnd(wrapNot(wrapBackAX(label_pred)),x)))) + | Ast.SequencibleAfterDots l -> + let afts = + List.map (process_bef_aft Tail quantified used_after n) l in + let ors = + List.fold_left (function x -> function y -> wrapOr(x,y)) + (List.hd afts) (List.tl afts) in + quantify (label_var::get_unquantified quantified [s]) + (wrapAnd(wrapEF(wrapAnd(ors,wrapBackAX(label_pred))), + body + (function x -> + wrapAnd(wrapNot(wrapBackAX(label_pred)),x)))) + | Ast.NotSequencible -> + quantify (label_var::get_unquantified quantified [s]) (body id)) + + | Ast.MetaStmt((s,i,d),seqible,_) -> + let label_var = (*fresh_label_var*) "_lab" in + let label_pred = wrapPred(Lib_engine.Label(label_var),CTL.Control) in + let prelabel_pred = + wrapPred(Lib_engine.PrefixLabel(label_var),CTL.Control) in + let matcher d = make_match (make_meta_rule_elem d) in + let first_metamatch = matcher d in + let rest_metamatch = + matcher + (match d with + Ast.MINUS(_) -> Ast.MINUS([]) + | Ast.CONTEXT(_) -> Ast.CONTEXT(Ast.NOTHING) + | Ast.PLUS -> failwith "not possible") in + (* first_nodea and first_nodeb are separated here and above to + improve let sharing - only first_nodea is unique to this site *) + let first_nodeb = first_metamatch in + let rest_nodes = wrapAnd(rest_metamatch,prelabel_pred) in + let last_node = and_opt (wrapNot(prelabel_pred)) after in + let body f = + wrapAnd + (label_pred, + f (wrapAnd + (make_raw_match ast, + (make_seq + [first_nodeb; wrapAU(rest_nodes,last_node)])))) in + (match seqible with + Ast.Sequencible | Ast.SequencibleAfterDots [] -> + quantify (label_var::get_unquantified quantified [s]) + (body + (function x -> wrapAnd(wrapNot(wrapBackAX(label_pred)),x))) + | Ast.SequencibleAfterDots l -> + let afts = + List.map (process_bef_aft Tail quantified used_after n) l in + let ors = + List.fold_left (function x -> function y -> wrapOr(x,y)) + (List.hd afts) (List.tl afts) in + quantify (label_var::get_unquantified quantified [s]) + (wrapAnd(wrapEF(wrapAnd(ors,wrapBackAX(label_pred))), + body + (function x -> + wrapAnd(wrapNot(wrapBackAX(label_pred)),x)))) + | Ast.NotSequencible -> + quantify (label_var::get_unquantified quantified [s]) + (body (function x -> x))) + | _ -> + let stmt_fvs = Ast.get_fvs stmt in + let fvs = get_unquantified quantified stmt_fvs in + let between_dots = Ast.get_dots_bef_aft stmt in + let term = make_match ast in + let term = + match between_dots with + Ast.BetweenDots brace_term -> + (match Ast.unwrap brace_term with + Ast.Atomic(brace_ast) -> + let case1 = + wrapAnd + (wrapOr + (wrapBackEX + (wrapPred(Lib_engine.TrueBranch,CTL.Control)), + wrapBackEX + (wrapBackEX(wrapPred(Lib_engine.FalseBranch, + CTL.Control)))), + make_match brace_ast) in + let case2 = + wrapAnd + (wrapNot + (wrapOr + (wrapBackEX + (wrapPred(Lib_engine.TrueBranch,CTL.Control)), + wrapBackEX + (wrapBackEX(wrapPred(Lib_engine.FalseBranch, + CTL.Control))))), + term) in + wrapOr(case1,case2) + | _ -> failwith "not possible") + | Ast.NoDots -> term in + make_seq_after (quantify fvs term) after) + | Ast.Seq(lbrace,decls,dots,body,rbrace) -> + let (lbfvs,b1fvs,_,b2fvs,_,b3fvs,rbfvs) = + seq_fvs4 quantified + (Ast.get_fvs lbrace) (Ast.get_fvs decls) + (Ast.get_fvs body) (Ast.get_fvs rbrace) in + let v = count_nested_braces stmt in + let paren_pred = wrapPred(Lib_engine.Paren v,CTL.Control) in + let start_brace = + wrapAnd(quantify lbfvs (make_match lbrace),paren_pred) in + let end_brace = + wrapAnd(quantify rbfvs (make_match rbrace),paren_pred) in + let new_quantified2 = + Common.union_set b1fvs (Common.union_set b2fvs quantified) in + let new_quantified3 = Common.union_set b3fvs new_quantified2 in + wrapExists + (v,quantify b1fvs + (make_seq + [start_brace; + quantify b2fvs + (statement_list decls used_after + (After + (decl_to_not_decl n dots stmt make_match + (quantify b3fvs + (statement_list body used_after + (After (make_seq_after end_brace after)) + new_quantified3 guard)))) + new_quantified2 guard)])) + | Ast.IfThen(ifheader,branch,aft) -> + +(* "if (test) thn" becomes: + if(test) & AX((TrueBranch & AX thn) v FallThrough v After) + + "if (test) thn; after" becomes: + if(test) & AX((TrueBranch & AX thn) v FallThrough v (After & AXAX after)) + & EX After +*) + + (* free variables *) + let (efvs,bfvs,_) = + seq_fvs2 quantified (Ast.get_fvs ifheader) (Ast.get_fvs branch) in + let new_quantified = Common.union_set bfvs quantified in + (* if header *) + let if_header = quantify efvs (make_match ifheader) in + (* then branch and after *) + let true_branch = + make_seq + [wrapPred(Lib_engine.TrueBranch,CTL.Control); + statement branch used_after (a2n after) new_quantified guard] in + let fall_branch = wrapPred(Lib_engine.FallThrough,CTL.Control) in + let after_pred = wrapPred(Lib_engine.After,CTL.Control) in + let (aft_needed,after_branch) = + match aft with + Ast.CONTEXT(Ast.NOTHING) -> (false,make_seq_after2 after_pred after) + | _ -> + (true, + make_seq_after after_pred + (After + (make_seq_after (make_match (make_meta_rule_elem aft)) + after))) in + let or_cases = wrapOr(true_branch,wrapOr(fall_branch,after_branch)) in + (* the code *) + (match (after,aft_needed) with + (After _,_) (* pattern doesn't end here *) + | (_,true) (* + code added after *) -> + quantify bfvs + (wrapAnd (if_header, wrapAnd(wrapAX or_cases, wrapEX after_pred))) + | _ -> quantify bfvs (wrapAnd(if_header, wrapAX or_cases))) + + | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) -> + +(* "if (test) thn else els" becomes: + if(test) & AX((TrueBranch & AX thn) v + (FalseBranch & AX (else & AX els)) v After) + & EX FalseBranch + + "if (test) thn else els; after" becomes: + if(test) & AX((TrueBranch & AX thn) v + (FalseBranch & AX (else & AX els)) v + (After & AXAX after)) + & EX FalseBranch + & EX After + + + Note that we rely on the well-formedness of C programs. For example, we + do not use EX to check that there is at least one then branch, because + there is always one. And we do not check that there is only one then or + else branch, because these again are always the case in a well-formed C + program. *) + (* free variables *) + let (e1fvs,b1fvs,s1fvs) = + seq_fvs2 quantified (Ast.get_fvs ifheader) (Ast.get_fvs branch1) in + let (e2fvs,b2fvs,s2fvs) = + seq_fvs2 quantified (Ast.get_fvs ifheader) (Ast.get_fvs branch2) in + let bothfvs = + Common.union_set + (Common.union_set b1fvs b2fvs) + (Common.inter_set s1fvs s2fvs) in + let exponlyfvs = Common.inter_set e1fvs e2fvs in + let new_quantified = Common.union_set bothfvs quantified in + (* if header *) + let if_header = quantify exponlyfvs (make_match ifheader) in + (* then and else branches *) + let true_branch = + make_seq + [wrapPred(Lib_engine.TrueBranch,CTL.Control); + statement branch1 used_after (a2n after) new_quantified guard] in + let false_pred = wrapPred(Lib_engine.FalseBranch,CTL.Control) in + let false_branch = + make_seq + [false_pred; make_match els; + statement branch2 used_after (a2n after) new_quantified guard] in + let after_pred = wrapPred(Lib_engine.After,CTL.Control) in + let (aft_needed,after_branch) = + match aft with + Ast.CONTEXT(Ast.NOTHING) -> (false,make_seq_after2 after_pred after) + | _ -> + (true, + make_seq_after after_pred + (After + (make_seq_after (make_match (make_meta_rule_elem aft)) + after))) in + let or_cases = wrapOr(true_branch,wrapOr(false_branch,after_branch)) in + (* the code *) + (match (after,aft_needed) with + (After _,_) (* pattern doesn't end here *) + | (_,true) (* + code added after *) -> + quantify bothfvs + (wrapAnd + (if_header, + wrapAnd(wrapAX or_cases, + wrapAnd(wrapEX false_pred,wrapEX after_pred)))) + | _ -> + quantify bothfvs + (wrapAnd (if_header, wrapAnd(wrapAX or_cases, wrapEX false_pred)))) + + | Ast.While(header,body,aft) | Ast.For(header,body,aft) -> + (* the translation in this case is similar to that of an if with no else *) + (* free variables *) + let (efvs,bfvs,_) = + seq_fvs2 quantified (Ast.get_fvs header) (Ast.get_fvs body) in + let new_quantified = Common.union_set bfvs quantified in + (* if header *) + let header = quantify efvs (make_match header) in + let body = + make_seq + [wrapPred(Lib_engine.TrueBranch,CTL.Control); + statement body used_after (a2n after) new_quantified guard] in + let after_pred = wrapPred(Lib_engine.FallThrough,CTL.Control) in + let (aft_needed,after_branch) = + match aft with + Ast.CONTEXT(Ast.NOTHING) -> (false,make_seq_after2 after_pred after) + | _ -> + (true, + make_seq_after after_pred + (After + (make_seq_after (make_match (make_meta_rule_elem aft)) + after))) in + let or_cases = wrapOr(body,after_branch) in + (* the code *) + (match (after,aft_needed) with + (After _,_) (* pattern doesn't end here *) + | (_,true) (* + code added after *) -> + quantify bfvs + (wrapAnd (header, wrapAnd(wrapAX or_cases, wrapEX after_pred))) + | _ -> quantify bfvs (wrapAnd(header, wrapAX or_cases))) + + | Ast.Disj(stmt_dots_list) -> + let processed = + List.map + (function x -> statement_list x used_after after quantified guard) + stmt_dots_list in + let rec loop = function + [] -> wrap n CTL.True + | [x] -> x + | x::xs -> wrapSeqOr(x,loop xs) in + loop processed +(* + let do_one e = + statement_list e used_after (a2n after) quantified true in + let add_nots l e = + List.fold_left + (function rest -> function cur -> wrapAnd(wrapNot(do_one cur),rest)) + e l in + let process_one nots cur = + match Ast.unwrap cur with + Ast.DOTS(x::xs) -> + let on = List.map (function x -> Ast.OrOther_dots x) nots in + (match Ast.unwrap x with + Ast.Dots(d,w,t) -> + List.iter + (function x -> + Printf.printf "a not\n"; + Pretty_print_cocci.statement_dots x) + nots; + let cur = + Ast.rewrap cur + (Ast.DOTS((Ast.rewrap x (Ast.Dots(d,w,on@t)))::xs)) in + statement_list cur used_after after quantified guard + | Ast.Nest(sd,w,t) -> + let cur = + Ast.rewrap cur + (Ast.DOTS((Ast.rewrap x (Ast.Nest(sd,w,on@t)))::xs)) in + statement_list cur used_after after quantified guard + | _ -> + add_nots nots + (statement_list cur used_after after quantified guard)) + | Ast.DOTS([]) -> + add_nots nots + (statement_list cur used_after after quantified guard) + | _ -> failwith "CIRCLES, STARS not supported" in + let rec loop after = function + [] -> failwith "disj shouldn't be empty" (*wrap n CTL.False*) + | [(nots,cur)] -> process_one nots cur + | (nots,cur)::rest -> wrapOr(process_one nots cur, loop after rest) in + loop after (preprocess_disj stmt_dots_list) +*) + | Ast.Nest(stmt_dots,whencode,befaft) -> + let dots_pattern = + statement_list stmt_dots used_after (a2n after) quantified guard in + let udots_pattern = + let whencodes = + List.map + (function sl -> + statement_list sl used_after (a2n after) quantified true) + whencode in + List.fold_left (function rest -> function cur -> wrapOr(cur,rest)) + (statement_list stmt_dots used_after (a2n after) quantified true) + whencodes in + (match (after,guard&&(whencode=[])) with + (After a,true) -> + let nots = + List.map (process_bef_aft after quantified used_after n) befaft in + (match nots with + [] -> wrapAF(wrapOr(a,aftret)) + | x::xs -> + let left = + wrapNot + (List.fold_left + (function rest -> function cur -> wrapOr(cur,rest)) + x xs) in + wrapAU(left,wrapOr(a,aftret))) + | (After a,false) -> + let left = wrapOr(dots_pattern,wrapNot udots_pattern) in + let nots = + List.map (process_bef_aft after quantified used_after n) befaft in + let left = + match nots with + [] -> left + | x::xs -> + wrapAnd + (wrapNot + (List.fold_left + (function rest -> function cur -> wrapOr(cur,rest)) + x xs), + left) in + wrapAU(left,wrapOr(a,aftret)) + | (_,true) -> wrap n CTL.True + | (_,false) -> wrapAG(wrapOr(dots_pattern,wrapNot udots_pattern))) + | Ast.Dots((_,i,d),whencodes,t) -> + let dot_code = + match d with + Ast.MINUS(_) -> + (* no need for the fresh metavar, but ... is a bit wierd as a + variable name *) + Some(make_match (make_meta_rule_elem d)) + | _ -> None in + let whencodes = + (match whencodes with + Ast.NoWhen -> [] + | Ast.WhenNot whencodes -> + [wrapNot + (statement_list whencodes used_after (a2n after) quantified + true)] + | Ast.WhenAlways s -> + [statement s used_after (a2n after) quantified true]) @ + (List.map wrapNot + (List.map (process_bef_aft after quantified used_after n) t)) in + let phi2 = + match whencodes with + [] -> None + | x::xs -> + Some + (List.fold_left + (function rest -> function cur -> wrapAnd(cur,rest)) + x xs) in + let phi3 = + match (dot_code,phi2) with (* add - on dots, if any *) + (None,None) -> None + | (Some dotcode,None) -> Some dotcode + | (None,Some whencode) -> Some whencode + | (Some dotcode,Some whencode) -> Some(wrapAnd (dotcode,whencode)) in + let exit = wrap n (CTL.Pred (Lib_engine.Exit,CTL.Control)) in + (* add in the after code to make the result *) + (match (after,phi3) with + (Tail,Some whencode) -> wrapAU(whencode,wrapOr(exit,aftret)) + | (Tail,None) -> wrapAF(wrapOr(exit,aftret)) + | (After f,Some whencode) | (Guard f,Some whencode) -> + wrapAU(whencode,wrapOr(f,aftret)) + | (After f,None) | (Guard f,None) -> wrapAF(wrapOr(f,aftret))) + | Ast.FunDecl(header,lbrace,decls,dots,body,rbrace) -> + let (hfvs,b1fvs,lbfvs,b2fvs,_,b3fvs,_,b4fvs,rbfvs) = + seq_fvs5 quantified (Ast.get_fvs header) (Ast.get_fvs lbrace) + (Ast.get_fvs decls) (Ast.get_fvs body) (Ast.get_fvs rbrace) in + let function_header = quantify hfvs (make_match header) in + let v = count_nested_braces stmt in + let paren_pred = wrapPred(Lib_engine.Paren v,CTL.Control) in + let start_brace = + wrapAnd(quantify lbfvs (make_match lbrace),paren_pred) in + let end_brace = + let stripped_rbrace = + match Ast.unwrap rbrace with + Ast.SeqEnd((data,info,_)) -> + Ast.rewrap rbrace + (Ast.SeqEnd ((data,info,Ast.CONTEXT(Ast.NOTHING)))) + | _ -> failwith "unexpected close brace" in + let exit = wrap n (CTL.Pred (Lib_engine.Exit,CTL.Control)) in + let errorexit = wrap n (CTL.Pred (Lib_engine.ErrorExit,CTL.Control)) in + wrapAnd(quantify rbfvs (make_match rbrace), + wrapAU(make_match stripped_rbrace, + wrapOr(exit,errorexit))) in + let new_quantified3 = + Common.union_set b1fvs + (Common.union_set b2fvs (Common.union_set b3fvs quantified)) in + let new_quantified4 = Common.union_set b4fvs new_quantified3 in + quantify b1fvs + (make_seq + [function_header; + wrapExists + (v, + (quantify b2fvs + (make_seq + [start_brace; + quantify b3fvs + (statement_list decls used_after + (After + (decl_to_not_decl n dots stmt + make_match + (quantify b4fvs + (statement_list body used_after + (After + (make_seq_after end_brace after)) + new_quantified4 guard)))) + new_quantified3 guard)])))]) + | Ast.OptStm(stm) -> + failwith "OptStm should have been compiled away\n"; + | Ast.UniqueStm(stm) -> + failwith "arities not yet supported" + | Ast.MultiStm(stm) -> + failwith "arities not yet supported" + | _ -> failwith "not supported" + +and process_bef_aft after quantified used_after ln = function + Ast.WParen (re,n) -> + let paren_pred = wrapPred ln (Lib_engine.Paren n,CTL.Control) in + wrapAnd ln (make_raw_match ln re,paren_pred) + | Ast.Other s -> statement s used_after (a2n after) quantified true + | Ast.Other_dots d -> statement_list d used_after (a2n after) quantified true + | Ast.OrOther_dots d -> statement_list d used_after Tail quantified true + +(* Returns a triple for each disj element. The first element of the triple is +Some v if the triple element needs a name, and None otherwise. The second +element is a list of names whose negations should be conjuncted with the +term. The third element is the original term *) +and (preprocess_disj : + Ast.statement Ast.dots list -> + (Ast.statement Ast.dots list * Ast.statement Ast.dots) list) = + function + [] -> [] + | [s] -> [([],s)] + | cur::rest -> + let template = + List.map (function r -> Unify_ast.unify_statement_dots cur r) rest in + let processed = preprocess_disj rest in + if List.exists (function Unify_ast.MAYBE -> true | _ -> false) template + then + ([], cur) :: + (List.map2 + (function ((nots,r) as x) -> + function Unify_ast.MAYBE -> (cur::nots,r) | Unify_ast.NO -> x) + processed template) + else ([], cur) :: processed + +(* --------------------------------------------------------------------- *) +(* Letify: +Phase 1: Use a hash table to identify formulas that appear more than once. +Phase 2: Replace terms by variables. +Phase 3: Drop lets to the point as close as possible to the uses of their +variables *) + +let formula_table = + (Hashtbl.create(50) : + ((cocci_predicate,string,Wrapper_ctl.info) CTL.generic_ctl, + int ref (* count *) * string ref (* name *) * bool ref (* processed *)) + Hashtbl.t) + +let add_hash phi = + let (cell,_,_) = + try Hashtbl.find formula_table phi + with Not_found -> + let c = (ref 0,ref "",ref false) in + Hashtbl.add formula_table phi c; + c in + cell := !cell + 1 + +let rec collect_duplicates f = + add_hash f; + match CTL.unwrap f with + CTL.False -> () + | CTL.True -> () + | CTL.Pred(p) -> () + | CTL.Not(phi) -> collect_duplicates phi + | CTL.Exists(v,phi) -> collect_duplicates phi + | CTL.And(phi1,phi2) -> collect_duplicates phi1; collect_duplicates phi2 + | CTL.Or(phi1,phi2) -> collect_duplicates phi1; collect_duplicates phi2 + | CTL.SeqOr(phi1,phi2) -> collect_duplicates phi1; collect_duplicates phi2 + | CTL.Implies(phi1,phi2) -> collect_duplicates phi1; collect_duplicates phi2 + | CTL.AF(_,phi1,phi2) -> collect_duplicates phi1; collect_duplicates phi2 + | CTL.AX(_,phi) -> collect_duplicates phi + | CTL.AG(_,phi) -> collect_duplicates phi + | CTL.AU(_,phi1,phi2,phi3,phi4) -> + collect_duplicates phi1; collect_duplicates phi2; + collect_duplicates phi3; collect_duplicates phi4 + | CTL.EF(_,phi) -> collect_duplicates phi + | CTL.EX(_,phi) -> collect_duplicates phi + | CTL.EG(_,phi) -> collect_duplicates phi + | CTL.EU(_,phi1,phi2) -> collect_duplicates phi1; collect_duplicates phi2 + | CTL.Uncheck(phi) -> collect_duplicates phi + | _ -> failwith "not possible" + +let assign_variables _ = + Hashtbl.iter + (function formula -> + function (cell,str,_) -> if !cell > 1 then str := fresh_let_var()) + formula_table + +let rec replace_formulas dec f = + let (ct,name,treated) = Hashtbl.find formula_table f in + let real_ct = !ct - dec in + if real_ct > 1 + then + if not !treated + then + begin + treated := true; + let (acc,new_f) = replace_subformulas (dec + (real_ct - 1)) f in + ((!name,new_f) :: acc, CTL.rewrap f (CTL.Ref !name)) + end + else ([],CTL.rewrap f (CTL.Ref !name)) + else replace_subformulas dec f + +and replace_subformulas dec f = + match CTL.unwrap f with + CTL.False -> ([],f) + | CTL.True -> ([],f) + | CTL.Pred(p) -> ([],f) + | CTL.Not(phi) -> + let (acc,new_phi) = replace_formulas dec phi in + (acc,CTL.rewrap f (CTL.Not(new_phi))) + | CTL.Exists(v,phi) -> + let (acc,new_phi) = replace_formulas dec phi in + (acc,CTL.rewrap f (CTL.Exists(v,new_phi))) + | CTL.And(phi1,phi2) -> + let (acc1,new_phi1) = replace_formulas dec phi1 in + let (acc2,new_phi2) = replace_formulas dec phi2 in + (acc1@acc2,CTL.rewrap f (CTL.And(new_phi1,new_phi2))) + | CTL.Or(phi1,phi2) -> + let (acc1,new_phi1) = replace_formulas dec phi1 in + let (acc2,new_phi2) = replace_formulas dec phi2 in + (acc1@acc2,CTL.rewrap f (CTL.Or(new_phi1,new_phi2))) + | CTL.SeqOr(phi1,phi2) -> + let (acc1,new_phi1) = replace_formulas dec phi1 in + let (acc2,new_phi2) = replace_formulas dec phi2 in + (acc1@acc2,CTL.rewrap f (CTL.SeqOr(new_phi1,new_phi2))) + | CTL.Implies(phi1,phi2) -> + let (acc1,new_phi1) = replace_formulas dec phi1 in + let (acc2,new_phi2) = replace_formulas dec phi2 in + (acc1@acc2,CTL.rewrap f (CTL.Implies(new_phi1,new_phi2))) + | CTL.AF(dir,phi1,phi2) -> + let (acc,new_phi1) = replace_formulas dec phi1 in + let (acc,new_phi2) = replace_formulas dec phi2 in + (acc,CTL.rewrap f (CTL.AF(dir,new_phi1,new_phi2))) + | CTL.AX(dir,phi) -> + let (acc,new_phi) = replace_formulas dec phi in + (acc,CTL.rewrap f (CTL.AX(dir,new_phi))) + | CTL.AG(dir,phi) -> + let (acc,new_phi) = replace_formulas dec phi in + (acc,CTL.rewrap f (CTL.AG(dir,new_phi))) + | CTL.AU(dir,phi1,phi2,phi3,phi4) -> + let (acc1,new_phi1) = replace_formulas dec phi1 in + let (acc2,new_phi2) = replace_formulas dec phi2 in + let (acc3,new_phi3) = replace_formulas dec phi3 in + let (acc4,new_phi4) = replace_formulas dec phi4 in + (acc1@acc2@acc3@acc4, + CTL.rewrap f (CTL.AU(dir,new_phi1,new_phi2,new_phi3,new_phi4))) + | CTL.EF(dir,phi) -> + let (acc,new_phi) = replace_formulas dec phi in + (acc,CTL.rewrap f (CTL.EF(dir,new_phi))) + | CTL.EX(dir,phi) -> + let (acc,new_phi) = replace_formulas dec phi in + (acc,CTL.rewrap f (CTL.EX(dir,new_phi))) + | CTL.EG(dir,phi) -> + let (acc,new_phi) = replace_formulas dec phi in + (acc,CTL.rewrap f (CTL.EG(dir,new_phi))) + | CTL.EU(dir,phi1,phi2) -> + let (acc1,new_phi1) = replace_formulas dec phi1 in + let (acc2,new_phi2) = replace_formulas dec phi2 in + (acc1@acc2,CTL.rewrap f (CTL.EU(dir,new_phi1,new_phi2))) + | _ -> failwith "not possible" + +let ctlfv_table = + (Hashtbl.create(50) : + ((cocci_predicate,string,Wrapper_ctl.info) CTL.generic_ctl, + string list (* fvs *) * + string list (* intersection of fvs of subterms *)) + Hashtbl.t) + +let rec ctl_fvs f = + try let (fvs,_) = Hashtbl.find ctlfv_table f in fvs + with Not_found -> + let ((fvs,_) as res) = + match CTL.unwrap f with + CTL.False | CTL.True | CTL.Pred(_) -> ([],[]) + | CTL.Not(phi) | CTL.Exists(_,phi) + | CTL.AX(_,phi) | CTL.AG(_,phi) + | CTL.EF(_,phi) | CTL.EX(_,phi) | CTL.EG(_,phi) -> (ctl_fvs phi,[]) + | CTL.AU(_,phi1,phi2,phi3,phi4) -> + let phi1fvs = ctl_fvs phi1 in + let phi2fvs = ctl_fvs phi2 in + (* phi3 has the same fvs as phi1 and phi4 as phi2 *) + (Common.union_set phi1fvs phi2fvs,intersect phi1fvs phi2fvs) + | CTL.And(phi1,phi2) | CTL.Or(phi1,phi2) | CTL.SeqOr(phi1,phi2) + | CTL.Implies(phi1,phi2) | CTL.AF(_,phi1,phi2) | CTL.EU(_,phi1,phi2) -> + let phi1fvs = ctl_fvs phi1 in + let phi2fvs = ctl_fvs phi2 in + (Common.union_set phi1fvs phi2fvs,intersect phi1fvs phi2fvs) + | CTL.Ref(v) -> ([v],[v]) + | CTL.Let(v,term,body) -> + let phi1fvs = ctl_fvs term in + let phi2fvs = Common.minus_set (ctl_fvs body) [v] in + (Common.union_set phi1fvs phi2fvs,intersect phi1fvs phi2fvs) in + Hashtbl.add ctlfv_table f res; + fvs + +let rev_order_bindings b = + let b = + List.map + (function (nm,term) -> + let (fvs,_) = Hashtbl.find ctlfv_table term in (nm,fvs,term)) + b in + let rec loop bound = function + [] -> [] + | unbound -> + let (now_bound,still_unbound) = + List.partition (function (_,fvs,_) -> subset fvs bound) + unbound in + let get_names = List.map (function (x,_,_) -> x) in + now_bound @ (loop ((get_names now_bound) @ bound) still_unbound) in + List.rev(loop [] b) + +let drop_bindings b f = (* innermost bindings first in b *) + let process_binary f ffvs inter nm term fail = + if List.mem nm inter + then CTL.rewrap f (CTL.Let(nm,term,f)) + else CTL.rewrap f (fail()) in + let find_fvs f = + let _ = ctl_fvs f in Hashtbl.find ctlfv_table f in + let rec drop_one nm term f = + match CTL.unwrap f with + CTL.False -> f + | CTL.True -> f + | CTL.Pred(p) -> f + | CTL.Not(phi) -> CTL.rewrap f (CTL.Not(drop_one nm term phi)) + | CTL.Exists(v,phi) -> CTL.rewrap f (CTL.Exists(v,drop_one nm term phi)) + | CTL.And(phi1,phi2) -> + let (ffvs,inter) = find_fvs f in + process_binary f ffvs inter nm term + (function _ -> CTL.And(drop_one nm term phi1,drop_one nm term phi2)) + | CTL.Or(phi1,phi2) -> + let (ffvs,inter) = find_fvs f in + process_binary f ffvs inter nm term + (function _ -> CTL.Or(drop_one nm term phi1,drop_one nm term phi2)) + | CTL.SeqOr(phi1,phi2) -> + let (ffvs,inter) = find_fvs f in + process_binary f ffvs inter nm term + (function _ -> + CTL.SeqOr(drop_one nm term phi1,drop_one nm term phi2)) + | CTL.Implies(phi1,phi2) -> + let (ffvs,inter) = find_fvs f in + process_binary f ffvs inter nm term + (function _ -> + CTL.Implies(drop_one nm term phi1,drop_one nm term phi2)) + | CTL.AF(dir,phi1,phi2) -> + let (ffvs,inter) = find_fvs f in + process_binary f ffvs inter nm term + (function _ -> + CTL.AF(dir,drop_one nm term phi1,drop_one nm term phi2)) + | CTL.AX(dir,phi) -> + CTL.rewrap f (CTL.AX(dir,drop_one nm term phi)) + | CTL.AG(dir,phi) -> CTL.rewrap f (CTL.AG(dir,drop_one nm term phi)) + | CTL.AU(dir,phi1,phi2,phi3,phi4) -> + let (ffvs,inter) = find_fvs f in + process_binary f ffvs inter nm term + (function _ -> + CTL.AU(dir,drop_one nm term phi1,drop_one nm term phi2, + drop_one nm term phi3,drop_one nm term phi4)) + | CTL.EF(dir,phi) -> CTL.rewrap f (CTL.EF(dir,drop_one nm term phi)) + | CTL.EX(dir,phi) -> + CTL.rewrap f (CTL.EX(dir,drop_one nm term phi)) + | CTL.EG(dir,phi) -> CTL.rewrap f (CTL.EG(dir,drop_one nm term phi)) + | CTL.EU(dir,phi1,phi2) -> + let (ffvs,inter) = find_fvs f in + process_binary f ffvs inter nm term + (function _ -> + CTL.EU(dir,drop_one nm term phi1,drop_one nm term phi2)) + | (CTL.Ref(v) as x) -> process_binary f [v] [v] nm term (function _ -> x) + | CTL.Let(v,term1,body) -> + let (ffvs,inter) = find_fvs f in + process_binary f ffvs inter nm term + (function _ -> + CTL.Let(v,drop_one nm term term1,drop_one nm term body)) in + List.fold_left + (function processed -> function (nm,_,term) -> drop_one nm term processed) + f b + +let letify f = + failwith "this code should not be used!!!"(*; + Hashtbl.clear formula_table; + Hashtbl.clear ctlfv_table; + (* create a count of the number of occurrences of each subformula *) + collect_duplicates f; + (* give names to things that appear more than once *) + assign_variables(); + (* replace duplicated formulas by their variables *) + let (bindings,new_f) = replace_formulas 0 f in + (* collect fvs of terms in bindings and new_f *) + List.iter (function f -> let _ = ctl_fvs f in ()) + (new_f::(List.map (function (_,term) -> term) bindings)); + (* sort bindings with uses before defs *) + let bindings = rev_order_bindings bindings in + (* insert bindings as lets into the formula *) + let res = drop_bindings bindings new_f in + res*) + +(* --------------------------------------------------------------------- *) +(* Function declaration *) + +let top_level used_after t = + match Ast.unwrap t with + Ast.DECL(decl) -> failwith "not supported decl" + | Ast.INCLUDE(inc,s) -> + (* no indication of whether inc or s is modified *) + wrap 0 (CTL.Pred((Lib_engine.Include(inc,s),CTL.Control))) + | Ast.FILEINFO(old_file,new_file) -> failwith "not supported fileinfo" + | Ast.FUNCTION(stmt) -> + (*Printf.printf "orig\n"; + Pretty_print_cocci.statement "" stmt; + Format.print_newline();*) + let unopt = elim_opt.V.rebuilder_statement stmt in + (*Printf.printf "unopt\n"; + Pretty_print_cocci.statement "" unopt; + Format.print_newline();*) + let unopt = preprocess_dots_e unopt in + (*letify*) + (statement unopt used_after Tail [] false) + | Ast.CODE(stmt_dots) -> + let unopt = elim_opt.V.rebuilder_statement_dots stmt_dots in + let unopt = preprocess_dots unopt in + (*letify*) + (statement_list unopt used_after Tail [] false) + | Ast.ERRORWORDS(exps) -> failwith "not supported errorwords" + +(* --------------------------------------------------------------------- *) +(* Contains dots *) + +let contains_dots = + let bind x y = x or y in + let option_default = false in + let mcode r x = false in + let statement r k s = + match Ast.unwrap s with Ast.Dots(_,_,_) -> true | _ -> k s in + let continue r k e = k e in + let stop r k e = false in + let res = + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + continue continue continue + stop stop stop stop stop stop stop statement continue continue in + res.V.combiner_top_level + +(* --------------------------------------------------------------------- *) +(* Entry points *) + +let asttoctl l used_after = + ctr := 0; + lctr := 0; + sctr := 0; + let l = + List.filter + (function t -> + match Ast.unwrap t with Ast.ERRORWORDS(exps) -> false | _ -> true) + l in + List.map2 top_level used_after l + +let pp_cocci_predicate (pred,modif) = + Pretty_print_engine.pp_predicate pred + +let cocci_predicate_to_string (pred,modif) = + Pretty_print_engine.predicate_to_string pred diff --git a/engine/asttoctl.mli b/engine/asttoctl.mli new file mode 100644 index 0000000..e1dcefa --- /dev/null +++ b/engine/asttoctl.mli @@ -0,0 +1,9 @@ +type cocci_predicate = Lib_engine.predicate * string Ast_ctl.modif +type formula = + (cocci_predicate,string, Wrapper_ctl.info) Ast_ctl.generic_ctl + +val asttoctl : Ast_cocci.rule -> string list list -> formula list + +val pp_cocci_predicate : cocci_predicate -> unit + +val cocci_predicate_to_string : cocci_predicate -> string diff --git a/engine/asttoctl2.ml b/engine/asttoctl2.ml new file mode 100644 index 0000000..bf9268b --- /dev/null +++ b/engine/asttoctl2.ml @@ -0,0 +1,2222 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* for MINUS and CONTEXT, pos is always None in this file *) +(*search for require*) +(* true = don't see all matched nodes, only modified ones *) +let onlyModif = ref true(*false*) + +type ex = Exists | Forall | ReverseForall +let exists = ref Forall + +module Ast = Ast_cocci +module V = Visitor_ast +module CTL = Ast_ctl + +let warning s = Printf.fprintf stderr "warning: %s\n" s + +type cocci_predicate = Lib_engine.predicate * Ast.meta_name Ast_ctl.modif +type formula = + (cocci_predicate,Ast.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl + +let union = Common.union_set +let intersect l1 l2 = List.filter (function x -> List.mem x l2) l1 +let subset l1 l2 = List.for_all (function x -> List.mem x l2) l1 + +let foldl1 f xs = List.fold_left f (List.hd xs) (List.tl xs) +let foldr1 f xs = + let xs = List.rev xs in List.fold_left f (List.hd xs) (List.tl xs) + +let used_after = ref ([] : Ast.meta_name list) +let guard_to_strict guard = if guard then CTL.NONSTRICT else CTL.STRICT + +let saved = ref ([] : Ast.meta_name list) + +let string2var x = ("",x) + +(* --------------------------------------------------------------------- *) +(* predicates matching various nodes in the graph *) + +let ctl_and s x y = + match (x,y) with + (CTL.False,_) | (_,CTL.False) -> CTL.False + | (CTL.True,a) | (a,CTL.True) -> a + | _ -> CTL.And(s,x,y) + +let ctl_or x y = + match (x,y) with + (CTL.True,_) | (_,CTL.True) -> CTL.True + | (CTL.False,a) | (a,CTL.False) -> a + | _ -> CTL.Or(x,y) + +let ctl_or_fl x y = + match (x,y) with + (CTL.True,_) | (_,CTL.True) -> CTL.True + | (CTL.False,a) | (a,CTL.False) -> a + | _ -> CTL.Or(y,x) + +let ctl_seqor x y = + match (x,y) with + (CTL.True,_) | (_,CTL.True) -> CTL.True + | (CTL.False,a) | (a,CTL.False) -> a + | _ -> CTL.SeqOr(x,y) + +let ctl_not = function + CTL.True -> CTL.False + | CTL.False -> CTL.True + | x -> CTL.Not(x) + +let ctl_ax s = function + CTL.True -> CTL.True + | CTL.False -> CTL.False + | x -> + match !exists with + Exists -> CTL.EX(CTL.FORWARD,x) + | Forall -> CTL.AX(CTL.FORWARD,s,x) + | ReverseForall -> failwith "not supported" + +let ctl_ax_absolute s = function + CTL.True -> CTL.True + | CTL.False -> CTL.False + | x -> CTL.AX(CTL.FORWARD,s,x) + +let ctl_ex = function + CTL.True -> CTL.True + | CTL.False -> CTL.False + | x -> CTL.EX(CTL.FORWARD,x) + +(* This stays being AX even for sgrep_mode, because it is used to identify +the structure of the term, not matching the pattern. *) +let ctl_back_ax = function + CTL.True -> CTL.True + | CTL.False -> CTL.False + | x -> CTL.AX(CTL.BACKWARD,CTL.NONSTRICT,x) + +let ctl_back_ex = function + CTL.True -> CTL.True + | CTL.False -> CTL.False + | x -> CTL.EX(CTL.BACKWARD,x) + +let ctl_ef = function + CTL.True -> CTL.True + | CTL.False -> CTL.False + | x -> CTL.EF(CTL.FORWARD,x) + +let ctl_ag s = function + CTL.True -> CTL.True + | CTL.False -> CTL.False + | x -> CTL.AG(CTL.FORWARD,s,x) + +let ctl_au s x y = + match (x,!exists) with + (CTL.True,Exists) -> CTL.EF(CTL.FORWARD,y) + | (CTL.True,Forall) -> CTL.AF(CTL.FORWARD,s,y) + | (CTL.True,ReverseForall) -> failwith "not supported" + | (_,Exists) -> CTL.EU(CTL.FORWARD,x,y) + | (_,Forall) -> CTL.AU(CTL.FORWARD,s,x,y) + | (_,ReverseForall) -> failwith "not supported" + +let ctl_anti_au s x y = (* only for ..., where the quantifier is changed *) + CTL.XX + (match (x,!exists) with + (CTL.True,Exists) -> CTL.AF(CTL.FORWARD,s,y) + | (CTL.True,Forall) -> CTL.EF(CTL.FORWARD,y) + | (CTL.True,ReverseForall) -> failwith "not supported" + | (_,Exists) -> CTL.AU(CTL.FORWARD,s,x,y) + | (_,Forall) -> CTL.EU(CTL.FORWARD,x,y) + | (_,ReverseForall) -> failwith "not supported") + +let ctl_uncheck = function + CTL.True -> CTL.True + | CTL.False -> CTL.False + | x -> CTL.Uncheck x + +let label_pred_maker = function + None -> CTL.True + | Some (label_var,used) -> + used := true; + CTL.Pred(Lib_engine.PrefixLabel(label_var),CTL.Control) + +let bclabel_pred_maker = function + None -> CTL.True + | Some (label_var,used) -> + used := true; + CTL.Pred(Lib_engine.BCLabel(label_var),CTL.Control) + +let predmaker guard pred label = + ctl_and (guard_to_strict guard) (CTL.Pred pred) (label_pred_maker label) + +let aftpred = predmaker false (Lib_engine.After, CTL.Control) +let retpred = predmaker false (Lib_engine.Return, CTL.Control) +let funpred = predmaker false (Lib_engine.FunHeader, CTL.Control) +let toppred = predmaker false (Lib_engine.Top, CTL.Control) +let exitpred = predmaker false (Lib_engine.ErrorExit, CTL.Control) +let endpred = predmaker false (Lib_engine.Exit, CTL.Control) +let gotopred = predmaker false (Lib_engine.Goto, CTL.Control) +let inlooppred = predmaker false (Lib_engine.InLoop, CTL.Control) +let truepred = predmaker false (Lib_engine.TrueBranch, CTL.Control) +let falsepred = predmaker false (Lib_engine.FalseBranch, CTL.Control) +let fallpred = predmaker false (Lib_engine.FallThrough, CTL.Control) + +let aftret label_var f = ctl_or (aftpred label_var) (exitpred label_var) + +let letctr = ref 0 +let get_let_ctr _ = + let cur = !letctr in + letctr := cur + 1; + Printf.sprintf "r%d" cur + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Eliminate OptStm *) + +(* for optional thing with nothing after, should check that the optional thing +never occurs. otherwise the matching stops before it occurs *) +let elim_opt = + let mcode x = x in + let donothing r k e = k e in + + let fvlist l = + List.fold_left Common.union_set [] (List.map Ast.get_fvs l) in + + let mfvlist l = + List.fold_left Common.union_set [] (List.map Ast.get_mfvs l) in + + let freshlist l = + List.fold_left Common.union_set [] (List.map Ast.get_fresh l) in + + let inheritedlist l = + List.fold_left Common.union_set [] (List.map Ast.get_inherited l) in + + let savedlist l = + List.fold_left Common.union_set [] (List.map Ast.get_saved l) in + + let varlists l = + (fvlist l, mfvlist l, freshlist l, inheritedlist l, savedlist l) in + + let rec dots_list unwrapped wrapped = + match (unwrapped,wrapped) with + ([],_) -> [] + + | (Ast.Dots(_,_,_,_)::Ast.OptStm(stm)::(Ast.Dots(_,_,_,_) as u)::urest, + d0::s::d1::rest) + | (Ast.Nest(_,_,_,_,_)::Ast.OptStm(stm)::(Ast.Dots(_,_,_,_) as u)::urest, + d0::s::d1::rest) -> + let l = Ast.get_line stm in + let new_rest1 = stm :: (dots_list (u::urest) (d1::rest)) in + let new_rest2 = dots_list urest rest in + let (fv_rest1,mfv_rest1,fresh_rest1,inherited_rest1,s1) = + varlists new_rest1 in + let (fv_rest2,mfv_rest2,fresh_rest2,inherited_rest2,s2) = + varlists new_rest2 in + [d0; + {(Ast.make_term + (Ast.Disj + [{(Ast.make_term(Ast.DOTS(new_rest1))) with + Ast.node_line = l; + Ast.free_vars = fv_rest1; + Ast.minus_free_vars = mfv_rest1; + Ast.fresh_vars = fresh_rest1; + Ast.inherited = inherited_rest1; + Ast.saved_witness = s1}; + {(Ast.make_term(Ast.DOTS(new_rest2))) with + Ast.node_line = l; + Ast.free_vars = fv_rest2; + Ast.minus_free_vars = mfv_rest2; + Ast.fresh_vars = fresh_rest2; + Ast.inherited = inherited_rest2; + Ast.saved_witness = s2}])) with + Ast.node_line = l; + Ast.free_vars = fv_rest1; + Ast.minus_free_vars = mfv_rest1; + Ast.fresh_vars = fresh_rest1; + Ast.inherited = inherited_rest1; + Ast.saved_witness = s1}] + + | (Ast.OptStm(stm)::urest,_::rest) -> + let l = Ast.get_line stm in + let new_rest1 = dots_list urest rest in + let new_rest2 = stm::new_rest1 in + let (fv_rest1,mfv_rest1,fresh_rest1,inherited_rest1,s1) = + varlists new_rest1 in + let (fv_rest2,mfv_rest2,fresh_rest2,inherited_rest2,s2) = + varlists new_rest2 in + [{(Ast.make_term + (Ast.Disj + [{(Ast.make_term(Ast.DOTS(new_rest2))) with + Ast.node_line = l; + Ast.free_vars = fv_rest2; + Ast.minus_free_vars = mfv_rest2; + Ast.fresh_vars = fresh_rest2; + Ast.inherited = inherited_rest2; + Ast.saved_witness = s2}; + {(Ast.make_term(Ast.DOTS(new_rest1))) with + Ast.node_line = l; + Ast.free_vars = fv_rest1; + Ast.minus_free_vars = mfv_rest1; + Ast.fresh_vars = fresh_rest1; + Ast.inherited = inherited_rest1; + Ast.saved_witness = s1}])) with + Ast.node_line = l; + Ast.free_vars = fv_rest2; + Ast.minus_free_vars = mfv_rest2; + Ast.fresh_vars = fresh_rest2; + Ast.inherited = inherited_rest2; + Ast.saved_witness = s2}] + + | ([Ast.Dots(_,_,_,_);Ast.OptStm(stm)],[d1;_]) -> + let l = Ast.get_line stm in + let fv_stm = Ast.get_fvs stm in + let mfv_stm = Ast.get_mfvs stm in + let fresh_stm = Ast.get_fresh stm in + let inh_stm = Ast.get_inherited stm in + let saved_stm = Ast.get_saved stm in + let fv_d1 = Ast.get_fvs d1 in + let mfv_d1 = Ast.get_mfvs d1 in + let fresh_d1 = Ast.get_fresh d1 in + let inh_d1 = Ast.get_inherited d1 in + let saved_d1 = Ast.get_saved d1 in + let fv_both = Common.union_set fv_stm fv_d1 in + let mfv_both = Common.union_set mfv_stm mfv_d1 in + let fresh_both = Common.union_set fresh_stm fresh_d1 in + let inh_both = Common.union_set inh_stm inh_d1 in + let saved_both = Common.union_set saved_stm saved_d1 in + [d1; + {(Ast.make_term + (Ast.Disj + [{(Ast.make_term(Ast.DOTS([stm]))) with + Ast.node_line = l; + Ast.free_vars = fv_stm; + Ast.minus_free_vars = mfv_stm; + Ast.fresh_vars = fresh_stm; + Ast.inherited = inh_stm; + Ast.saved_witness = saved_stm}; + {(Ast.make_term(Ast.DOTS([d1]))) with + Ast.node_line = l; + Ast.free_vars = fv_d1; + Ast.minus_free_vars = mfv_d1; + Ast.fresh_vars = fresh_d1; + Ast.inherited = inh_d1; + Ast.saved_witness = saved_d1}])) with + Ast.node_line = l; + Ast.free_vars = fv_both; + Ast.minus_free_vars = mfv_both; + Ast.fresh_vars = fresh_both; + Ast.inherited = inh_both; + Ast.saved_witness = saved_both}] + + | ([Ast.Nest(_,_,_,_,_);Ast.OptStm(stm)],[d1;_]) -> + let l = Ast.get_line stm in + let rw = Ast.rewrap stm in + let rwd = Ast.rewrap stm in + let dots = Ast.Dots(Ast.make_mcode "...",[],[],[]) in + [d1;rw(Ast.Disj + [rwd(Ast.DOTS([stm])); + {(Ast.make_term(Ast.DOTS([rw dots]))) + with Ast.node_line = l}])] + + | (_::urest,stm::rest) -> stm :: (dots_list urest rest) + | _ -> failwith "not possible" in + + let stmtdotsfn r k d = + let d = k d in + Ast.rewrap d + (match Ast.unwrap d with + Ast.DOTS(l) -> Ast.DOTS(dots_list (List.map Ast.unwrap l) l) + | Ast.CIRCLES(l) -> failwith "elimopt: not supported" + | Ast.STARS(l) -> failwith "elimopt: not supported") in + + V.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing stmtdotsfn donothing + donothing donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing + +(* --------------------------------------------------------------------- *) +(* after management *) +(* We need Guard for the following case: +<... + a + <... + b + ...> +...> +foo(); + +Here the inner <... b ...> should not go past foo. But foo is not the +"after" of the body of the outer nest, because we don't want to search for +it in the case where the body of the outer nest ends in something other +than dots or a nest. *) + +(* what is the difference between tail and end??? *) + +type after = After of formula | Guard of formula | Tail | End | VeryEnd + +let a2n = function After x -> Guard x | a -> a + +let print_ctl x = + let pp_pred (x,_) = Pretty_print_engine.pp_predicate x in + let pp_meta (_,x) = Common.pp x in + Pretty_print_ctl.pp_ctl (pp_pred,pp_meta) false x; + Format.print_newline() + +let print_after = function + After ctl -> Printf.printf "After:\n"; print_ctl ctl + | Guard ctl -> Printf.printf "Guard:\n"; print_ctl ctl + | Tail -> Printf.printf "Tail\n" + | VeryEnd -> Printf.printf "Very End\n" + | End -> Printf.printf "End\n" + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +let fresh_var _ = string2var "_v" +let fresh_pos _ = string2var "_pos" (* must be a constant *) + +let fresh_metavar _ = "_S" + +(* fvinfo is going to end up being from the whole associated statement. + it would be better if it were just the free variables in d, but free_vars.ml + doesn't keep track of free variables on + code *) +let make_meta_rule_elem d fvinfo = + let nm = fresh_metavar() in + Ast.make_meta_rule_elem nm d fvinfo + +let get_unquantified quantified vars = + List.filter (function x -> not (List.mem x quantified)) vars + +let make_seq guard l = + let s = guard_to_strict guard in + foldr1 (function rest -> function cur -> ctl_and s cur (ctl_ax s rest)) l + +let make_seq_after2 guard first rest = + let s = guard_to_strict guard in + match rest with + After rest -> ctl_and s first (ctl_ax s (ctl_ax s rest)) + | _ -> first + +let make_seq_after guard first rest = + match rest with + After rest -> make_seq guard [first;rest] + | _ -> first + +let opt_and guard first rest = + let s = guard_to_strict guard in + match first with + None -> rest + | Some first -> ctl_and s first rest + +let and_after guard first rest = + let s = guard_to_strict guard in + match rest with After rest -> ctl_and s first rest | _ -> first + +let contains_modif = + let bind x y = x or y in + let option_default = false in + let mcode r (_,_,kind,_) = + match kind with + Ast.MINUS(_,_) -> true + | Ast.PLUS -> failwith "not possible" + | Ast.CONTEXT(_,info) -> not (info = Ast.NOTHING) in + let do_nothing r k e = k e in + let rule_elem r k re = + let res = k re in + match Ast.unwrap re with + Ast.FunHeader(bef,_,fninfo,name,lp,params,rp) -> + bind (mcode r ((),(),bef,Ast.NoMetaPos)) res + | Ast.Decl(bef,_,decl) -> bind (mcode r ((),(),bef,Ast.NoMetaPos)) res + | _ -> res in + let recursor = + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + do_nothing do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing + do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in + recursor.V.combiner_rule_elem + +(* code is not a DisjRuleElem *) +let make_match label guard code = + let v = fresh_var() in + let matcher = Lib_engine.Match(code) in + if contains_modif code && not guard + then CTL.Exists(true,v,predmaker guard (matcher,CTL.Modif v) label) + else + let iso_info = !Flag.track_iso_usage && not (Ast.get_isos code = []) in + (match (iso_info,!onlyModif,guard, + intersect !used_after (Ast.get_fvs code)) with + (false,true,_,[]) | (_,_,true,_) -> + predmaker guard (matcher,CTL.Control) label + | _ -> CTL.Exists(true,v,predmaker guard (matcher,CTL.UnModif v) label)) + +let make_raw_match label guard code = + predmaker guard (Lib_engine.Match(code),CTL.Control) label + +let rec seq_fvs quantified = function + [] -> [] + | fv1::fvs -> + let t1fvs = get_unquantified quantified fv1 in + let termfvs = + List.fold_left Common.union_set [] + (List.map (get_unquantified quantified) fvs) in + let bothfvs = Common.inter_set t1fvs termfvs in + let t1onlyfvs = Common.minus_set t1fvs bothfvs in + let new_quantified = Common.union_set bothfvs quantified in + (t1onlyfvs,bothfvs)::(seq_fvs new_quantified fvs) + +let quantify guard = + List.fold_right + (function cur -> + function code -> CTL.Exists (not guard && List.mem cur !saved,cur,code)) + +let non_saved_quantify = + List.fold_right + (function cur -> function code -> CTL.Exists (false,cur,code)) + +let intersectll lst nested_list = + List.filter (function x -> List.exists (List.mem x) nested_list) lst + +(* --------------------------------------------------------------------- *) +(* Count depth of braces. The translation of a closed brace appears deeply +nested within the translation of the sequence term, so the name of the +paren var has to take into account the names of the nested braces. On the +other hand the close brace does not escape, so we don't have to take into +account other paren variable names. *) + +(* called repetitively, which is inefficient, but less trouble than adding a +new field to Seq and FunDecl *) +let count_nested_braces s = + let bind x y = max x y in + let option_default = 0 in + let stmt_count r k s = + match Ast.unwrap s with + Ast.Seq(_,_,_,_) | Ast.FunDecl(_,_,_,_,_) -> (k s) + 1 + | _ -> k s in + let donothing r k e = k e in + let mcode r x = 0 in + let recursor = V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing + donothing donothing stmt_count donothing donothing donothing in + let res = string_of_int (recursor.V.combiner_statement s) in + string2var ("p"^res) + +let labelctr = ref 0 +let get_label_ctr _ = + let cur = !labelctr in + labelctr := cur + 1; + string2var (Printf.sprintf "l%d" cur) + +(* --------------------------------------------------------------------- *) +(* annotate dots with before and after neighbors *) + +let print_bef_aft = function + Ast.WParen (re,n) -> + Printf.printf "bef/aft\n"; + Pretty_print_cocci.rule_elem "" re; + Format.print_newline() + | Ast.Other s -> + Printf.printf "bef/aft\n"; + Pretty_print_cocci.statement "" s; + Format.print_newline() + | Ast.Other_dots d -> + Printf.printf "bef/aft\n"; + Pretty_print_cocci.statement_dots d; + Format.print_newline() + +(* [] can only occur if we are in a disj, where it comes from a ? In that +case, we want to use a, which accumulates all of the previous patterns in +their entirety. *) +let rec get_before_elem sl a = + match Ast.unwrap sl with + Ast.DOTS(x) -> + let rec loop sl a = + match sl with + [] -> ([],Common.Right a) + | [e] -> + let (e,ea) = get_before_e e a in + ([e],Common.Left ea) + | e::sl -> + let (e,ea) = get_before_e e a in + let (sl,sla) = loop sl ea in + (e::sl,sla) in + let (l,a) = loop x a in + (Ast.rewrap sl (Ast.DOTS(l)),a) + | Ast.CIRCLES(x) -> failwith "not supported" + | Ast.STARS(x) -> failwith "not supported" + +and get_before sl a = + match get_before_elem sl a with + (term,Common.Left x) -> (term,x) + | (term,Common.Right x) -> (term,x) + +and get_before_whencode wc = + List.map + (function + Ast.WhenNot w -> let (w,_) = get_before w [] in Ast.WhenNot w + | Ast.WhenAlways w -> let (w,_) = get_before_e w [] in Ast.WhenAlways w + | Ast.WhenModifier(x) -> Ast.WhenModifier(x)) + wc + +and get_before_e s a = + match Ast.unwrap s with + Ast.Dots(d,w,_,aft) -> + (Ast.rewrap s (Ast.Dots(d,get_before_whencode w,a,aft)),a) + | Ast.Nest(stmt_dots,w,multi,_,aft) -> + let w = get_before_whencode w in + let (sd,_) = get_before stmt_dots a in + let a = + List.filter + (function + Ast.Other a -> + let unifies = + Unify_ast.unify_statement_dots + (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in + (match unifies with + Unify_ast.MAYBE -> false + | _ -> true) + | Ast.Other_dots a -> + let unifies = Unify_ast.unify_statement_dots a stmt_dots in + (match unifies with + Unify_ast.MAYBE -> false + | _ -> true) + | _ -> true) + a in + (Ast.rewrap s (Ast.Nest(sd,w,multi,a,aft)),[Ast.Other_dots stmt_dots]) + | Ast.Disj(stmt_dots_list) -> + let (dsl,dsla) = + List.split (List.map (function e -> get_before e a) stmt_dots_list) in + (Ast.rewrap s (Ast.Disj(dsl)),List.fold_left Common.union_set [] dsla) + | Ast.Atomic(ast) -> + (match Ast.unwrap ast with + Ast.MetaStmt(_,_,_,_) -> (s,[]) + | _ -> (s,[Ast.Other s])) + | Ast.Seq(lbrace,decls,body,rbrace) -> + let index = count_nested_braces s in + let (de,dea) = get_before decls [Ast.WParen(lbrace,index)] in + let (bd,_) = get_before body dea in + (Ast.rewrap s (Ast.Seq(lbrace,de,bd,rbrace)), + [Ast.WParen(rbrace,index)]) + | Ast.Define(header,body) -> + let (body,_) = get_before body [] in + (Ast.rewrap s (Ast.Define(header,body)), [Ast.Other s]) + | Ast.IfThen(ifheader,branch,aft) -> + let (br,_) = get_before_e branch [] in + (Ast.rewrap s (Ast.IfThen(ifheader,br,aft)), [Ast.Other s]) + | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) -> + let (br1,_) = get_before_e branch1 [] in + let (br2,_) = get_before_e branch2 [] in + (Ast.rewrap s (Ast.IfThenElse(ifheader,br1,els,br2,aft)),[Ast.Other s]) + | Ast.While(header,body,aft) -> + let (bd,_) = get_before_e body [] in + (Ast.rewrap s (Ast.While(header,bd,aft)),[Ast.Other s]) + | Ast.For(header,body,aft) -> + let (bd,_) = get_before_e body [] in + (Ast.rewrap s (Ast.For(header,bd,aft)),[Ast.Other s]) + | Ast.Do(header,body,tail) -> + let (bd,_) = get_before_e body [] in + (Ast.rewrap s (Ast.Do(header,bd,tail)),[Ast.Other s]) + | Ast.Iterator(header,body,aft) -> + let (bd,_) = get_before_e body [] in + (Ast.rewrap s (Ast.Iterator(header,bd,aft)),[Ast.Other s]) + | Ast.Switch(header,lb,cases,rb) -> + let cases = + List.map + (function case_line -> + match Ast.unwrap case_line with + Ast.CaseLine(header,body) -> + let (body,_) = get_before body [] in + Ast.rewrap case_line (Ast.CaseLine(header,body)) + | Ast.OptCase(case_line) -> failwith "not supported") + cases in + (Ast.rewrap s (Ast.Switch(header,lb,cases,rb)),[Ast.Other s]) + | Ast.FunDecl(header,lbrace,decls,body,rbrace) -> + let (de,dea) = get_before decls [] in + let (bd,_) = get_before body dea in + (Ast.rewrap s (Ast.FunDecl(header,lbrace,de,bd,rbrace)),[]) + | _ -> failwith "get_before_e: not supported" + +let rec get_after sl a = + match Ast.unwrap sl with + Ast.DOTS(x) -> + let rec loop sl = + match sl with + [] -> ([],a) + | e::sl -> + let (sl,sla) = loop sl in + let (e,ea) = get_after_e e sla in + (e::sl,ea) in + let (l,a) = loop x in + (Ast.rewrap sl (Ast.DOTS(l)),a) + | Ast.CIRCLES(x) -> failwith "not supported" + | Ast.STARS(x) -> failwith "not supported" + +and get_after_whencode a wc = + List.map + (function + Ast.WhenNot w -> let (w,_) = get_after w a (*?*) in Ast.WhenNot w + | Ast.WhenAlways w -> let (w,_) = get_after_e w a in Ast.WhenAlways w + | Ast.WhenModifier(x) -> Ast.WhenModifier(x)) + wc + +and get_after_e s a = + match Ast.unwrap s with + Ast.Dots(d,w,bef,_) -> + (Ast.rewrap s (Ast.Dots(d,get_after_whencode a w,bef,a)),a) + | Ast.Nest(stmt_dots,w,multi,bef,_) -> + let w = get_after_whencode a w in + let (sd,_) = get_after stmt_dots a in + let a = + List.filter + (function + Ast.Other a -> + let unifies = + Unify_ast.unify_statement_dots + (Ast.rewrap s (Ast.DOTS([a]))) stmt_dots in + (match unifies with + Unify_ast.MAYBE -> false + | _ -> true) + | Ast.Other_dots a -> + let unifies = Unify_ast.unify_statement_dots a stmt_dots in + (match unifies with + Unify_ast.MAYBE -> false + | _ -> true) + | _ -> true) + a in + (Ast.rewrap s (Ast.Nest(sd,w,multi,bef,a)),[Ast.Other_dots stmt_dots]) + | Ast.Disj(stmt_dots_list) -> + let (dsl,dsla) = + List.split (List.map (function e -> get_after e a) stmt_dots_list) in + (Ast.rewrap s (Ast.Disj(dsl)),List.fold_left Common.union_set [] dsla) + | Ast.Atomic(ast) -> + (match Ast.unwrap ast with + Ast.MetaStmt(nm,keep,Ast.SequencibleAfterDots _,i) -> + (* check "after" information for metavar optimization *) + (* if the error is not desired, could just return [], then + the optimization (check for EF) won't take place *) + List.iter + (function + Ast.Other x -> + (match Ast.unwrap x with + Ast.Dots(_,_,_,_) | Ast.Nest(_,_,_,_,_) -> + failwith + "dots/nest not allowed before and after stmt metavar" + | _ -> ()) + | Ast.Other_dots x -> + (match Ast.undots x with + x::_ -> + (match Ast.unwrap x with + Ast.Dots(_,_,_,_) | Ast.Nest(_,_,_,_,_) -> + failwith + ("dots/nest not allowed before and after stmt "^ + "metavar") + | _ -> ()) + | _ -> ()) + | _ -> ()) + a; + (Ast.rewrap s + (Ast.Atomic + (Ast.rewrap s + (Ast.MetaStmt(nm,keep,Ast.SequencibleAfterDots a,i)))),[]) + | Ast.MetaStmt(_,_,_,_) -> (s,[]) + | _ -> (s,[Ast.Other s])) + | Ast.Seq(lbrace,decls,body,rbrace) -> + let index = count_nested_braces s in + let (bd,bda) = get_after body [Ast.WParen(rbrace,index)] in + let (de,_) = get_after decls bda in + (Ast.rewrap s (Ast.Seq(lbrace,de,bd,rbrace)), + [Ast.WParen(lbrace,index)]) + | Ast.Define(header,body) -> + let (body,_) = get_after body a in + (Ast.rewrap s (Ast.Define(header,body)), [Ast.Other s]) + | Ast.IfThen(ifheader,branch,aft) -> + let (br,_) = get_after_e branch a in + (Ast.rewrap s (Ast.IfThen(ifheader,br,aft)),[Ast.Other s]) + | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) -> + let (br1,_) = get_after_e branch1 a in + let (br2,_) = get_after_e branch2 a in + (Ast.rewrap s (Ast.IfThenElse(ifheader,br1,els,br2,aft)),[Ast.Other s]) + | Ast.While(header,body,aft) -> + let (bd,_) = get_after_e body a in + (Ast.rewrap s (Ast.While(header,bd,aft)),[Ast.Other s]) + | Ast.For(header,body,aft) -> + let (bd,_) = get_after_e body a in + (Ast.rewrap s (Ast.For(header,bd,aft)),[Ast.Other s]) + | Ast.Do(header,body,tail) -> + let (bd,_) = get_after_e body a in + (Ast.rewrap s (Ast.Do(header,bd,tail)),[Ast.Other s]) + | Ast.Iterator(header,body,aft) -> + let (bd,_) = get_after_e body a in + (Ast.rewrap s (Ast.Iterator(header,bd,aft)),[Ast.Other s]) + | Ast.Switch(header,lb,cases,rb) -> + let cases = + List.map + (function case_line -> + match Ast.unwrap case_line with + Ast.CaseLine(header,body) -> + let (body,_) = get_after body [] in + Ast.rewrap case_line (Ast.CaseLine(header,body)) + | Ast.OptCase(case_line) -> failwith "not supported") + cases in + (Ast.rewrap s (Ast.Switch(header,lb,cases,rb)),[Ast.Other s]) + | Ast.FunDecl(header,lbrace,decls,body,rbrace) -> + let (bd,bda) = get_after body [] in + let (de,_) = get_after decls bda in + (Ast.rewrap s (Ast.FunDecl(header,lbrace,de,bd,rbrace)),[]) + | _ -> failwith "get_after_e: not supported" + +let preprocess_dots sl = + let (sl,_) = get_before sl [] in + let (sl,_) = get_after sl [] in + sl + +let preprocess_dots_e sl = + let (sl,_) = get_before_e sl [] in + let (sl,_) = get_after_e sl [] in + sl + +(* --------------------------------------------------------------------- *) +(* various return_related things *) + +let rec ends_in_return stmt_list = + match Ast.unwrap stmt_list with + Ast.DOTS(x) -> + (match List.rev x with + x::_ -> + (match Ast.unwrap x with + Ast.Atomic(x) -> + (match Ast.unwrap x with + Ast.Return(_,_) | Ast.ReturnExpr(_,_,_) -> true + | _ -> false) + | Ast.Disj(disjs) -> List.for_all ends_in_return disjs + | _ -> false) + | _ -> false) + | Ast.CIRCLES(x) -> failwith "not supported" + | Ast.STARS(x) -> failwith "not supported" + +(* --------------------------------------------------------------------- *) +(* expressions *) + +let exptymatch l make_match make_guard_match = + let pos = fresh_pos() in + let matches_guard_matches = + List.map + (function x -> + let pos = Ast.make_mcode pos in + (make_match (Ast.set_pos x (Some pos)), + make_guard_match (Ast.set_pos x (Some pos)))) + l in + let (matches,guard_matches) = List.split matches_guard_matches in + let rec suffixes = function + [] -> [] + | x::xs -> xs::(suffixes xs) in + let prefixes = List.rev (suffixes (List.rev guard_matches)) in + let info = (* not null *) + List.map2 + (function matcher -> + function negates -> + CTL.Exists + (false,pos, + ctl_and CTL.NONSTRICT matcher + (ctl_not + (ctl_uncheck (List.fold_left ctl_or_fl CTL.False negates))))) + matches prefixes in + CTL.InnerAnd(List.fold_left ctl_or_fl CTL.False (List.rev info)) + +(* code might be a DisjRuleElem, in which case we break it apart + code might contain an Exp or Ty + this one pushes the quantifier inwards *) +let do_re_matches label guard res quantified minus_quantified = + let make_guard_match x = + let stmt_fvs = Ast.get_mfvs x in + let fvs = get_unquantified minus_quantified stmt_fvs in + non_saved_quantify fvs (make_match None true x) in + let make_match x = + let stmt_fvs = Ast.get_fvs x in + let fvs = get_unquantified quantified stmt_fvs in + quantify guard fvs (make_match None guard x) in + ctl_and CTL.NONSTRICT (label_pred_maker label) + (match List.map Ast.unwrap res with + [] -> failwith "unexpected empty disj" + | Ast.Exp(e)::rest -> exptymatch res make_match make_guard_match + | Ast.Ty(t)::rest -> exptymatch res make_match make_guard_match + | all -> + if List.exists (function Ast.Exp(_) | Ast.Ty(_) -> true | _ -> false) + all + then failwith "unexpected exp or ty"; + List.fold_left ctl_seqor CTL.False + (List.rev (List.map make_match res))) + +(* code might be a DisjRuleElem, in which case we break it apart + code doesn't contain an Exp or Ty + this one is for use when it is not practical to push the quantifier inwards + *) +let header_match label guard code : ('a, Ast.meta_name, 'b) CTL.generic_ctl = + match Ast.unwrap code with + Ast.DisjRuleElem(res) -> + let make_match = make_match None guard in + let orop = if guard then ctl_or else ctl_seqor in + ctl_and CTL.NONSTRICT (label_pred_maker label) + (List.fold_left orop CTL.False (List.map make_match res)) + | _ -> make_match label guard code + +(* --------------------------------------------------------------------- *) +(* control structures *) + +let end_control_structure fvs header body after_pred + after_checks no_after_checks (afvs,afresh,ainh,aft) after label guard = + (* aft indicates what is added after the whole if, which has to be added + to the endif node *) + let (aft_needed,after_branch) = + match aft with + Ast.CONTEXT(_,Ast.NOTHING) -> + (false,make_seq_after2 guard after_pred after) + | _ -> + let match_endif = + make_match label guard + (make_meta_rule_elem aft (afvs,afresh,ainh)) in + (true, + make_seq_after guard after_pred + (After(make_seq_after guard match_endif after))) in + let body = body after_branch in + let s = guard_to_strict guard in + (* the code *) + quantify guard fvs + (ctl_and s header + (opt_and guard + (match (after,aft_needed) with + (After _,_) (* pattern doesn't end here *) + | (_,true) (* + code added after *) -> after_checks + | _ -> no_after_checks) + (ctl_ax_absolute s body))) + +let ifthen ifheader branch ((afvs,_,_,_) as aft) after + quantified minus_quantified label llabel slabel recurse make_match guard = +(* "if (test) thn" becomes: + if(test) & AX((TrueBranch & AX thn) v FallThrough v After) + + "if (test) thn; after" becomes: + if(test) & AX((TrueBranch & AX thn) v FallThrough v (After & AXAX after)) + & EX After +*) + (* free variables *) + let (efvs,bfvs) = + match seq_fvs quantified + [Ast.get_fvs ifheader;Ast.get_fvs branch;afvs] with + [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs) + | _ -> failwith "not possible" in + let new_quantified = Common.union_set bfvs quantified in + let (mefvs,mbfvs) = + match seq_fvs minus_quantified + [Ast.get_mfvs ifheader;Ast.get_mfvs branch;[]] with + [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs) + | _ -> failwith "not possible" in + let new_mquantified = Common.union_set mbfvs minus_quantified in + (* if header *) + let if_header = quantify guard efvs (make_match ifheader) in + (* then branch and after *) + let lv = get_label_ctr() in + let used = ref false in + let true_branch = + make_seq guard + [truepred label; recurse branch Tail new_quantified new_mquantified + (Some (lv,used)) llabel slabel guard] in + let after_pred = aftpred label in + let or_cases after_branch = + ctl_or true_branch (ctl_or (fallpred label) after_branch) in + let (if_header,wrapper) = + if !used + then + let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in + (ctl_and CTL.NONSTRICT(*???*) if_header label_pred, + (function body -> quantify true [lv] body)) + else (if_header,function x -> x) in + wrapper + (end_control_structure bfvs if_header or_cases after_pred + (Some(ctl_ex after_pred)) None aft after label guard) + +let ifthenelse ifheader branch1 els branch2 ((afvs,_,_,_) as aft) after + quantified minus_quantified label llabel slabel recurse make_match guard = +(* "if (test) thn else els" becomes: + if(test) & AX((TrueBranch & AX thn) v + (FalseBranch & AX (else & AX els)) v After) + & EX FalseBranch + + "if (test) thn else els; after" becomes: + if(test) & AX((TrueBranch & AX thn) v + (FalseBranch & AX (else & AX els)) v + (After & AXAX after)) + & EX FalseBranch + & EX After +*) + (* free variables *) + let (e1fvs,b1fvs,s1fvs) = + match seq_fvs quantified + [Ast.get_fvs ifheader;Ast.get_fvs branch1;afvs] with + [(e1fvs,b1fvs);(s1fvs,b1afvs);_] -> + (e1fvs,Common.union_set b1fvs b1afvs,s1fvs) + | _ -> failwith "not possible" in + let (e2fvs,b2fvs,s2fvs) = + (* fvs on else? *) + match seq_fvs quantified + [Ast.get_fvs ifheader;Ast.get_fvs branch2;afvs] with + [(e2fvs,b2fvs);(s2fvs,b2afvs);_] -> + (e2fvs,Common.union_set b2fvs b2afvs,s2fvs) + | _ -> failwith "not possible" in + let bothfvs = union (union b1fvs b2fvs) (intersect s1fvs s2fvs) in + let exponlyfvs = intersect e1fvs e2fvs in + let new_quantified = union bothfvs quantified in + (* minus free variables *) + let (me1fvs,mb1fvs,ms1fvs) = + match seq_fvs minus_quantified + [Ast.get_mfvs ifheader;Ast.get_mfvs branch1;[]] with + [(e1fvs,b1fvs);(s1fvs,b1afvs);_] -> + (e1fvs,Common.union_set b1fvs b1afvs,s1fvs) + | _ -> failwith "not possible" in + let (me2fvs,mb2fvs,ms2fvs) = + (* fvs on else? *) + match seq_fvs minus_quantified + [Ast.get_mfvs ifheader;Ast.get_mfvs branch2;[]] with + [(e2fvs,b2fvs);(s2fvs,b2afvs);_] -> + (e2fvs,Common.union_set b2fvs b2afvs,s2fvs) + | _ -> failwith "not possible" in + let mbothfvs = union (union mb1fvs mb2fvs) (intersect ms1fvs ms2fvs) in + let new_mquantified = union mbothfvs minus_quantified in + (* if header *) + let if_header = quantify guard exponlyfvs (make_match ifheader) in + (* then and else branches *) + let lv = get_label_ctr() in + let used = ref false in + let true_branch = + make_seq guard + [truepred label; recurse branch1 Tail new_quantified new_mquantified + (Some (lv,used)) llabel slabel guard] in + let false_branch = + make_seq guard + [falsepred label; make_match els; + recurse branch2 Tail new_quantified new_mquantified + (Some (lv,used)) llabel slabel guard] in + let after_pred = aftpred label in + let or_cases after_branch = + ctl_or true_branch (ctl_or false_branch after_branch) in + let s = guard_to_strict guard in + let (if_header,wrapper) = + if !used + then + let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in + (ctl_and CTL.NONSTRICT(*???*) if_header label_pred, + (function body -> quantify true [lv] body)) + else (if_header,function x -> x) in + wrapper + (end_control_structure bothfvs if_header or_cases after_pred + (Some(ctl_and s (ctl_ex (falsepred label)) (ctl_ex after_pred))) + (Some(ctl_ex (falsepred label))) + aft after label guard) + +let forwhile header body ((afvs,_,_,_) as aft) after + quantified minus_quantified label recurse make_match guard = + let process _ = + (* the translation in this case is similar to that of an if with no else *) + (* free variables *) + let (efvs,bfvs) = + match seq_fvs quantified [Ast.get_fvs header;Ast.get_fvs body;afvs] with + [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs) + | _ -> failwith "not possible" in + let new_quantified = Common.union_set bfvs quantified in + (* minus free variables *) + let (mefvs,mbfvs) = + match seq_fvs minus_quantified + [Ast.get_mfvs header;Ast.get_mfvs body;[]] with + [(efvs,b1fvs);(_,b2fvs);_] -> (efvs,Common.union_set b1fvs b2fvs) + | _ -> failwith "not possible" in + let new_mquantified = Common.union_set mbfvs minus_quantified in + (* loop header *) + let header = quantify guard efvs (make_match header) in + let lv = get_label_ctr() in + let used = ref false in + let body = + make_seq guard + [inlooppred label; + recurse body Tail new_quantified new_mquantified + (Some (lv,used)) (Some (lv,used)) None guard] in + let after_pred = fallpred label in + let or_cases after_branch = ctl_or body after_branch in + let (header,wrapper) = + if !used + then + let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in + (ctl_and CTL.NONSTRICT(*???*) header label_pred, + (function body -> quantify true [lv] body)) + else (header,function x -> x) in + wrapper + (end_control_structure bfvs header or_cases after_pred + (Some(ctl_ex after_pred)) None aft after label guard) in + match (Ast.unwrap body,aft) with + (Ast.Atomic(re),(_,_,_,Ast.CONTEXT(_,Ast.NOTHING))) -> + (match Ast.unwrap re with + Ast.MetaStmt((_,_,Ast.CONTEXT(_,Ast.NOTHING),_), + Type_cocci.Unitary,_,false) -> + let (efvs) = + match seq_fvs quantified [Ast.get_fvs header] with + [(efvs,_)] -> efvs + | _ -> failwith "not possible" in + quantify guard efvs (make_match header) + | _ -> process()) + | _ -> process() + +(* --------------------------------------------------------------------- *) +(* statement metavariables *) + +(* issue: an S metavariable that is not an if branch/loop body + should not match an if branch/loop body, so check that the labels + of the nodes before the first node matched by the S are different + from the label of the first node matched by the S *) +let sequencibility body label_pred process_bef_aft = function + Ast.Sequencible | Ast.SequencibleAfterDots [] -> + body + (function x -> + (ctl_and CTL.NONSTRICT (ctl_not (ctl_back_ax label_pred)) x)) + | Ast.SequencibleAfterDots l -> + (* S appears after some dots. l is the code that comes after the S. + want to search for that first, because S can match anything, while + the stuff after is probably more restricted *) + let afts = List.map process_bef_aft l in + let ors = foldl1 ctl_or afts in + ctl_and CTL.NONSTRICT + (ctl_ef (ctl_and CTL.NONSTRICT ors (ctl_back_ax label_pred))) + (body + (function x -> + ctl_and CTL.NONSTRICT (ctl_not (ctl_back_ax label_pred)) x)) + | Ast.NotSequencible -> body (function x -> x) + +let svar_context_with_add_after stmt s label quantified d ast + seqible after process_bef_aft guard fvinfo = + let label_var = (*fresh_label_var*) string2var "_lab" in + let label_pred = + CTL.Pred (Lib_engine.Label(label_var),CTL.Control) in + let prelabel_pred = + CTL.Pred (Lib_engine.PrefixLabel(label_var),CTL.Control) in + let matcher d = make_match None guard (make_meta_rule_elem d fvinfo) in + let full_metamatch = matcher d in + let first_metamatch = + matcher + (match d with + Ast.CONTEXT(pos,Ast.BEFOREAFTER(bef,_)) -> + Ast.CONTEXT(pos,Ast.BEFORE(bef)) + | Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING) + | Ast.MINUS(_,_) | Ast.PLUS -> failwith "not possible") in + let middle_metamatch = + matcher + (match d with + Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING) + | Ast.MINUS(_,_) | Ast.PLUS -> failwith "not possible") in + let last_metamatch = + matcher + (match d with + Ast.CONTEXT(pos,Ast.BEFOREAFTER(_,aft)) -> + Ast.CONTEXT(pos,Ast.AFTER(aft)) + | Ast.CONTEXT(_,_) -> d + | Ast.MINUS(_,_) | Ast.PLUS -> failwith "not possible") in + + let rest_nodes = + ctl_and CTL.NONSTRICT middle_metamatch prelabel_pred in + let left_or = (* the whole statement is one node *) + make_seq guard + [full_metamatch; and_after guard (ctl_not prelabel_pred) after] in + let right_or = (* the statement covers multiple nodes *) + make_seq guard + [first_metamatch; + ctl_au CTL.NONSTRICT + rest_nodes + (make_seq guard + [ctl_and CTL.NONSTRICT last_metamatch label_pred; + and_after guard + (ctl_not prelabel_pred) after])] in + let body f = + ctl_and CTL.NONSTRICT label_pred + (f (ctl_and CTL.NONSTRICT + (make_raw_match label false ast) (ctl_or left_or right_or))) in + let stmt_fvs = Ast.get_fvs stmt in + let fvs = get_unquantified quantified stmt_fvs in + quantify guard (label_var::fvs) + (sequencibility body label_pred process_bef_aft seqible) + +let svar_minus_or_no_add_after stmt s label quantified d ast + seqible after process_bef_aft guard fvinfo = + let label_var = (*fresh_label_var*) string2var "_lab" in + let label_pred = + CTL.Pred (Lib_engine.Label(label_var),CTL.Control) in + let prelabel_pred = + CTL.Pred (Lib_engine.PrefixLabel(label_var),CTL.Control) in + let matcher d = make_match None guard (make_meta_rule_elem d fvinfo) in + let pure_d = + (* don't have to put anything before the beginning, so don't have to + distinguish the first node. so don't have to bother about paths, + just use the label. label ensures that found nodes match up with + what they should because it is in the lhs of the andany. *) + match d with + Ast.MINUS(pos,[]) -> true + | Ast.CONTEXT(pos,Ast.NOTHING) -> true + | _ -> false in + let ender = + match (pure_d,after) with + (true,Tail) | (true,End) | (true,VeryEnd) -> + (* the label sharing makes it safe to use AndAny *) + CTL.HackForStmt(CTL.FORWARD,CTL.NONSTRICT, + ctl_and CTL.NONSTRICT label_pred + (make_raw_match label false ast), + ctl_and CTL.NONSTRICT (matcher d) prelabel_pred) + | _ -> + (* more safe but less efficient *) + let first_metamatch = matcher d in + let rest_metamatch = + matcher + (match d with + Ast.MINUS(pos,_) -> Ast.MINUS(pos,[]) + | Ast.CONTEXT(pos,_) -> Ast.CONTEXT(pos,Ast.NOTHING) + | Ast.PLUS -> failwith "not possible") in + let rest_nodes = ctl_and CTL.NONSTRICT rest_metamatch prelabel_pred in + let last_node = and_after guard (ctl_not prelabel_pred) after in + (ctl_and CTL.NONSTRICT (make_raw_match label false ast) + (make_seq guard + [first_metamatch; + ctl_au CTL.NONSTRICT rest_nodes last_node])) in + let body f = ctl_and CTL.NONSTRICT label_pred (f ender) in + let stmt_fvs = Ast.get_fvs stmt in + let fvs = get_unquantified quantified stmt_fvs in + quantify guard (label_var::fvs) + (sequencibility body label_pred process_bef_aft seqible) + +(* --------------------------------------------------------------------- *) +(* dots and nests *) + +let dots_au is_strict toend label s wrapcode x seq_after y quantifier = + let matchgoto = gotopred None in + let matchbreak = + make_match None false + (wrapcode + (Ast.Break(Ast.make_mcode "break",Ast.make_mcode ";"))) in + let matchcontinue = + make_match None false + (wrapcode + (Ast.Continue(Ast.make_mcode "continue",Ast.make_mcode ";"))) in + let stop_early v = + if !exists = Exists + then CTL.False + else if toend + then CTL.Or(aftpred label,exitpred label) + else if is_strict + then aftpred label + else + let lv = get_label_ctr() in + let labelpred = CTL.Pred(Lib_engine.Label lv,CTL.Control) in + let preflabelpred = label_pred_maker (Some (lv,ref true)) in + ctl_or (aftpred label) + (quantify false [lv] + (ctl_and CTL.NONSTRICT + (ctl_and CTL.NONSTRICT (truepred label) labelpred) + (ctl_au CTL.NONSTRICT + (ctl_and CTL.NONSTRICT (ctl_not v) preflabelpred) + (ctl_and CTL.NONSTRICT preflabelpred + (ctl_or (retpred None) + (if !Flag_engine.only_return_is_error_exit + then CTL.True + else + (ctl_or matchcontinue + (ctl_and CTL.NONSTRICT + (ctl_or matchgoto matchbreak) + (ctl_ag s (ctl_not seq_after)))))))))) in + let v = get_let_ctr() in + let op = if quantifier = !exists then ctl_au else ctl_anti_au in + op s x (CTL.Let(v,y,ctl_or (CTL.Ref v) (stop_early (CTL.Ref v)))) + +let rec dots_and_nests plus nest whencodes bef aft dotcode after label + process_bef_aft statement_list statement guard wrapcode = + let ctl_and_ns = ctl_and CTL.NONSTRICT in + (* proces bef_aft *) + let shortest l = + List.fold_left ctl_or_fl CTL.False (List.map process_bef_aft l) in + let bef_aft = (* to be negated *) + try + let _ = + List.find + (function Ast.WhenModifier(Ast.WhenAny) -> true | _ -> false) + whencodes in + CTL.False + with Not_found -> shortest (Common.union_set bef aft) in + let is_strict = + List.exists + (function Ast.WhenModifier(Ast.WhenStrict) -> true | _ -> false) + whencodes in + let check_quantifier quant other = + if List.exists + (function Ast.WhenModifier(x) -> x = quant | _ -> false) + whencodes + then + if List.exists + (function Ast.WhenModifier(x) -> x = other | _ -> false) + whencodes + then failwith "inconsistent annotation on dots" + else true + else false in + let quantifier = + if check_quantifier Ast.WhenExists Ast.WhenForall + then Exists + else + if check_quantifier Ast.WhenExists Ast.WhenForall + then Forall + else !exists in + (* the following is used when we find a goto, etc and consider accepting + without finding the rest of the pattern *) + let aft = shortest aft in + (* process whencode *) + let labelled = label_pred_maker label in + let whencodes arg = + let (poswhen,negwhen) = + List.fold_left + (function (poswhen,negwhen) -> + function + Ast.WhenNot whencodes -> + (poswhen,ctl_or (statement_list whencodes) negwhen) + | Ast.WhenAlways stm -> + (ctl_and CTL.NONSTRICT (statement stm) poswhen,negwhen) + | Ast.WhenModifier(_) -> (poswhen,negwhen)) + (CTL.True,bef_aft) (List.rev whencodes) in + let poswhen = ctl_and_ns arg poswhen in + let negwhen = +(* if !exists + then*) + (* add in After, because it's not part of the program *) + ctl_or (aftpred label) negwhen + (*else negwhen*) in + ctl_and_ns poswhen (ctl_not negwhen) in + (* process dot code, if any *) + let dotcode = + match (dotcode,guard) with + (None,_) | (_,true) -> CTL.True + | (Some dotcode,_) -> dotcode in + (* process nest code, if any *) + (* whencode goes in the negated part of the nest; if no nest, just goes + on the "true" in between code *) + let plus_var = if plus then get_label_ctr() else string2var "" in + let plus_var2 = if plus then get_label_ctr() else string2var "" in + let ornest = + match (nest,guard && not plus) with + (None,_) | (_,true) -> whencodes CTL.True + | (Some nest,false) -> + let v = get_let_ctr() in + let is_plus x = + if plus + then + (* the idea is that BindGood is sort of a witness; a witness to + having found the subterm in at least one place. If there is + not a witness, then there is a risk that it will get thrown + away, if it is merged with a node that has an empty + environment. See tests/nestplus. But this all seems + rather suspicious *) + CTL.And(CTL.NONSTRICT,x, + CTL.Exists(true,plus_var2, + CTL.Pred(Lib_engine.BindGood(plus_var), + CTL.Modif plus_var2))) + else x in + CTL.Let(v,nest, + CTL.Or(is_plus (CTL.Ref v), + whencodes (CTL.Not(ctl_uncheck (CTL.Ref v))))) in + let plus_modifier x = + if plus + then + CTL.Exists + (false,plus_var, + (CTL.And + (CTL.NONSTRICT,x, + CTL.Not(CTL.Pred(Lib_engine.BindBad(plus_var),CTL.Control))))) + else x in + + let ender = + match after with + After f -> f + | Guard f -> ctl_uncheck f + | VeryEnd -> + let exit = endpred label in + let errorexit = exitpred label in + ctl_or exit errorexit + (* not at all sure what the next two mean... *) + | End -> CTL.True + | Tail -> + (match label with + Some (lv,used) -> used := true; + ctl_or (CTL.Pred(Lib_engine.Label lv,CTL.Control)) + (ctl_back_ex (ctl_or (retpred label) (gotopred label))) + | None -> endpred label) + (* was the following, but not clear why sgrep should allow + incomplete patterns + let exit = endpred label in + let errorexit = exitpred label in + if !exists + then ctl_or exit errorexit (* end anywhere *) + else exit (* end at the real end of the function *) *) in + plus_modifier + (dots_au is_strict ((after = Tail) or (after = VeryEnd)) + label (guard_to_strict guard) wrapcode + (ctl_and_ns dotcode (ctl_and_ns ornest labelled)) + aft ender quantifier) + +(* --------------------------------------------------------------------- *) +(* the main translation loop *) + +let rec statement_list stmt_list after quantified minus_quantified + label llabel slabel dots_before guard = + let isdots x = + (* include Disj to be on the safe side *) + match Ast.unwrap x with + Ast.Dots _ | Ast.Nest _ | Ast.Disj _ -> true | _ -> false in + let compute_label l e db = if db or isdots e then l else None in + match Ast.unwrap stmt_list with + Ast.DOTS(x) -> + let rec loop quantified minus_quantified dots_before label llabel slabel + = function + ([],_,_) -> (match after with After f -> f | _ -> CTL.True) + | ([e],_,_) -> + statement e after quantified minus_quantified + (compute_label label e dots_before) + llabel slabel guard + | (e::sl,fv::fvs,mfv::mfvs) -> + let shared = intersectll fv fvs in + let unqshared = get_unquantified quantified shared in + let new_quantified = Common.union_set unqshared quantified in + let minus_shared = intersectll mfv mfvs in + let munqshared = + get_unquantified minus_quantified minus_shared in + let new_mquantified = + Common.union_set munqshared minus_quantified in + quantify guard unqshared + (statement e + (After + (let (label1,llabel1,slabel1) = + match Ast.unwrap e with + Ast.Atomic(re) -> + (match Ast.unwrap re with + Ast.Goto _ -> (None,None,None) + | _ -> (label,llabel,slabel)) + | _ -> (label,llabel,slabel) in + loop new_quantified new_mquantified (isdots e) + label1 llabel1 slabel1 + (sl,fvs,mfvs))) + new_quantified new_mquantified + (compute_label label e dots_before) llabel slabel guard) + | _ -> failwith "not possible" in + loop quantified minus_quantified dots_before + label llabel slabel + (x,List.map Ast.get_fvs x,List.map Ast.get_mfvs x) + | Ast.CIRCLES(x) -> failwith "not supported" + | Ast.STARS(x) -> failwith "not supported" + +(* llabel is the label of the enclosing loop and slabel is the label of the + enclosing switch *) +and statement stmt after quantified minus_quantified + label llabel slabel guard = + let ctl_au = ctl_au CTL.NONSTRICT in + let ctl_ax = ctl_ax CTL.NONSTRICT in + let ctl_and = ctl_and CTL.NONSTRICT in + let make_seq = make_seq guard in + let make_seq_after = make_seq_after guard in + let real_make_match = make_match in + let make_match = header_match label guard in + + let dots_done = ref false in (* hack for dots cases we can easily handle *) + + let term = + match Ast.unwrap stmt with + Ast.Atomic(ast) -> + (match Ast.unwrap ast with + (* the following optimisation is not a good idea, because when S + is alone, we would like it not to match a declaration. + this makes more matching for things like when (...) S, but perhaps + that matching is not so costly anyway *) + (*Ast.MetaStmt(_,Type_cocci.Unitary,_,false) when guard -> CTL.True*) + | Ast.MetaStmt((s,_,(Ast.CONTEXT(_,Ast.BEFOREAFTER(_,_)) as d),_), + keep,seqible,_) + | Ast.MetaStmt((s,_,(Ast.CONTEXT(_,Ast.AFTER(_)) as d),_), + keep,seqible,_)-> + svar_context_with_add_after stmt s label quantified d ast seqible + after + (process_bef_aft quantified minus_quantified + label llabel slabel true) + guard + (Ast.get_fvs stmt, Ast.get_fresh stmt, Ast.get_inherited stmt) + + | Ast.MetaStmt((s,_,d,_),keep,seqible,_) -> + svar_minus_or_no_add_after stmt s label quantified d ast seqible + after + (process_bef_aft quantified minus_quantified + label llabel slabel true) + guard + (Ast.get_fvs stmt, Ast.get_fresh stmt, Ast.get_inherited stmt) + + | _ -> + let term = + match Ast.unwrap ast with + Ast.DisjRuleElem(res) -> + do_re_matches label guard res quantified minus_quantified + | Ast.Exp(_) | Ast.Ty(_) -> + let stmt_fvs = Ast.get_fvs stmt in + let fvs = get_unquantified quantified stmt_fvs in + CTL.InnerAnd(quantify guard fvs (make_match ast)) + | _ -> + let stmt_fvs = Ast.get_fvs stmt in + let fvs = get_unquantified quantified stmt_fvs in + quantify guard fvs (make_match ast) in + match Ast.unwrap ast with + Ast.Break(brk,semi) -> + (match (llabel,slabel) with + (_,Some(lv,used)) -> (* use switch label if there is one *) + ctl_and term (bclabel_pred_maker slabel) + | _ -> ctl_and term (bclabel_pred_maker llabel)) + | Ast.Continue(brk,semi) -> ctl_and term (bclabel_pred_maker llabel) + | Ast.Return((_,info,retmc,pos),(_,_,semmc,_)) -> + (* discard pattern that comes after return *) + let normal_res = make_seq_after term after in + (* the following code tries to propagate the modifications on + return; to a close brace, in the case where the final return + is absent *) + let new_mc = + match (retmc,semmc) with + (Ast.MINUS(_,l1),Ast.MINUS(_,l2)) when !Flag.sgrep_mode2 -> + (* in sgrep mode, we can propagate the - *) + Some (Ast.MINUS(Ast.NoPos,l1@l2)) + | (Ast.MINUS(_,l1),Ast.MINUS(_,l2)) + | (Ast.CONTEXT(_,Ast.BEFORE(l1)), + Ast.CONTEXT(_,Ast.AFTER(l2))) -> + Some (Ast.CONTEXT(Ast.NoPos,Ast.BEFORE(l1@l2))) + | (Ast.CONTEXT(_,Ast.BEFORE(_)),Ast.CONTEXT(_,Ast.NOTHING)) + | (Ast.CONTEXT(_,Ast.NOTHING),Ast.CONTEXT(_,Ast.NOTHING)) -> + Some retmc + | (Ast.CONTEXT(_,Ast.NOTHING),Ast.CONTEXT(_,Ast.AFTER(l))) -> + Some (Ast.CONTEXT(Ast.NoPos,Ast.BEFORE(l))) + | _ -> None in + let ret = Ast.make_mcode "return" in + let edots = + Ast.rewrap ast (Ast.Edots(Ast.make_mcode "...",None)) in + let semi = Ast.make_mcode ";" in + let simple_return = + make_match(Ast.rewrap ast (Ast.Return(ret,semi))) in + let return_expr = + make_match(Ast.rewrap ast (Ast.ReturnExpr(ret,edots,semi))) in + (match new_mc with + Some new_mc -> + let exit = endpred None in + let mod_rbrace = + Ast.rewrap ast (Ast.SeqEnd (("}",info,new_mc,pos))) in + let stripped_rbrace = + Ast.rewrap ast (Ast.SeqEnd(Ast.make_mcode "}")) in + ctl_or normal_res + (ctl_and (make_match mod_rbrace) + (ctl_and + (ctl_back_ax + (ctl_not + (ctl_uncheck + (ctl_or simple_return return_expr)))) + (ctl_au + (make_match stripped_rbrace) + (* error exit not possible; it is in the middle + of code, so a return is needed *) + exit))) + | _ -> + (* some change in the middle of the return, so have to + find an actual return *) + normal_res) + | _ -> + (* should try to deal with the dots_bef_aft problem elsewhere, + but don't have the courage... *) + let term = + if guard + then term + else + do_between_dots stmt term End + quantified minus_quantified label llabel slabel guard in + dots_done := true; + make_seq_after term after) + | Ast.Seq(lbrace,decls,body,rbrace) -> + let (lbfvs,b1fvs,b2fvs,b3fvs,rbfvs) = + match + seq_fvs quantified + [Ast.get_fvs lbrace;Ast.get_fvs decls; + Ast.get_fvs body;Ast.get_fvs rbrace] + with + [(lbfvs,b1fvs);(_,b2fvs);(_,b3fvs);(rbfvs,_)] -> + (lbfvs,b1fvs,b2fvs,b3fvs,rbfvs) + | _ -> failwith "not possible" in + let (mlbfvs,mb1fvs,mb2fvs,mb3fvs,mrbfvs) = + match + seq_fvs minus_quantified + [Ast.get_mfvs lbrace;Ast.get_mfvs decls; + Ast.get_mfvs body;Ast.get_mfvs rbrace] + with + [(lbfvs,b1fvs);(_,b2fvs);(_,b3fvs);(rbfvs,_)] -> + (lbfvs,b1fvs,b2fvs,b3fvs,rbfvs) + | _ -> failwith "not possible" in + let pv = count_nested_braces stmt in + let lv = get_label_ctr() in + let paren_pred = CTL.Pred(Lib_engine.Paren pv,CTL.Control) in + let label_pred = CTL.Pred(Lib_engine.Label lv,CTL.Control) in + let start_brace = + ctl_and + (quantify guard lbfvs (make_match lbrace)) + (ctl_and paren_pred label_pred) in + let end_brace = + (* label is not needed; paren_pred is enough *) + ctl_and + (quantify guard rbfvs (real_make_match None guard rbrace)) + paren_pred in + let new_quantified2 = + Common.union_set b1fvs (Common.union_set b2fvs quantified) in + let new_quantified3 = Common.union_set b3fvs new_quantified2 in + let new_mquantified2 = + Common.union_set mb1fvs (Common.union_set mb2fvs minus_quantified) in + let new_mquantified3 = Common.union_set mb3fvs new_mquantified2 in + let pattern_as_given = + let new_quantified2 = Common.union_set [pv] new_quantified2 in + let new_quantified3 = Common.union_set [pv] new_quantified3 in + quantify true [pv;lv] + (quantify guard b1fvs + (make_seq + [start_brace; + quantify guard b2fvs + (statement_list decls + (After + (quantify guard b3fvs + (statement_list body + (After (make_seq_after end_brace after)) + new_quantified3 new_mquantified3 + (Some (lv,ref true)) (* label mostly useful *) + llabel slabel true guard))) + new_quantified2 new_mquantified2 + (Some (lv,ref true)) llabel slabel false guard)])) in + if ends_in_return body + then + (* matching error handling code *) + (* Cases: + 1. The pattern as given + 2. A goto, and then some close braces, and then the pattern as + given, but without the braces (only possible if there are no + decls, and open and close braces are unmodified) + 3. Part of the pattern as given, then a goto, and then the rest + of the pattern. For this case, we just check that all paths have + a goto within the current braces. checking for a goto at every + point in the pattern seems expensive and not worthwhile. *) + let pattern2 = + let empty_rbrace = + match Ast.unwrap rbrace with + Ast.SeqEnd((data,info,_,pos)) -> + Ast.rewrap rbrace(Ast.SeqEnd(Ast.make_mcode data)) + | _ -> failwith "unexpected close brace" in + let body = preprocess_dots body in (* redo, to drop braces *) + make_seq + [gotopred label; + ctl_au + (make_match empty_rbrace) + (ctl_ax (* skip the destination label *) + (quantify guard b3fvs + (statement_list body End + new_quantified3 new_mquantified3 None llabel slabel + true guard)))] in + let pattern3 = + let new_quantified2 = Common.union_set [pv] new_quantified2 in + let new_quantified3 = Common.union_set [pv] new_quantified3 in + quantify true [pv;lv] + (quantify guard b1fvs + (make_seq + [start_brace; + ctl_and + (CTL.AU (* want AF even for sgrep *) + (CTL.FORWARD,CTL.STRICT, + CTL.Pred(Lib_engine.PrefixLabel(lv),CTL.Control), + ctl_and (* brace must be eventually after goto *) + (gotopred (Some (lv,ref true))) + (* want AF even for sgrep *) + (CTL.AF(CTL.FORWARD,CTL.STRICT,end_brace)))) + (quantify guard b2fvs + (statement_list decls + (After + (quantify guard b3fvs + (statement_list body Tail + (*After + (make_seq_after + nopv_end_brace after)*) + new_quantified3 new_mquantified3 + None llabel slabel true guard))) + new_quantified2 new_mquantified2 + (Some (lv,ref true)) + llabel slabel false guard))])) in + ctl_or pattern_as_given + (match Ast.unwrap decls with + Ast.DOTS([]) -> ctl_or pattern2 pattern3 + | Ast.DOTS(l) -> pattern3 + | _ -> failwith "circles and stars not supported") + else pattern_as_given + | Ast.IfThen(ifheader,branch,aft) -> + ifthen ifheader branch aft after quantified minus_quantified + label llabel slabel statement make_match guard + + | Ast.IfThenElse(ifheader,branch1,els,branch2,aft) -> + ifthenelse ifheader branch1 els branch2 aft after quantified + minus_quantified label llabel slabel statement make_match guard + + | Ast.While(header,body,aft) | Ast.For(header,body,aft) + | Ast.Iterator(header,body,aft) -> + forwhile header body aft after quantified minus_quantified + label statement make_match guard + + | Ast.Disj(stmt_dots_list) -> (* list shouldn't be empty *) + ctl_and + (label_pred_maker label) + (List.fold_left ctl_seqor CTL.False + (List.map + (function sl -> + statement_list sl after quantified minus_quantified label + llabel slabel true guard) + stmt_dots_list)) + + | Ast.Nest(stmt_dots,whencode,multi,bef,aft) -> + (* label in recursive call is None because label check is already + wrapped around the corresponding code *) + + let bfvs = + match seq_fvs quantified [Ast.get_wcfvs whencode;Ast.get_fvs stmt_dots] + with + [(wcfvs,bothfvs);(bdfvs,_)] -> bothfvs + | _ -> failwith "not possible" in + + (* no minus version because when code doesn't contain any minus code *) + let new_quantified = Common.union_set bfvs quantified in + + quantify guard bfvs + (let dots_pattern = + statement_list stmt_dots (a2n after) new_quantified minus_quantified + None llabel slabel true guard in + dots_and_nests multi + (Some dots_pattern) whencode bef aft None after label + (process_bef_aft new_quantified minus_quantified + None llabel slabel true) + (function x -> + statement_list x Tail new_quantified minus_quantified None + llabel slabel true true) + (function x -> + statement x Tail new_quantified minus_quantified None + llabel slabel true) + guard (function x -> Ast.set_fvs [] (Ast.rewrap stmt x))) + + | Ast.Dots((_,i,d,_),whencodes,bef,aft) -> + let dot_code = + match d with + Ast.MINUS(_,_) -> + (* no need for the fresh metavar, but ... is a bit wierd as a + variable name *) + Some(make_match (make_meta_rule_elem d ([],[],[]))) + | _ -> None in + dots_and_nests false None whencodes bef aft dot_code after label + (process_bef_aft quantified minus_quantified None llabel slabel true) + (function x -> + statement_list x Tail quantified minus_quantified + None llabel slabel true true) + (function x -> + statement x Tail quantified minus_quantified None llabel slabel true) + guard (function x -> Ast.set_fvs [] (Ast.rewrap stmt x)) + + | Ast.Switch(header,lb,cases,rb) -> + let rec intersect_all = function + [] -> [] + | [x] -> x + | x::xs -> intersect x (intersect_all xs) in + let rec union_all l = List.fold_left union [] l in + (* start normal variables *) + let header_fvs = Ast.get_fvs header in + let lb_fvs = Ast.get_fvs lb in + let case_fvs = List.map Ast.get_fvs cases in + let rb_fvs = Ast.get_fvs rb in + let (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs, + all_casefvs,all_b3fvs,all_rbfvs) = + List.fold_left + (function (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs, + all_casefvs,all_b3fvs,all_rbfvs) -> + function case_fvs -> + match seq_fvs quantified [header_fvs;lb_fvs;case_fvs;rb_fvs] with + [(efvs,b1fvs);(lbfvs,b2fvs);(casefvs,b3fvs);(rbfvs,_)] -> + (efvs::all_efvs,b1fvs::all_b1fvs,lbfvs::all_lbfvs, + b2fvs::all_b2fvs,casefvs::all_casefvs,b3fvs::all_b3fvs, + rbfvs::all_rbfvs) + | _ -> failwith "not possible") + ([],[],[],[],[],[],[]) case_fvs in + let (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs, + all_casefvs,all_b3fvs,all_rbfvs) = + (List.rev all_efvs,List.rev all_b1fvs,List.rev all_lbfvs, + List.rev all_b2fvs,List.rev all_casefvs,List.rev all_b3fvs, + List.rev all_rbfvs) in + let exponlyfvs = intersect_all all_efvs in + let lbonlyfvs = intersect_all all_lbfvs in +(* don't do anything with right brace. Hope there is no + code on it *) +(* let rbonlyfvs = intersect_all all_rbfvs in*) + let b1fvs = union_all all_b1fvs in + let new1_quantified = union b1fvs quantified in + let b2fvs = union (union_all all_b1fvs) (intersect_all all_casefvs) in + let new2_quantified = union b2fvs new1_quantified in +(* let b3fvs = union_all all_b3fvs in*) + (* ------------------- start minus free variables *) + let header_mfvs = Ast.get_mfvs header in + let lb_mfvs = Ast.get_mfvs lb in + let case_mfvs = List.map Ast.get_mfvs cases in + let rb_mfvs = Ast.get_mfvs rb in + let (all_mefvs,all_mb1fvs,all_mlbfvs,all_mb2fvs, + all_mcasefvs,all_mb3fvs,all_mrbfvs) = + List.fold_left + (function (all_efvs,all_b1fvs,all_lbfvs,all_b2fvs, + all_casefvs,all_b3fvs,all_rbfvs) -> + function case_mfvs -> + match + seq_fvs quantified + [header_mfvs;lb_mfvs;case_mfvs;rb_mfvs] with + [(efvs,b1fvs);(lbfvs,b2fvs);(casefvs,b3fvs);(rbfvs,_)] -> + (efvs::all_efvs,b1fvs::all_b1fvs,lbfvs::all_lbfvs, + b2fvs::all_b2fvs,casefvs::all_casefvs,b3fvs::all_b3fvs, + rbfvs::all_rbfvs) + | _ -> failwith "not possible") + ([],[],[],[],[],[],[]) case_mfvs in + let (all_mefvs,all_mb1fvs,all_mlbfvs,all_mb2fvs, + all_mcasefvs,all_mb3fvs,all_mrbfvs) = + (List.rev all_mefvs,List.rev all_mb1fvs,List.rev all_mlbfvs, + List.rev all_mb2fvs,List.rev all_mcasefvs,List.rev all_mb3fvs, + List.rev all_mrbfvs) in +(* don't do anything with right brace. Hope there is no + code on it *) +(* let rbonlyfvs = intersect_all all_rbfvs in*) + let mb1fvs = union_all all_mb1fvs in + let new1_mquantified = union mb1fvs quantified in + let mb2fvs = union (union_all all_mb1fvs) (intersect_all all_mcasefvs) in + let new2_mquantified = union mb2fvs new1_mquantified in +(* let b3fvs = union_all all_b3fvs in*) + (* ------------------- end collection of free variables *) + let switch_header = quantify guard exponlyfvs (make_match header) in + let lb = quantify guard lbonlyfvs (make_match lb) in +(* let rb = quantify guard rbonlyfvs (make_match rb) in*) + let case_headers = + List.map + (function case_line -> + match Ast.unwrap case_line with + Ast.CaseLine(header,body) -> + let e1fvs = + match seq_fvs new2_quantified [Ast.get_fvs header] with + [(e1fvs,_)] -> e1fvs + | _ -> failwith "not possible" in + quantify guard e1fvs (real_make_match label true header) + | Ast.OptCase(case_line) -> failwith "not supported") + cases in + let no_header = + ctl_not (List.fold_left ctl_or_fl CTL.False case_headers) in + let lv = get_label_ctr() in + let used = ref false in + let case_code = + List.map + (function case_line -> + match Ast.unwrap case_line with + Ast.CaseLine(header,body) -> + let (e1fvs,b1fvs,s1fvs) = + let fvs = [Ast.get_fvs header;Ast.get_fvs body] in + match seq_fvs new2_quantified fvs with + [(e1fvs,b1fvs);(s1fvs,_)] -> (e1fvs,b1fvs,s1fvs) + | _ -> failwith "not possible" in + let (me1fvs,mb1fvs,ms1fvs) = + let fvs = [Ast.get_mfvs header;Ast.get_mfvs body] in + match seq_fvs new2_mquantified fvs with + [(e1fvs,b1fvs);(s1fvs,_)] -> (e1fvs,b1fvs,s1fvs) + | _ -> failwith "not possible" in + let case_header = + quantify guard e1fvs (make_match header) in + let new3_quantified = union b1fvs new2_quantified in + let new3_mquantified = union mb1fvs new2_mquantified in + let body = + statement_list body Tail + new3_quantified new3_mquantified label llabel + (Some (lv,used)) true(*?*) guard in + quantify guard b1fvs (make_seq [case_header; body]) + | Ast.OptCase(case_line) -> failwith "not supported") + cases in + let default_required = + if List.exists + (function case -> + match Ast.unwrap case with + Ast.CaseLine(header,_) -> + (match Ast.unwrap header with + Ast.Default(_,_) -> true + | _ -> false) + | _ -> false) + cases + then function x -> x + else function x -> ctl_or (fallpred label) x in + let after_pred = aftpred label in + let body after_branch = + ctl_or + (default_required + (quantify guard b2fvs + (make_seq + [ctl_and lb + (List.fold_left ctl_and CTL.True + (List.map ctl_ex case_headers)); + List.fold_left ctl_or_fl no_header case_code]))) + after_branch in + let aft = + (rb_fvs,Ast.get_fresh rb,Ast.get_inherited rb, + match Ast.unwrap rb with + Ast.SeqEnd(rb) -> Ast.get_mcodekind rb + | _ -> failwith "not possible") in + let (switch_header,wrapper) = + if !used + then + let label_pred = CTL.Pred (Lib_engine.Label(lv),CTL.Control) in + (ctl_and switch_header label_pred, + (function body -> quantify true [lv] body)) + else (switch_header,function x -> x) in + wrapper + (end_control_structure b1fvs switch_header body + after_pred (Some(ctl_ex after_pred)) None aft after label guard) + | Ast.FunDecl(header,lbrace,decls,body,rbrace) -> + let (hfvs,b1fvs,lbfvs,b2fvs,b3fvs,b4fvs,rbfvs) = + match + seq_fvs quantified + [Ast.get_fvs header;Ast.get_fvs lbrace;Ast.get_fvs decls; + Ast.get_fvs body;Ast.get_fvs rbrace] + with + [(hfvs,b1fvs);(lbfvs,b2fvs);(_,b3fvs);(_,b4fvs);(rbfvs,_)] -> + (hfvs,b1fvs,lbfvs,b2fvs,b3fvs,b4fvs,rbfvs) + | _ -> failwith "not possible" in + let (mhfvs,mb1fvs,mlbfvs,mb2fvs,mb3fvs,mb4fvs,mrbfvs) = + match + seq_fvs quantified + [Ast.get_mfvs header;Ast.get_mfvs lbrace;Ast.get_mfvs decls; + Ast.get_mfvs body;Ast.get_mfvs rbrace] + with + [(hfvs,b1fvs);(lbfvs,b2fvs);(_,b3fvs);(_,b4fvs);(rbfvs,_)] -> + (hfvs,b1fvs,lbfvs,b2fvs,b3fvs,b4fvs,rbfvs) + | _ -> failwith "not possible" in + let function_header = quantify guard hfvs (make_match header) in + let start_brace = quantify guard lbfvs (make_match lbrace) in + let stripped_rbrace = + match Ast.unwrap rbrace with + Ast.SeqEnd((data,info,_,_)) -> + Ast.rewrap rbrace(Ast.SeqEnd (Ast.make_mcode data)) + | _ -> failwith "unexpected close brace" in + let end_brace = + let exit = CTL.Pred (Lib_engine.Exit,CTL.Control) in + let errorexit = CTL.Pred (Lib_engine.ErrorExit,CTL.Control) in + let fake_brace = CTL.Pred (Lib_engine.FakeBrace,CTL.Control) in + ctl_and + (quantify guard rbfvs (make_match rbrace)) + (ctl_and + (* the following finds the beginning of the fake braces, + if there are any, not completely sure how this works. + sse the examples sw and return *) + (ctl_back_ex (ctl_not fake_brace)) + (ctl_au (make_match stripped_rbrace) (ctl_or exit errorexit))) in + let new_quantified3 = + Common.union_set b1fvs + (Common.union_set b2fvs (Common.union_set b3fvs quantified)) in + let new_quantified4 = Common.union_set b4fvs new_quantified3 in + let new_mquantified3 = + Common.union_set mb1fvs + (Common.union_set mb2fvs + (Common.union_set mb3fvs minus_quantified)) in + let new_mquantified4 = Common.union_set mb4fvs new_mquantified3 in + let fn_nest = + match (Ast.undots decls,Ast.undots body,contains_modif rbrace) with + ([],[body],false) -> + (match Ast.unwrap body with + Ast.Nest(stmt_dots,[],multi,_,_) -> + if multi + then None (* not sure how to optimize this case *) + else Some (Common.Left stmt_dots) + | Ast.Dots(_,whencode,_,_) -> Some (Common.Right whencode) + | _ -> None) + | _ -> None in + let body_code = + match fn_nest with + Some (Common.Left stmt_dots) -> + (* special case for function header + body - header is unambiguous + and unique, so we can just look for the nested body anywhere + else in the CFG *) + CTL.AndAny + (CTL.FORWARD,guard_to_strict guard,start_brace, + statement_list stmt_dots + (* discards match on right brace, but don't need it *) + (Guard (make_seq_after end_brace after)) + new_quantified4 new_mquantified4 + None llabel slabel true guard) + | Some (Common.Right whencode) -> + (* try to be more efficient for the case where the body is just + ... Perhaps this is too much of a special case, but useful + for dropping a parameter and checking that it is never used. *) + make_seq + [start_brace; + match whencode with + [] -> CTL.True + | _ -> + let leftarg = + ctl_and + (ctl_not + (List.fold_left + (function prev -> + function + Ast.WhenAlways(s) -> prev + | Ast.WhenNot(sl) -> + let x = + statement_list sl Tail + new_quantified4 new_mquantified4 + label llabel slabel true true in + ctl_or prev x + | Ast.WhenModifier(Ast.WhenAny) -> CTL.False + | Ast.WhenModifier(_) -> prev) + CTL.False whencode)) + (List.fold_left + (function prev -> + function + Ast.WhenAlways(s) -> + let x = + statement s Tail + new_quantified4 new_mquantified4 + label llabel slabel true in + ctl_and prev x + | Ast.WhenNot(sl) -> prev + | Ast.WhenModifier(Ast.WhenAny) -> CTL.True + | Ast.WhenModifier(_) -> prev) + CTL.True whencode) in + ctl_au leftarg (make_match stripped_rbrace)] + | None -> + make_seq + [start_brace; + quantify guard b3fvs + (statement_list decls + (After + (quantify guard b4fvs + (statement_list body + (After (make_seq_after end_brace after)) + new_quantified4 new_mquantified4 + None llabel slabel true guard))) + new_quantified3 new_mquantified3 None llabel slabel + false guard)] in + quantify guard b1fvs + (make_seq [function_header; quantify guard b2fvs body_code]) + | Ast.Define(header,body) -> + let (hfvs,bfvs,bodyfvs) = + match seq_fvs quantified [Ast.get_fvs header;Ast.get_fvs body] + with + [(hfvs,b1fvs);(bodyfvs,_)] -> (hfvs,b1fvs,bodyfvs) + | _ -> failwith "not possible" in + let (mhfvs,mbfvs,mbodyfvs) = + match seq_fvs minus_quantified [Ast.get_mfvs header;Ast.get_mfvs body] + with + [(hfvs,b1fvs);(bodyfvs,_)] -> (hfvs,b1fvs,bodyfvs) + | _ -> failwith "not possible" in + let define_header = quantify guard hfvs (make_match header) in + let body_code = + statement_list body after + (Common.union_set bfvs quantified) + (Common.union_set mbfvs minus_quantified) + None llabel slabel true guard in + quantify guard bfvs (make_seq [define_header; body_code]) + | Ast.OptStm(stm) -> + failwith "OptStm should have been compiled away\n" + | Ast.UniqueStm(stm) -> failwith "arities not yet supported" + | _ -> failwith "not supported" in + if guard or !dots_done + then term + else + do_between_dots stmt term after quantified minus_quantified + label llabel slabel guard + +(* term is the translation of stmt *) +and do_between_dots stmt term after quantified minus_quantified + label llabel slabel guard = + match Ast.get_dots_bef_aft stmt with + Ast.AddingBetweenDots (brace_term,n) + | Ast.DroppingBetweenDots (brace_term,n) -> + let match_brace = + statement brace_term after quantified minus_quantified + label llabel slabel guard in + let v = Printf.sprintf "_r_%d" n in + let case1 = ctl_and CTL.NONSTRICT (CTL.Ref v) match_brace in + let case2 = ctl_and CTL.NONSTRICT (ctl_not (CTL.Ref v)) term in + CTL.Let + (v,ctl_or + (ctl_back_ex (ctl_or (truepred label) (inlooppred label))) + (ctl_back_ex (ctl_back_ex (falsepred label))), + ctl_or case1 case2) + | Ast.NoDots -> term + +(* un_process_bef_aft is because we don't want to do transformation in this + code, and thus don't case about braces before or after it *) +and process_bef_aft quantified minus_quantified label llabel slabel guard = + function + Ast.WParen (re,n) -> + let paren_pred = CTL.Pred (Lib_engine.Paren n,CTL.Control) in + let s = guard_to_strict guard in + quantify true (get_unquantified quantified [n]) + (ctl_and s (make_raw_match None guard re) paren_pred) + | Ast.Other s -> + statement s Tail quantified minus_quantified label llabel slabel guard + | Ast.Other_dots d -> + statement_list d Tail quantified minus_quantified + label llabel slabel true guard + +(* --------------------------------------------------------------------- *) +(* cleanup: convert AX to EX for pdots. +Concretely: AX(A[...] & E[...]) becomes AX(A[...]) & EX(E[...]) +This is what we wanted in the first place, but it wasn't possible to make +because the AX and its argument are not created in the same place. +Rather clunky... *) +(* also cleanup XX, which is a marker for the case where the programmer +specifies to change the quantifier on .... Assumed to only occur after one AX +or EX, or at top level. *) + +let rec cleanup c = + let c = match c with CTL.XX(c) -> c | _ -> c in + match c with + CTL.False -> CTL.False + | CTL.True -> CTL.True + | CTL.Pred(p) -> CTL.Pred(p) + | CTL.Not(phi) -> CTL.Not(cleanup phi) + | CTL.Exists(keep,v,phi) -> CTL.Exists(keep,v,cleanup phi) + | CTL.AndAny(dir,s,phi1,phi2) -> + CTL.AndAny(dir,s,cleanup phi1,cleanup phi2) + | CTL.HackForStmt(dir,s,phi1,phi2) -> + CTL.HackForStmt(dir,s,cleanup phi1,cleanup phi2) + | CTL.And(s,phi1,phi2) -> CTL.And(s,cleanup phi1,cleanup phi2) + | CTL.Or(phi1,phi2) -> CTL.Or(cleanup phi1,cleanup phi2) + | CTL.SeqOr(phi1,phi2) -> CTL.SeqOr(cleanup phi1,cleanup phi2) + | CTL.Implies(phi1,phi2) -> CTL.Implies(cleanup phi1,cleanup phi2) + | CTL.AF(dir,s,phi1) -> CTL.AF(dir,s,cleanup phi1) + | CTL.AX(CTL.FORWARD,s, + CTL.Let(v1,e1, + CTL.And(CTL.NONSTRICT,CTL.AU(CTL.FORWARD,s2,e2,e3), + CTL.EU(CTL.FORWARD,e4,e5)))) -> + CTL.Let(v1,e1, + CTL.And(CTL.NONSTRICT, + CTL.AX(CTL.FORWARD,s,CTL.AU(CTL.FORWARD,s2,e2,e3)), + CTL.EX(CTL.FORWARD,CTL.EU(CTL.FORWARD,e4,e5)))) + | CTL.AX(dir,s,CTL.XX(phi)) -> CTL.EX(dir,CTL.XX(cleanup phi)) + | CTL.EX(dir,CTL.XX((CTL.AU(_,s,_,_)) as phi)) -> + CTL.AX(dir,s,CTL.XX(cleanup phi)) + | CTL.XX(phi) -> failwith "bad XX" + | CTL.AX(dir,s,phi1) -> CTL.AX(dir,s,cleanup phi1) + | CTL.AG(dir,s,phi1) -> CTL.AG(dir,s,cleanup phi1) + | CTL.EF(dir,phi1) -> CTL.EF(dir,cleanup phi1) + | CTL.EX(dir,phi1) -> CTL.EX(dir,cleanup phi1) + | CTL.EG(dir,phi1) -> CTL.EG(dir,cleanup phi1) + | CTL.AW(dir,s,phi1,phi2) -> CTL.AW(dir,s,cleanup phi1,cleanup phi2) + | CTL.AU(dir,s,phi1,phi2) -> CTL.AU(dir,s,cleanup phi1,cleanup phi2) + | CTL.EU(dir,phi1,phi2) -> CTL.EU(dir,cleanup phi1,cleanup phi2) + | CTL.Let (x,phi1,phi2) -> CTL.Let (x,cleanup phi1,cleanup phi2) + | CTL.LetR (dir,x,phi1,phi2) -> CTL.LetR (dir,x,cleanup phi1,cleanup phi2) + | CTL.Ref(s) -> CTL.Ref(s) + | CTL.Uncheck(phi1) -> CTL.Uncheck(cleanup phi1) + | CTL.InnerAnd(phi1) -> CTL.InnerAnd(cleanup phi1) + +(* --------------------------------------------------------------------- *) +(* Function declaration *) + +let top_level name (ua,pos) t = + let ua = List.filter (function (nm,_) -> nm = name) ua in + used_after := ua; + saved := Ast.get_saved t; + let quantified = Common.minus_set ua pos in + quantify false quantified + (match Ast.unwrap t with + Ast.FILEINFO(old_file,new_file) -> failwith "not supported fileinfo" + | Ast.DECL(stmt) -> + let unopt = elim_opt.V.rebuilder_statement stmt in + let unopt = preprocess_dots_e unopt in + cleanup(statement unopt VeryEnd quantified [] None None None false) + | Ast.CODE(stmt_dots) -> + let unopt = elim_opt.V.rebuilder_statement_dots stmt_dots in + let unopt = preprocess_dots unopt in + let starts_with_dots = + match Ast.undots stmt_dots with + d::ds -> + (match Ast.unwrap d with + Ast.Dots(_,_,_,_) | Ast.Circles(_,_,_,_) + | Ast.Stars(_,_,_,_) -> true + | _ -> false) + | _ -> false in + let starts_with_brace = + match Ast.undots stmt_dots with + d::ds -> + (match Ast.unwrap d with + Ast.Seq(_) -> true + | _ -> false) + | _ -> false in + let res = + statement_list unopt VeryEnd quantified [] None None None + false false in + cleanup + (if starts_with_dots + then + (* EX because there is a loop on enter/top *) + ctl_and CTL.NONSTRICT (toppred None) (ctl_ex res) + else if starts_with_brace + then + ctl_and CTL.NONSTRICT + (ctl_not(CTL.EX(CTL.BACKWARD,(funpred None)))) res + else res) + | Ast.ERRORWORDS(exps) -> failwith "not supported errorwords") + +(* --------------------------------------------------------------------- *) +(* Entry points *) + +let asttoctlz (name,(_,_,exists_flag),l) used_after positions = + letctr := 0; + labelctr := 0; + (match exists_flag with + Ast.Exists -> exists := Exists + | Ast.Forall -> exists := Forall + | Ast.ReverseForall -> exists := ReverseForall + | Ast.Undetermined -> + exists := if !Flag.sgrep_mode2 then Exists else Forall); + + let (l,used_after) = + List.split + (List.filter + (function (t,_) -> + match Ast.unwrap t with Ast.ERRORWORDS(exps) -> false | _ -> true) + (List.combine l (List.combine used_after positions))) in + let res = List.map2 (top_level name) used_after l in + exists := Forall; + res + +let asttoctl r used_after positions = + match r with + Ast.ScriptRule _ -> [] + | Ast.CocciRule (a,b,c,_) -> asttoctlz (a,b,c) used_after positions + +let pp_cocci_predicate (pred,modif) = + Pretty_print_engine.pp_predicate pred + +let cocci_predicate_to_string (pred,modif) = + Pretty_print_engine.predicate_to_string pred diff --git a/engine/asttoctl2.mli b/engine/asttoctl2.mli new file mode 100644 index 0000000..a872298 --- /dev/null +++ b/engine/asttoctl2.mli @@ -0,0 +1,12 @@ +type cocci_predicate = Lib_engine.predicate * Ast_cocci.meta_name Ast_ctl.modif +type formula = + (cocci_predicate,Ast_cocci.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl + +val asttoctl : + Ast_cocci.rule -> Ast_cocci.meta_name list list (* used after *) -> + Ast_cocci.meta_name list list (* positions *) -> + formula list + +val pp_cocci_predicate : cocci_predicate -> unit + +val cocci_predicate_to_string : cocci_predicate -> string diff --git a/engine/asttomember.ml b/engine/asttomember.ml new file mode 100644 index 0000000..7a1d34f --- /dev/null +++ b/engine/asttomember.ml @@ -0,0 +1,327 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* on the first pass, onlyModif is true, so we don't see all matched nodes, +only modified ones *) + +module Ast = Ast_cocci +module V = Visitor_ast +module CTL = Ast_ctl + +let mcode r (_,_,kind,_) = + match kind with + Ast.MINUS(_,_) -> true + | Ast.PLUS -> failwith "not possible" + | Ast.CONTEXT(_,info) -> not (info = Ast.NOTHING) + +let no_mcode _ _ = false + +let contains_modif used_after x = + if List.exists (function x -> List.mem x used_after) (Ast.get_fvs x) + then true + else + let bind x y = x or y in + let option_default = false in + let do_nothing r k e = k e in + let rule_elem r k re = + let res = k re in + match Ast.unwrap re with + Ast.FunHeader(bef,_,fninfo,name,lp,params,rp) -> + bind (mcode r ((),(),bef,Ast.NoMetaPos)) res + | Ast.Decl(bef,_,decl) -> + bind (mcode r ((),(),bef,Ast.NoMetaPos)) res + | _ -> res in + let recursor = + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode mcode + do_nothing do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing + do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in + recursor.V.combiner_rule_elem x + +(* contains an inherited metavariable or contains a constant *) +let contains_constant x = + match Ast.get_inherited x with + [] -> + let bind x y = x or y in + let option_default = false in + let do_nothing r k e = k e in + let mcode _ _ = false in + let ident r k i = + match Ast.unwrap i with + Ast.Id(name) -> true + | _ -> k i in + let expr r k e = + match Ast.unwrap e with + Ast.Constant(const) -> true + | _ -> k e in + let recursor = + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode mcode + do_nothing do_nothing do_nothing do_nothing + ident expr do_nothing do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing in + recursor.V.combiner_rule_elem x + | _ -> true + +(* --------------------------------------------------------------------- *) + +let print_info = function + [] -> Printf.printf "no information\n" + | l -> + List.iter + (function disj -> + Printf.printf "one set of required things %d:\n" + (List.length disj); + List.iter + (function (_,thing) -> + Printf.printf "%s\n" + (Pretty_print_cocci.rule_elem_to_string thing)) + disj;) + l + +(* --------------------------------------------------------------------- *) + +(* drop all distinguishing information from a term *) +let strip = + let do_nothing r k e = Ast.make_term (Ast.unwrap (k e)) in + let do_absolutely_nothing r k e = k e in + let mcode m = Ast.make_mcode(Ast.unwrap_mcode m) in + let rule_elem r k re = + let res = do_nothing r k re in + let no_mcode = Ast.CONTEXT(Ast.NoPos,Ast.NOTHING) in + match Ast.unwrap res with + Ast.FunHeader(bef,b,fninfo,name,lp,params,rp) -> + Ast.rewrap res + (Ast.FunHeader(no_mcode,b,fninfo,name,lp,params,rp)) + | Ast.Decl(bef,b,decl) -> Ast.rewrap res (Ast.Decl(no_mcode,b,decl)) + | _ -> res in + let recursor = + V.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + do_nothing do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing + do_nothing rule_elem do_nothing do_nothing + do_nothing do_absolutely_nothing in + recursor.V.rebuilder_rule_elem + +(* --------------------------------------------------------------------- *) + +let disj l1 l2 = l1 l2 + +let rec conj xs ys = + match (xs,ys) with + ([],_) -> ys + | (_,[]) -> xs + | _ -> + List.fold_left + (function prev -> + function x -> + List.fold_left + (function prev -> + function cur -> + let cur_res = (List.sort compare (Common.union_set x cur)) in + cur_res :: + (List.filter + (function x -> not (Common.include_set cur_res x)) + prev)) + prev ys) + [] xs + +let conj_wrapped x l = conj [List.map (function x -> (1,strip x)) x] l + +(* --------------------------------------------------------------------- *) +(* the main translation loop *) + +let rule_elem re = + match Ast.unwrap re with + Ast.DisjRuleElem(res) -> [[(List.length res,strip re)]] + | _ -> [[(1,strip re)]] + +let conj_one testfn x l = + if testfn x + then conj (rule_elem x) l + else l + +let rec statement_list testfn mcode tail stmt_list : 'a list list = + match Ast.unwrap stmt_list with + Ast.DOTS(x) | Ast.CIRCLES(x) | Ast.STARS(x) -> + (match List.rev x with + [] -> [] + | last::rest -> + List.fold_right + (function cur -> + function rest -> + conj (statement testfn mcode false cur) rest) + rest (statement testfn mcode tail last)) + +and statement testfn mcode tail stmt : 'a list list = + match Ast.unwrap stmt with + Ast.Atomic(ast) -> + (match Ast.unwrap ast with + (* modifications on return are managed in some other way *) + Ast.Return(_,_) | Ast.ReturnExpr(_,_,_) when tail -> [] + | _ -> if testfn ast then rule_elem ast else []) + | Ast.Seq(lbrace,decls,body,rbrace) -> + let body_info = + conj + (statement_list testfn mcode false decls) + (statement_list testfn mcode tail body) in + if testfn lbrace or testfn rbrace + then conj_wrapped [lbrace;rbrace] body_info + else body_info + + | Ast.IfThen(header,branch,(_,_,_,aft)) + | Ast.While(header,branch,(_,_,_,aft)) + | Ast.For(header,branch,(_,_,_,aft)) + | Ast.Iterator(header,branch,(_,_,_,aft)) -> + if testfn header or mcode () ((),(),aft,Ast.NoMetaPos) + then conj (rule_elem header) (statement testfn mcode tail branch) + else statement testfn mcode tail branch + + | Ast.Switch(header,lb,cases,rb) -> + let body_info = case_lines testfn mcode tail cases in + if testfn header or testfn lb or testfn rb + then conj (rule_elem header) body_info + else body_info + + | Ast.IfThenElse(ifheader,branch1,els,branch2,(_,_,_,aft)) -> + let branches = + conj + (statement testfn mcode tail branch1) + (statement testfn mcode tail branch2) in + if testfn ifheader or mcode () ((),(),aft,Ast.NoMetaPos) + then conj (rule_elem ifheader) branches + else branches + + | Ast.Disj(stmt_dots_list) -> + let processed = + List.map (statement_list testfn mcode tail) stmt_dots_list in + (* if one branch gives no information, then we have to take anything *) + if List.exists (function [] -> true | _ -> false) processed + then [] + else Common.union_all processed + + | Ast.Nest(stmt_dots,whencode,true,_,_) -> + statement_list testfn mcode false stmt_dots + + | Ast.Nest(stmt_dots,whencode,false,_,_) -> [] + + | Ast.Dots(_,whencodes,_,_) -> [] + + | Ast.FunDecl(header,lbrace,decls,body,rbrace) -> + let body_info = + conj + (statement_list testfn mcode false decls) + (statement_list testfn mcode true body) in + if testfn header or testfn lbrace or testfn rbrace + then conj (rule_elem header) body_info + else body_info + + | Ast.Define(header,body) -> + conj_one testfn header (statement_list testfn mcode tail body) + + | Ast.OptStm(stm) -> [] + + | Ast.UniqueStm(stm) -> statement testfn mcode tail stm + + | _ -> failwith "not supported" + +and case_lines testfn mcode tail cases = + match cases with + [] -> [] + | last::rest -> + List.fold_right + (function cur -> + function rest -> + conj (case_line testfn mcode false cur) rest) + rest (case_line testfn mcode tail last) + +and case_line testfn mcode tail case = + match Ast.unwrap case with + Ast.CaseLine(header,code) -> + conj_one testfn header (statement_list testfn mcode tail code) + + | Ast.OptCase(case) -> [] + +(* --------------------------------------------------------------------- *) +(* Function declaration *) + +let top_level testfn mcode t : 'a list list = + match Ast.unwrap t with + Ast.FILEINFO(old_file,new_file) -> failwith "not supported fileinfo" + | Ast.DECL(stmt) -> statement testfn mcode false stmt + | Ast.CODE(stmt_dots) -> statement_list testfn mcode false stmt_dots + | Ast.ERRORWORDS(exps) -> failwith "not supported errorwords" + +(* --------------------------------------------------------------------- *) +(* Entry points *) + +let debug = false + +(* if we end up with nothing, we assume that this rule is only here because +someone depends on it, and thus we try again with testfn as contains_modif. +Alternatively, we could check that this rule is mentioned in some +dependency, but that would be a little more work, and doesn't seem +worthwhile. *) + +(* lists are sorted such that smaller DisjRuleElem are first, because they +are cheaper to test *) + +let asttomemberz (_,_,l) used_after = + let process_one (l : (int * Ast_cocci.rule_elem) list list) = + if debug + then print_info l; + List.map + (function info -> + let info = + List.sort (function (n1,_) -> function (n2,_) -> compare n1 n2) + info in + List.map (function (_,x) -> (Lib_engine.Match(x),CTL.Control)) info) + l in + List.map2 + (function min -> function (max,big_max) -> + match min with + [] -> + (match max() with + [] -> process_one (big_max()) + | max -> process_one max) + | _ -> process_one min) + (List.map (top_level contains_constant no_mcode) l) + (List.combine + (List.map2 + (function x -> function ua -> function _ -> + top_level (contains_modif ua) mcode x) + l used_after) + (List.map + (function x -> function _ -> + top_level (function _ -> true) no_mcode x) + l)) + +let asttomember r used_after = + match r with + Ast.ScriptRule _ -> [] + | Ast.CocciRule (a,b,c,_) -> asttomemberz (a,b,c) used_after + diff --git a/engine/asttomember.mli b/engine/asttomember.mli new file mode 100644 index 0000000..5d3a39a --- /dev/null +++ b/engine/asttomember.mli @@ -0,0 +1,2 @@ +val asttomember : Ast_cocci.rule -> Ast_cocci.meta_name list list -> + (Lib_engine.predicate * Ast_cocci.meta_name Ast_ctl.modif) list list list diff --git a/engine/c_vs_c.ml b/engine/c_vs_c.ml new file mode 100644 index 0000000..440f7ba --- /dev/null +++ b/engine/c_vs_c.ml @@ -0,0 +1,291 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Common + +open Ast_c + +(* For the moment I do only eq_type and not eq_expr, etc. The reason + * for eq_type is related to the typedef and struct isomorphism. Sometimes + * one use the typedef and sometimes the structname. + * + * TODO: should use the isomorphisms engine of julia. + * Maybe I can transform my ast_c in ast_cocci, and use julia's code ? + * Maybe I can add some Disj in my ast_c ? + *) + + +module type PARAM = + sig + type tin + type 'x tout + + type 'a matcher = 'a -> 'a -> tin -> 'a tout + + val (>>=): + (tin -> 'a tout) -> + ('a -> (tin -> 'b tout)) -> + (tin -> 'b tout) + + val (>&&>) : bool -> (tin -> 'x tout) -> (tin -> 'x tout) + + val return : 'a -> tin -> 'a tout + val fail : tin -> 'a tout +end + + +module C_VS_C = + functor (X : PARAM) -> +struct + +type 'a matcher = 'a -> 'a -> X.tin -> 'a X.tout + +let (>>=) = X.(>>=) +let (>&&>) = X.(>&&>) +let return = X.return +let fail = X.fail + +let (option: 'a matcher -> ('a option matcher)) = fun f t1 t2 -> + match (t1,t2) with + | (Some t1, Some t2) -> + f t1 t2 >>= (fun t -> + return (Some t) + ) + | (None, None) -> return None + | _ -> fail + + +let rec fullType a b = + let ((qua,iiqa), tya) = a in + let ((qub,iiqb), tyb) = b in + (qua.const =:= qub.const && qua.volatile =:= qub.volatile) >&&> + + let (qu,iiq) = (qua, iiqa) in + typeC tya tyb >>= (fun ty -> + return ((qu,iiq), ty) + ) + +and typeC tya tyb = + let (a, iia) = tya in + let (b, iib) = tyb in + + let iix = iia in + + match a, b with + | BaseType a, BaseType b -> + a =*= b >&&> return (BaseType a, iix) + | Pointer a, Pointer b -> + fullType a b >>= (fun x -> return (Pointer x, iix)) + + | StructUnionName (sua, sa), StructUnionName (sub, sb) -> + (sua =*= sub && sa =$= sb) >&&> + return (StructUnionName (sua, sa), iix) + + | TypeName (sa, opta), TypeName (sb, optb) -> + (* assert compatible opta optb ? *) + (*option fullType opta optb*) + sa =$= sb >&&> + let opt = + (match opta, optb with + | None, None -> None + | Some x, _ + | _, Some x + -> Some x + ) + in + return (TypeName (sa, opt), iix) + + + | Array (ea, a), Array (eb,b) -> + let get_option f = function Some x -> Some (f x) | None -> None in + let ea = get_option Lib_parsing_c.al_expr ea in + let eb = get_option Lib_parsing_c.al_expr eb in + ea =*= eb >&&> fullType a b >>= (fun x -> return (Array (ea, x), iix)) + + | FunctionType (returna, paramsa), FunctionType (returnb, paramsb) -> + let (tsa, (ba,iihas3dotsa)) = paramsa in + let (tsb, (bb,iihas3dotsb)) = paramsb in + + let bx = ba in + let iihas3dotsx = iihas3dotsa in + + (ba = bb && List.length tsa = List.length tsb) >&&> + fullType returna returnb >>= (fun returnx -> + + Common.zip tsa tsb +> List.fold_left + (fun acc ((parama,iia),(paramb,iib))-> + let iix = iia in + acc >>= (fun xs -> + + let (((ba, saopt, ta), ii_b_sa)) = parama in + let (((bb, sbopt, tb), ii_b_sb)) = paramb in + + let bx = ba in + let sxopt = saopt in + let ii_b_sx = ii_b_sa in + + (ba =:= bb && saopt =*= sbopt) >&&> + fullType ta tb >>= (fun tx -> + let paramx = (((bx, sxopt, tx), ii_b_sx)) in + return ((paramx,iix)::xs) + ) + ) + ) (return []) + >>= (fun tsx -> + let paramsx = (List.rev tsx, (bx, iihas3dotsx)) in + return (FunctionType (returnx, paramsx), iix) + )) + + | Enum (saopt, enuma), Enum (sbopt, enumb) -> + (saopt =*= sbopt && + List.length enuma = List.length enumb && + Common.zip enuma enumb +> List.for_all (fun + ((((sa, eopta),ii_s_eqa), iicommaa), (((sb, eoptb),ii_s_eqb),iicommab)) + -> + sa =$= sb && + eopta =*= eoptb + ) + ) >&&> + return (Enum (saopt, enuma), iix) + + | EnumName sa, EnumName sb -> sa =$= sb >&&> return (EnumName sa, iix) + + | ParenType a, ParenType b -> + (* iso here ? *) + fullType a b >>= (fun x -> + return (ParenType x, iix) + ) + + | TypeOfExpr ea, TypeOfExpr eb -> + let ea = Lib_parsing_c.al_expr ea in + let eb = Lib_parsing_c.al_expr eb in + ea =*= eb >&&> return (TypeOfExpr ea, iix) + + | TypeOfType a, TypeOfType b -> + fullType a b >>= (fun x -> return (TypeOfType x, iix)) + +(* | TypeOfType a, b -> + | a, TypeOfType b -> +*) + + + | StructUnion (sua, saopt, sta), StructUnion (sub, sbopt, stb) -> + (sua =*= sub && saopt =*= sbopt && List.length sta = List.length stb) + >&&> + Common.zip sta stb +> List.fold_left + (fun acc ((xfielda, iia), (xfieldb, iib)) -> + let iix = iia in + acc >>= (fun xs -> + match xfielda, xfieldb with + | EmptyField, EmptyField -> return ((EmptyField, iix)::xs) + + | FieldDeclList fa, FieldDeclList fb -> + (List.length fa =|= List.length fb) >&&> + + Common.zip fa fb +> List.fold_left + (fun acc2 ((fielda,iia),(fieldb,iib))-> + let iix = iia in + acc2 >>= (fun xs -> + let (fa, ii2a) = fielda in + let (fb, ii2b) = fieldb in + let ii2x = ii2a in + match fa, fb with + | Simple (saopt, ta), Simple (sbopt, tb) -> + saopt =*= sbopt >&&> + fullType ta tb >>= (fun tx -> + return (((Simple (saopt, tx), ii2x), iix)::xs) + ) + + | BitField (sopta, ta, ea), BitField (soptb, tb, eb) -> + (sopta =*= soptb && ea =*= eb) >&&> + fullType ta tb >>= (fun tx -> + return (((BitField (sopta,tx,ea), ii2x), iix)::xs) + ) + | _,_ -> fail + ) + ) (return []) + >>= (fun fx -> + return ((FieldDeclList (List.rev fx), iix)::xs) + ) + | _ -> fail + ) + + + ) (return []) + >>= (fun stx -> + return (StructUnion (sua, saopt, List.rev stx), iix) + ) + + + + (* choose the lub. + * subtil: in the return must put iia, not iix, and in following case + * must put iib and not iix, because we want the token corresponding + * to the typedef. + *) + | TypeName (s, Some a), _ -> + fullType a (Ast_c.nQ, tyb) >>= (fun x -> + return (TypeName (s, Some x), iia) + ) + + | _, TypeName (s, Some b) -> + fullType b (Ast_c.nQ, tya) >>= (fun x -> + return (TypeName (s, Some x), iib) (* subtil: *) + ) + + | _, _ -> fail + + + +end + +module XEQ = struct + type tin = unit + type 'a tout = 'a option + + type 'a matcher = 'a -> 'a -> tin -> 'a tout + + let return x = fun tin -> Some x + let fail = fun tin -> None + + let (>>=) m f = fun tin -> + match m tin with + | None -> None + | Some x -> f x tin + + let (>&&>) b m = fun tin -> + if b then m tin + else fail tin + +end + +module EQ = C_VS_C (XEQ) + + +let eq_type2 a b = EQ.fullType a b () <> None +let merge_type2 a b = Common.some (EQ.fullType a b ()) + +let eq_type a b = + Common.profile_code "C_vs_c" (fun () -> eq_type2 a b) + +let merge_type a b = + Common.profile_code "C_vs_c" (fun () -> merge_type2 a b) diff --git a/engine/c_vs_c.mli b/engine/c_vs_c.mli new file mode 100644 index 0000000..63548fb --- /dev/null +++ b/engine/c_vs_c.mli @@ -0,0 +1,3 @@ + +val eq_type : Ast_c.fullType -> Ast_c.fullType -> bool +val merge_type : Ast_c.fullType -> Ast_c.fullType -> Ast_c.fullType diff --git a/engine/check_exhaustive_pattern.ml b/engine/check_exhaustive_pattern.ml new file mode 100644 index 0000000..a716d1b --- /dev/null +++ b/engine/check_exhaustive_pattern.ml @@ -0,0 +1,183 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + + +(* Just to warn me when there is some news in the types in + * ast_cocci.ml or even ast_c.ml, so that I can then adjust my code in + * pattern.ml or transformation.ml. + * + * For the moment I do it only for myself (pad), that is I check only + * for news in ast_cocci.ml, because I already know when I add stuff in + * my code in ast_c.ml or control_flow_c.ml. *) + +module A = Ast_cocci +module B = Ast_c +module F = Control_flow_c + +(* dependencies_to_adjust: pattern.ml, transformaton.ml *) + +let dumb_astcocci_rule_elem = function + | A.MetaRuleElem _ -> () + | A.MetaStmt (ida,_,_,_) -> () + | A.MetaStmtList _ -> () + | A.Exp expr -> () + | A.TopExp expr -> () + | A.Ty ty -> () + | A.FunHeader (bef,allminus, fninfo, ida, _, paramsa, _) -> () + | A.Decl (bef,allminus,decla) -> () + | A.SeqStart _ -> () + | A.SeqEnd _ -> () + | A.ExprStatement (ea, _) -> () + | A.IfHeader (_,_, ea, _) -> () + | A.Else _ -> () + | A.WhileHeader (_, _, ea, _) -> () + | A.DoHeader _ -> () + | A.WhileTail (_,_,ea,_,_) -> () + | A.ForHeader (_, _, ea1opt, _, ea2opt, _, ea3opt, _) -> () + | A.IteratorHeader (ia1, ia2, ea, ia3) -> () + | A.SwitchHeader _ -> () + | A.Break _ -> () + | A.Continue _ -> () + | A.Label _ -> () + | A.Goto(_,_,_) -> () + | A.Return _ -> () + | A.ReturnExpr (_, ea, _) -> () + | A.DefineHeader _ -> () + | A.Include _ -> () + | A.Default _ -> () + | A.Case _ -> () + | A.DisjRuleElem _ -> failwith "not possible - compiled away in asttoctl" + +let dumb_astcocci_decl = function + | A.UnInit (stg, typa, sa, _) -> () + | A.Init (stg, typa, sa, _, expa, _) -> () + | A.TyDecl (typa, _) -> () + | A.MacroDecl(fn, _, eas, _, _) -> () + | A.Ddots(dots,whencode) -> () + | A.MetaDecl _ -> () + | A.Typedef(d,ty1,ty2,pv) -> () + | A.DisjDecl xs -> () + | A.OptDecl _ | A.UniqueDecl _ -> () + +let dumb_astcocci_initialiser = function + A.Init(stg,ty,id,eq,ini,sem) -> () + | A.UnInit(stg,ty,id,sem) -> () + | A.MacroDecl(fn, _, eas, _, _) -> () + | A.TyDecl(ty,sem) -> () + | A.Typedef(d,ty1,ty2,pv) -> () + | A.DisjDecl(decls) -> () + | A.Ddots(dots,whencode) -> () + | A.MetaDecl(name,_,_) -> () + | A.OptDecl(decl) -> () + | A.UniqueDecl(decl) -> () + +let dumb_astcocci_expr = function + | A.MetaExpr (ida,_,_, opttypa, _, _) -> () + | A.Edots (_,_) -> () + | A.MetaErr _ -> () + | A.Ident ida -> () + | A.Constant (A.String sa,_,_,_) -> () + | A.Constant (A.Char sa,_,_,_) -> () + | A.Constant (A.Int sa,_,_,_) -> () + | A.Constant (A.Float sa,_,_,_) -> () + | A.FunCall (ea1, _, eas, _) -> () + | A.Assignment (ea1, opa, ea2, _) -> () + | A.CondExpr (ea1,_,ea2opt,_,ea3) -> () + | A.Postfix (ea, opa) -> () + | A.Infix (ea, opa) -> () + | A.Unary (ea, opa) -> () + | A.Binary (ea1, opa, ea2) -> () + | A.Nested (ea1, opa, ea2) -> () + | A.ArrayAccess (ea1, _, ea2, _) -> () + | A.RecordAccess (ea, _, ida) -> () + | A.RecordPtAccess (ea, _, ida) -> () + | A.Cast (_, typa, _, ea) -> () + | A.SizeOfExpr (_, ea) -> () + | A.SizeOfType (_, _, typa, _) -> () + | A.TypeExp (typa) -> () + | A.Paren (_, ea, _) -> () + | A.NestExpr _ -> () + | A.MetaExprList _ -> () + | A.EComma _ -> () + | A.Ecircles _ -> () + | A.Estars _ -> () + | A.DisjExpr eas -> () + | A.UniqueExp _ -> () + | A.OptExp _ -> () + +let dumb_astcocci_fulltype = function + A.Type(cv,ty) -> () + | A.DisjType(types) -> () + | A.OptType(ty) -> () + | A.UniqueType(ty) -> () + +let dumb_astcocci_type = function + | A.MetaType(ida,_,_) -> () + | A.BaseType (basea, signaopt) -> () + | A.ImplicitInt (signa) -> () + | A.Pointer (typa, _) -> () + | A.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> () + | A.FunctionType _ -> () + | A.Array (typa, _, eaopt, _) -> () + | A.StructUnionName(sa, sua) -> () + | A.StructUnionDef(ty, lb, decls, rb) -> () + | A.TypeName sa -> () + + +(* ------------------------------------------------------------------------- *) +(* for C *) +(* + | (Ident (_) | Constant _ | FunCall (_,_) | CondExpr (_,_,_) + | Sequence (_,_) + | Assignment (_,_,_) + | Postfix (_,_) | Infix (_,_) | Unary (_,_) | Binary (_,_,_) + | ArrayAccess (_,_) | RecordAccess (_,_) | RecordPtAccess (_,_) + | SizeOfExpr (_) | SizeOfType (_) | Cast (_,_) + | StatementExpr (_) | Constructor + | ParenExpr (_) | MacroCall (_) | MacroCall2 (_) + ),_ -> + + | ( Labeled (Label (_,_)) | Labeled (Case (_,_)) + | Labeled (CaseRange (_,_,_)) | Labeled (Default _) + | Compound _ | ExprStatement _ + | Selection (If (_, _, _)) | Selection (Switch (_, _)) + | Iteration (While (_, _)) | Iteration (DoWhile (_, _)) + | Iteration (For ((_,_), (_,_), (_, _), _)) + | Jump (Goto _) | Jump ((Continue|Break|Return)) | Jump (ReturnExpr _) + | Decl _ | Asm | Selection (IfCpp (_,_)) + ), _ -> +*) + +(* for control flow nodes + + | ( F.ExprStatement (_, _) + | F.IfHeader (_, _) | F.SwitchHeader (_, _) + | F.WhileHeader (_, _) | (* F.DoHeader (_, _) | *) F.DoWhileTail (_, _) + | F.ForHeader (_, _) + | F.Return (_, _) | F.ReturnExpr (_, _) + (* no counter part in cocci *) + | F.Label (_, _) + | F.Case (_,_) | (* F.CaseRange (_, _) | *) F.Default (_, _) + | F.Goto (_, _) | F.Continue (_, _) | F.Break (_, _) + ) -> raise Impossible + +*) diff --git a/engine/check_reachability.ml b/engine/check_reachability.ml new file mode 100644 index 0000000..297a7d4 --- /dev/null +++ b/engine/check_reachability.ml @@ -0,0 +1,208 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* ---------------------------------------------------------------- *) +(* code to check for ambiguities *) + +(* Idea: for each node that is said to be modified in any witness tree, we + check that all backward paths end up at the root of some witness tree + that says that the node should be modified. We then give a warning, if + the node itself appears more than once in such a path, because then there + could be some instances that are modified and some that are not. An + example is as follows: + + f(); ... g(); ... - h(); + + with C code: f(); while(E) { h(); g(); } g(); h(); + + Then the h() in the while loop matches both the first ... and the - h(); + + Concretely, if a node 47 is in the witness tree rooted at 1 and the + witness tree rooted at 2, then we give an error if 47 is not in the set + of nodes satisfying AF[1v2] and give a warning if 47 is in the set of + nodes satisfying EXEF(47 & EXEF(1v2)). (Note that the root of a witness + tree here is the node causing the pattern to match; there might not be + any witnesses associated with this node.) + + Another try on the exists formula: + !(1v2) & EXE[!(1v2) U 47] + The first !(1v2) is to discard immediately cases where the beginning and + end of the path are the same. Afterwards, it would only seem necessary to + serach up to the next occurrence of 47 (leaf), ensuring that there are not + 1s or 2s (starting points) along the way. Then the second 47 would be in + the path, but possible not transformed. + *) + +module G = Ograph_extended +module CTL = Ast_ctl + +(* Step 1: for each tree, make a mapping from the modified nodes to the root +of the tree *) + +let modified = (Hashtbl.create(25) : (G.nodei, G.nodei list ref) Hashtbl.t) + +let build_modified (n,_,wits) = + let rec loop = function + CTL.Wit(st,[CTL.Subst(x,Wrapper_ctl.PredVal(CTL.Modif(v)))],anno,wit) -> + let cell = + try Hashtbl.find modified st + with Not_found -> + let cell = ref [] in Hashtbl.add modified st cell; cell in + cell := n :: !cell; + List.iter loop wit + | CTL.Wit(st,_,anno,wit) -> List.iter loop wit + | CTL.NegWit(wit) -> () in + List.iter loop wits + +(* Step 2: For each node in the hash table, create the error and warning + formulas *) + +type 'a nodes = Node of 'a | After + +let create_formulas _ = + Hashtbl.fold + (function node -> + function roots -> + function acc -> + (*let exef f = + wrap + (Ast_ctl.EX + (Ast_ctl.BACKWARD,wrap(Ast_ctl.EF(Ast_ctl.BACKWARD,f)))) in*) + let match_node = Ast_ctl.Pred(Node(node)) in + let match_roots = + List.map (function n -> Ast_ctl.Pred(Node(n))) + (List.sort compare !roots) in + let roots = + List.fold_left + (function prev -> function cur -> Ast_ctl.Or(prev,cur)) + (List.hd match_roots) (List.tl match_roots) in + (node, + Ast_ctl.AF(Ast_ctl.BACKWARD,Ast_ctl.NONSTRICT, + Ast_ctl.Or(roots,Ast_ctl.Pred(After))), + Ast_ctl.And + (Ast_ctl.NONSTRICT, + Ast_ctl.Not(roots), + Ast_ctl.EX + (Ast_ctl.BACKWARD, + Ast_ctl.EU(Ast_ctl.BACKWARD,roots,match_node)))) + (*exef + (wrap(Ast_ctl.And(Ast_ctl.NONSTRICT,match_node,exef(roots))))*) + :: acc) + modified [] + +(* Step 3: check the formula on the control-flow graph *) + +module PRED = + struct + type t = Ograph_extended.nodei nodes + let print_predicate = function + After -> Format.print_string "after" + | Node x -> Format.print_string (string_of_int x) + end + +module ENV = + struct + type value = unit + type mvar = unit + let eq_mvar x x' = failwith "should not be invoked" + let eq_val v v' = failwith "should not be invoked" + let merge_val v v' = failwith "should not be invoked" + + let print_mvar s = failwith "should not be invoked" + let print_value x = failwith "should not be invoked" + end + + +module CFG = + struct + type node = Ograph_extended.nodei + type cfg = + (Control_flow_c.node, Control_flow_c.edge) + Ograph_extended.ograph_mutable + let predecessors cfg n = List.map fst ((cfg#predecessors n)#tolist) + let successors cfg n = List.map fst ((cfg#successors n)#tolist) + let extract_is_loop cfg n = + Control_flow_c.extract_is_loop (cfg#nodes#find n) + let print_node i = Format.print_string (string_of_int i) + let size cfg = cfg#nodes#length + end + +module ENGINE = Ctl_engine.CTL_ENGINE (ENV) (CFG) (PRED) + +let test_formula state formula cfg = + let label = function + Node pred -> [(pred,[],[])] + | After -> + List.concat + (List.map + (fun (nodei, node) -> + match Control_flow_c.unwrap node with + Control_flow_c.AfterNode -> [(nodei,[],[])] + | _ -> []) + cfg#nodes#tolist) in + let verbose = !Flag_ctl.verbose_ctl_engine in + let pm = !Flag_ctl.partial_match in + Flag_ctl.verbose_ctl_engine := false; + Flag_ctl.partial_match := false; + let res = + ENGINE.sat (cfg,label,List.map fst cfg#nodes#tolist) + (CTL.And(CTL.NONSTRICT,CTL.Pred(Node(state)),formula)) + [[Node(state)]] in + Flag_ctl.verbose_ctl_engine := verbose; + Flag_ctl.partial_match := pm; + match res with [] -> false | _ -> true + +(* ---------------------------------------------------------------- *) +(* Entry point *) + +(* The argument is a list of triples with a node name, an empty environment +and a witness tree *) + +type witness = + (Ograph_extended.nodei, unit, + (Ograph_extended.nodei, unit, unit) Ast_ctl.generic_ctl list) + Ast_ctl.generic_witnesstree + +type ('a,'b,'c,'d,'e) triples = + (Ograph_extended.nodei * 'a * + (Ograph_extended.nodei, + ('b, ('c, 'd) Wrapper_ctl.wrapped_binding) CTL.generic_subst list, 'e) + CTL.generic_witnesstree list) list + +let check_reachability triples cfg = + Hashtbl.clear modified; + List.iter build_modified triples; + let formulas = create_formulas() in + List.iter + (function (node,af_formula,ef_formula) -> + if test_formula node af_formula cfg + then + if test_formula node ef_formula cfg + then + Printf.printf "warning: node %d may be inconsistently modified\n" + node + else () + else + failwith + (Printf.sprintf + "node %d reachable by inconsistent control-flow paths" node)) + formulas diff --git a/engine/check_reachability.mli b/engine/check_reachability.mli new file mode 100644 index 0000000..21ef7be --- /dev/null +++ b/engine/check_reachability.mli @@ -0,0 +1,13 @@ +type witness = + (Ograph_extended.nodei, unit, + (Ograph_extended.nodei, unit, unit) Ast_ctl.generic_ctl list) + Ast_ctl.generic_witnesstree + +type ('a,'b,'c,'d,'e) triples = + (Ograph_extended.nodei * 'a * + (Ograph_extended.nodei, + ('b, ('c,'d) Wrapper_ctl.wrapped_binding) Ast_ctl.generic_subst list, 'e) + Ast_ctl.generic_witnesstree list) list + +val check_reachability : + ('a,'b,'c,'d,'e) triples -> Control_flow_c.cflow -> unit diff --git a/engine/cocci_vs_c_3.ml b/engine/cocci_vs_c_3.ml new file mode 100644 index 0000000..fc1f4c0 --- /dev/null +++ b/engine/cocci_vs_c_3.ml @@ -0,0 +1,3419 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Common + +module A = Ast_cocci +module B = Ast_c + +module F = Control_flow_c + +(*****************************************************************************) +(* Wrappers *) +(*****************************************************************************) + +(*****************************************************************************) +(* Helpers *) +(*****************************************************************************) + +type sequence = Ordered | Unordered + +let seqstyle eas = + match A.unwrap eas with + | A.DOTS _ -> Ordered + | A.CIRCLES _ -> Unordered + | A.STARS _ -> failwith "not handling stars" + +let (redots : 'a A.dots -> 'a list -> 'a A.dots)=fun eas easundots -> + A.rewrap eas ( + match A.unwrap eas with + | A.DOTS _ -> A.DOTS easundots + | A.CIRCLES _ -> A.CIRCLES easundots + | A.STARS _ -> A.STARS easundots + ) + + +let (need_unordered_initialisers : B.initialiser B.wrap2 list -> bool) = + fun ibs -> + ibs +> List.exists (fun (ib, icomma) -> + match B.unwrap ib with + | B.InitDesignators _ + | B.InitFieldOld _ + | B.InitIndexOld _ + -> true + | B.InitExpr _ + | B.InitList _ + -> false + ) + +(* For the #include in the .cocci, need to find where is + * the '+' attached to this element, to later find the first concrete + * #include or last one in the serie of #includes in the + * .c. + *) +type include_requirement = + | IncludeMcodeBefore + | IncludeMcodeAfter + | IncludeNothing + + + +(* todo? put in semantic_c.ml *) +type info_ident = + | Function + | LocalFunction (* entails Function *) + | DontKnow + + +let term mc = A.unwrap_mcode mc +let mcodekind mc = A.get_mcodekind mc + + +let mcode_contain_plus = function + | A.CONTEXT (_,A.NOTHING) -> false + | A.CONTEXT _ -> true + | A.MINUS (_,[]) -> false + | A.MINUS (_,x::xs) -> true + | A.PLUS -> raise Impossible + +let mcode_simple_minus = function + | A.MINUS (_,[]) -> true + | _ -> false + + +(* In transformation.ml sometime I build some mcodekind myself and + * julia has put None for the pos. But there is no possible raise + * NoMatch in those cases because it is for the minusall trick or for + * the distribute, so either have to build those pos, in fact a range, + * because for the distribute have to erase a fullType with one + * mcodekind, or add an argument to tag_with_mck such as "safe" that + * don't do the check_pos. Hence this DontCarePos constructor. *) + +let minusizer = + ("fake","fake"), + {A.line = 0; column =0; A.strbef=[]; A.straft=[];}, + (A.MINUS(A.DontCarePos, [])), + A.NoMetaPos + +let generalize_mcode ia = + let (s1, i, mck, pos) = ia in + let new_mck = + match mck with + | A.PLUS -> raise Impossible + | A.CONTEXT (A.NoPos,x) -> + A.CONTEXT (A.DontCarePos,x) + | A.MINUS (A.NoPos,x) -> + A.MINUS (A.DontCarePos,x) + | _ -> raise Impossible in + (s1, i, new_mck, pos) + + + +(*---------------------------------------------------------------------------*) + +(* 0x0 is equivalent to 0, value format isomorphism *) +let equal_c_int s1 s2 = + try + int_of_string s1 = int_of_string s2 + with Failure("int_of_string") -> + s1 =$= s2 + + + +(*---------------------------------------------------------------------------*) +(* Normally A should reuse some types of Ast_c, so those + * functions should not exist. + * + * update: but now Ast_c depends on A, so can't make too + * A depends on Ast_c, so have to stay with those equal_xxx + * functions. + *) + +let equal_unaryOp a b = + match a, b with + | A.GetRef , B.GetRef -> true + | A.DeRef , B.DeRef -> true + | A.UnPlus , B.UnPlus -> true + | A.UnMinus , B.UnMinus -> true + | A.Tilde , B.Tilde -> true + | A.Not , B.Not -> true + | _, _ -> false + +let equal_arithOp a b = + match a, b with + | A.Plus , B.Plus -> true + | A.Minus , B.Minus -> true + | A.Mul , B.Mul -> true + | A.Div , B.Div -> true + | A.Mod , B.Mod -> true + | A.DecLeft , B.DecLeft -> true + | A.DecRight , B.DecRight -> true + | A.And , B.And -> true + | A.Or , B.Or -> true + | A.Xor , B.Xor -> true + | _ , _ -> false + +let equal_logicalOp a b = + match a, b with + | A.Inf , B.Inf -> true + | A.Sup , B.Sup -> true + | A.InfEq , B.InfEq -> true + | A.SupEq , B.SupEq -> true + | A.Eq , B.Eq -> true + | A.NotEq , B.NotEq -> true + | A.AndLog , B.AndLog -> true + | A.OrLog , B.OrLog -> true + | _ , _ -> false + +let equal_assignOp a b = + match a, b with + | A.SimpleAssign, B.SimpleAssign -> true + | A.OpAssign a, B.OpAssign b -> equal_arithOp a b + | _ -> false + +let equal_fixOp a b = + match a, b with + | A.Dec, B.Dec -> true + | A.Inc, B.Inc -> true + | _ -> false + +let equal_binaryOp a b = + match a, b with + | A.Arith a, B.Arith b -> equal_arithOp a b + | A.Logical a, B.Logical b -> equal_logicalOp a b + | _ -> false + +let equal_structUnion a b = + match a, b with + | A.Struct, B.Struct -> true + | A.Union, B.Union -> true + | _, _ -> false + +let equal_sign a b = + match a, b with + | A.Signed, B.Signed -> true + | A.Unsigned, B.UnSigned -> true + | _, _ -> false + +let equal_storage a b = + match a, b with + | A.Static , B.Sto B.Static + | A.Auto , B.Sto B.Auto + | A.Register , B.Sto B.Register + | A.Extern , B.Sto B.Extern + -> true + | _ -> false + +(*---------------------------------------------------------------------------*) + +let equal_metavarval valu valu' = + match valu, valu' with + | Ast_c.MetaIdVal a, Ast_c.MetaIdVal b -> a =$= b + | Ast_c.MetaFuncVal a, Ast_c.MetaFuncVal b -> a =$= b + | Ast_c.MetaLocalFuncVal a, Ast_c.MetaLocalFuncVal b -> + (* do something more ? *) + a =$= b + + (* al_expr before comparing !!! and accept when they match. + * Note that here we have Astc._expression, so it is a match + * modulo isomorphism (there is no metavariable involved here, + * just isomorphisms). => TODO call isomorphism_c_c instead of + * =*=. Maybe would be easier to transform ast_c in ast_cocci + * and call the iso engine of julia. *) + | Ast_c.MetaExprVal a, Ast_c.MetaExprVal b -> + Lib_parsing_c.al_expr a =*= Lib_parsing_c.al_expr b + | Ast_c.MetaExprListVal a, Ast_c.MetaExprListVal b -> + Lib_parsing_c.al_arguments a =*= Lib_parsing_c.al_arguments b + + | Ast_c.MetaStmtVal a, Ast_c.MetaStmtVal b -> + Lib_parsing_c.al_statement a =*= Lib_parsing_c.al_statement b + | Ast_c.MetaTypeVal a, Ast_c.MetaTypeVal b -> + (* old: Lib_parsing_c.al_type a =*= Lib_parsing_c.al_type b *) + C_vs_c.eq_type a b + + | Ast_c.MetaListlenVal a, Ast_c.MetaListlenVal b -> a =|= b + + | Ast_c.MetaParamVal a, Ast_c.MetaParamVal b -> + Lib_parsing_c.al_param a =*= Lib_parsing_c.al_param b + | Ast_c.MetaParamListVal a, Ast_c.MetaParamListVal b -> + Lib_parsing_c.al_params a =*= Lib_parsing_c.al_params b + + | Ast_c.MetaPosVal (posa1,posa2), Ast_c.MetaPosVal (posb1,posb2) -> + Ast_cocci.equal_pos posa1 posb1 && Ast_cocci.equal_pos posa2 posb2 + + | Ast_c.MetaPosValList l1, Ast_c.MetaPosValList l2 -> + List.exists + (function (fla,posa1,posa2) -> + List.exists + (function (flb,posb1,posb2) -> + fla = flb && + Ast_c.equal_posl posa1 posb1 && Ast_c.equal_posl posa2 posb2) + l2) + l1 + | _ -> raise Impossible + + + +(*---------------------------------------------------------------------------*) +(* could put in ast_c.ml, next to the split/unsplit_comma *) +let split_signb_baseb_ii (baseb, ii) = + let iis = ii +> List.map (fun info -> (B.str_of_info info), info) in + match baseb, iis with + + | B.Void, ["void",i1] -> None, [i1] + + | B.FloatType (B.CFloat),["float",i1] -> None, [i1] + | B.FloatType (B.CDouble),["double",i1] -> None, [i1] + | B.FloatType (B.CLongDouble),["long",i1;"double",i2] -> None,[i1;i2] + + | B.IntType (B.CChar), ["char",i1] -> None, [i1] + + + | B.IntType (B.Si (sign, base)), xs -> + (match sign, base, xs with + | B.Signed, B.CChar2, ["signed",i1;"char",i2] -> + Some (B.Signed, i1), [i2] + | B.UnSigned, B.CChar2, ["unsigned",i1;"char",i2] -> + Some (B.UnSigned, i1), [i2] + + | B.Signed, B.CShort, ["short",i1] -> + None, [i1] + | B.Signed, B.CShort, ["signed",i1;"short",i2] -> + Some (B.Signed, i1), [i2] + | B.UnSigned, B.CShort, ["unsigned",i1;"short",i2] -> + Some (B.UnSigned, i1), [i2] + | B.Signed, B.CShort, ["short",i1;"int",i2] -> + None, [i1;i2] + + | B.Signed, B.CInt, ["int",i1] -> + None, [i1] + | B.Signed, B.CInt, ["signed",i1;"int",i2] -> + Some (B.Signed, i1), [i2] + | B.UnSigned, B.CInt, ["unsigned",i1;"int",i2] -> + Some (B.UnSigned, i1), [i2] + + | B.Signed, B.CInt, ["signed",i1;] -> + Some (B.Signed, i1), [] + | B.UnSigned, B.CInt, ["unsigned",i1;] -> + Some (B.UnSigned, i1), [] + + | B.Signed, B.CLong, ["long",i1] -> + None, [i1] + | B.Signed, B.CLong, ["long",i1;"int",i2] -> + None, [i1;i2] + | B.Signed, B.CLong, ["signed",i1;"long",i2] -> + Some (B.Signed, i1), [i2] + | B.UnSigned, B.CLong, ["unsigned",i1;"long",i2] -> + Some (B.UnSigned, i1), [i2] + + | B.Signed, B.CLongLong, ["long",i1;"long",i2] -> None, [i1;i2] + | B.Signed, B.CLongLong, ["signed",i1;"long",i2;"long",i3] -> + Some (B.Signed, i1), [i2;i3] + | B.UnSigned, B.CLongLong, ["unsigned",i1;"long",i2;"long",i3] -> + Some (B.UnSigned, i1), [i2;i3] + + + | B.UnSigned, B.CShort, ["unsigned",i1;"short",i2; "int", i3] -> + Some (B.UnSigned, i1), [i2;i3] + + + + | _ -> failwith "strange type1, maybe because of weird order" + ) + | _ -> failwith "strange type2, maybe because of weird order" + +(*---------------------------------------------------------------------------*) + +let rec unsplit_icomma xs = + match xs with + | [] -> [] + | x::y::xs -> + (match A.unwrap y with + | A.IComma mcode -> + (x, y)::unsplit_icomma xs + | _ -> failwith "wrong ast_cocci in initializer" + ) + | _ -> + failwith ("wrong ast_cocci in initializer, should have pair " ^ + "number of Icomma") + + + +let resplit_initialiser ibs iicomma = + match iicomma, ibs with + | [], [] -> [] + | [], _ -> + failwith "should have a iicomma, do you generate fakeInfo in parser?" + | _, [] -> + failwith "shouldn't have a iicomma" + | [iicomma], x::xs -> + let elems = List.map fst (x::xs) in + let commas = List.map snd (x::xs) +> List.flatten in + let commas = commas @ [iicomma] in + zip elems commas + | _ -> raise Impossible + + + +let rec split_icomma xs = + match xs with + | [] -> [] + | (x,y)::xs -> x::y::split_icomma xs + +let rec unsplit_initialiser ibs_unsplit = + match ibs_unsplit with + | [] -> [], [] (* empty iicomma *) + | (x, commax)::xs -> + let (xs, lastcomma) = unsplit_initialiser_bis commax xs in + (x, [])::xs, lastcomma + +and unsplit_initialiser_bis comma_before = function + | [] -> [], [comma_before] + | (x, commax)::xs -> + let (xs, lastcomma) = unsplit_initialiser_bis commax xs in + (x, [comma_before])::xs, lastcomma + + + + +(*---------------------------------------------------------------------------*) +(* coupling: same in type_annotater_c.ml *) +let structdef_to_struct_name ty = + match ty with + | qu, (B.StructUnion (su, sopt, fields), iis) -> + (match sopt,iis with + | Some s , [i1;i2;i3;i4] -> + qu, (B.StructUnionName (su, s), [i1;i2]) + | None, _ -> + ty + + | x -> raise Impossible + ) + | _ -> raise Impossible + +(*---------------------------------------------------------------------------*) +let initialisation_to_affectation decl = + match decl with + | B.MacroDecl _ -> F.Decl decl + | B.DeclList (xs, iis) -> + + (* todo?: should not do that if the variable is an array cos + * will have x[] = , mais de toute facon ca sera pas un InitExp + *) + (match xs with + | [] -> raise Impossible + | [x] -> + let ((var, returnType, storage, local),iisep) = x in + + (match var with + | Some ((s, ini), iis::iini) -> + (match ini with + | Some (B.InitExpr e, ii_empty2) -> + let local = + match local with + Ast_c.NotLocalDecl -> Ast_c.NotLocalVar + | Ast_c.LocalDecl -> Ast_c.LocalVar (iis.Ast_c.pinfo) in + + let typ = + ref (Some ((Lib_parsing_c.al_type returnType),local), + Ast_c.NotTest) in + let id = (B.Ident s, typ),[iis] in + F.DefineExpr + ((B.Assignment (id, B.SimpleAssign, e), + Ast_c.noType()), iini) + | _ -> F.Decl decl + ) + | _ -> F.Decl decl + ) + | x::xs -> + pr2_once "TODO: initialisation_to_affectation for multi vars"; + (* todo? do a fold_left and generate 'x = a, y = b' etc, use + * the Sequence expression operator of C and make an + * ExprStatement from that. + *) + F.Decl decl + ) + + + + + +(*****************************************************************************) +(* Functor parameter combinators *) +(*****************************************************************************) +(* monad like stuff + * src: papers on parser combinators in haskell (cf a pearl by meijer in ICFP) + * + * version0: was not tagging the SP, so just tag the C + * val (>>=): + * (tin -> 'c tout) -> ('c -> (tin -> 'b tout)) -> (tin -> 'b tout) + * val return : 'b -> tin -> 'b tout + * val fail : tin -> 'b tout + * + * version1: now also tag the SP so return a ('a * 'b) + *) + +type mode = PatternMode | TransformMode + +module type PARAM = + sig + type tin + type 'x tout + + + type ('a, 'b) matcher = 'a -> 'b -> tin -> ('a * 'b) tout + + val mode : mode + + val (>>=): + (tin -> ('a * 'b) tout) -> + ('a -> 'b -> (tin -> ('c * 'd) tout)) -> + (tin -> ('c * 'd) tout) + + val return : ('a * 'b) -> tin -> ('a *'b) tout + val fail : tin -> ('a * 'b) tout + + val (>||>) : + (tin -> 'x tout) -> + (tin -> 'x tout) -> + (tin -> 'x tout) + + val (>|+|>) : + (tin -> 'x tout) -> + (tin -> 'x tout) -> + (tin -> 'x tout) + + val (>&&>) : (tin -> bool) -> (tin -> 'x tout) -> (tin -> 'x tout) + + val tokenf : ('a A.mcode, B.info) matcher + val tokenf_mck : (A.mcodekind, B.info) matcher + + val distrf_e : + (A.meta_name A.mcode, B.expression) matcher + val distrf_args : + (A.meta_name A.mcode, (Ast_c.argument, Ast_c.il) either list) matcher + val distrf_type : + (A.meta_name A.mcode, Ast_c.fullType) matcher + val distrf_params : + (A.meta_name A.mcode, + (Ast_c.parameterType, Ast_c.il) either list) matcher + val distrf_param : + (A.meta_name A.mcode, Ast_c.parameterType) matcher + val distrf_ini : + (A.meta_name A.mcode, Ast_c.initialiser) matcher + val distrf_node : + (A.meta_name A.mcode, Control_flow_c.node) matcher + + val distrf_define_params : + (A.meta_name A.mcode, (string Ast_c.wrap, Ast_c.il) either list) + matcher + + val distrf_struct_fields : + (A.meta_name A.mcode, B.field B.wrap list) matcher + + val distrf_cst : + (A.meta_name A.mcode, (B.constant, string) either B.wrap) matcher + + val cocciExp : + (A.expression, B.expression) matcher -> (A.expression, F.node) matcher + + val cocciExpExp : + (A.expression, B.expression) matcher -> + (A.expression, B.expression) matcher + + val cocciTy : + (A.fullType, B.fullType) matcher -> (A.fullType, F.node) matcher + + val envf : + A.keep_binding -> A.inherited -> + A.meta_name A.mcode * Ast_c.metavar_binding_kind * + (unit -> Common.filename * Ast_c.posl * Ast_c.posl) -> + (unit -> tin -> 'x tout) -> (tin -> 'x tout) + + val check_constraints : + ('a, 'b) matcher -> 'a list -> 'b -> + (unit -> tin -> 'x tout) -> (tin -> 'x tout) + + val all_bound : A.meta_name list -> (tin -> bool) + + val optional_storage_flag : (bool -> tin -> 'x tout) -> (tin -> 'x tout) + val optional_qualifier_flag : (bool -> tin -> 'x tout) -> (tin -> 'x tout) + val value_format_flag: (bool -> tin -> 'x tout) -> (tin -> 'x tout) + + + end + +(*****************************************************************************) +(* Functor code, "Cocci vs C" *) +(*****************************************************************************) + +module COCCI_VS_C = + functor (X : PARAM) -> +struct + +type ('a, 'b) matcher = 'a -> 'b -> X.tin -> ('a * 'b) X.tout + +let (>>=) = X.(>>=) +let return = X.return +let fail = X.fail + +let (>||>) = X.(>||>) +let (>|+|>) = X.(>|+|>) +let (>&&>) = X.(>&&>) + +let tokenf = X.tokenf + +(* should be raise Impossible when called from transformation.ml *) +let fail2 () = + match X.mode with + | PatternMode -> fail + | TransformMode -> raise Impossible + + +let (option: ('a,'b) matcher -> ('a option,'b option) matcher)= fun f t1 t2 -> + match (t1,t2) with + | (Some t1, Some t2) -> + f t1 t2 >>= (fun t1 t2 -> + return (Some t1, Some t2) + ) + | (None, None) -> return (None, None) + | _ -> fail + +(* Dots are sometimes used as metavariables, since like metavariables they +can match other things. But they no longer have the same type. Perhaps these +functions could be avoided by introducing an appropriate level of polymorphism, +but I don't know how to declare polymorphism across functors *) +let dots2metavar (_,info,mcodekind,pos) = (("","..."),info,mcodekind,pos) +let metavar2dots (_,info,mcodekind,pos) = ("...",info,mcodekind,pos) + +(*---------------------------------------------------------------------------*) +(* toc: + * - expression + * - ident + * - arguments + * - parameters + * - declaration + * - initialisers + * - type + * - node + *) + +(*---------------------------------------------------------------------------*) +let rec (expression: (A.expression, Ast_c.expression) matcher) = + fun ea eb -> + X.all_bound (A.get_inherited ea) >&&> + let wa x = A.rewrap ea x in + match A.unwrap ea, eb with + + (* general case: a MetaExpr can match everything *) + | A.MetaExpr (ida,constraints,keep,opttypa,form,inherited), + (((expr, opttypb), ii) as expb) -> + + (* old: before have a MetaConst. Now we factorize and use 'form' to + * differentiate between different cases *) + let rec matches_id = function + B.Ident(c) -> true + | B.Cast(ty,e) -> matches_id (B.unwrap_expr e) + | _ -> false in + let form_ok = + match (form,expr) with + (A.ANY,_) -> true + | (A.CONST,e) -> + let rec matches = function + B.Constant(c) -> true + | B.Ident idb when idb =~ "^[A-Z_][A-Z_0-9]*$" -> + pr2_once ("warning: I consider " ^ idb ^ " as a constant"); + true + | B.Cast(ty,e) -> matches (B.unwrap_expr e) + | B.Unary(e,B.UnMinus) -> matches (B.unwrap_expr e) + | B.SizeOfExpr(exp) -> true + | B.SizeOfType(ty) -> true + | _ -> false in + matches e + | (A.LocalID,e) -> + (matches_id e) && + (match !opttypb with + (Some (_,Ast_c.LocalVar _),_) -> true + | _ -> false) + | (A.ID,e) -> matches_id e in + + if form_ok + then + (let (opttypb,_testb) = !opttypb in + match opttypa, opttypb with + | None, _ -> return ((),()) + | Some _, None -> + pr2_once ("Missing type information. Certainly a pb in " ^ + "annotate_typer.ml"); + fail + + | Some tas, Some tb -> + tas +> List.fold_left (fun acc ta -> + acc >|+|> compatible_type ta tb) fail + ) >>= + (fun () () -> + X.check_constraints expression constraints eb + (fun () -> + let max_min _ = + Lib_parsing_c.lin_col_by_pos (Lib_parsing_c.ii_of_expr expb) in + X.envf keep inherited (ida, Ast_c.MetaExprVal expb, max_min) + (fun () -> + X.distrf_e ida expb >>= (fun ida expb -> + return ( + A.MetaExpr (ida,constraints,keep,opttypa,form,inherited)+> + A.rewrap ea, + expb + )) + ))) + else fail + + (* old: + * | A.MetaExpr(ida,false,opttypa,_inherited), expb -> + * D.distribute_mck (mcodekind ida) D.distribute_mck_e expb binding + * + * but bug! because if have not tagged SP, then transform without doing + * any checks. Hopefully now have tagged SP technique. + *) + + + (* old: + * | A.Edots _, _ -> raise Impossible. + * + * In fact now can also have the Edots inside normal expression, not + * just in arg lists. in 'x[...];' less: in if(<... x ... y ...>) + *) + | A.Edots (mcode, None), expb -> + X.distrf_e (dots2metavar mcode) expb >>= (fun mcode expb -> + return ( + A.Edots (metavar2dots mcode, None) +> A.rewrap ea , + expb + )) + + + | A.Edots (_, Some expr), _ -> failwith "not handling when on Edots" + + + | A.Ident ida, ((B.Ident idb, typ),ii) -> + let ib1 = tuple_of_list1 ii in + ident DontKnow ida (idb, ib1) >>= (fun ida (idb, ib1) -> + return ( + ((A.Ident ida)) +> wa, + ((B.Ident idb, typ),[ib1]) + )) + + + + + | A.MetaErr _, _ -> failwith "not handling MetaErr" + + (* todo?: handle some isomorphisms in int/float ? can have different + * format : 1l can match a 1. + * + * todo: normally string can contain some metavar too, so should + * recurse on the string + *) + | A.Constant (ia1), ((B.Constant (ib) , typ),ii) -> + (* for everything except the String case where can have multi elems *) + let do1 () = + let ib1 = tuple_of_list1 ii in + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + return ( + ((A.Constant ia1)) +> wa, + ((B.Constant (ib), typ),[ib1]) + )) + in + (match term ia1, ib with + | A.Int x, B.Int y -> + X.value_format_flag (fun use_value_equivalence -> + if use_value_equivalence + then + if equal_c_int x y + then do1() + else fail + else + if x =$= y + then do1() + else fail + ) + | A.Char x, B.Char (y,_) when x =$= y (* todo: use kind ? *) + -> do1() + | A.Float x, B.Float (y,_) when x =$= y (* todo: use floatType ? *) + -> do1() + + | A.String sa, B.String (sb,_kind) when sa =$= sb -> + (match ii with + | [ib1] -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + return ( + ((A.Constant ia1)) +> wa, + ((B.Constant (ib), typ),[ib1]) + )) + | _ -> fail (* multi string, not handled *) + ) + | _, _ -> fail + ) + + + | A.FunCall (ea, ia1, eas, ia2), ((B.FunCall (eb, ebs), typ),ii) -> + (* todo: do special case to allow IdMetaFunc, cos doing the + * recursive call will be too late, match_ident will not have the + * info whether it was a function. todo: but how detect when do + * x.field = f; how know that f is a Func ? By having computed + * some information before the matching! + * + * Allow match with FunCall containing types. Now ast_cocci allow + * type in parameter, and morover ast_cocci allow f(...) and those + * ... could match type. + *) + let (ib1, ib2) = tuple_of_list2 ii in + expression ea eb >>= (fun ea eb -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + arguments (seqstyle eas) (A.undots eas) ebs >>= (fun easundots ebs -> + let eas = redots eas easundots in + return ( + ((A.FunCall (ea, ia1, eas, ia2)) +> wa, + ((B.FunCall (eb, ebs),typ), [ib1;ib2]) + )))))) + + + + + | A.Assignment (ea1, opa, ea2, simple), + ((B.Assignment (eb1, opb, eb2), typ),ii) -> + let (opbi) = tuple_of_list1 ii in + if equal_assignOp (term opa) opb + then + expression ea1 eb1 >>= (fun ea1 eb1 -> + expression ea2 eb2 >>= (fun ea2 eb2 -> + tokenf opa opbi >>= (fun opa opbi -> + return ( + ((A.Assignment (ea1, opa, ea2, simple))) +> wa, + ((B.Assignment (eb1, opb, eb2), typ), [opbi]) + )))) + else fail + + | A.CondExpr(ea1,ia1,ea2opt,ia2,ea3),((B.CondExpr(eb1,eb2opt,eb3),typ),ii) -> + let (ib1, ib2) = tuple_of_list2 ii in + expression ea1 eb1 >>= (fun ea1 eb1 -> + option expression ea2opt eb2opt >>= (fun ea2opt eb2opt -> + expression ea3 eb3 >>= (fun ea3 eb3 -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + return ( + ((A.CondExpr(ea1,ia1,ea2opt,ia2,ea3))) +> wa, + ((B.CondExpr (eb1, eb2opt, eb3),typ), [ib1;ib2]) + )))))) + + (* todo?: handle some isomorphisms here ? *) + | A.Postfix (ea, opa), ((B.Postfix (eb, opb), typ),ii) -> + let opbi = tuple_of_list1 ii in + if equal_fixOp (term opa) opb + then + expression ea eb >>= (fun ea eb -> + tokenf opa opbi >>= (fun opa opbi -> + return ( + ((A.Postfix (ea, opa))) +> wa, + ((B.Postfix (eb, opb), typ),[opbi]) + ))) + else fail + + + | A.Infix (ea, opa), ((B.Infix (eb, opb), typ),ii) -> + let opbi = tuple_of_list1 ii in + if equal_fixOp (term opa) opb + then + expression ea eb >>= (fun ea eb -> + tokenf opa opbi >>= (fun opa opbi -> + return ( + ((A.Infix (ea, opa))) +> wa, + ((B.Infix (eb, opb), typ),[opbi]) + ))) + else fail + + | A.Unary (ea, opa), ((B.Unary (eb, opb), typ),ii) -> + let opbi = tuple_of_list1 ii in + if equal_unaryOp (term opa) opb + then + expression ea eb >>= (fun ea eb -> + tokenf opa opbi >>= (fun opa opbi -> + return ( + ((A.Unary (ea, opa))) +> wa, + ((B.Unary (eb, opb), typ),[opbi]) + ))) + else fail + + | A.Binary (ea1, opa, ea2), ((B.Binary (eb1, opb, eb2), typ),ii) -> + let opbi = tuple_of_list1 ii in + if equal_binaryOp (term opa) opb + then + expression ea1 eb1 >>= (fun ea1 eb1 -> + expression ea2 eb2 >>= (fun ea2 eb2 -> + tokenf opa opbi >>= (fun opa opbi -> + return ( + ((A.Binary (ea1, opa, ea2))) +> wa, + ((B.Binary (eb1, opb, eb2), typ),[opbi] + ))))) + else fail + + | A.Nested (ea1, opa, ea2), eb -> + let rec loop eb = + (if A.get_test_exp ea1 && not (Ast_c.is_test eb) then fail + else expression ea1 eb) >|+|> + (match eb with + ((B.Binary (eb1, opb, eb2), typ),ii) + when equal_binaryOp (term opa) opb -> + let opbi = tuple_of_list1 ii in + let left_to_right = + (expression ea1 eb1 >>= (fun ea1 eb1 -> + expression ea2 eb2 >>= (fun ea2 eb2 -> + tokenf opa opbi >>= (fun opa opbi -> + return ( + ((A.Nested (ea1, opa, ea2))) +> wa, + ((B.Binary (eb1, opb, eb2), typ),[opbi] + )))))) in + let right_to_left = + (expression ea2 eb1 >>= (fun ea2 eb1 -> + expression ea1 eb2 >>= (fun ea1 eb2 -> + tokenf opa opbi >>= (fun opa opbi -> + return ( + ((A.Nested (ea1, opa, ea2))) +> wa, + ((B.Binary (eb1, opb, eb2), typ),[opbi] + )))))) in + let in_left = + (loop eb1 >>= (fun ea1 eb1 -> + expression ea2 eb2 >>= (fun ea2 eb2 -> + tokenf opa opbi >>= (fun opa opbi -> + return ( + ((A.Nested (ea1, opa, ea2))) +> wa, + ((B.Binary (eb1, opb, eb2), typ),[opbi] + )))))) in + let in_right = + (expression ea2 eb1 >>= (fun ea2 eb1 -> + loop eb2 >>= (fun ea1 eb2 -> + tokenf opa opbi >>= (fun opa opbi -> + return ( + ((A.Nested (ea1, opa, ea2))) +> wa, + ((B.Binary (eb1, opb, eb2), typ),[opbi] + )))))) in + left_to_right >|+|> right_to_left >|+|> in_left >|+|> in_right + | _ -> fail) in + loop eb + + (* todo?: handle some isomorphisms here ? (with pointers = Unary Deref) *) + | A.ArrayAccess (ea1, ia1, ea2, ia2),((B.ArrayAccess (eb1, eb2), typ),ii) -> + let (ib1, ib2) = tuple_of_list2 ii in + expression ea1 eb1 >>= (fun ea1 eb1 -> + expression ea2 eb2 >>= (fun ea2 eb2 -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + return ( + ((A.ArrayAccess (ea1, ia1, ea2, ia2))) +> wa, + ((B.ArrayAccess (eb1, eb2),typ), [ib1;ib2]) + ))))) + + (* todo?: handle some isomorphisms here ? *) + | A.RecordAccess (ea, ia1, ida), ((B.RecordAccess (eb, idb), typ),ii) -> + let (ib1, ib2) = tuple_of_list2 ii in + ident DontKnow ida (idb, ib2) >>= (fun ida (idb, ib2) -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + expression ea eb >>= (fun ea eb -> + return ( + ((A.RecordAccess (ea, ia1, ida))) +> wa, + ((B.RecordAccess (eb, idb), typ), [ib1;ib2]) + )))) + + + + | A.RecordPtAccess (ea,ia1,ida),((B.RecordPtAccess (eb, idb), typ), ii) -> + let (ib1, ib2) = tuple_of_list2 ii in + ident DontKnow ida (idb, ib2) >>= (fun ida (idb, ib2) -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + expression ea eb >>= (fun ea eb -> + return ( + ((A.RecordPtAccess (ea, ia1, ida))) +> wa, + ((B.RecordPtAccess (eb, idb), typ), [ib1;ib2]) + )))) + + + (* todo?: handle some isomorphisms here ? + * todo?: do some iso-by-absence on cast ? + * by trying | ea, B.Case (typb, eb) -> match_e_e ea eb ? + *) + + | A.Cast (ia1, typa, ia2, ea), ((B.Cast (typb, eb), typ),ii) -> + let (ib1, ib2) = tuple_of_list2 ii in + fullType typa typb >>= (fun typa typb -> + expression ea eb >>= (fun ea eb -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + return ( + ((A.Cast (ia1, typa, ia2, ea))) +> wa, + ((B.Cast (typb, eb),typ),[ib1;ib2]) + ))))) + + | A.SizeOfExpr (ia1, ea), ((B.SizeOfExpr (eb), typ),ii) -> + let ib1 = tuple_of_list1 ii in + expression ea eb >>= (fun ea eb -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + return ( + ((A.SizeOfExpr (ia1, ea))) +> wa, + ((B.SizeOfExpr (eb), typ),[ib1]) + ))) + + | A.SizeOfType (ia1, ia2, typa, ia3), ((B.SizeOfType typb, typ),ii) -> + let (ib1,ib2,ib3) = tuple_of_list3 ii in + fullType typa typb >>= (fun typa typb -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + tokenf ia3 ib3 >>= (fun ia3 ib3 -> + return ( + ((A.SizeOfType (ia1, ia2, typa, ia3))) +> wa, + ((B.SizeOfType (typb),typ),[ib1;ib2;ib3]) + ))))) + + + (* todo? iso ? allow all the combinations ? *) + | A.Paren (ia1, ea, ia2), ((B.ParenExpr (eb), typ),ii) -> + let (ib1, ib2) = tuple_of_list2 ii in + expression ea eb >>= (fun ea eb -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + return ( + ((A.Paren (ia1, ea, ia2))) +> wa, + ((B.ParenExpr (eb), typ), [ib1;ib2]) + )))) + + | A.NestExpr(exps,None,true), eb -> + (match A.unwrap exps with + A.DOTS [exp] -> + X.cocciExpExp expression exp eb >>= (fun exp eb -> + return ( + (A.NestExpr(A.rewrap exps (A.DOTS [exp]),None,true)) +> wa, + eb + ) + ) + | _ -> + failwith + "for nestexpr, only handling the case with dots and only one exp") + + | A.NestExpr _, _ -> + failwith "only handling multi and no when code in a nest expr" + + (* only in arg lists or in define body *) + | A.TypeExp _, _ -> fail + + (* only in arg lists *) + | A.MetaExprList _, _ + | A.EComma _, _ + | A.Ecircles _, _ + | A.Estars _, _ + -> + raise Impossible + + | A.DisjExpr eas, eb -> + eas +> List.fold_left (fun acc ea -> acc >|+|> (expression ea eb)) fail + + | A.UniqueExp _,_ | A.OptExp _,_ -> + failwith "not handling Opt/Unique/Multi on expr" + + (* Because of Exp cant put a raise Impossible; have to put a fail *) + + (* have not a counter part in coccinelle, for the moment *) + | _, ((B.Sequence _,_),_) + | _, ((B.StatementExpr _,_),_) + | _, ((B.Constructor _,_),_) + -> fail + + | _, _ -> fail + + + +(* ------------------------------------------------------------------------- *) +and (ident: info_ident -> (A.ident, string * Ast_c.info) matcher) = + fun infoidb ida ((idb, iib) as ib) -> + X.all_bound (A.get_inherited ida) >&&> + match A.unwrap ida with + | A.Id sa -> + if (term sa) =$= idb then + tokenf sa iib >>= (fun sa iib -> + return ( + ((A.Id sa)) +> A.rewrap ida, + (idb, iib) + )) + else fail + + + | A.MetaId(mida,constraints,keep,inherited) -> + X.check_constraints (ident infoidb) constraints ib + (fun () -> + let max_min _ = Lib_parsing_c.lin_col_by_pos [iib] in + (* use drop_pos for ids so that the pos is not added a second time in + the call to tokenf *) + X.envf keep inherited (A.drop_pos mida, Ast_c.MetaIdVal (idb), max_min) + (fun () -> + tokenf mida iib >>= (fun mida iib -> + return ( + ((A.MetaId (mida, constraints, keep, inherited)) +> A.rewrap ida, + (idb, iib) + ))) + )) + + | A.MetaFunc(mida,constraints,keep,inherited) -> + let is_function _ = + X.check_constraints (ident infoidb) constraints ib + (fun () -> + let max_min _ = Lib_parsing_c.lin_col_by_pos [iib] in + X.envf keep inherited (A.drop_pos mida,Ast_c.MetaFuncVal idb,max_min) + (fun () -> + tokenf mida iib >>= (fun mida iib -> + return ( + ((A.MetaFunc(mida,constraints,keep,inherited)))+>A.rewrap ida, + (idb, iib) + )) + )) in + (match infoidb with + | LocalFunction | Function -> is_function() + | DontKnow -> + failwith "MetaFunc, need more semantic info about id" + (* the following implementation could possibly be useful, if one + follows the convention that a macro is always in capital letters + and that a macro is not a function. + (if idb =~ "^[A-Z_][A-Z_0-9]*$" then fail else is_function())*) + ) + + | A.MetaLocalFunc(mida,constraints,keep,inherited) -> + (match infoidb with + | LocalFunction -> + X.check_constraints (ident infoidb) constraints ib + (fun () -> + let max_min _ = Lib_parsing_c.lin_col_by_pos [iib] in + X.envf keep inherited + (A.drop_pos mida,Ast_c.MetaLocalFuncVal idb, max_min) + (fun () -> + tokenf mida iib >>= (fun mida iib -> + return ( + ((A.MetaLocalFunc(mida,constraints,keep,inherited))) + +> A.rewrap ida, + (idb, iib) + )) + )) + | Function -> fail + | DontKnow -> failwith "MetaLocalFunc, need more semantic info about id" + ) + + | A.OptIdent _ | A.UniqueIdent _ -> + failwith "not handling Opt/Unique for ident" + + + +(* ------------------------------------------------------------------------- *) +and (arguments: sequence -> + (A.expression list, Ast_c.argument Ast_c.wrap2 list) matcher) = + fun seqstyle eas ebs -> + match seqstyle with + | Unordered -> failwith "not handling ooo" + | Ordered -> + arguments_bis eas (Ast_c.split_comma ebs) >>= (fun eas ebs_splitted -> + return (eas, (Ast_c.unsplit_comma ebs_splitted)) + ) +(* because '...' can match nothing, need to take care when have + * ', ...' or '...,' as in f(..., X, Y, ...). It must match + * f(1,2) for instance. + * So I have added special cases such as (if startxs = []) and code + * in the Ecomma matching rule. + * + * old: Must do some try, for instance when f(...,X,Y,...) have to + * test the transfo for all the combinaitions and if multiple transfo + * possible ? pb ? => the type is to return a expression option ? use + * some combinators to help ? + * update: with the tag-SP approach, no more a problem. + *) + +and arguments_bis = fun eas ebs -> + match eas, ebs with + | [], [] -> return ([], []) + | [], eb::ebs -> fail + | ea::eas, ebs -> + X.all_bound (A.get_inherited ea) >&&> + (match A.unwrap ea, ebs with + | A.Edots (mcode, optexpr), ys -> + (* todo: if optexpr, then a WHEN and so may have to filter yys *) + if optexpr <> None then failwith "not handling when in argument"; + + (* '...' can take more or less the beginnings of the arguments *) + let startendxs = Common.zip (Common.inits ys) (Common.tails ys) in + startendxs +> List.fold_left (fun acc (startxs, endxs) -> + acc >||> ( + + (* allow '...', and maybe its associated ',' to match nothing. + * for the associated ',' see below how we handle the EComma + * to match nothing. + *) + (if startxs = [] + then + if mcode_contain_plus (mcodekind mcode) + then fail + (* failwith "I have no token that I could accroche myself on" *) + else return (dots2metavar mcode, []) + else + (* subtil: we dont want the '...' to match until the + * comma. cf -test pb_params_iso. We would get at + * "already tagged" error. + * this is because both f (... x, ...) and f (..., x, ...) + * would match a f(x,3) with our "optional-comma" strategy. + *) + (match Common.last startxs with + | Right _ -> fail + | Left _ -> + X.distrf_args (dots2metavar mcode) startxs + ) + ) + >>= (fun mcode startxs -> + let mcode = metavar2dots mcode in + arguments_bis eas endxs >>= (fun eas endxs -> + return ( + (A.Edots (mcode, optexpr) +> A.rewrap ea) ::eas, + startxs ++ endxs + ))) + ) + ) fail + + | A.EComma ia1, Right ii::ebs -> + let ib1 = tuple_of_list1 ii in + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + arguments_bis eas ebs >>= (fun eas ebs -> + return ( + (A.EComma ia1 +> A.rewrap ea)::eas, + (Right [ib1])::ebs + ) + )) + | A.EComma ia1, ebs -> + (* allow ',' to maching nothing. optional comma trick *) + if mcode_contain_plus (mcodekind ia1) + then fail + else arguments_bis eas ebs + + | A.MetaExprList(ida,leninfo,keep,inherited),ys -> + let startendxs = Common.zip (Common.inits ys) (Common.tails ys) in + startendxs +> List.fold_left (fun acc (startxs, endxs) -> + acc >||> ( + let ok = + if startxs = [] + then + if mcode_contain_plus (mcodekind ida) + then false + (* failwith "no token that I could accroche myself on" *) + else true + else + (match Common.last startxs with + | Right _ -> false + | Left _ -> true + ) + in + if not ok + then fail + else + let startxs' = Ast_c.unsplit_comma startxs in + let len = List.length startxs' in + + (match leninfo with + | Some (lenname,lenkeep,leninherited) -> + let max_min _ = failwith "no pos" in + X.envf lenkeep leninherited + (lenname, Ast_c.MetaListlenVal (len), max_min) + | None -> function f -> f() + ) + (fun () -> + let max_min _ = + Lib_parsing_c.lin_col_by_pos + (Lib_parsing_c.ii_of_args startxs) in + X.envf keep inherited + (ida, Ast_c.MetaExprListVal startxs', max_min) + (fun () -> + if startxs = [] + then return (ida, []) + else X.distrf_args ida (Ast_c.split_comma startxs') + ) + >>= (fun ida startxs -> + arguments_bis eas endxs >>= (fun eas endxs -> + return ( + (A.MetaExprList(ida,leninfo,keep,inherited)) + +> A.rewrap ea::eas, + startxs ++ endxs + )) + ) + ) + )) fail + + + | _unwrapx, (Left eb)::ebs -> + argument ea eb >>= (fun ea eb -> + arguments_bis eas ebs >>= (fun eas ebs -> + return (ea::eas, Left eb::ebs) + )) + | _unwrapx, (Right y)::ys -> raise Impossible + | _unwrapx, [] -> fail + ) + + +and argument arga argb = + X.all_bound (A.get_inherited arga) >&&> + match A.unwrap arga, argb with + | A.TypeExp tya, Right (B.ArgType (((b, sopt, tyb), ii_b_s))) -> + + if b || sopt <> None + then + (* failwith "the argument have a storage and ast_cocci does not have"*) + fail + else + fullType tya tyb >>= (fun tya tyb -> + return ( + (A.TypeExp tya) +> A.rewrap arga, + (Right (B.ArgType (((b, sopt, tyb), ii_b_s)))) + )) + + | A.TypeExp tya, _ -> fail + | _, Right (B.ArgType (tyb, sto_iisto)) -> fail + | _, Left argb -> + expression arga argb >>= (fun arga argb -> + return (arga, Left argb) + ) + | _, Right (B.ArgAction y) -> fail + + +(* ------------------------------------------------------------------------- *) +(* todo? facto code with argument ? *) +and (parameters: sequence -> + (A.parameterTypeDef list, Ast_c.parameterType Ast_c.wrap2 list) + matcher) = + fun seqstyle eas ebs -> + match seqstyle with + | Unordered -> failwith "not handling ooo" + | Ordered -> + parameters_bis eas (Ast_c.split_comma ebs) >>= (fun eas ebs_splitted -> + return (eas, (Ast_c.unsplit_comma ebs_splitted)) + ) + + +and parameters_bis eas ebs = + match eas, ebs with + | [], [] -> return ([], []) + | [], eb::ebs -> fail + | ea::eas, ebs -> + (* the management of positions is inlined into each case, because + sometimes there is a Param and sometimes a ParamList *) + X.all_bound (A.get_inherited ea) >&&> + (match A.unwrap ea, ebs with + | A.Pdots (mcode), ys -> + + (* '...' can take more or less the beginnings of the arguments *) + let startendxs = Common.zip (Common.inits ys) (Common.tails ys) in + startendxs +> List.fold_left (fun acc (startxs, endxs) -> + acc >||> ( + + (if startxs = [] + then + if mcode_contain_plus (mcodekind mcode) + then fail + (* failwith "I have no token that I could accroche myself on"*) + else return (dots2metavar mcode, []) + else + (match Common.last startxs with + | Right _ -> fail + | Left _ -> + X.distrf_params (dots2metavar mcode) startxs + ) + ) >>= (fun mcode startxs -> + let mcode = metavar2dots mcode in + parameters_bis eas endxs >>= (fun eas endxs -> + return ( + (A.Pdots (mcode) +> A.rewrap ea) ::eas, + startxs ++ endxs + ))) + ) + ) fail + + | A.PComma ia1, Right ii::ebs -> + let ib1 = tuple_of_list1 ii in + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + parameters_bis eas ebs >>= (fun eas ebs -> + return ( + (A.PComma ia1 +> A.rewrap ea)::eas, + (Right [ib1])::ebs + ) + )) + + | A.PComma ia1, ebs -> + (* try optional comma trick *) + if mcode_contain_plus (mcodekind ia1) + then fail + else parameters_bis eas ebs + + + | A.MetaParamList(ida,leninfo,keep,inherited),ys-> + let startendxs = Common.zip (Common.inits ys) (Common.tails ys) in + startendxs +> List.fold_left (fun acc (startxs, endxs) -> + acc >||> ( + let ok = + if startxs = [] + then + if mcode_contain_plus (mcodekind ida) + then false + (* failwith "I have no token that I could accroche myself on" *) + else true + else + (match Common.last startxs with + | Right _ -> false + | Left _ -> true + ) + in + if not ok + then fail + else + let startxs' = Ast_c.unsplit_comma startxs in + let len = List.length startxs' in + + (match leninfo with + Some (lenname,lenkeep,leninherited) -> + let max_min _ = failwith "no pos" in + X.envf lenkeep leninherited + (lenname, Ast_c.MetaListlenVal (len), max_min) + | None -> function f -> f() + ) + (fun () -> + let max_min _ = + Lib_parsing_c.lin_col_by_pos + (Lib_parsing_c.ii_of_params startxs) in + X.envf keep inherited + (ida, Ast_c.MetaParamListVal startxs', max_min) + (fun () -> + if startxs = [] + then return (ida, []) + else X.distrf_params ida (Ast_c.split_comma startxs') + ) >>= (fun ida startxs -> + parameters_bis eas endxs >>= (fun eas endxs -> + return ( + (A.MetaParamList(ida,leninfo,keep,inherited)) + +> A.rewrap ea::eas, + startxs ++ endxs + )) + ) + )) + ) fail + + + | A.VoidParam ta, ys -> + (match eas, ebs with + | [], [Left eb] -> + let ((hasreg, idbopt, tb), ii_b_s) = eb in + if idbopt = None && null ii_b_s + then + match tb with + | (qub, (B.BaseType B.Void,_)) -> + fullType ta tb >>= (fun ta tb -> + return ( + [(A.VoidParam ta) +> A.rewrap ea], + [Left ((hasreg, idbopt, tb), ii_b_s)] + )) + | _ -> fail + else fail + | _ -> fail + ) + + | (A.OptParam _ | A.UniqueParam _), _ -> + failwith "handling Opt/Unique for Param" + + | A.Pcircles (_), ys -> raise Impossible (* in Ordered mode *) + + + | A.MetaParam (ida,keep,inherited), (Left eb)::ebs -> + (* todo: use quaopt, hasreg ? *) + let max_min _ = + Lib_parsing_c.lin_col_by_pos (Lib_parsing_c.ii_of_param eb) in + X.envf keep inherited (ida,Ast_c.MetaParamVal eb,max_min) (fun () -> + X.distrf_param ida eb + ) >>= (fun ida eb -> + parameters_bis eas ebs >>= (fun eas ebs -> + return ( + (A.MetaParam(ida,keep,inherited))+> A.rewrap ea::eas, + (Left eb)::ebs + ))) + + + | A.Param (typa, idaopt), (Left eb)::ebs -> + (*this should succeed if the C code has a name, and fail otherwise*) + parameter (idaopt, typa) eb >>= (fun (idaopt, typa) eb -> + parameters_bis eas ebs >>= (fun eas ebs -> + return ( + (A.Param (typa, idaopt))+> A.rewrap ea :: eas, + (Left eb)::ebs + ))) + + | _unwrapx, (Right y)::ys -> raise Impossible + | _unwrapx, [] -> fail + ) + + + + + +and parameter = fun (idaopt, typa) ((hasreg, idbopt, typb), ii_b_s) -> + fullType typa typb >>= (fun typa typb -> + match idaopt, Ast_c.split_register_param (hasreg, idbopt, ii_b_s) with + | Some ida, Left (idb, iihasreg, iidb) -> + (* todo: if minus on ida, should also minus the iihasreg ? *) + ident DontKnow ida (idb,iidb) >>= (fun ida (idb,iidb) -> + return ( + (Some ida, typa), + ((hasreg, Some idb, typb), iihasreg++[iidb]) + )) + + | None, Right iihasreg -> + return ( + (None, typa), + ((hasreg, None, typb), iihasreg) + ) + + + (* why handle this case ? because of transform_proto ? we may not + * have an ident in the proto. + * If have some plus on ida ? do nothing about ida ? + *) + (* not anymore !!! now that julia is handling the proto. + | _, Right iihasreg -> + return ( + (idaopt, typa), + ((hasreg, None, typb), iihasreg) + ) + *) + + | Some _, Right _ -> fail + | None, Left _ -> fail + ) + + + + +(* ------------------------------------------------------------------------- *) +and (declaration: (A.mcodekind * bool * A.declaration,B.declaration) matcher) = + fun (mckstart, allminus, decla) declb -> + X.all_bound (A.get_inherited decla) >&&> + match A.unwrap decla, declb with + + (* Un MetaDecl est introduit dans l'asttoctl pour sauter au dessus + * de toutes les declarations qui sont au debut d'un fonction et + * commencer le reste du match au premier statement. Alors, ca matche + * n'importe quelle declaration. On n'a pas besoin d'ajouter + * quoi que ce soit dans l'environnement. C'est une sorte de DDots. + * + * When the SP want to remove the whole function, the minus is not + * on the MetaDecl but on the MetaRuleElem. So there should + * be no transform of MetaDecl, just matching are allowed. + *) + + | A.MetaDecl(ida,_keep,_inherited), _ -> (* keep ? inherited ? *) + (* todo: should not happen in transform mode *) + return ((mckstart, allminus, decla), declb) + + + + | _, (B.DeclList ([var], iiptvirgb::iifakestart::iisto)) -> + onedecl allminus decla (var,iiptvirgb,iisto) >>= + (fun decla (var,iiptvirgb,iisto)-> + X.tokenf_mck mckstart iifakestart >>= (fun mckstart iifakestart -> + return ( + (mckstart, allminus, decla), + (B.DeclList ([var], iiptvirgb::iifakestart::iisto)) + ))) + + | _, (B.DeclList (xs, iiptvirgb::iifakestart::iisto)) -> + if X.mode = PatternMode + then + xs +> List.fold_left (fun acc var -> + acc >||> ( + X.tokenf_mck mckstart iifakestart >>= (fun mckstart iifakestart -> + onedecl allminus decla (var, iiptvirgb, iisto) >>= + (fun decla (var, iiptvirgb, iisto) -> + return ( + (mckstart, allminus, decla), + (B.DeclList ([var], iiptvirgb::iifakestart::iisto)) + ))))) + fail + else + failwith "More that one variable in decl. Have to split to transform." + + | A.MacroDecl (sa,lpa,eas,rpa,enda), B.MacroDecl ((sb,ebs),ii) -> + let (iisb, lpb, rpb, iiendb, iifakestart, iistob) = + (match ii with + | iisb::lpb::rpb::iiendb::iifakestart::iisto -> + (iisb,lpb,rpb,iiendb, iifakestart,iisto) + | _ -> raise Impossible + ) in + (if allminus + then minusize_list iistob + else return ((), iistob) + ) >>= (fun () iistob -> + + X.tokenf_mck mckstart iifakestart >>= (fun mckstart iifakestart -> + ident DontKnow sa (sb, iisb) >>= (fun sa (sb, iisb) -> + tokenf lpa lpb >>= (fun lpa lpb -> + tokenf rpa rpb >>= (fun rpa rpb -> + tokenf enda iiendb >>= (fun enda iiendb -> + arguments (seqstyle eas) (A.undots eas) ebs >>= (fun easundots ebs -> + let eas = redots eas easundots in + + return ( + (mckstart, allminus, + (A.MacroDecl (sa,lpa,eas,rpa,enda)) +> A.rewrap decla), + (B.MacroDecl ((sb,ebs), + [iisb;lpb;rpb;iiendb;iifakestart] ++ iistob)) + )))))))) + + | _ -> fail + + + +and onedecl = fun allminus decla (declb, iiptvirgb, iistob) -> + X.all_bound (A.get_inherited decla) >&&> + match A.unwrap decla, declb with + + (* kind of typedef iso, we must unfold, it's for the case + * T { }; that we want to match against typedef struct { } xx_t; + *) + | A.TyDecl (tya0, ptvirga), + ((Some ((idb, None),[iidb]), typb0, (B.StoTypedef, inl), local), iivirg) -> + + (match A.unwrap tya0, typb0 with + | A.Type(cv1,tya1), ((qu,il),typb1) -> + + (match A.unwrap tya1, typb1 with + | A.StructUnionDef(tya2, lba, declsa, rba), + (B.StructUnion (sub, sbopt, declsb), ii) -> + + let (iisub, iisbopt, lbb, rbb) = + match sbopt with + | None -> + let (iisub, lbb, rbb) = tuple_of_list3 ii in + (iisub, [], lbb, rbb) + | Some s -> + pr2 (sprintf + "warning: both a typedef (%s) and struct name introduction (%s)" + idb s + ); + pr2 "warning: I will consider only the typedef"; + let (iisub, iisb, lbb, rbb) = tuple_of_list4 ii in + (iisub, [iisb], lbb, rbb) + in + let structnameb = + structdef_to_struct_name + (Ast_c.nQ, (B.StructUnion (sub, sbopt, declsb), ii)) + in + let fake_typeb = + Ast_c.nQ,((B.TypeName (idb, Some + (Lib_parsing_c.al_type structnameb))), [iidb]) + in + + tokenf ptvirga iiptvirgb >>= (fun ptvirga iiptvirgb -> + tokenf lba lbb >>= (fun lba lbb -> + tokenf rba rbb >>= (fun rba rbb -> + struct_fields (A.undots declsa) declsb >>=(fun undeclsa declsb -> + let declsa = redots declsa undeclsa in + + (match A.unwrap tya2 with + | A.Type(cv3, tya3) -> + (match A.unwrap tya3 with + | A.MetaType(ida,keep, inherited) -> + + fullType tya2 fake_typeb >>= (fun tya2 fake_typeb -> + let tya1 = + A.StructUnionDef(tya2,lba,declsa,rba)+> A.rewrap tya1 in + let tya0 = A.Type(cv1, tya1) +> A.rewrap tya0 in + + + let typb1 = B.StructUnion (sub,sbopt, declsb), + [iisub] @ iisbopt @ [lbb;rbb] in + let typb0 = ((qu, il), typb1) in + + match fake_typeb with + | _nQ, ((B.TypeName (idb,_typ)), [iidb]) -> + + return ( + (A.TyDecl (tya0, ptvirga)) +> A.rewrap decla, + (((Some ((idb, None),[iidb]), typb0, (B.StoTypedef, inl), + local), + iivirg),iiptvirgb,iistob) + ) + | _ -> raise Impossible + ) + + | A.StructUnionName(sua, sa) -> + + fullType tya2 structnameb >>= (fun tya2 structnameb -> + + let tya1 = A.StructUnionDef(tya2,lba,declsa,rba)+> A.rewrap tya1 + in + let tya0 = A.Type(cv1, tya1) +> A.rewrap tya0 in + + match structnameb with + | _nQ, (B.StructUnionName (sub, s), [iisub;iisbopt]) -> + + let typb1 = B.StructUnion (sub,sbopt, declsb), + [iisub;iisbopt;lbb;rbb] in + let typb0 = ((qu, il), typb1) in + + return ( + (A.TyDecl (tya0, ptvirga)) +> A.rewrap decla, + (((Some ((idb, None),[iidb]), typb0, + (B.StoTypedef, inl), local), + iivirg),iiptvirgb,iistob) + ) + | _ -> raise Impossible + ) + | _ -> raise Impossible + ) + | _ -> fail + ))))) + | _ -> fail + ) + | _ -> fail + ) + + | A.UnInit (stoa, typa, ida, ptvirga), + ((Some ((idb, _),[iidb]), typb, (B.StoTypedef,_), _local), iivirg) -> + fail + + | A.Init (stoa, typa, ida, eqa, inia, ptvirga), + ((Some ((idb, _),[iidb]), typb, (B.StoTypedef,_), _local), iivirg) -> + fail + + + + (* could handle iso here but handled in standard.iso *) + | A.UnInit (stoa, typa, ida, ptvirga), + ((Some ((idb, None),[iidb]), typb, stob, local), iivirg) -> + tokenf ptvirga iiptvirgb >>= (fun ptvirga iiptvirgb -> + fullType typa typb >>= (fun typa typb -> + ident DontKnow ida (idb, iidb) >>= (fun ida (idb, iidb) -> + storage_optional_allminus allminus stoa (stob, iistob) >>= + (fun stoa (stob, iistob) -> + return ( + (A.UnInit (stoa, typa, ida, ptvirga)) +> A.rewrap decla, + (((Some ((idb,None),[iidb]),typb,stob,local),iivirg), + iiptvirgb,iistob) + ))))) + + | A.Init (stoa, typa, ida, eqa, inia, ptvirga), + ((Some((idb,Some inib),[iidb;iieqb]),typb,stob,local),iivirg) + -> + tokenf ptvirga iiptvirgb >>= (fun ptvirga iiptvirgb -> + tokenf eqa iieqb >>= (fun eqa iieqb -> + fullType typa typb >>= (fun typa typb -> + ident DontKnow ida (idb, iidb) >>= (fun ida (idb, iidb) -> + storage_optional_allminus allminus stoa (stob, iistob) >>= + (fun stoa (stob, iistob) -> + initialiser inia inib >>= (fun inia inib -> + return ( + (A.Init (stoa, typa, ida, eqa, inia, ptvirga)) +> A.rewrap decla, + (((Some((idb,Some inib),[iidb;iieqb]),typb,stob,local),iivirg), + iiptvirgb,iistob) + ))))))) + + (* do iso-by-absence here ? allow typedecl and var ? *) + | A.TyDecl (typa, ptvirga), ((None, typb, stob, local), iivirg) -> + if stob = (B.NoSto, false) + then + tokenf ptvirga iiptvirgb >>= (fun ptvirga iiptvirgb -> + fullType typa typb >>= (fun typa typb -> + return ( + (A.TyDecl (typa, ptvirga)) +> A.rewrap decla, + (((None, typb, stob, local), iivirg), iiptvirgb, iistob) + ))) + else fail + + + | A.Typedef (stoa, typa, ida, ptvirga), + ((Some ((idb, None),[iidb]),typb,(B.StoTypedef,inline),local),iivirg) -> + + tokenf ptvirga iiptvirgb >>= (fun ptvirga iiptvirgb -> + fullType typa typb >>= (fun typa typb -> + (match iistob with + | [iitypedef] -> + tokenf stoa iitypedef >>= (fun stoa iitypedef -> + return (stoa, [iitypedef]) + ) + | _ -> failwith "wierd, have both typedef and inline or nothing"; + ) >>= (fun stoa iistob -> + (match A.unwrap ida with + | A.MetaType(_,_,_) -> + + let fake_typeb = + Ast_c.nQ, ((B.TypeName (idb, Ast_c.noTypedefDef())), [iidb]) + in + fullTypebis ida fake_typeb >>= (fun ida fake_typeb -> + match fake_typeb with + | _nQ, ((B.TypeName (idb,_typ)), [iidb]) -> + return (ida, (idb, iidb)) + | _ -> raise Impossible + ) + + | A.TypeName sa -> + if (term sa) =$= idb + then + tokenf sa iidb >>= (fun sa iidb -> + return ( + (A.TypeName sa) +> A.rewrap ida, + (idb, iidb) + )) + else fail + | _ -> raise Impossible + + ) >>= (fun ida (idb, iidb) -> + return ( + (A.Typedef (stoa, typa, ida, ptvirga)) +> A.rewrap decla, + (((Some ((idb, None),[iidb]), typb, (B.StoTypedef,inline),local), + iivirg), + iiptvirgb, iistob) + ) + )))) + + + | _, ((None, typb, sto, _local), _) -> + (* old: failwith "no variable in this declaration, wierd" *) + fail + + + + | A.DisjDecl declas, declb -> + declas +> List.fold_left (fun acc decla -> + acc >|+|> + (* (declaration (mckstart, allminus, decla) declb) *) + (onedecl allminus decla (declb,iiptvirgb, iistob)) + ) fail + + + + (* only in struct type decls *) + | A.Ddots(dots,whencode), _ -> + raise Impossible + + | A.OptDecl _, _ | A.UniqueDecl _, _ -> + failwith "not handling Opt/Unique Decl" + + + | _, _ -> fail + + + +(* ------------------------------------------------------------------------- *) + +and (initialiser: (A.initialiser, Ast_c.initialiser) matcher) = fun ia ib -> + X.all_bound (A.get_inherited ia) >&&> + match (A.unwrap ia,ib) with + + | (A.InitExpr expa, ib) -> + (match A.unwrap expa, ib with + | A.Edots (mcode, None), ib -> + X.distrf_ini (dots2metavar mcode) ib >>= (fun mcode ib -> + return ( + A.InitExpr + (A.Edots (metavar2dots mcode, None) +> A.rewrap expa) + +> A.rewrap ia, + ib + )) + + | A.Edots (_, Some expr), _ -> failwith "not handling when on Edots" + + | _, (B.InitExpr expb, ii) -> + assert (null ii); + expression expa expb >>= (fun expa expb -> + return ( + (A.InitExpr expa) +> A.rewrap ia, + (B.InitExpr expb, ii) + )) + | _ -> fail + ) + + | (A.InitList (ia1, ias, ia2, []), (B.InitList ibs, ii)) -> + (match ii with + | ib1::ib2::iicommaopt -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + initialisers ias (ibs, iicommaopt) >>= (fun ias (ibs,iicommaopt) -> + return ( + (A.InitList (ia1, ias, ia2, [])) +> A.rewrap ia, + (B.InitList ibs, ib1::ib2::iicommaopt) + )))) + + | _ -> raise Impossible + ) + + | (A.InitList (i1, ias, i2, whencode),(B.InitList ibs, _ii)) -> + failwith "TODO: not handling whencode in initialisers" + + + | (A.InitGccDotName (ia1, ida, ia2, inia), + (B.InitDesignators ([B.DesignatorField idb,ii1], inib), ii2))-> + + let (iidot, iidb) = tuple_of_list2 ii1 in + let iieq = tuple_of_list1 ii2 in + + tokenf ia1 iidot >>= (fun ia1 iidot -> + tokenf ia2 iieq >>= (fun ia2 iieq -> + ident DontKnow ida (idb, iidb) >>= (fun ida (idb, iidb) -> + initialiser inia inib >>= (fun inia inib -> + return ( + (A.InitGccDotName (ia1, ida, ia2, inia)) +> A.rewrap ia, + (B.InitDesignators + ([B.DesignatorField idb, [iidot;iidb]], inib), [iieq]) + ))))) + + + | (A.InitGccIndex (ia1,ea,ia2,ia3,inia), + (B.InitDesignators ([B.DesignatorIndex eb, ii1], inib), ii2)) -> + + let (ib1, ib2) = tuple_of_list2 ii1 in + let ib3 = tuple_of_list1 ii2 in + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + tokenf ia3 ib3 >>= (fun ia3 ib3 -> + expression ea eb >>= (fun ea eb -> + initialiser inia inib >>= (fun inia inib -> + return ( + (A.InitGccIndex (ia1,ea,ia2,ia3,inia)) +> A.rewrap ia, + (B.InitDesignators + ([B.DesignatorIndex eb, [ib1;ib2]], inib), [ib3]) + )))))) + + + | (A.InitGccRange (ia1,e1a,ia2,e2a,ia3,ia4,inia), + (B.InitDesignators ([B.DesignatorRange (e1b, e2b), ii1], inib), ii2)) -> + + let (ib1, ib2, ib3) = tuple_of_list3 ii1 in + let (ib4) = tuple_of_list1 ii2 in + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + tokenf ia3 ib3 >>= (fun ia3 ib3 -> + tokenf ia4 ib4 >>= (fun ia4 ib4 -> + expression e1a e1b >>= (fun e1a e1b -> + expression e2a e2b >>= (fun e2a e2b -> + initialiser inia inib >>= (fun inia inib -> + return ( + (A.InitGccRange (ia1,e1a,ia2,e2a,ia3,ia4,inia)) +> A.rewrap ia, + (B.InitDesignators + ([B.DesignatorRange (e1b, e2b),[ib1;ib2;ib3]], inib), [ib4]) + )))))))) + + + + + | (A.InitGccName (ida, ia1, inia), (B.InitFieldOld (idb, inib), ii)) -> + (match ii with + | [iidb;iicolon] -> + ident DontKnow ida (idb, iidb) >>= (fun ida (idb, iidb) -> + initialiser inia inib >>= (fun inia inib -> + tokenf ia1 iicolon >>= (fun ia1 iicolon -> + return ( + (A.InitGccName (ida, ia1, inia)) +> A.rewrap ia, + (B.InitFieldOld (idb, inib), [iidb;iicolon]) + )))) + | _ -> fail + ) + + + + | A.IComma(comma), _ -> + raise Impossible + + | A.UniqueIni _,_ | A.OptIni _,_ -> + failwith "not handling Opt/Unique on initialisers" + + | _, _ -> fail + + + + + +and initialisers = fun ias (ibs, iicomma) -> + let ias_unsplit = unsplit_icomma ias in + let ibs_split = resplit_initialiser ibs iicomma in + + let f = + if need_unordered_initialisers ibs + then initialisers_unordered2 + else initialisers_ordered2 + in + f ias_unsplit ibs_split >>= + (fun ias_unsplit ibs_split -> + return ( + split_icomma ias_unsplit, + unsplit_initialiser ibs_split + ) + ) + +(* todo: one day julia will reput a IDots *) +and initialisers_ordered2 = fun ias ibs -> + match ias, ibs with + | [], [] -> return ([], []) + | (x, xcomma)::xs, (y, commay)::ys -> + (match A.unwrap xcomma with + | A.IComma commax -> + tokenf commax commay >>= (fun commax commay -> + initialiser x y >>= (fun x y -> + initialisers_ordered2 xs ys >>= (fun xs ys -> + return ( + (x, (A.IComma commax) +> A.rewrap xcomma)::xs, + (y, commay)::ys + ) + ))) + | _ -> raise Impossible (* unsplit_iicomma wrong *) + ) + | _ -> fail + + + +and initialisers_unordered2 = fun ias ibs -> + + match ias, ibs with + | [], ys -> return ([], ys) + | (x,xcomma)::xs, ys -> + + let permut = Common.uncons_permut_lazy ys in + permut +> List.fold_left (fun acc ((e, pos), rest) -> + acc >||> + ( + (match A.unwrap xcomma, e with + | A.IComma commax, (y, commay) -> + tokenf commax commay >>= (fun commax commay -> + initialiser x y >>= (fun x y -> + return ( + (x, (A.IComma commax) +> A.rewrap xcomma), + (y, commay)) + ) + ) + | _ -> raise Impossible (* unsplit_iicomma wrong *) + ) + >>= (fun x e -> + let rest = Lazy.force rest in + initialisers_unordered2 xs rest >>= (fun xs rest -> + return ( + x::xs, + Common.insert_elem_pos (e, pos) rest + )))) + ) fail + + +(* ------------------------------------------------------------------------- *) +and (struct_fields: (A.declaration list, B.field B.wrap list) matcher) = + fun eas ebs -> + match eas, ebs with + | [], [] -> return ([], []) + | [], eb::ebs -> fail + | ea::eas, ebs -> + X.all_bound (A.get_inherited ea) >&&> + (match A.unwrap ea, ebs with + | A.Ddots (mcode, optwhen), ys -> + if optwhen <> None then failwith "not handling when in argument"; + + (* '...' can take more or less the beginnings of the arguments *) + let startendxs = Common.zip (Common.inits ys) (Common.tails ys) in + startendxs +> List.fold_left (fun acc (startxs, endxs) -> + acc >||> ( + + (if startxs = [] + then + if mcode_contain_plus (mcodekind mcode) + then fail + (* failwith "I have no token that I could accroche myself on" *) + else return (dots2metavar mcode, []) + else + + X.distrf_struct_fields (dots2metavar mcode) startxs + ) >>= (fun mcode startxs -> + let mcode = metavar2dots mcode in + struct_fields eas endxs >>= (fun eas endxs -> + return ( + (A.Ddots (mcode, optwhen) +> A.rewrap ea) ::eas, + startxs ++ endxs + ))) + ) + ) fail + | _unwrapx, eb::ebs -> + struct_field ea eb >>= (fun ea eb -> + struct_fields eas ebs >>= (fun eas ebs -> + return (ea::eas, eb::ebs) + )) + + | _unwrapx, [] -> fail + ) + +and (struct_field: (A.declaration, B.field B.wrap) matcher) = fun fa fb -> + let (xfield, ii) = fb in + let iiptvirgb = tuple_of_list1 ii in + + match xfield with + | B.FieldDeclList onefield_multivars -> + + (match onefield_multivars with + | [] -> raise Impossible + | [onevar,iivirg] -> + assert (null iivirg); + (match onevar with + | B.BitField (sopt, typb, expr), ii -> + pr2_once "warning: bitfield not handled by ast_cocci"; + fail + | B.Simple (None, typb), ii -> + pr2_once "warning: unamed struct field not handled by ast_cocci"; + fail + | B.Simple (Some idb, typb), ii -> + let (iidb) = tuple_of_list1 ii in + + (* build a declaration from a struct field *) + let allminus = false in + let iisto = [] in + let stob = B.NoSto, false in + let fake_var = + ((Some ((idb, None),[iidb]), typb, stob, Ast_c.NotLocalDecl), + iivirg) + in + onedecl allminus fa (fake_var,iiptvirgb,iisto) >>= + (fun fa (var,iiptvirgb,iisto) -> + + match fake_var with + | ((Some ((idb, None),[iidb]), typb, stob, local), iivirg) -> + let onevar = B.Simple (Some idb, typb), [iidb] in + + return ( + (fa), + (B.FieldDeclList [onevar, iivirg], [iiptvirgb]) + ) + | _ -> raise Impossible + ) + ) + + | x::y::xs -> + pr2_once "PB: More that one variable in decl. Have to split"; + fail + ) + | B.EmptyField -> fail + + + +(* ------------------------------------------------------------------------- *) +and (fullType: (A.fullType, Ast_c.fullType) matcher) = + fun typa typb -> + X.optional_qualifier_flag (fun optional_qualifier -> + X.all_bound (A.get_inherited typa) >&&> + match A.unwrap typa, typb with + | A.Type(cv,ty1), ((qu,il),ty2) -> + + if qu.B.const && qu.B.volatile + then + pr2_once + ("warning: the type is both const & volatile but cocci " ^ + "does not handle that"); + + (* Drop out the const/volatile part that has been matched. + * This is because a SP can contain const T v; in which case + * later in match_t_t when we encounter a T, we must not add in + * the environment the whole type. + *) + + + (match cv with + (* "iso-by-absence" *) + | None -> + let do_stuff () = + fullTypebis ty1 ((qu,il), ty2) >>= (fun ty1 fullty2 -> + return ( + (A.Type(None, ty1)) +> A.rewrap typa, + fullty2 + )) + in + (match optional_qualifier, qu.B.const || qu.B.volatile with + | false, false -> do_stuff () + | false, true -> fail + | true, false -> do_stuff () + | true, true -> + if !Flag.show_misc + then pr2_once "USING optional_qualifier builtin isomorphism"; + do_stuff() + ) + + + | Some x -> + (* todo: can be __const__ ? can be const & volatile so + * should filter instead ? + *) + (match term x, il with + | A.Const, [i1] when qu.B.const -> + + tokenf x i1 >>= (fun x i1 -> + fullTypebis ty1 (Ast_c.nQ,ty2) >>= (fun ty1 (_, ty2) -> + return ( + (A.Type(Some x, ty1)) +> A.rewrap typa, + ((qu, [i1]), ty2) + ))) + + | A.Volatile, [i1] when qu.B.volatile -> + tokenf x i1 >>= (fun x i1 -> + fullTypebis ty1 (Ast_c.nQ,ty2) >>= (fun ty1 (_, ty2) -> + return ( + (A.Type(Some x, ty1)) +> A.rewrap typa, + ((qu, [i1]), ty2) + ))) + + | _ -> fail + ) + ) + + | A.DisjType typas, typb -> + typas +> + List.fold_left (fun acc typa -> acc >|+|> (fullType typa typb)) fail + + | A.OptType(_), _ | A.UniqueType(_), _ + -> failwith "not handling Opt/Unique on type" + ) + + +(* + * Why not (A.typeC, Ast_c.typeC) matcher ? + * because when there is MetaType, we want that T record the whole type, + * including the qualifier, and so this type (and the new_il function in + * preceding function). +*) + +and (fullTypebis: (A.typeC, Ast_c.fullType) matcher) = + fun ta tb -> + X.all_bound (A.get_inherited ta) >&&> + match A.unwrap ta, tb with + + (* cas general *) + | A.MetaType(ida,keep, inherited), typb -> + let max_min _ = + Lib_parsing_c.lin_col_by_pos (Lib_parsing_c.ii_of_type typb) in + X.envf keep inherited (ida, B.MetaTypeVal typb, max_min) (fun () -> + X.distrf_type ida typb >>= (fun ida typb -> + return ( + A.MetaType(ida,keep, inherited) +> A.rewrap ta, + typb + )) + ) + | unwrap, (qub, typb) -> + typeC ta typb >>= (fun ta typb -> + return (ta, (qub, typb)) + ) + + +and (typeC: (A.typeC, Ast_c.typeC) matcher) = + fun ta tb -> + match A.unwrap ta, tb with + | A.BaseType (basea, signaopt), (B.BaseType baseb, ii) -> + (* In ii there is a list, sometimes of length 1 or 2 or 3. + * And even if in baseb we have a Signed Int, that does not mean + * that ii is of length 2, cos Signed is the default, so if in signa + * we have Signed explicitely ? we cant "accrocher" this mcode to + * something :( So for the moment when there is signed in cocci, + * we force that there is a signed in c too (done in pattern.ml). + *) + let signbopt, iibaseb = split_signb_baseb_ii (baseb, ii) in + + + (* handle some iso on type ? (cf complex C rule for possible implicit + casting) *) + (match term basea, baseb with + | A.VoidType, B.Void + | A.FloatType, B.FloatType (B.CFloat) + | A.DoubleType, B.FloatType (B.CDouble) -> + assert (signaopt = None); + let (ibaseb) = tuple_of_list1 ii in + tokenf basea ibaseb >>= (fun basea ibaseb -> + return ( + (A.BaseType (basea, signaopt)) +> A.rewrap ta, + (B.BaseType baseb, [ibaseb]) + )) + + | A.CharType, B.IntType B.CChar when signaopt = None -> + let ibaseb = tuple_of_list1 ii in + tokenf basea ibaseb >>= (fun basea ibaseb -> + return ( + (A.BaseType (basea, signaopt)) +> A.rewrap ta, + (B.BaseType (B.IntType B.CChar), [ibaseb]) + )) + + | A.CharType,B.IntType (B.Si (_sign, B.CChar2)) when signaopt <> None -> + let ibaseb = tuple_of_list1 iibaseb in + sign signaopt signbopt >>= (fun signaopt iisignbopt -> + tokenf basea ibaseb >>= (fun basea ibaseb -> + return ( + (A.BaseType (basea, signaopt)) +> A.rewrap ta, + (B.BaseType (baseb), iisignbopt ++ [ibaseb]) + ))) + + | A.ShortType, B.IntType (B.Si (_, B.CShort)) + | A.IntType, B.IntType (B.Si (_, B.CInt)) + | A.LongType, B.IntType (B.Si (_, B.CLong)) -> + (match iibaseb with + | [] -> + (* iso-by-presence ? *) + (* when unsigned int in SP, allow have just unsigned in C ? *) + if mcode_contain_plus (mcodekind basea) + then fail + else + + sign signaopt signbopt >>= (fun signaopt iisignbopt -> + return ( + (A.BaseType (basea, signaopt)) +> A.rewrap ta, + (B.BaseType (baseb), iisignbopt ++ []) + )) + + + | [x;y] -> + pr2_once + "warning: long int or short int not handled by ast_cocci"; + fail + + | [ibaseb] -> + sign signaopt signbopt >>= (fun signaopt iisignbopt -> + tokenf basea ibaseb >>= (fun basea ibaseb -> + return ( + (A.BaseType (basea, signaopt)) +> A.rewrap ta, + (B.BaseType (baseb), iisignbopt ++ [ibaseb]) + ))) + | _ -> raise Impossible + + ) + + + | _, B.IntType (B.Si (_, B.CLongLong)) + | _, B.FloatType B.CLongDouble + -> + pr2_once + "warning: long long or long double not handled by ast_cocci"; + fail + + + | _, _ -> fail + + + ) + + | A.ImplicitInt (signa), (B.BaseType baseb, ii) -> + let signbopt, iibaseb = split_signb_baseb_ii (baseb, ii) in + (match iibaseb, baseb with + | [], B.IntType (B.Si (_sign, B.CInt)) -> + sign (Some signa) signbopt >>= (fun signaopt iisignbopt -> + match signaopt with + | None -> raise Impossible + | Some signa -> + return ( + (A.ImplicitInt (signa)) +> A.rewrap ta, + (B.BaseType baseb, iisignbopt) + ) + ) + | _ -> fail + ) + + + + (* todo? iso with array *) + | A.Pointer (typa, iamult), (B.Pointer typb, ii) -> + let (ibmult) = tuple_of_list1 ii in + fullType typa typb >>= (fun typa typb -> + tokenf iamult ibmult >>= (fun iamult ibmult -> + return ( + (A.Pointer (typa, iamult)) +> A.rewrap ta, + (B.Pointer typb, [ibmult]) + ))) + + | A.FunctionType(allminus,tyaopt,lpa,paramsa,rpa), + (B.FunctionType(tyb, (paramsb, (isvaargs, iidotsb))), ii) -> + + let (lpb, rpb) = tuple_of_list2 ii in + if isvaargs + then + pr2_once + ("Not handling well variable length arguments func. "^ + "You have been warned"); + tokenf lpa lpb >>= (fun lpa lpb -> + tokenf rpa rpb >>= (fun rpa rpb -> + fullType_optional_allminus allminus tyaopt tyb >>= (fun tyaopt tyb -> + parameters (seqstyle paramsa) (A.undots paramsa) paramsb >>= + (fun paramsaundots paramsb -> + let paramsa = redots paramsa paramsaundots in + return ( + (A.FunctionType(allminus,tyaopt,lpa,paramsa,rpa) +> A.rewrap ta, + (B.FunctionType(tyb, (paramsb, (isvaargs, iidotsb))), [lpb;rpb]) + ) + ))))) + + + + + + | A.FunctionPointer(tya,lp1a,stara,rp1a,lp2a,paramsa,rp2a), + (B.ParenType t1, ii) -> + let (lp1b, rp1b) = tuple_of_list2 ii in + let (qu1b, t1b) = t1 in + (match t1b with + | B.Pointer t2, ii -> + let (starb) = tuple_of_list1 ii in + let (qu2b, t2b) = t2 in + (match t2b with + | B.FunctionType (tyb, (paramsb, (isvaargs, iidotsb))), ii -> + let (lp2b, rp2b) = tuple_of_list2 ii in + + if isvaargs + then + pr2_once + ("Not handling well variable length arguments func. "^ + "You have been warned"); + + fullType tya tyb >>= (fun tya tyb -> + tokenf lp1a lp1b >>= (fun lp1a lp1b -> + tokenf rp1a rp1b >>= (fun rp1a rp1b -> + tokenf lp2a lp2b >>= (fun lp2a lp2b -> + tokenf rp2a rp2b >>= (fun rp2a rp2b -> + tokenf stara starb >>= (fun stara starb -> + parameters (seqstyle paramsa) (A.undots paramsa) paramsb >>= + (fun paramsaundots paramsb -> + let paramsa = redots paramsa paramsaundots in + + let t2 = + (qu2b, + (B.FunctionType (tyb, (paramsb, (isvaargs, iidotsb))), + [lp2b;rp2b])) + in + let t1 = + (qu1b, + (B.Pointer t2, [starb])) + in + + return ( + (A.FunctionPointer(tya,lp1a,stara,rp1a,lp2a,paramsa,rp2a)) + +> A.rewrap ta, + (B.ParenType t1, [lp1b;rp1b]) + ) + ))))))) + + + + | _ -> fail + ) + | _ -> fail + ) + + + + (* todo: handle the iso on optionnal size specifification ? *) + | A.Array (typa, ia1, eaopt, ia2), (B.Array (ebopt, typb), ii) -> + let (ib1, ib2) = tuple_of_list2 ii in + fullType typa typb >>= (fun typa typb -> + option expression eaopt ebopt >>= (fun eaopt ebopt -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + return ( + (A.Array (typa, ia1, eaopt, ia2)) +> A.rewrap ta, + (B.Array (ebopt, typb), [ib1;ib2]) + ))))) + + + (* todo: could also match a Struct that has provided a name *) + (* This is for the case where the SmPL code contains "struct x", without + a definition. In this case, the name field is always present. + This case is also called from the case for A.StructUnionDef when + a name is present in the C code. *) + | A.StructUnionName(sua, Some sa), (B.StructUnionName (sub, sb), ii) -> + (* sa is now an ident, not an mcode, old: ... && (term sa) =$= sb *) + let (ib1, ib2) = tuple_of_list2 ii in + if equal_structUnion (term sua) sub + then + ident DontKnow sa (sb, ib2) >>= (fun sa (sb, ib2) -> + tokenf sua ib1 >>= (fun sua ib1 -> + return ( + (A.StructUnionName (sua, Some sa)) +> A.rewrap ta, + (B.StructUnionName (sub, sb), [ib1;ib2]) + ))) + else fail + + + | A.StructUnionDef(ty, lba, declsa, rba), + (B.StructUnion (sub, sbopt, declsb), ii) -> + + let (ii_sub_sb, lbb, rbb) = + match ii with + [iisub; lbb; rbb] -> (Common.Left iisub,lbb,rbb) + | [iisub; iisb; lbb; rbb] -> (Common.Right (iisub,iisb),lbb,rbb) + | _ -> failwith "list of length 3 or 4 expected" in + + let process_type = + match (sbopt,ii_sub_sb) with + (None,Common.Left iisub) -> + (* the following doesn't reconstruct the complete SP code, just + the part that matched *) + let rec loop s = + match A.unwrap s with + A.Type(None,ty) -> + (match A.unwrap ty with + A.StructUnionName(sua, None) -> + tokenf sua iisub >>= (fun sua iisub -> + let ty = + A.Type(None, + A.StructUnionName(sua, None) +> A.rewrap ty) + +> A.rewrap s in + return (ty,[iisub])) + | _ -> fail) + | A.DisjType(disjs) -> + disjs +> + List.fold_left (fun acc disj -> acc >|+|> (loop disj)) fail + | _ -> fail in + loop ty + + | (Some sb,Common.Right (iisub,iisb)) -> + + (* build a StructUnionName from a StructUnion *) + let fake_su = B.nQ, (B.StructUnionName (sub, sb), [iisub;iisb]) in + + fullType ty fake_su >>= (fun ty fake_su -> + match fake_su with + | _nQ, (B.StructUnionName (sub, sb), [iisub;iisb]) -> + return (ty, [iisub; iisb]) + | _ -> raise Impossible) + | _ -> fail in + + process_type + >>= (fun ty ii_sub_sb -> + + tokenf lba lbb >>= (fun lba lbb -> + tokenf rba rbb >>= (fun rba rbb -> + struct_fields (A.undots declsa) declsb >>=(fun undeclsa declsb -> + let declsa = redots declsa undeclsa in + + return ( + (A.StructUnionDef(ty, lba, declsa, rba)) +> A.rewrap ta, + (B.StructUnion (sub, sbopt, declsb),ii_sub_sb@[lbb;rbb]) + ))))) + + + (* todo? handle isomorphisms ? because Unsigned Int can be match on a + * uint in the C code. But some CEs consists in renaming some types, + * so we don't want apply isomorphisms every time. + *) + | A.TypeName sa, (B.TypeName (sb,typb), ii) -> + let (isb) = tuple_of_list1 ii in + if (term sa) =$= sb + then + tokenf sa isb >>= (fun sa isb -> + return ( + (A.TypeName sa) +> A.rewrap ta, + (B.TypeName (sb,typb), [isb]) + )) + else fail + + | _, (B.TypeOfExpr e, ii) -> fail + | _, (B.TypeOfType e, ii) -> fail + + | _, _ -> fail + +(* todo: iso on sign, if not mentioned then free. tochange? + * but that require to know if signed int because explicit + * signed int, or because implicit signed int. + *) + +and sign signa signb = + match signa, signb with + | None, None -> return (None, []) + | Some signa, Some (signb, ib) -> + if equal_sign (term signa) signb + then tokenf signa ib >>= (fun signa ib -> + return (Some signa, [ib]) + ) + else fail + | _, _ -> fail + + +and minusize_list iixs = + iixs +> List.fold_left (fun acc ii -> + acc >>= (fun xs ys -> + tokenf minusizer ii >>= (fun minus ii -> + return (minus::xs, ii::ys) + ))) (return ([],[])) + >>= (fun _xsminys ys -> + return ((), List.rev ys) + ) + +and storage_optional_allminus allminus stoa (stob, iistob) = + (* "iso-by-absence" for storage, and return type. *) + X.optional_storage_flag (fun optional_storage -> + match stoa, stob with + | None, (stobis, inline) -> + let do_minus () = + if allminus + then + minusize_list iistob >>= (fun () iistob -> + return (None, (stob, iistob)) + ) + else return (None, (stob, iistob)) + in + + (match optional_storage, stobis with + | false, B.NoSto -> do_minus () + | false, _ -> fail + | true, B.NoSto -> do_minus () + | true, _ -> + if !Flag.show_misc + then pr2_once "USING optional_storage builtin isomorphism"; + do_minus() + ) + + | Some x, ((stobis, inline)) -> + if equal_storage (term x) stobis + then + match iistob with + | [i1] -> + tokenf x i1 >>= (fun x i1 -> + return (Some x, ((stobis, inline), [i1])) + ) + (* or if have inline ? have to do a split_storage_inline a la + * split_signb_baseb_ii *) + | _ -> raise Impossible + else fail + ) + + + + + +and fullType_optional_allminus allminus tya retb = + match tya with + | None -> + if allminus + then + X.distrf_type minusizer retb >>= (fun _x retb -> + return (None, retb) + ) + + else return (None, retb) + | Some tya -> + fullType tya retb >>= (fun tya retb -> + return (Some tya, retb) + ) + + + +(*---------------------------------------------------------------------------*) +and compatible_type a (b,_local) = + let ok = return ((),()) in + + let rec loop = function + | Type_cocci.BaseType (a, signa), (qua, (B.BaseType b,ii)) -> + (match a, b with + | Type_cocci.VoidType, B.Void -> + assert (signa = None); + ok + | Type_cocci.CharType, B.IntType B.CChar when signa = None -> + ok + | Type_cocci.CharType, B.IntType (B.Si (signb, B.CChar2)) -> + compatible_sign signa signb + | Type_cocci.ShortType, B.IntType (B.Si (signb, B.CShort)) -> + compatible_sign signa signb + | Type_cocci.IntType, B.IntType (B.Si (signb, B.CInt)) -> + compatible_sign signa signb + | Type_cocci.LongType, B.IntType (B.Si (signb, B.CLong)) -> + compatible_sign signa signb + | _, B.IntType (B.Si (signb, B.CLongLong)) -> + pr2_once "no longlong in cocci"; + fail + | Type_cocci.FloatType, B.FloatType B.CFloat -> + assert (signa = None); + ok + | Type_cocci.DoubleType, B.FloatType B.CDouble -> + assert (signa = None); + ok + | _, B.FloatType B.CLongDouble -> + pr2_once "no longdouble in cocci"; + fail + | Type_cocci.BoolType, _ -> failwith "no booltype in C" + | _ -> fail + + ) + | Type_cocci.Pointer a, (qub, (B.Pointer b, ii)) -> + loop (a,b) + | Type_cocci.FunctionPointer a, _ -> + failwith + "TODO: function pointer type doesn't store enough information to determine compatability" + | Type_cocci.Array a, (qub, (B.Array (eopt, b),ii)) -> + (* no size info for cocci *) + loop (a,b) + | Type_cocci.StructUnionName (sua, _, sa), + (qub, (B.StructUnionName (sub, sb),ii)) -> + if equal_structUnion_type_cocci sua sub && sa = sb + then ok + else fail + + | Type_cocci.TypeName sa, (qub, (B.TypeName (sb,_typb), ii)) -> + if sa = sb + then ok + else fail + + | Type_cocci.ConstVol (qua, a), (qub, b) -> + if (fst qub).B.const && (fst qub).B.volatile + then + begin + pr2_once ("warning: the type is both const & volatile but cocci " ^ + "does not handle that"); + fail + end + else + if + (match qua with + | Type_cocci.Const -> (fst qub).B.const + | Type_cocci.Volatile -> (fst qub).B.volatile + ) + then loop (a,(Ast_c.nQ, b)) + else fail + + | Type_cocci.MetaType (ida,keep,inherited), typb -> + let max_min _ = + Lib_parsing_c.lin_col_by_pos (Lib_parsing_c.ii_of_type typb) in + X.envf keep inherited (A.make_mcode ida, B.MetaTypeVal typb, max_min) + (fun () -> ok + ) + + (* subtil: must be after the MetaType case *) + | a, (qub, (B.TypeName (sb,Some b), ii)) -> + (* kind of typedef iso *) + loop (a,b) + + + + + + (* for metavariables of type expression *^* *) + | Type_cocci.Unknown , _ -> ok + + | _ -> fail in + loop (a,b) + +and compatible_sign signa signb = + let ok = return ((),()) in + match signa, signb with + | None, B.Signed + | Some Type_cocci.Signed, B.Signed + | Some Type_cocci.Unsigned, B.UnSigned + -> ok + | _ -> fail + + +and equal_structUnion_type_cocci a b = + match a, b with + | Type_cocci.Struct, B.Struct -> true + | Type_cocci.Union, B.Union -> true + | _, _ -> false + + + +(*---------------------------------------------------------------------------*) +and inc_file (a, before_after) (b, h_rel_pos) = + + let rec aux_inc (ass, bss) passed = + match ass, bss with + | [], [] -> true + | [A.IncDots], _ -> + let passed = List.rev passed in + + (match before_after, !h_rel_pos with + | IncludeNothing, _ -> true + | IncludeMcodeBefore, Some x -> + List.mem passed (x.Ast_c.first_of) + + | IncludeMcodeAfter, Some x -> + List.mem passed (x.Ast_c.last_of) + + (* no info, maybe cos of a #include that was already in a .h *) + | _, None -> false + ) + + | (A.IncPath x)::xs, y::ys -> x = y && aux_inc (xs, ys) (x::passed) + | _ -> failwith "IncDots not in last place or other pb" + + in + + match a, b with + | A.Local ass, B.Local bss -> + aux_inc (ass, bss) [] + | A.NonLocal ass, B.NonLocal bss -> + aux_inc (ass, bss) [] + | _ -> false + + + +(*---------------------------------------------------------------------------*) + +and (define_params: sequence -> + (A.define_param list, (string B.wrap) B.wrap2 list) matcher) = + fun seqstyle eas ebs -> + match seqstyle with + | Unordered -> failwith "not handling ooo" + | Ordered -> + define_paramsbis eas (Ast_c.split_comma ebs) >>= (fun eas ebs_splitted -> + return (eas, (Ast_c.unsplit_comma ebs_splitted)) + ) + +(* todo? facto code with argument and parameters ? *) +and define_paramsbis = fun eas ebs -> + match eas, ebs with + | [], [] -> return ([], []) + | [], eb::ebs -> fail + | ea::eas, ebs -> + X.all_bound (A.get_inherited ea) >&&> + (match A.unwrap ea, ebs with + | A.DPdots (mcode), ys -> + + (* '...' can take more or less the beginnings of the arguments *) + let startendxs = Common.zip (Common.inits ys) (Common.tails ys) in + startendxs +> List.fold_left (fun acc (startxs, endxs) -> + acc >||> ( + + (if startxs = [] + then + if mcode_contain_plus (mcodekind mcode) + then fail + (* failwith "I have no token that I could accroche myself on" *) + else return (dots2metavar mcode, []) + else + (match Common.last startxs with + | Right _ -> fail + | Left _ -> + X.distrf_define_params (dots2metavar mcode) startxs + ) + ) >>= (fun mcode startxs -> + let mcode = metavar2dots mcode in + define_paramsbis eas endxs >>= (fun eas endxs -> + return ( + (A.DPdots (mcode) +> A.rewrap ea) ::eas, + startxs ++ endxs + ))) + ) + ) fail + + | A.DPComma ia1, Right ii::ebs -> + let ib1 = tuple_of_list1 ii in + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + define_paramsbis eas ebs >>= (fun eas ebs -> + return ( + (A.DPComma ia1 +> A.rewrap ea)::eas, + (Right [ib1])::ebs + ) + )) + + | A.DPComma ia1, ebs -> + if mcode_contain_plus (mcodekind ia1) + then fail + else + (define_paramsbis eas ebs) (* try optional comma trick *) + + | (A.OptDParam _ | A.UniqueDParam _), _ -> + failwith "handling Opt/Unique for define parameters" + + | A.DPcircles (_), ys -> raise Impossible (* in Ordered mode *) + + | A.DParam ida, (Left (idb, ii))::ebs -> + let ib1 = tuple_of_list1 ii in + ident DontKnow ida (idb, ib1) >>= (fun ida (idb, ib1) -> + define_paramsbis eas ebs >>= (fun eas ebs -> + return ( + (A.DParam ida)+> A.rewrap ea :: eas, + (Left (idb, [ib1]))::ebs + ))) + + | _unwrapx, (Right y)::ys -> raise Impossible + | _unwrapx, [] -> fail + ) + + + +(*****************************************************************************) +(* Entry points *) +(*****************************************************************************) + +(* no global solution for positions here, because for a statement metavariable +we want a MetaStmtVal, and for the others, it's not clear what we want *) + +let rec (rule_elem_node: (A.rule_elem, Control_flow_c.node) matcher) = + fun re node -> + let rewrap x = + x >>= (fun a b -> return (A.rewrap re a, F.rewrap node b)) + in + X.all_bound (A.get_inherited re) >&&> + + rewrap ( + match A.unwrap re, F.unwrap node with + + (* note: the order of the clauses is important. *) + + | _, F.Enter | _, F.Exit | _, F.ErrorExit -> fail2() + + (* the metaRuleElem contains just '-' information. We dont need to add + * stuff in the environment. If we need stuff in environment, because + * there is a + S somewhere, then this will be done via MetaStmt, not + * via MetaRuleElem. + * Can match TrueNode/FalseNode/... so must be placed before those cases. + *) + + | A.MetaRuleElem(mcode,keep,inherited), unwrap_node -> + let default = A.MetaRuleElem(mcode,keep,inherited), unwrap_node in + (match unwrap_node with + | F.CaseNode _ + | F.TrueNode | F.FalseNode | F.AfterNode | F.FallThroughNode + | F.InLoopNode -> + if X.mode = PatternMode + then return default + else + if mcode_contain_plus (mcodekind mcode) + then failwith "try add stuff on fake node" + (* minusize or contextize a fake node is ok *) + else return default + + | F.EndStatement None -> + if X.mode = PatternMode then return default + else + (* DEAD CODE NOW ? only useful in -no_cocci_vs_c_3 ? + if mcode_contain_plus (mcodekind mcode) + then + let fake_info = Ast_c.fakeInfo() in + distrf distrf_node (mcodekind mcode) + (F.EndStatement (Some fake_info)) + else return unwrap_node + *) + raise Todo + + | F.EndStatement (Some i1) -> + tokenf mcode i1 >>= (fun mcode i1 -> + return ( + A.MetaRuleElem (mcode,keep, inherited), + F.EndStatement (Some i1) + )) + + | F.FunHeader _ -> + if X.mode = PatternMode then return default + else failwith "a MetaRuleElem can't transform a headfunc" + | _n -> + if X.mode = PatternMode then return default + else + X.distrf_node (generalize_mcode mcode) node >>= (fun mcode node -> + return ( + A.MetaRuleElem(mcode,keep, inherited), + F.unwrap node + )) + ) + + + (* rene cant have found that a state containing a fake/exit/... should be + * transformed + * TODO: and F.Fake ? + *) + | _, F.EndStatement _ | _, F.CaseNode _ + | _, F.TrueNode | _, F.FalseNode | _, F.AfterNode | _, F.FallThroughNode + | _, F.InLoopNode + -> fail2() + + (* really ? diff between pattern.ml and transformation.ml *) + | _, F.Fake -> fail2() + + + (* cas general: a Meta can match everything. It matches only + * "header"-statement. We transform only MetaRuleElem, not MetaStmt. + * So can't have been called in transform. + *) + | A.MetaStmt (ida,keep,metainfoMaybeTodo,inherited), F.Decl(_) -> fail + + | A.MetaStmt (ida,keep,metainfoMaybeTodo,inherited), unwrap_node -> + (* todo: should not happen in transform mode *) + + (match Control_flow_c.extract_fullstatement node with + | Some stb -> + let max_min _ = + Lib_parsing_c.lin_col_by_pos (Lib_parsing_c.ii_of_stmt stb) in + X.envf keep inherited (ida, Ast_c.MetaStmtVal stb, max_min) + (fun () -> + (* no need tag ida, we can't be called in transform-mode *) + return ( + A.MetaStmt (ida, keep, metainfoMaybeTodo, inherited), + unwrap_node + ) + ) + | None -> fail + ) + + (* not me?: *) + | A.MetaStmtList _, _ -> + failwith "not handling MetaStmtList" + + | A.TopExp ea, F.DefineExpr eb -> + expression ea eb >>= (fun ea eb -> + return ( + A.TopExp ea, + F.DefineExpr eb + )) + + | A.TopExp ea, F.DefineType eb -> + (match A.unwrap ea with + A.TypeExp(ft) -> + fullType ft eb >>= (fun ft eb -> + return ( + A.TopExp (A.rewrap ea (A.TypeExp(ft))), + F.DefineType eb + )) + | _ -> fail) + + + + (* It is important to put this case before the one that fails because + * of the lack of the counter part of a C construct in SmPL (for instance + * there is not yet a CaseRange in SmPL). Even if SmPL don't handle + * yet certain constructs, those constructs may contain expression + * that we still want and can transform. + *) + + | A.Exp exp, nodeb -> + + (* kind of iso, initialisation vs affectation *) + let node = + match A.unwrap exp, nodeb with + | A.Assignment (ea, op, eb, true), F.Decl decl -> + initialisation_to_affectation decl +> F.rewrap node + | _ -> node + in + + + (* Now keep fullstatement inside the control flow node, + * so that can then get in a MetaStmtVar the fullstatement to later + * pp back when the S is in a +. But that means that + * Exp will match an Ifnode even if there is no such exp + * inside the condition of the Ifnode (because the exp may + * be deeper, in the then branch). So have to not visit + * all inside a node anymore. + * + * update: j'ai choisi d'accrocher au noeud du CFG à la + * fois le fullstatement et le partialstatement et appeler le + * visiteur que sur le partialstatement. + *) + let expfn = + match Ast_cocci.get_pos re with + | None -> expression + | Some pos -> + (fun ea eb -> + let (max,min) = + Lib_parsing_c.max_min_by_pos (Lib_parsing_c.ii_of_expr eb) in + let keep = Type_cocci.Unitary in + let inherited = false in + let max_min _ = failwith "no pos" in + X.envf keep inherited (pos, B.MetaPosVal (min,max), max_min) + (fun () -> + expression ea eb + ) + ) + in + X.cocciExp expfn exp node >>= (fun exp node -> + return ( + A.Exp exp, + F.unwrap node + ) + ) + + + + | A.Ty ty, nodeb -> + X.cocciTy fullType ty node >>= (fun ty node -> + return ( + A.Ty ty, + F.unwrap node + ) + ) + + + | A.FunHeader (mckstart, allminus, fninfoa, ida, oparen, paramsa, cparen), + F.FunHeader ((idb, (retb, (paramsb, (isvaargs, iidotsb))), stob), ii) -> + + (* fninfoa records the order in which the SP specified the various + information, but this isn't taken into account in the matching. + Could this be a problem for transformation? *) + let stoa = + match + List.filter (function A.FStorage(s) -> true | _ -> false) fninfoa + with [A.FStorage(s)] -> Some s | _ -> None in + let tya = + match List.filter (function A.FType(s) -> true | _ -> false) fninfoa + with [A.FType(t)] -> Some t | _ -> None in + + (match List.filter (function A.FInline(i) -> true | _ -> false) fninfoa + with [A.FInline(i)] -> failwith "not checking inline" | _ -> ()); + + (match List.filter (function A.FAttr(a) -> true | _ -> false) fninfoa + with [A.FAttr(a)] -> failwith "not checking attributes" | _ -> ()); + + (match ii with + | iidb::ioparenb::icparenb::iifakestart::iistob -> + + (* maybe important to put ident as the first tokens to transform. + * It's related to transform_proto. So don't change order + * between the >>=. + *) + ident LocalFunction ida (idb, iidb) >>= (fun ida (idb, iidb) -> + X.tokenf_mck mckstart iifakestart >>= (fun mckstart iifakestart -> + tokenf oparen ioparenb >>= (fun oparen ioparenb -> + tokenf cparen icparenb >>= (fun cparen icparenb -> + parameters (seqstyle paramsa) + (A.undots paramsa) paramsb >>= + (fun paramsaundots paramsb -> + let paramsa = redots paramsa paramsaundots in + storage_optional_allminus allminus + stoa (stob, iistob) >>= (fun stoa (stob, iistob) -> + ( + if isvaargs + then + pr2_once + ("Not handling well variable length arguments func. "^ + "You have been warned"); + if allminus + then minusize_list iidotsb + else return ((),iidotsb) + ) >>= (fun () iidotsb -> + + fullType_optional_allminus allminus tya retb >>= (fun tya retb -> + + let fninfoa = + (match stoa with Some st -> [A.FStorage st] | None -> []) ++ + (match tya with Some t -> [A.FType t] | None -> []) + + in + + return ( + A.FunHeader(mckstart,allminus,fninfoa,ida,oparen, + paramsa,cparen), + F.FunHeader ((idb, (retb, (paramsb, (isvaargs, iidotsb))), + stob), + iidb::ioparenb::icparenb::iifakestart::iistob) + ) + )))))))) + | _ -> raise Impossible + ) + + + + + + + | A.Decl (mckstart,allminus,decla), F.Decl declb -> + declaration (mckstart,allminus,decla) declb >>= + (fun (mckstart,allminus,decla) declb -> + return ( + A.Decl (mckstart,allminus,decla), + F.Decl declb + )) + + + | A.SeqStart mcode, F.SeqStart (st, level, i1) -> + tokenf mcode i1 >>= (fun mcode i1 -> + return ( + A.SeqStart mcode, + F.SeqStart (st, level, i1) + )) + + | A.SeqEnd mcode, F.SeqEnd (level, i1) -> + tokenf mcode i1 >>= (fun mcode i1 -> + return ( + A.SeqEnd mcode, + F.SeqEnd (level, i1) + )) + + | A.ExprStatement (ea, ia1), F.ExprStatement (st, (Some eb, ii)) -> + let ib1 = tuple_of_list1 ii in + expression ea eb >>= (fun ea eb -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + return ( + A.ExprStatement (ea, ia1), + F.ExprStatement (st, (Some eb, [ib1])) + ) + )) + + + | A.IfHeader (ia1,ia2, ea, ia3), F.IfHeader (st, (eb,ii)) -> + let (ib1, ib2, ib3) = tuple_of_list3 ii in + expression ea eb >>= (fun ea eb -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + tokenf ia3 ib3 >>= (fun ia3 ib3 -> + return ( + A.IfHeader (ia1, ia2, ea, ia3), + F.IfHeader (st, (eb,[ib1;ib2;ib3])) + ))))) + + | A.Else ia, F.Else ib -> + tokenf ia ib >>= (fun ia ib -> + return (A.Else ia, F.Else ib) + ) + + | A.WhileHeader (ia1, ia2, ea, ia3), F.WhileHeader (st, (eb, ii)) -> + let (ib1, ib2, ib3) = tuple_of_list3 ii in + expression ea eb >>= (fun ea eb -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + tokenf ia3 ib3 >>= (fun ia3 ib3 -> + return ( + A.WhileHeader (ia1, ia2, ea, ia3), + F.WhileHeader (st, (eb, [ib1;ib2;ib3])) + ))))) + + | A.DoHeader ia, F.DoHeader (st, ib) -> + tokenf ia ib >>= (fun ia ib -> + return ( + A.DoHeader ia, + F.DoHeader (st, ib) + )) + | A.WhileTail (ia1,ia2,ea,ia3,ia4), F.DoWhileTail (eb, ii) -> + let (ib1, ib2, ib3, ib4) = tuple_of_list4 ii in + expression ea eb >>= (fun ea eb -> + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + tokenf ia3 ib3 >>= (fun ia3 ib3 -> + tokenf ia4 ib4 >>= (fun ia4 ib4 -> + return ( + A.WhileTail (ia1,ia2,ea,ia3,ia4), + F.DoWhileTail (eb, [ib1;ib2;ib3;ib4]) + )))))) + | A.IteratorHeader (ia1, ia2, eas, ia3), F.MacroIterHeader (st, ((s,ebs),ii)) + -> + let (ib1, ib2, ib3) = tuple_of_list3 ii in + + ident DontKnow ia1 (s, ib1) >>= (fun ia1 (s, ib1) -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + tokenf ia3 ib3 >>= (fun ia3 ib3 -> + arguments (seqstyle eas) (A.undots eas) ebs >>= (fun easundots ebs -> + let eas = redots eas easundots in + return ( + A.IteratorHeader (ia1, ia2, eas, ia3), + F.MacroIterHeader (st, ((s,ebs), [ib1;ib2;ib3])) + ))))) + + + + | A.ForHeader (ia1, ia2, ea1opt, ia3, ea2opt, ia4, ea3opt, ia5), + F.ForHeader (st, (((eb1opt,ib3s), (eb2opt,ib4s), (eb3opt,ib4vide)), ii)) + -> + assert (null ib4vide); + let (ib1, ib2, ib5) = tuple_of_list3 ii in + let ib3 = tuple_of_list1 ib3s in + let ib4 = tuple_of_list1 ib4s in + + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + tokenf ia3 ib3 >>= (fun ia3 ib3 -> + tokenf ia4 ib4 >>= (fun ia4 ib4 -> + tokenf ia5 ib5 >>= (fun ia5 ib5 -> + option expression ea1opt eb1opt >>= (fun ea1opt eb1opt -> + option expression ea2opt eb2opt >>= (fun ea2opt eb2opt -> + option expression ea3opt eb3opt >>= (fun ea3opt eb3opt -> + return ( + A.ForHeader (ia1, ia2, ea1opt, ia3, ea2opt, ia4, ea3opt, ia5), + F.ForHeader (st, (((eb1opt,[ib3]), (eb2opt,[ib4]), (eb3opt,[])), + [ib1;ib2;ib5])) + + ))))))))) + + + | A.SwitchHeader(ia1,ia2,ea,ia3), F.SwitchHeader (st, (eb,ii)) -> + let (ib1, ib2, ib3) = tuple_of_list3 ii in + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + tokenf ia3 ib3 >>= (fun ia3 ib3 -> + expression ea eb >>= (fun ea eb -> + return ( + A.SwitchHeader(ia1,ia2,ea,ia3), + F.SwitchHeader (st, (eb,[ib1;ib2;ib3])) + ))))) + + | A.Break (ia1, ia2), F.Break (st, ((),ii)) -> + let (ib1, ib2) = tuple_of_list2 ii in + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + return ( + A.Break (ia1, ia2), + F.Break (st, ((),[ib1;ib2])) + ))) + + | A.Continue (ia1, ia2), F.Continue (st, ((),ii)) -> + let (ib1, ib2) = tuple_of_list2 ii in + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + return ( + A.Continue (ia1, ia2), + F.Continue (st, ((),[ib1;ib2])) + ))) + + | A.Return (ia1, ia2), F.Return (st, ((),ii)) -> + let (ib1, ib2) = tuple_of_list2 ii in + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + return ( + A.Return (ia1, ia2), + F.Return (st, ((),[ib1;ib2])) + ))) + + | A.ReturnExpr (ia1, ea, ia2), F.ReturnExpr (st, (eb, ii)) -> + let (ib1, ib2) = tuple_of_list2 ii in + tokenf ia1 ib1 >>= (fun ia1 ib1 -> + tokenf ia2 ib2 >>= (fun ia2 ib2 -> + expression ea eb >>= (fun ea eb -> + return ( + A.ReturnExpr (ia1, ea, ia2), + F.ReturnExpr (st, (eb, [ib1;ib2])) + )))) + + + + | A.Include(incla,filea), F.Include ((fileb, ii), (h_rel_pos, inifdef)) -> + + let include_requirment = + match mcodekind incla, mcodekind filea with + | A.CONTEXT (_, A.BEFORE _), _ -> + IncludeMcodeBefore + | _, A.CONTEXT (_, A.AFTER _) -> + IncludeMcodeAfter + | _ -> + IncludeNothing + in + + let (inclb, iifileb) = tuple_of_list2 ii in + if inc_file (term filea, include_requirment) (fileb, h_rel_pos) + then + tokenf incla inclb >>= (fun incla inclb -> + tokenf filea iifileb >>= (fun filea iifileb -> + return ( + A.Include(incla, filea), + F.Include ((fileb, [inclb;iifileb]), (h_rel_pos, inifdef)) + ))) + else fail + + + + | A.DefineHeader(definea,ida,params), F.DefineHeader ((idb, ii), defkind) -> + let (defineb, iidb, ieol) = tuple_of_list3 ii in + ident DontKnow ida (idb, iidb) >>= (fun ida (idb, iidb) -> + tokenf definea defineb >>= (fun definea defineb -> + (match A.unwrap params, defkind with + | A.NoParams, B.DefineVar -> + return ( + A.NoParams +> A.rewrap params, + B.DefineVar + ) + | A.DParams(lpa,eas,rpa), (B.DefineFunc (ebs, ii)) -> + let (lpb, rpb) = tuple_of_list2 ii in + tokenf lpa lpb >>= (fun lpa lpb -> + tokenf rpa rpb >>= (fun rpa rpb -> + + define_params (seqstyle eas) (A.undots eas) ebs >>= + (fun easundots ebs -> + let eas = redots eas easundots in + return ( + A.DParams (lpa,eas,rpa) +> A.rewrap params, + B.DefineFunc (ebs,[lpb;rpb]) + ) + ))) + | _ -> fail + ) >>= (fun params defkind -> + return ( + A.DefineHeader (definea, ida, params), + F.DefineHeader ((idb,[defineb;iidb;ieol]),defkind) + )) + )) + + + | A.Default(def,colon), F.Default (st, ((),ii)) -> + let (ib1, ib2) = tuple_of_list2 ii in + tokenf def ib1 >>= (fun def ib1 -> + tokenf colon ib2 >>= (fun colon ib2 -> + return ( + A.Default(def,colon), + F.Default (st, ((),[ib1;ib2])) + ))) + + + + | A.Case(case,ea,colon), F.Case (st, (eb,ii)) -> + let (ib1, ib2) = tuple_of_list2 ii in + tokenf case ib1 >>= (fun case ib1 -> + expression ea eb >>= (fun ea eb -> + tokenf colon ib2 >>= (fun colon ib2 -> + return ( + A.Case(case,ea,colon), + F.Case (st, (eb,[ib1;ib2])) + )))) + + (* only occurs in the predicates generated by asttomember *) + | A.DisjRuleElem eas, _ -> + (eas +> + List.fold_left (fun acc ea -> acc >|+|> (rule_elem_node ea node)) fail) + >>= (fun ea eb -> return (A.unwrap ea,F.unwrap eb)) + + | _, F.ExprStatement (_, (None, ii)) -> fail (* happen ? *) + + | A.Label(id,dd), F.Label (st,(s,ii)) -> + let (ib1,ib2) = tuple_of_list2 ii in + let (string_of_id,rebuild) = + match A.unwrap id with + A.Id(s) -> (s,function s -> A.rewrap id (A.Id(s))) + | _ -> failwith "labels with metavariables not supported" in + if (term string_of_id) =$= s + then + tokenf string_of_id ib1 >>= (fun string_of_id ib1 -> + tokenf dd ib2 >>= (fun dd ib2 -> + return ( + A.Label(rebuild string_of_id,dd), + F.Label (st,(s,[ib1;ib2])) + ))) + else fail + + | A.Goto(goto,id,sem), F.Goto (st,(s,ii)) -> + let (ib1,ib2,ib3) = tuple_of_list3 ii in + tokenf goto ib1 >>= (fun goto ib1 -> + ident DontKnow id (s, ib2) >>= (fun id (s, ib2) -> + tokenf sem ib3 >>= (fun sem ib3 -> + return( + A.Goto(goto,id,sem), + F.Goto (st,(s,[ib1;ib2;ib3])) + )))) + + (* have not a counter part in coccinelle, for the moment *) + (* todo?: print a warning at least ? *) + | _, F.CaseRange _ + | _, F.Asm _ + | _, F.Ifdef _ + | _, F.MacroTop _ + -> fail2() + + + | _, _ -> fail + ) +end + diff --git a/engine/cocci_vs_c_3.mli b/engine/cocci_vs_c_3.mli new file mode 100644 index 0000000..57cbe35 --- /dev/null +++ b/engine/cocci_vs_c_3.mli @@ -0,0 +1,181 @@ +(*****************************************************************************) +(* Cocci vs C *) +(*****************************************************************************) + +(* This module was introduced to factorize code between + * pattern.ml and transformation.ml. In both cases we need + * to "compare" a piece of C with a piece of Cocci, and depending + * if we want just to pattern or transform, we perform different + * actions on the tokens. So, the common code is in this module + * and the module specific actions are in pattern.ml and transformation.ml. + * + * We could have used a visitor approach as in visitor_c but I prefer + * this time to use a functor. The specific actions are passed + * via a module to the functor. + * + * If the functor is too complex too understand, you can look at + * the comments in pattern.ml and transformation.ml to look at + * how it was done before, which may help to understand how + * it is done now. + * + * You can also look at the papers on parser combinators in haskell + * (cf a pearl by meijer in ICFP) to understand our monadic + * approach to matching/unifying. + *) + + +(* should be used as less as possible. Most of the time the code in + * cocci_vs_c should be the same if we pattern or transform *) +type mode = PatternMode | TransformMode + +(* used in both pattern and transform, in envf *) +val equal_metavarval : + Ast_c.metavar_binding_kind -> Ast_c.metavar_binding_kind -> bool + +(*****************************************************************************) +(* The parameter of the functor (the specific actions) *) +(*****************************************************************************) + + +module type PARAM = + sig + type tin + type 'a tout + + (* a matcher between 'a' and 'b' take 'a' and 'b' in parameter, + * and "something" (tin; a state that is threaded across calls), + * and return a new 'a' and 'b' encapsulated in "something" (tout) + *) + type ('a, 'b) matcher = 'a -> 'b -> tin -> ('a * 'b) tout + + val mode : mode + + (* -------------------------------------------------------------------- *) + (* The monadic combinators *) + (* -------------------------------------------------------------------- *) + + (* it kinds of take a matcher in parameter, and another matcher, + * and returns a matcher, so =~ matcher -> matcher -> matcher + *) + val ( >>= ) : + (tin -> ('a * 'b) tout) -> + ('a -> 'b -> tin -> ('c * 'd) tout) -> + tin -> ('c * 'd) tout + + val return : 'a * 'b -> tin -> ('a * 'b) tout + val fail : tin -> ('a * 'b) tout + + val ( >||> ) : (tin -> 'a tout) -> (tin -> 'a tout) -> tin -> 'a tout + val ( >|+|> ) : (tin -> 'a tout) -> (tin -> 'a tout) -> tin -> 'a tout + val ( >&&> ) : (tin -> bool) -> (tin -> 'a tout) -> tin -> 'a tout + + (* -------------------------------------------------------------------- *) + (* Tokens tagging *) + (* -------------------------------------------------------------------- *) + val tokenf : ('a Ast_cocci.mcode, Ast_c.info) matcher + val tokenf_mck : (Ast_cocci.mcodekind, Ast_c.info) matcher + + (* -------------------------------------------------------------------- *) + (* Distr_f functions, to tag a range of tokens *) + (* -------------------------------------------------------------------- *) + + val distrf_e : + (Ast_cocci.meta_name Ast_cocci.mcode, Ast_c.expression) matcher + + val distrf_args : + (Ast_cocci.meta_name Ast_cocci.mcode, + (Ast_c.argument, Ast_c.il) Common.either list) + matcher + + val distrf_type : + (Ast_cocci.meta_name Ast_cocci.mcode, Ast_c.fullType) matcher + + val distrf_params : + (Ast_cocci.meta_name Ast_cocci.mcode, + (Ast_c.parameterType, Ast_c.il) Common.either list) + matcher + val distrf_param : + (Ast_cocci.meta_name Ast_cocci.mcode, Ast_c.parameterType) matcher + + val distrf_ini : + (Ast_cocci.meta_name Ast_cocci.mcode, Ast_c.initialiser) matcher + + val distrf_node : + (Ast_cocci.meta_name Ast_cocci.mcode, Control_flow_c.node) matcher + + val distrf_define_params : + (Ast_cocci.meta_name Ast_cocci.mcode, + (string Ast_c.wrap, Ast_c.il) Common.either list) + matcher + + val distrf_struct_fields : + (Ast_cocci.meta_name Ast_cocci.mcode, Ast_c.field Ast_c.wrap list) + matcher + + val distrf_cst : + (Ast_cocci.meta_name Ast_cocci.mcode, + (Ast_c.constant, string) Common.either Ast_c.wrap) + matcher + + (* -------------------------------------------------------------------- *) + (* Modifying nested expression and nested types, with Exp and Ty *) + (* -------------------------------------------------------------------- *) + + val cocciExp : + (Ast_cocci.expression, Ast_c.expression) matcher -> + (Ast_cocci.expression, Control_flow_c.node) matcher + + val cocciExpExp : + (Ast_cocci.expression, Ast_c.expression) matcher -> + (Ast_cocci.expression, Ast_c.expression) matcher + + val cocciTy : + (Ast_cocci.fullType, Ast_c.fullType) matcher -> + (Ast_cocci.fullType, Control_flow_c.node) matcher + + (* -------------------------------------------------------------------- *) + (* Environment manipulation. Extract info from tin, the "something" *) + (* -------------------------------------------------------------------- *) + val envf : + Ast_cocci.keep_binding -> + Ast_cocci.inherited -> + Ast_cocci.meta_name Ast_cocci.mcode * Ast_c.metavar_binding_kind * + (* pos info, if needed *) + (unit -> Common.filename * Ast_c.posl * Ast_c.posl) -> + (unit -> tin -> 'x tout) -> (tin -> 'x tout) + + val check_constraints : + ('a, 'b) matcher -> 'a list -> 'b -> + (unit -> tin -> 'x tout) -> (tin -> 'x tout) + + val all_bound : Ast_cocci.meta_name list -> tin -> bool + + + val optional_storage_flag : (bool -> tin -> 'x tout) -> (tin -> 'x tout) + val optional_qualifier_flag : (bool -> tin -> 'x tout) -> (tin -> 'x tout) + val value_format_flag: (bool -> tin -> 'x tout) -> (tin -> 'x tout) + + + end + + +(*****************************************************************************) +(* The functor itself *) +(*****************************************************************************) + +module COCCI_VS_C : + functor (X : PARAM) -> + sig + type ('a, 'b) matcher = 'a -> 'b -> X.tin -> ('a * 'b) X.tout + + val rule_elem_node : (Ast_cocci.rule_elem, Control_flow_c.node) matcher + + val expression : (Ast_cocci.expression, Ast_c.expression) matcher + + (* there is far more functions in this functor but they do not have + * to be exported + *) + + end + + diff --git a/engine/ctlcocci_integration.ml b/engine/ctlcocci_integration.ml new file mode 100644 index 0000000..5f736aa --- /dev/null +++ b/engine/ctlcocci_integration.ml @@ -0,0 +1,422 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Common + +open Ograph_extended + +module F = Control_flow_c + +(*****************************************************************************) +(* Debugging functions *) +(*****************************************************************************) +let show_or_not_predicate pred = + if !Flag_engine.debug_engine then begin + indent_do (fun () -> + adjust_pp_with_indent_and_header "labeling: pred = " (fun () -> + Pretty_print_engine.pp_predicate pred; + ); + ) + end + +let show_or_not_nodes nodes = + if !Flag_engine.debug_engine then begin + indent_do (fun () -> + adjust_pp_with_indent_and_header "labeling: result = " (fun () -> + Common.pp_do_in_box (fun () -> + pp "{"; + Common.print_between + (fun () -> pp ";"; Format.print_cut()) + (fun (nodei, (_predTODO, subst)) -> + Format.print_int nodei; + Common.pp_do_in_box (fun () -> + Pretty_print_engine.pp_binding2_ctlsubst subst + ) + ) nodes; + pp "}"; + ); + ) + ) + end + +let show_isos rule_elem = + match Ast_cocci.get_isos rule_elem with + [] -> () + | isos -> + let line = Ast_cocci.get_line rule_elem in + Printf.printf "rule elem: "; + Pretty_print_cocci.rule_elem "" rule_elem; + Format.print_newline(); + List.iter + (function (nm,x) -> + Printf.printf " iso: %s(%d): " nm line; + Pretty_print_cocci.pp_print_anything x; + Format.print_newline()) + isos + +(*****************************************************************************) +(* Labeling function *) +(*****************************************************************************) +let (-->) x v = Ast_ctl.Subst (x,v);; + +(* Take list of predicate and for each predicate returns where in the + * control flow it matches, and the set of subsitutions for this match. + *) +let (labels_for_ctl: string list (* dropped isos *) -> + (nodei * F.node) list -> Lib_engine.metavars_binding -> + Lib_engine.label_ctlcocci) = + fun dropped_isos nodes binding -> + + (fun p -> + show_or_not_predicate p; + + let nodes' = nodes +> List.map (fun (nodei, node) -> + (* todo? put part of this code in pattern ? *) + (match p, F.unwrap node with + | Lib_engine.Paren s, (F.SeqStart (_, bracelevel, _)) -> + let make_var x = ("",i_to_s x) in + [(nodei, (p,[(s --> (Lib_engine.ParenVal (make_var bracelevel)))]))] + | Lib_engine.Paren s, (F.SeqEnd (bracelevel, _)) -> + let make_var x = ("",i_to_s x) in + [(nodei, (p,[(s --> (Lib_engine.ParenVal (make_var bracelevel)))]))] + | Lib_engine.Paren _, _ -> [] + | Lib_engine.Label s, _ -> + let labels = F.extract_labels node in + [(nodei, (p,[(s --> (Lib_engine.LabelVal labels))]))] + | Lib_engine.BCLabel s, _ -> + (match F.extract_bclabels node with + [] -> [] (* null for all nodes that are not break or continue *) + | labels -> + [(nodei, (p,[(s --> (Lib_engine.LabelVal labels))]))]) + | Lib_engine.PrefixLabel s, _ -> + let labels = F.extract_labels node in + let prefixes = Common.inits labels +> Common.tail in + prefixes +> List.map (fun prefixlabels -> + (nodei, (p,[(s --> (Lib_engine.LabelVal prefixlabels))])) + ) + + | Lib_engine.Match (re), _unwrapnode -> + let substs = + Pattern3.match_re_node dropped_isos re node binding + +> List.map (fun (re', subst) -> + Lib_engine.Match (re'), subst + ) + in + substs +> List.map (fun (p', subst) -> + (nodei, + (p', + subst +> List.map (fun (s, meta) -> + s --> Lib_engine.NormalMetaVal meta + )))) + + | Lib_engine.InLoop, F.InLoopNode -> [nodei, (p,[])] + | Lib_engine.TrueBranch , F.TrueNode -> [nodei, (p,[])] + | Lib_engine.FalseBranch, F.FalseNode -> [nodei, (p,[])] + | Lib_engine.After, F.AfterNode -> [nodei, (p,[])] + | Lib_engine.FallThrough, F.FallThroughNode -> [nodei,(p,[])] + | Lib_engine.FunHeader, F.FunHeader _ -> [nodei, (p,[])] + | Lib_engine.Top, F.TopNode -> [nodei, (p,[])] + | Lib_engine.Exit, F.Exit -> [nodei, (p,[])] + | Lib_engine.ErrorExit, F.ErrorExit -> [nodei, (p,[])] + | Lib_engine.Goto, F.Goto(_,_) -> [nodei, (p,[])] + + | Lib_engine.InLoop , _ -> [] + | Lib_engine.TrueBranch , _ -> [] + | Lib_engine.FalseBranch, _ -> [] + | Lib_engine.After, _ -> [] + | Lib_engine.FallThrough, _ -> [] + | Lib_engine.FunHeader, _ -> [] + | Lib_engine.Top, _ -> [] + | Lib_engine.Exit, _ -> [] + | Lib_engine.ErrorExit, _ -> [] + | Lib_engine.Goto, _ -> [] + + | Lib_engine.BindGood s, _ -> [(nodei, (p,[(s --> Lib_engine.GoodVal)]))] + | Lib_engine.BindBad s, _ -> [(nodei, (p,[(s --> Lib_engine.BadVal)]))] + | Lib_engine.FakeBrace, _ -> + if F.extract_is_fake node then [nodei, (p,[])] else [] + + | Lib_engine.Return, node -> + (match node with + (* todo? should match the Exit code ? + * todo: one day try also to match the special function + * such as panic(); + *) + | F.Return _ -> [nodei, (p,[])] + | F.ReturnExpr _ -> [nodei, (p,[])] + | _ -> [] + ) + ) + ) +> List.concat + in + + show_or_not_nodes nodes'; + nodes' + ) + +(*****************************************************************************) +(* Some fix flow, for CTL, for unparse *) +(*****************************************************************************) +(* could erase info on nodes, and edge, because they are not used by rene *) +let (control_flow_for_ctl: F.cflow -> ('a, 'b) ograph_mutable) = + fun cflow -> cflow + + + +(* Just make the final node of the control flow loop over itself. + * It seems that one hypothesis of the SAT algorithm is that each node as at + * least a successor. + * + * update: do same for errorexit node. + * + * update: also erase the fake nodes (and adjust the edges accordingly), + * so that AX in CTL can now work. + * Indeed, à la fin de la branche then (et else), on devrait aller directement + * au suivant du endif, sinon si ecrit if(1) { foo(); }; bar(); + * sans '...' entre le if et bar(), alors ca matchera pas car le CTL + * generera un AX bar() qui il tombera d'abord sur le [endif] :( + * Mais chiant de changer l'algo de generation, marche pas tres bien avec + * ma facon de faire recursive et compositionnel. + * => faire une fonction qui applique des fixes autour de ce control flow, + * comme ca passe un bon flow a rene, mais garde un flow a moi pour pouvoir + * facilement generate back the ast. + * alt: faire un wrapper autourde mon graphe pour lui passer dans le module CFG + * une fonction qui passe a travers les Fake, mais bof. + * + * update: also make loop the deadcode nodes, the one that have + * no predecessor. + *) +let (fix_flow_ctl2: F.cflow -> F.cflow) = fun flow -> + let g = ref flow in + + let topi = F.first_node !g in + !g#add_arc ((topi, topi), F.Direct); + + (* for the #define CFG who have no Exit but have at least a EndNode *) + (try + let endi = F.find_node (fun x -> x = F.EndNode) !g in + !g#add_arc ((endi, endi), F.Direct); + with Not_found -> () + ); + + (* for the regular functions *) + (try + let exitnodei = F.find_node (fun x -> x = F.Exit) !g in + let errornodei = F.find_node (fun x -> x = F.ErrorExit) !g in + + !g#add_arc ((exitnodei, exitnodei), F.Direct); + + if null ((!g#successors errornodei)#tolist) && + null ((!g#predecessors errornodei)#tolist) + then !g#del_node errornodei + else !g#add_arc ((errornodei, errornodei), F.Direct); + with Not_found -> () + ); + + let fake_nodes = !g#nodes#tolist +> List.filter (fun (nodei, node) -> + match F.unwrap node with + | F.CaseNode _ + | F.Enter + (*| F.Fake*) (* [endif], [endswitch], ... *) + -> true + | _ -> false + ) in + + fake_nodes +> List.iter (fun (nodei, node) -> F.remove_one_node nodei !g); + + (* even when have deadcode, julia want loop over those nodes *) + !g#nodes#tolist +> List.iter (fun (nodei, node) -> + if (!g#predecessors nodei)#null + then begin + let fakei = !g#add_node (F.mk_node F.Fake [] [] "DEADCODELOOP") in + !g#add_arc ((fakei, nodei), F.Direct); + !g#add_arc ((fakei, fakei), F.Direct); + end + ); + + !g#nodes#tolist +> List.iter (fun (nodei, node) -> + assert (List.length ((!g#successors nodei)#tolist) >= 1); + (* no: && List.length ((!g#predecessors nodei)#tolist) >= 1 + because the enter node at least have no predecessors *) + ); + + !g +let fix_flow_ctl a = + Common.profile_code "fix_flow" (fun () -> fix_flow_ctl2 a) + + + + + +(*****************************************************************************) +(* subtil: the label must operate on newflow, not (old) cflow + * update: now I supposed that we give me a fixed_flow + *) +let model_for_ctl dropped_isos cflow binding = + let newflow = cflow (* old: fix_flow_ctl (control_flow_for_ctl cflow) *) in + let labels = labels_for_ctl dropped_isos (newflow#nodes#tolist) binding in + let states = List.map fst newflow#nodes#tolist in + newflow, labels, states + + +(*****************************************************************************) + +module PRED = + struct + type t = Lib_engine.predicate + let print_predicate x = + Pretty_print_cocci.print_plus_flag := false; + Pretty_print_cocci.print_minus_flag := false; + Pretty_print_engine.pp_predicate x + end + +module ENV = + struct + type value = Lib_engine.metavar_binding_kind2 + type mvar = Ast_cocci.meta_name + let eq_mvar x x' = x = x' + let eq_val v v' = + (* v = v' *) + match (v,v') with + (Lib_engine.NormalMetaVal(Ast_c.MetaPosVal(min1,max1)), + Lib_engine.NormalMetaVal(Ast_c.MetaPosVal(min2,max2))) -> + ((min1 <= min2) && (max1 >= max2)) or + ((min2 <= min1) && (max2 >= max1)) + | (Lib_engine.NormalMetaVal(Ast_c.MetaTypeVal a), + Lib_engine.NormalMetaVal(Ast_c.MetaTypeVal b)) -> + C_vs_c.eq_type a b + | _ -> v = v' + let merge_val v v' = (* values guaranteed to be compatible *) + (* v *) + match (v,v') with + (Lib_engine.NormalMetaVal(Ast_c.MetaPosVal(min1,max1)), + Lib_engine.NormalMetaVal(Ast_c.MetaPosVal(min2,max2))) -> + if (min1 <= min2) && (max1 >= max2) + then Lib_engine.NormalMetaVal(Ast_c.MetaPosVal(min1,max1)) + else + if (min2 <= min1) && (max2 >= max1) + then Lib_engine.NormalMetaVal(Ast_c.MetaPosVal(min2,max2)) + else failwith "incompatible positions give to merge" + | (Lib_engine.NormalMetaVal(Ast_c.MetaTypeVal a), + Lib_engine.NormalMetaVal(Ast_c.MetaTypeVal b)) -> + Lib_engine.NormalMetaVal (Ast_c.MetaTypeVal (C_vs_c.merge_type a b)) + + | _ -> v + let print_mvar (_,s) = Format.print_string s + let print_value x = Pretty_print_engine.pp_binding_kind2 x + end + +module CFG = + struct + type node = int + type cfg = (F.node, F.edge) Ograph_extended.ograph_mutable + let predecessors cfg n = List.map fst ((cfg#predecessors n)#tolist) + let successors cfg n = List.map fst ((cfg#successors n)#tolist) + let extract_is_loop cfg n = + Control_flow_c.extract_is_loop (cfg#nodes#find n) + let print_node i = Format.print_string (i_to_s i) + let size cfg = cfg#nodes#length + end + + +module WRAPPED_ENGINE = Wrapper_ctl.CTL_ENGINE_BIS (ENV) (CFG) (PRED) + +let print_bench _ = WRAPPED_ENGINE.print_bench() + +type pred = Lib_engine.predicate * Ast_cocci.meta_name Ast_ctl.modif + +(*****************************************************************************) +let metavars_binding2_to_binding binding2 = + binding2 +> Common.map_filter (fun (s, kind2) -> + match kind2 with + | Lib_engine.NormalMetaVal kind -> Some (s, kind) + (* I thought it was Impossible to have this when called from + satbis_to_trans_info but it does not seems so *) + | Lib_engine.ParenVal _ -> None + | Lib_engine.LabelVal _ -> None + | Lib_engine.BadVal -> None (* should not occur *) + | Lib_engine.GoodVal -> None (* should not occur *) + ) + +let metavars_binding_to_binding2 binding = + binding +> List.map (fun (s, kind) -> s, Lib_engine.NormalMetaVal kind) + + +let (satbis_to_trans_info: + (nodei * Lib_engine.metavars_binding2 * Lib_engine.predicate) list -> + (nodei * Lib_engine.metavars_binding * Ast_cocci.rule_elem) list) = + fun xs -> + xs +> List.fold_left (fun prev (nodei, binding2, pred) -> + match pred with + | Lib_engine.Match (rule_elem) -> + if !Flag.track_iso_usage then show_isos rule_elem; + (nodei, metavars_binding2_to_binding binding2, rule_elem) + ::prev + (* see BindGood in asttotctl2 *) + | Lib_engine.BindGood (_) -> prev + | _ -> raise Impossible + ) [] + +(*****************************************************************************) + +let rec coalesce_positions = function + [] -> [] + | (x,Ast_c.MetaPosValList l)::rest -> + let (same,others) = List.partition (function (x1,_) -> x = x1) rest in + let ls = + List.concat + (List.map + (function + (_,Ast_c.MetaPosValList l) -> l + | _ -> failwith "unexpected non-position") + same) in + let new_ls = List.sort compare (l@ls) in + (x,Ast_c.MetaPosValList new_ls) :: coalesce_positions others + | x::rest -> x :: coalesce_positions rest + +(*****************************************************************************) +(* Call ctl engine *) +(*****************************************************************************) +let (mysat2: + Lib_engine.model -> + (Lib_engine.ctlcocci * (pred list list)) -> + (Lib_engine.mvar list*Lib_engine.metavars_binding) -> + (Lib_engine.transformation_info * bool * Lib_engine.metavars_binding list)) = + fun (flow, label, states) ctl (used_after, binding) -> + let binding2 = metavars_binding_to_binding2 binding in + let (triples,(trans_info2, returned_any_states, used_after_envs)) = + WRAPPED_ENGINE.satbis (flow, label, states) ctl (used_after, binding2) + in + if not (!Flag_parsing_cocci.sgrep_mode || !Flag.sgrep_mode2 || + !Flag_engine.allow_inconsistent_paths) + then Check_reachability.check_reachability triples flow; + let (trans_info2,used_after_fresh_envs) = + Postprocess_transinfo.process used_after binding2 trans_info2 in + let used_after_envs = + Common.uniq(List.map2 (@) used_after_fresh_envs used_after_envs) in + let trans_info = satbis_to_trans_info trans_info2 in + let newbindings = List.map metavars_binding2_to_binding used_after_envs in + let newbindings = List.map coalesce_positions newbindings in + (trans_info, returned_any_states, newbindings) + +let mysat a b c = + Common.profile_code "mysat" (fun () -> mysat2 a b c) diff --git a/engine/ctlcocci_integration.mli b/engine/ctlcocci_integration.mli new file mode 100644 index 0000000..8dbeb76 --- /dev/null +++ b/engine/ctlcocci_integration.mli @@ -0,0 +1,25 @@ +open Ograph_extended + +val labels_for_ctl : + string list (* dropped isos *) -> + (nodei * Control_flow_c.node) list -> Lib_engine.metavars_binding -> + Lib_engine.label_ctlcocci + + +val fix_flow_ctl : Control_flow_c.cflow -> Control_flow_c.cflow + +val model_for_ctl : + string list (* dropped isos *) -> + Control_flow_c.cflow -> Lib_engine.metavars_binding -> Lib_engine.model + + +type pred = Lib_engine.predicate * Ast_cocci.meta_name Ast_ctl.modif + +val mysat : + Lib_engine.model -> + (Lib_engine.ctlcocci * (pred list list)) -> + (Lib_engine.mvar list * Lib_engine.metavars_binding) -> + (Lib_engine.transformation_info * bool * Lib_engine.metavars_binding list) + + +val print_bench : unit -> unit diff --git a/engine/ctltotex.ml b/engine/ctltotex.ml new file mode 100644 index 0000000..20b188e --- /dev/null +++ b/engine/ctltotex.ml @@ -0,0 +1,308 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module CTL = Ast_ctl + +let prelude = + "\\documentclass{article}\n"^ + "\\usepackage{fullpage}\n\n"^ + "\\newcommand{\\U}{\\,\\mbox{\\sf{U}}\\,}\n"^ + "\\newcommand{\\A}{\\mbox{\\sf{A}}}\n"^ + "\\newcommand{\\E}{\\mbox{\\sf{E}}}\n"^ + "\\newcommand{\\AX}{\\mbox{\\sf{AX}}}\n"^ + "\\newcommand{\\EX}{\\mbox{\\sf{EX}}}\n"^ + "\\newcommand{\\AF}{\\mbox{\\sf{AF}}}\n"^ + "\\newcommand{\\EF}{\\mbox{\\sf{EF}}}\n"^ + "\\newcommand{\\AG}{\\mbox{\\sf{AG}}}\n"^ + "\\newcommand{\\EG}{\\mbox{\\sf{EG}}}\n\n"^ + "\\newcommand{\\mita}[1]{\\mbox{\\it{{#1}}}}\n"^ + "\\newcommand{\\mtt}[1]{\\mbox{\\tt{{#1}}}}\n"^ + "\\newcommand{\\msf}[1]{\\mbox{\\sf{{#1}}}}\n"^ + "\\newcommand{\\mrm}[1]{\\mbox{\\rm{{#1}}}}\n"^ + "\\newcommand{\\mth}[1]{\\({#1}\\)}\n\n"^ + "\\newcommand{\\ttlb}{\\mbox{\\tt \\char'173}}\n"^ + "\\newcommand{\\ttrb}{\\mbox{\\tt \\char'175}}\n\n"^ + "\\begin{document}\n" + +let postlude = "\\end{document}" + +let check_ct ct res = if ct > 60 then (res^"\\\\\\mbox{}",0) else (res,ct) +let texify s = + let len = String.length s in + let rec loop n = + if n = len + then "" + else + match String.get s n with + '_' -> Printf.sprintf "\\_%s" (loop (n+1)) + | '{' -> Printf.sprintf "{\\ttlb}%s" (loop (n+1)) + | '}' -> Printf.sprintf "{\\ttrb}%s" (loop (n+1)) + | '>' -> Printf.sprintf "\\mth{>}%s" (loop (n+1)) + | c -> Printf.sprintf "%c%s" c (loop (n+1)) in + (Printf.sprintf "\\mita{%s}" (loop 0),len) + +let modif2c pv = function + CTL.Modif(v) -> let (s,n) = texify(pv v) in (Printf.sprintf "_{%s}" s,n) + | CTL.UnModif(v) -> let (s,n) = texify(pv v) in (Printf.sprintf "_{%s}" s,n) + | CTL.Control -> ("",0) + +let print_diamond ct = function + CTL.FORWARD -> ("",ct) + | CTL.BACKWARD -> ("\\Delta",ct+1) + +let rec ctl2c ct pp pv = function + CTL.False -> ("\\msf{false}",5) + | CTL.True -> ("\\msf{true}",4) + | CTL.Pred(p,v) -> + let (res,n) = pp p in + let (resv,n1) = modif2c pv v in + (res^resv,ct+n+n1) + | CTL.Not(f) -> + let (res,ct) = wrap (ct+1) pp pv f in + ("\\neg "^res,ct) + | CTL.Exists(_,v,f) -> + let (res1,len) = texify(pv v) in + let ct = ct + len in + let (res1,ct) = check_ct ct res1 in + let (res2,ct) = existswrap (ct+1) pp pv f in + ("\\exists "^res1^" . "^res2,ct) + | CTL.And(_,f1,f2) -> + let (res1,ct) = andwrap ct pp pv f1 in + let (res1,ct) = check_ct ct res1 in + let (res2,ct) = andwrap (ct+1) pp pv f2 in + (res1^" \\wedge "^res2,ct) + | CTL.AndAny(dir,_,f1,f2) -> + let (diamond,ct) = print_diamond (ct+2) dir in + let (res1,ct) = andwrap ct pp pv f1 in + let (res1,ct) = check_ct ct res1 in + let (res2,ct) = andwrap (ct+1) pp pv f2 in + (res1^" \\wedge? "^diamond^res2,ct) + | CTL.HackForStmt(dir,_,f1,f2) -> + let (diamond,ct) = print_diamond (ct+2) dir in + let (res1,ct) = andwrap ct pp pv f1 in + let (res1,ct) = check_ct ct res1 in + let (res2,ct) = andwrap (ct+1) pp pv f2 in + (res1^" \\wedge{h} "^diamond^res2,ct) + | CTL.Or(f1,f2) -> + let (res1,ct) = orwrap ct pp pv f1 in + let (res1,ct) = check_ct ct res1 in + let (res2,ct) = orwrap (ct+1) pp pv f2 in + (res1^" \\vee "^res2,ct) + | CTL.SeqOr(f1,f2) -> + let (res1,ct) = orwrap ct pp pv f1 in + let (res1,ct) = check_ct ct res1 in + let (res2,ct) = orwrap (ct+1) pp pv f2 in + (res1^" \\mid "^res2,ct) + | CTL.Implies(f1,f2) -> + let (res1,ct) = wrap ct pp pv f1 in + let (res1,ct) = check_ct ct res1 in + let (res2,ct) = wrap (ct+1) pp pv f2 in + (res1^" \\rightarrow "^res2,ct) + | CTL.AF(dir,_,f) -> + let (diamond,ct) = print_diamond (ct+2) dir in + let (res,ct) = pathwrap ct pp pv f + in ("\\AF"^diamond^res,ct) + | CTL.AX(dir,_,f) -> + let (diamond,ct) = print_diamond (ct+2) dir in + let (res,ct) = pathwrap ct pp pv f + in ("\\AX"^diamond^res,ct) + | CTL.AG(dir,_,f) -> + let (diamond,ct) = print_diamond (ct+2) dir in + let (res,ct) = pathwrap ct pp pv f + in ("\\AG"^diamond^res,ct) + | CTL.AW(dir,_,f1,f2) -> + let (diamond,ct) = print_diamond (ct+1) dir in + let (res1,ct) = existswrap (ct+1) pp pv f1 in + let (res1,ct) = check_ct ct res1 in + let (res2,ct) = existswrap (ct+3) pp pv f2 in + ("\\"^diamond^"A["^res1^" W "^res2^"]\n",ct) + | CTL.AU(dir,_,f1,f2) -> + let (diamond,ct) = print_diamond (ct+1) dir in + let (res1,ct) = existswrap (ct+1) pp pv f1 in + let (res1,ct) = check_ct ct res1 in + let (res2,ct) = existswrap (ct+3) pp pv f2 in + ("\\"^diamond^"A["^res1^" \\U "^res2^"]\n",ct) + | CTL.EF(dir,f) -> + let (diamond,ct) = print_diamond (ct+2) dir in + let (res,ct) = pathwrap ct pp pv f + in ("\\EF"^diamond^res,ct) + | CTL.EX(dir,f) -> + let (diamond,ct) = print_diamond (ct+2) dir in + let (res,ct) = pathwrap ct pp pv f + in ("\\EX"^diamond^res,ct) + | CTL.EG(dir,f) -> + let (diamond,ct) = print_diamond (ct+2) dir in + let (res,ct) = pathwrap ct pp pv f + in ("\\EG"^diamond^res,ct) + | CTL.EU(dir,f1,f2) -> + let (diamond,ct) = print_diamond (ct+1) dir in + let (res1,ct) = existswrap (ct+1) pp pv f1 in + let (res1,ct) = check_ct ct res1 in + let (res2,ct) = existswrap (ct+3) pp pv f2 in + ("\\E"^diamond^"["^res1^" \\U "^res2^"]\n",ct) + | CTL.Ref(v) -> + let (v,len) = texify(pv (make_var v)) in (v,len+ct) + | CTL.Let(v,f1,f2) -> + let (v,len) = texify (pv (make_var v)) in + let (res1,ct) = letwrap (ct+len+5) pp pv f1 in + let (res1,ct) = check_ct ct res1 in + let (res2,ct) = letwrap (ct+3) pp pv f2 in + let (res2,ct) = check_ct ct res2 in + (Printf.sprintf + "\\mita{\\sf{let}} \\, %s = %s \\, \\mita{\\sf{in}} \\, %s\n" + v res1 res2, ct) + | CTL.LetR(d,v,f1,f2) -> + let (diamond,ct) = print_diamond (ct+2) d in + let (v,len) = texify (pv (make_var v)) in + let (res1,ct) = letwrap (ct+len+5) pp pv f1 in + let (res1,ct) = check_ct ct res1 in + let (res2,ct) = letwrap (ct+3) pp pv f2 in + let (res2,ct) = check_ct ct res2 in + (Printf.sprintf + "\\mita{\\sf{let}}%s \\, %s = %s \\, \\mita{\\sf{in}} \\, %s\n" + diamond v res1 res2, ct) + | CTL.Uncheck(f) -> + let (res,ct) = pathwrap ct pp pv f + in (res^"^u",ct+1) + | CTL.InnerAnd(f) -> + let (res,ct) = pathwrap ct pp pv f + in ("("^res^")^{innerAnd}",ct+10) + | CTL.XX(_) -> failwith "should not be printed" + +and make_var x = ("",x) + +and wrap ct pp pv x = + match x with + CTL.Ref _ | CTL.False | CTL.True | CTL.Pred(_) -> ctl2c ct pp pv x + | _ -> + let (res,ct) = ctl2c (ct+1) pp pv x in + (Printf.sprintf "(%s)" res,ct+1) + +and andwrap ct pp pv x = + match x with + CTL.Ref _ | CTL.And(_,_,_) | CTL.False | CTL.True | CTL.Pred(_) -> + ctl2c ct pp pv x + | _ -> + let (res,ct) = ctl2c (ct+1) pp pv x in + (Printf.sprintf "(%s)" res,ct+1) + +and orwrap ct pp pv x = + match x with + CTL.Ref _ | CTL.Or(_,_) | CTL.False | CTL.True | CTL.Pred(_) -> + ctl2c ct pp pv x + | _ -> + let (res,ct) = ctl2c (ct+1) pp pv x in + (Printf.sprintf "(%s)" res,ct+1) + +and pathwrap ct pp pv x = + match x with + CTL.Ref _ | CTL.AX(_,_,_) | CTL.AF(_,_,_) | CTL.AG(_,_,_) | CTL.AU(_,_,_,_) + | CTL.EX(_,_) | CTL.EF(_,_) | CTL.EG(_,_) | CTL.EU(_,_,_) -> + ctl2c ct pp pv x + | _ -> + let (res,ct) = ctl2c (ct+1) pp pv x in + (Printf.sprintf "(%s)" res,ct+1) + +and existswrap ct pp pv x = + match x with + CTL.Ref _ | CTL.AX(_,_,_) | CTL.AF(_,_,_) | CTL.AG(_,_,_) | CTL.AU(_,_,_,_) + | CTL.Pred(_) + | CTL.EX(_,_) | CTL.EF(_,_) | CTL.EG(_,_) | CTL.EU(_,_,_) | CTL.Exists(_,_,_) + | CTL.True | CTL.False | CTL.Not(_) -> + ctl2c ct pp pv x + | _ -> + let (res,ct) = ctl2c (ct+1) pp pv x in + (Printf.sprintf "(%s)" res,ct+1) + +and letwrap ct pp pv x = + match x with + CTL.Let(_,_,_) -> + let (res,ct) = ctl2c (ct+1) pp pv x in (Printf.sprintf "(%s)" res,ct+1) + | _ -> ctl2c ct pp pv x + +let ctltotex rule pp pv ctls o = + Printf.fprintf o "\\begin{quote}\\begin{verbatim}\n"; + Printf.fprintf o "%s\n" (Pretty_print_cocci.unparse_to_string rule); + Printf.fprintf o "\\end{verbatim}\\end{quote}\n\n"; + List.iter + (function ctl -> + Printf.fprintf o "\\[\\begin{array}{l}\n"; + let (res,_) = ctl2c 0 pp pv ctl in + Printf.fprintf o "%s\n" res) + ctls; + Printf.fprintf o "\\end{array}\\]\n\n" + +let make_prelude o = Printf.fprintf o "%s\n" prelude +let make_postlude o = Printf.fprintf o "%s\n" postlude + +(* ----------------------------------------------------------------------- *) + +let meta2c (_,s) = s + +let pred2c = function + Lib_engine.InLoop -> ("\\msf{InLoop}",6) + | Lib_engine.TrueBranch -> ("\\msf{TrueBranch}",10) + | Lib_engine.FalseBranch -> ("\\msf{FalseBranch}",11) + | Lib_engine.After -> ("\\msf{After}",5) + | Lib_engine.FallThrough -> ("\\msf{FallThrough}",11) + | Lib_engine.Return -> ("\\msf{Return}",6) + | Lib_engine.FunHeader -> ("\\msf{FunHeader}",9) + | Lib_engine.Top -> ("\\msf{Top}",3) + | Lib_engine.Exit -> ("\\msf{Exit}",4) + | Lib_engine.ErrorExit -> ("\\msf{ErrorExit}",9) + | Lib_engine.Paren(s) -> + let s = meta2c s in + ("\\msf{Paren}("^s^")",7+(String.length s)) + | Lib_engine.Label(s) -> + let s = meta2c s in + ("\\msf{Label}("^s^")",7+(String.length s)) + | Lib_engine.BCLabel(s) -> + let s = meta2c s in + ("\\msf{BreakContinueLabel}("^s^")",20+(String.length s)) + | Lib_engine.PrefixLabel(s) -> + let s = meta2c s in + ("\\msf{PrefixLabel}("^s^")",13+(String.length s)) + | Lib_engine.Match(re) -> + let s = Pretty_print_cocci.rule_elem_to_string re in + let (s,len) = texify s in + (Printf.sprintf "%s" s,len) + | Lib_engine.BindGood(nm) -> + let s = meta2c nm in + ("\\msf{Good}("^s^")",6+(String.length s)) + | Lib_engine.BindBad(nm) -> + let s = meta2c nm in + ("\\msf{Bad}("^s^")",5+(String.length s)) + | Lib_engine.Goto -> ("goto",4) + | Lib_engine.FakeBrace -> ("fake\\_brace",10) + +let totex out_file rules ctls = + let o = open_out out_file in + make_prelude o; + List.iter2 + (function ast_list -> + function ctls -> + let (ctls,_) = List.split ctls in + ctltotex ast_list pred2c (function (_,x) -> x) ctls o) + rules ctls; + make_postlude o; + close_out o + diff --git a/engine/ctltotex.mli b/engine/ctltotex.mli new file mode 100644 index 0000000..68354f5 --- /dev/null +++ b/engine/ctltotex.mli @@ -0,0 +1,7 @@ +val totex : + string -> + Ast_cocci.rule list -> + ((Lib_engine.predicate * Ast_cocci.meta_name Ast_ctl.modif, + Ast_cocci.meta_name,Wrapper_ctl.info) + Ast_ctl.generic_ctl * 'a) list list -> + unit diff --git a/engine/flag_engine.ml b/engine/flag_engine.ml new file mode 100644 index 0000000..3140109 --- /dev/null +++ b/engine/flag_engine.ml @@ -0,0 +1,34 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +let debug_engine = ref false + +(* false = simpler formulas, only for debugging *) +let useEU = ref true + +let disallow_nested_exps = ref false + +(* if this flag is not set, then break and continue are also error exits *) +let only_return_is_error_exit = ref false + +(* a hack to allow adding code in some more sgrep-like uses *) +let allow_inconsistent_paths = ref false diff --git a/engine/isomorphisms_c_c.ml b/engine/isomorphisms_c_c.ml new file mode 100644 index 0000000..d4a4074 --- /dev/null +++ b/engine/isomorphisms_c_c.ml @@ -0,0 +1,72 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Common + +(* When in a semantic patch there is f(X) ... f(X) we want to force + * the two X to be equal in the concrete code, but we would like that + * there be equal modulo some isomorphisms, so that the following + * concrete code also match: f(a && b) g(); f(b && a) + + * Maybe would be easier to transform ast_c in ast_cocci and call the + * iso engine of julia. *) + +open Ast_c + +let rec (iso_e_e: expression -> expression -> bool) = fun a b -> + raise Todo + (* + let rec (=~=) a b = + match (a, b) with + | (Ident a, typa, iia), (Ident b, typb, iib) -> a = b + | (Constant a, typa, iia), (Constant b, typb, iib) -> a = b + | (FunCall (ea, eas), typa, iia), (FunCall (eb, ebs), typb, iib) -> + ea =~= eb && + List.length eas = List.length ebs && + List.for_all (fun (a, b) -> + match (a, b) with + | (Left ea, iia), (Left eb, iib) -> ea =~= eb + | _ -> raise Todo + ) + (zip eas ebs) + | (Binary (ea1,Logical AndLog,ea2),typa, iia), (Binary (eb1,Logical AndLog, eb2), typb, iib) -> + (ea1 =~= eb1 && ea2 =~= eb2) + || + (ea1 =~= eb2 && ea2 =~= eb1) + + | _ -> raise Todo + in + a =~= b + *) + +and (iso_st_st: statement -> statement -> bool) = fun a b -> + raise Todo +and (iso_t_t: fullType -> fullType -> bool) = fun a b -> + raise Todo + + +(* +let _ = assert (iso_e_e + (cexpression_of_string "a&&b") + (cexpression_of_string "b&&a") +*) + diff --git a/engine/lib_engine.ml b/engine/lib_engine.ml new file mode 100644 index 0000000..ba36fc4 --- /dev/null +++ b/engine/lib_engine.ml @@ -0,0 +1,84 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Ograph_extended + +(*****************************************************************************) +(* the different ctl formula related types *) +(*****************************************************************************) +type mvar = Ast_cocci.meta_name + +type predicate = + InLoop | TrueBranch | FalseBranch + | After (* pointer to the code after an if or while *) + | FallThrough + | Return (* any exit from the current function *) + | FunHeader | Top | Exit | ErrorExit | Goto + | Paren of Ast_cocci.meta_name + | Match of Ast_cocci.rule_elem + | Label of Ast_cocci.meta_name + | BCLabel of Ast_cocci.meta_name (* parent of break or continue *) + | PrefixLabel of Ast_cocci.meta_name + | BindGood of Ast_cocci.meta_name (* used to implement \+ *) + | BindBad of Ast_cocci.meta_name + | FakeBrace + +type ctlcocci = (predicate, Ast_cocci.meta_name) Wrapper_ctl.wrapped_ctl + + +(*****************************************************************************) +(* the different binding types *) +(*****************************************************************************) +type metavars_binding = Ast_c.metavars_binding + +(* used in ctlcocci_integration *) +type metavar_binding_kind2 = + | NormalMetaVal of Ast_c.metavar_binding_kind + | ParenVal of Ast_cocci.meta_name + | LabelVal of int list + | GoodVal | BadVal (* used to implement \+ *) + +and metavars_binding2 = (mvar, metavar_binding_kind2) Common.assoc + + + +(*****************************************************************************) +(* the CTL model related types *) +(*****************************************************************************) +type label_ctlcocci = + predicate -> + (nodei * + (predicate * (mvar, metavar_binding_kind2) Ast_ctl.generic_substitution)) + list + +type model = Control_flow_c.cflow * label_ctlcocci * nodei list + +type transformation_info = + (nodei * metavars_binding * Ast_cocci.rule_elem) list + + +(*****************************************************************************) +(* comparing binding *) +(*****************************************************************************) + +let equal_binding xs ys = + List.sort compare xs = List.sort compare ys diff --git a/engine/main.ml b/engine/main.ml new file mode 100644 index 0000000..01311b0 --- /dev/null +++ b/engine/main.ml @@ -0,0 +1,45 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* ----------------------------------------------------------------------- *) +(* Entry point *) + +let in_file = ref "" +let out_file = ref "" + +let anonymous s = + if !in_file = "" then in_file := s else out_file := s + +let speclist = [] + +let usage = + Printf.sprintf + "Usage: %s [options] \nOptions are:" + (Filename.basename Sys.argv.(0)) + +let main _ = + Arg.parse speclist anonymous usage; + if !in_file = "" then failwith "in_filename required"; + let (ast_lists,ua) = Parse_cocci.process !in_file None false in + Ctltotex.totex !out_file ast_lists (List.map2 Asttoctl.asttoctl ast_lists ua) + +let _ = main () diff --git a/engine/pattern3.ml b/engine/pattern3.ml new file mode 100644 index 0000000..5b04d31 --- /dev/null +++ b/engine/pattern3.ml @@ -0,0 +1,467 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Common + +(*****************************************************************************) +(* The functor argument *) +(*****************************************************************************) + +(* info passed recursively in monad in addition to binding *) +type xinfo = { + optional_storage_iso : bool; + optional_qualifier_iso : bool; + value_format_iso : bool; +} + +module XMATCH = struct + + (* ------------------------------------------------------------------------*) + (* Combinators history *) + (* ------------------------------------------------------------------------*) + (* + * version0: + * type ('a, 'b) matcher = 'a -> 'b -> bool + * + * version1: same but with a global variable holding the current binding + * BUT bug + * - can have multiple possibilities + * - globals sux + * - sometimes have to undo, cos if start match, then it binds, + * and if later it does not match, then must undo the first binds. + * ex: when match parameters, can try to match, but then we found far + * later that the last argument of a function does not match + * => have to uando the binding !!! + * (can handle that too with a global, by saving the + * global, ... but sux) + * => better not use global + * + * version2: + * type ('a, 'b) matcher = binding -> 'a -> 'b -> binding list + * + * Empty list mean failure (let matchfailure = []). + * To be able to have pretty code, have to use partial application + * powa, and so the type is in fact + * + * version3: + * type ('a, 'b) matcher = 'a -> 'b -> binding -> binding list + * + * Then by defining the correct combinators, can have quite pretty code (that + * looks like the clean code of version0). + * + * opti: return a lazy list of possible matchs ? + * + * version4: type tin = Lib_engine.metavars_binding + *) + + (* ------------------------------------------------------------------------*) + (* Standard type and operators *) + (* ------------------------------------------------------------------------*) + + type tin = { + extra: xinfo; + binding: Lib_engine.metavars_binding; + } + (* 'x is a ('a * 'b) but in fact dont care about 'b, we just tag the SP *) + (* opti? use set instead of list *) + type 'x tout = ('x * Lib_engine.metavars_binding) list + + type ('a, 'b) matcher = 'a -> 'b -> tin -> ('a * 'b) tout + + (* was >&&> *) + let (>>=) m1 m2 = fun tin -> + let xs = m1 tin in + let xxs = xs +> List.map (fun ((a,b), binding) -> + m2 a b {extra = tin.extra; binding = binding} + ) in + List.flatten xxs + + (* Je compare les bindings retournés par les differentes branches. + * Si la deuxieme branche amene a des bindings qui sont deja presents + * dans la premiere branche, alors je ne les accepte pas. + * + * update: still useful now that julia better handle Exp directly via + * ctl tricks using positions ? + *) + let (>|+|>) m1 m2 = fun tin -> +(* CHOICE + let xs = m1 tin in + if null xs + then m2 tin + else xs +*) + let res1 = m1 tin in + let res2 = m2 tin in + let list_bindings_already = List.map snd res1 in + res1 ++ + (res2 +> List.filter (fun (x, binding) -> + not + (list_bindings_already +> List.exists (fun already -> + Lib_engine.equal_binding binding already)) + )) + + + + + let (>||>) m1 m2 = fun tin -> +(* CHOICE + let xs = m1 tin in + if null xs + then m2 tin + else xs +*) + (* opti? use set instead of list *) + m1 tin ++ m2 tin + + + let return res = fun tin -> + [res, tin.binding] + + let fail = fun tin -> + [] + + let (>&&>) f m = fun tin -> + if f tin + then m tin + else fail tin + + + let mode = Cocci_vs_c_3.PatternMode + + (* ------------------------------------------------------------------------*) + (* Exp *) + (* ------------------------------------------------------------------------*) + let cocciExp = fun expf expa node -> fun tin -> + + let globals = ref [] in + let bigf = { + (* julia's style *) + Visitor_c.default_visitor_c with + Visitor_c.kexpr = (fun (k, bigf) expb -> + match expf expa expb tin with + | [] -> (* failed *) k expb + | xs -> + globals := xs @ !globals; + if not !Flag_engine.disallow_nested_exps then k expb (* CHOICE *) + ); + (* pad's style. + * push2 expr globals; k expr + * ... + * !globals +> List.fold_left (fun acc e -> acc >||> match_e_e expr e) + * (return false) + * + *) + } + in + Visitor_c.vk_node bigf node; + !globals +> List.map (fun ((a, _exp), binding) -> + (a, node), binding + ) + + (* same as cocciExp, but for expressions in an expression, not expressions + in a node *) + let cocciExpExp = fun expf expa expb -> fun tin -> + + let globals = ref [] in + let bigf = { + (* julia's style *) + Visitor_c.default_visitor_c with + Visitor_c.kexpr = (fun (k, bigf) expb -> + match expf expa expb tin with + | [] -> (* failed *) k expb + | xs -> + globals := xs @ !globals; + if not !Flag_engine.disallow_nested_exps then k expb (* CHOICE *) + ); + (* pad's style. + * push2 expr globals; k expr + * ... + * !globals +> List.fold_left (fun acc e -> acc >||> match_e_e expr e) + * (return false) + * + *) + } + in + Visitor_c.vk_expr bigf expb; + !globals +> List.map (fun ((a, _exp), binding) -> + (a, expb), binding + ) + + let cocciTy = fun expf expa node -> fun tin -> + + let globals = ref [] in + let bigf = { + Visitor_c.default_visitor_c with + Visitor_c.ktype = (fun (k, bigf) expb -> + match expf expa expb tin with + | [] -> (* failed *) k expb + | xs -> globals := xs @ !globals); + + } + in + Visitor_c.vk_node bigf node; + !globals +> List.map (fun ((a, _exp), binding) -> + (a, node), binding + ) + + + (* ------------------------------------------------------------------------*) + (* Distribute mcode *) + (* ------------------------------------------------------------------------*) + let tag_mck_pos mck posmck = + match mck with + | Ast_cocci.PLUS -> Ast_cocci.PLUS + | Ast_cocci.CONTEXT (pos, xs) -> + assert (pos = Ast_cocci.NoPos || pos = Ast_cocci.DontCarePos); + Ast_cocci.CONTEXT (posmck, xs) + | Ast_cocci.MINUS (pos, xs) -> + assert (pos = Ast_cocci.NoPos || pos = Ast_cocci.DontCarePos); + Ast_cocci.MINUS (posmck, xs) + + + let tag_mck_pos_mcode (x,info,mck,pos) posmck stuff = fun tin -> + [((x, info, tag_mck_pos mck posmck, pos),stuff), tin.binding] + + + let distrf (ii_of_x_f) = + fun mcode x -> fun tin -> + let (max, min) = Lib_parsing_c.max_min_by_pos (ii_of_x_f x) + in + let posmck = Ast_cocci.FixPos (min, max) (* subtil: and not max, min !!*) + in + tag_mck_pos_mcode mcode posmck x tin + + let distrf_e = distrf (Lib_parsing_c.ii_of_expr) + let distrf_args = distrf (Lib_parsing_c.ii_of_args) + let distrf_type = distrf (Lib_parsing_c.ii_of_type) + let distrf_param = distrf (Lib_parsing_c.ii_of_param) + let distrf_params = distrf (Lib_parsing_c.ii_of_params) + let distrf_ini = distrf (Lib_parsing_c.ii_of_ini) + let distrf_node = distrf (Lib_parsing_c.ii_of_node) + let distrf_struct_fields = distrf (Lib_parsing_c.ii_of_struct_fields) + let distrf_cst = distrf (Lib_parsing_c.ii_of_cst) + let distrf_define_params = distrf (Lib_parsing_c.ii_of_define_params) + + + (* ------------------------------------------------------------------------*) + (* Constraints on metavariable values *) + (* ------------------------------------------------------------------------*) + let check_constraints matcher constraints exp = fun f tin -> + let rec loop = function + [] -> f () tin (* success *) + | c::cs -> + match matcher c exp tin with + [] (* failure *) -> loop cs + | _ (* success *) -> fail tin in + loop constraints + + let check_pos_constraints constraints pvalu f tin = + check_constraints + (fun c exp tin -> + let success = [[]] in + let failure = [] in + (match Common.optionise (fun () -> tin.binding +> List.assoc c) with + Some valu' -> + if Cocci_vs_c_3.equal_metavarval exp valu' + then success else failure + | None -> + (* if the variable is not there, it puts no constraints *) + (* not sure this is still useful *) + failure)) + constraints pvalu f tin + + (* ------------------------------------------------------------------------*) + (* Environment *) + (* ------------------------------------------------------------------------*) + (* pre: if have declared a new metavar that hide another one, then + * must be passed with a binding that deleted this metavar + * + * Here we dont use the keep argument of julia. cf f(X,X), J'ai + * besoin de garder le X en interne, meme si julia s'en fout elle du + * X et qu'elle a mis X a DontSaved. + *) + let check_add_metavars_binding strip _keep inherited = fun (k, valu) tin -> + (match Common.optionise (fun () -> tin.binding +> List.assoc k) with + | Some (valu') -> + if Cocci_vs_c_3.equal_metavarval valu valu' + then Some tin.binding + else None + + | None -> + if inherited + then None + else + let valu' = + match valu with + Ast_c.MetaIdVal a -> Ast_c.MetaIdVal a + | Ast_c.MetaFuncVal a -> Ast_c.MetaFuncVal a + | Ast_c.MetaLocalFuncVal a -> Ast_c.MetaLocalFuncVal a (*more?*) + | Ast_c.MetaExprVal a -> + Ast_c.MetaExprVal + (if strip + then Lib_parsing_c.al_expr a + else Lib_parsing_c.semi_al_expr a) + | Ast_c.MetaExprListVal a -> + Ast_c.MetaExprListVal + (if strip + then Lib_parsing_c.al_arguments a + else Lib_parsing_c.semi_al_arguments a) + + | Ast_c.MetaStmtVal a -> + Ast_c.MetaStmtVal + (if strip + then Lib_parsing_c.al_statement a + else Lib_parsing_c.semi_al_statement a) + | Ast_c.MetaTypeVal a -> + Ast_c.MetaTypeVal + (if strip + then Lib_parsing_c.al_type a + else Lib_parsing_c.semi_al_type a) + + | Ast_c.MetaListlenVal a -> Ast_c.MetaListlenVal a + + | Ast_c.MetaParamVal a -> failwith "not handling MetaParamVal" + | Ast_c.MetaParamListVal a -> + Ast_c.MetaParamListVal + (if strip + then Lib_parsing_c.al_params a + else Lib_parsing_c.semi_al_params a) + + | Ast_c.MetaPosVal (pos1,pos2) -> Ast_c.MetaPosVal (pos1,pos2) + | Ast_c.MetaPosValList l -> Ast_c.MetaPosValList l + in Some (tin.binding +> Common.insert_assoc (k, valu')) + ) + + let envf keep inherited = fun (k, valu, get_max_min) f tin -> + let x = Ast_cocci.unwrap_mcode k in + match check_add_metavars_binding true keep inherited (x, valu) tin with + | Some binding -> + let new_tin = {extra = tin.extra; binding = binding} in + (match Ast_cocci.get_pos_var k with + Ast_cocci.MetaPos(name,constraints,per,keep,inherited) -> + let pvalu = + let (file,min,max) = get_max_min() in + Ast_c.MetaPosValList[(file,min,max)] in + (* check constraints. success means that there is a match with + one of the constraints, which will ultimately result in + failure. *) + check_pos_constraints constraints pvalu + (function () -> + (* constraints are satisfied, now see if we are compatible + with existing bindings *) + function new_tin -> + let x = Ast_cocci.unwrap_mcode name in + (match + check_add_metavars_binding false keep inherited (x, pvalu) + new_tin with + | Some binding -> + f () {extra = new_tin.extra; binding = binding} + | None -> fail tin)) + new_tin + | Ast_cocci.NoMetaPos -> f () new_tin) + | None -> fail tin + + (* ------------------------------------------------------------------------*) + (* Environment, allbounds *) + (* ------------------------------------------------------------------------*) + (* all referenced inherited variables have to be bound. This would + * be naturally checked for the minus or context ones in the + * matching process, but have to check the plus ones as well. The + * result of get_inherited contains all of these, but the potential + * redundant checking for the minus and context ones is probably not + * a big deal. If it's a problem, could fix free_vars to distinguish + * between + variables and the other ones. *) + + let (all_bound : Ast_cocci.meta_name list -> tin -> bool) = fun l tin -> + l +> List.for_all (fun inhvar -> + match Common.optionise (fun () -> tin.binding +> List.assoc inhvar) with + | Some _ -> true + | None -> false + ) + + let optional_storage_flag f = fun tin -> + f (tin.extra.optional_storage_iso) tin + + let optional_qualifier_flag f = fun tin -> + f (tin.extra.optional_qualifier_iso) tin + + let value_format_flag f = fun tin -> + f (tin.extra.value_format_iso) tin + + + (* ------------------------------------------------------------------------*) + (* Tokens *) + (* ------------------------------------------------------------------------*) + let tokenf ia ib = fun tin -> + let pos = Ast_c.info_to_fixpos ib in + let posmck = Ast_cocci.FixPos (pos, pos) in + let finish tin = tag_mck_pos_mcode ia posmck ib tin in + match Ast_cocci.get_pos_var ia with + Ast_cocci.MetaPos(name,constraints,per,keep,inherited) -> + let mpos = Lib_parsing_c.lin_col_by_pos [ib] in + let pvalu = Ast_c.MetaPosValList [mpos] in + check_pos_constraints constraints pvalu + (function () -> + (* constraints are satisfied, now see if we are compatible + with existing bindings *) + function new_tin -> + let x = Ast_cocci.unwrap_mcode name in + (match + check_add_metavars_binding false keep inherited (x, pvalu) tin + with + Some binding -> finish {extra = tin.extra; binding = binding} + | None -> fail tin)) + tin + | _ -> finish tin + + let tokenf_mck mck ib = fun tin -> + let pos = Ast_c.info_to_fixpos ib in + let posmck = Ast_cocci.FixPos (pos, pos) in + [(tag_mck_pos mck posmck, ib), tin.binding] + +end + +(*****************************************************************************) +(* Entry point *) +(*****************************************************************************) +module MATCH = Cocci_vs_c_3.COCCI_VS_C (XMATCH) + + +let match_re_node2 dropped_isos a b binding = + + let tin = { + XMATCH.extra = { + optional_storage_iso = not(List.mem "optional_storage" dropped_isos); + optional_qualifier_iso = not(List.mem "optional_qualifier" dropped_isos); + value_format_iso = not(List.mem "value_format" dropped_isos); + }; + XMATCH.binding = binding; + } in + + MATCH.rule_elem_node a b tin + (* take only the tagged-SP, the 'a' *) + +> List.map (fun ((a,_b), binding) -> a, binding) + + +let match_re_node a b c d = + Common.profile_code "Pattern3.match_re_node" + (fun () -> match_re_node2 a b c d) diff --git a/engine/pattern3.mli b/engine/pattern3.mli new file mode 100644 index 0000000..76525ff --- /dev/null +++ b/engine/pattern3.mli @@ -0,0 +1,6 @@ + +val match_re_node : + string list (* dropped isos *) -> + Ast_cocci.rule_elem -> Control_flow_c.node -> + Lib_engine.metavars_binding -> + (Ast_cocci.rule_elem * Lib_engine.metavars_binding) list diff --git a/engine/postprocess_transinfo.ml b/engine/postprocess_transinfo.ml new file mode 100644 index 0000000..89b30b7 --- /dev/null +++ b/engine/postprocess_transinfo.ml @@ -0,0 +1,105 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* two goals: first drop from the environments things that are not used, + and second prompt for the names of fresh variables that are used *) + +(* have to add in the whole inherited env because inherited variables are +not returned by get_fvs. It would be better if that were the case, but +since at the moment I think we can only inherit one value per variable, +perhaps it doesn't matter - these bindings will always be the same no matter +how we reached a particular match *) + +module Ast = Ast_cocci + +let extra_counter = ref 0 +let get_extra _ = + let ctr = !extra_counter in + extra_counter := !extra_counter + 1; + "__extra_counter__"^(string_of_int ctr) + +let read_fresh_id () = + try + let s = read_line () in + match Parse_c.tokens_string s with + [Parser_c.TIdent _; Parser_c.EOF _] -> s + | _ -> failwith ("wrong fresh id: " ^ s) + with End_of_file -> get_extra() + +let get_vars = function + Lib_engine.Match(re) -> (Ast.get_fvs re, Ast.get_fresh re) + | _ -> ([],[]) + +let string2val str = Lib_engine.NormalMetaVal(Ast_c.MetaIdVal(str)) + +(* ----------------------------------------------------------------------- *) +(* Get values for fresh variables *) + +let process_tree inherited_env l = + let (all_fresh,local_freshs,new_triples) = + List.fold_left + (function (all_fresh,local_freshs,new_triples) -> + function (node,env,pred) -> + let (other,fresh) = get_vars pred in + let env = List.filter (function (x,_) -> List.mem x other) env in + (Common.union_set fresh all_fresh, + fresh::local_freshs, + (node,env@inherited_env,pred)::new_triples)) + ([],[],[]) l in + let local_freshs = List.rev local_freshs in + let new_triples = List.rev new_triples in + let fresh_env = + List.map + (function ((r,n) as fresh) -> + Printf.printf "%s: name for %s: " r n; (* not debugging code!!! *) + flush stdout; + (fresh,string2val(read_fresh_id()))) + all_fresh in + let (_,res) = + List.split + (List.fold_left + (function freshs_node_env_preds -> + function (fresh,_) as elem -> + List.map + (function (freshs,((node,env,pred) as cur)) -> + if List.mem fresh freshs + then (freshs,(node,elem::env,pred)) + else (freshs,cur)) + freshs_node_env_preds) + (List.combine local_freshs new_triples) + fresh_env) in + (List.rev res, fresh_env) + +(* ----------------------------------------------------------------------- *) +(* Create the environment to be used afterwards *) + +let collect_used_after used_after envs = + List.map (List.filter (function (v,vl) -> List.mem v used_after)) envs + +(* ----------------------------------------------------------------------- *) +(* entry point *) + +let process used_after inherited_env l = + extra_counter := 0; + let (trees, fresh_envs) = + List.split (List.map (process_tree inherited_env) l) in + (Common.uniq(List.concat trees), collect_used_after used_after fresh_envs) diff --git a/engine/postprocess_transinfo.mli b/engine/postprocess_transinfo.mli new file mode 100644 index 0000000..8fa8506 --- /dev/null +++ b/engine/postprocess_transinfo.mli @@ -0,0 +1,11 @@ +val process : + Ast_cocci.meta_name list (* used after *) -> + (Ast_cocci.meta_name * Lib_engine.metavar_binding_kind2) list + (*inherited env*)-> + (Ograph_extended.nodei * + (Ast_cocci.meta_name * Lib_engine.metavar_binding_kind2) list * + Lib_engine.predicate) list list -> + (Ograph_extended.nodei * + (Ast_cocci.meta_name * Lib_engine.metavar_binding_kind2) list * + Lib_engine.predicate) list * + (Ast_cocci.meta_name * Lib_engine.metavar_binding_kind2) list list diff --git a/engine/pretty_print_engine.ml b/engine/pretty_print_engine.ml new file mode 100644 index 0000000..0dd3bb3 --- /dev/null +++ b/engine/pretty_print_engine.ml @@ -0,0 +1,161 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Common.Infix + +open Lib_engine + + +let pp = Common.pp + +let pp_meta (_,x) = pp x + +let rec pp_binding_kind = function + | Ast_c.MetaIdVal s -> pp ("id " ^ s) + | Ast_c.MetaFuncVal s -> pp ("func " ^ s) + | Ast_c.MetaLocalFuncVal s -> pp ("localfunc " ^ s) + | Ast_c.MetaExprVal expr -> + Pretty_print_c.pp_expression_simple expr + | Ast_c.MetaExprListVal expr_list -> pp "<>" + | Ast_c.MetaTypeVal typ -> + Pretty_print_c.pp_type_simple typ + | Ast_c.MetaStmtVal statement -> + Pretty_print_c.pp_statement_simple statement + | Ast_c.MetaParamVal params -> pp "<>" + | Ast_c.MetaParamListVal params -> pp "<>" + | Ast_c.MetaListlenVal n -> pp (string_of_int n) + | Ast_c.MetaPosVal (pos1, pos2) -> + let print_pos = function + Ast_cocci.Real x -> string_of_int x + | Ast_cocci.Virt(x,off) -> Printf.sprintf "%d+%d" x off in + pp (Common.sprintf ("pos(%s,%s)") (print_pos pos1) (print_pos pos2)) + | Ast_c.MetaPosValList l -> + pp (Common.sprintf ("poss[%s]") + (String.concat ", " + (List.map + (function (fl,(minl,minc),(maxl,maxc)) -> + Printf.sprintf "(%s,(%d,%d),(%d,%d))" + fl minl minc maxl maxc) + l))) + +and pp_binding subst = + begin + pp "["; + Common.print_between (fun () -> pp ";"; Format.print_cut() ) + (fun ((_,s), kind) -> pp s; pp " --> "; pp_binding_kind kind) + subst; + pp "]"; + end + + +let pp_binding_kind2 = function + | ParenVal s -> pp "pv("; pp_meta s; pp ")" + | NormalMetaVal x -> pp_binding_kind x + | LabelVal xs -> + begin + pp "labelval"; + pp "("; + Common.print_between (fun () -> pp ",") Format.print_int xs; + pp ")"; + end + | GoodVal -> pp "goodval" + | BadVal -> pp "badval" + + +let rec pp_predicate = function + | InLoop -> pp "InLoop" + | TrueBranch -> pp "TrueBranch" + | FalseBranch -> pp "FalseBranch" + | After -> pp "After" + | FallThrough -> pp "FallThrough" + | Return -> pp "Return" + | FunHeader -> pp "FunHeader" + | Top -> pp "Top" + | ErrorExit -> pp "ErrorExit" + | Exit -> pp "Exit" + | Goto -> pp "Goto" + | Paren s -> pp "Paren("; pp_meta s; pp ")" + | Match (re) -> Pretty_print_cocci.print_rule_elem re + | Label s -> pp "Label("; pp_meta s; pp ")" + | BCLabel s -> pp "BreakContinueLabel("; pp_meta s; pp ")" + | PrefixLabel s -> pp "PrefixLabel("; pp_meta s; pp ")" + | BindGood s -> pp "BindGood("; pp_meta s; pp ")" + | BindBad s -> pp "BindBad("; pp_meta s; pp ")" + | FakeBrace -> pp "FakeBrace" + +and pp_binding2 subst = + begin + pp "["; + Common.print_between (fun () -> pp ";";Format.print_cut(); ) + (fun (s, kind) -> pp s; pp " --> "; pp_binding_kind2 kind) + subst; + pp "]"; + end + +and pp_binding2_ctlsubst subst = + begin + pp "["; + Common.print_between (fun () -> pp ";"; Format.print_cut(); ) + (function + Ast_ctl.Subst (s, kind) -> + pp_meta s; pp " --> "; pp_binding_kind2 kind; + | Ast_ctl.NegSubst (s, kind) -> + pp_meta s; pp " -/-> "; pp_binding_kind2 kind; + ) + subst; + pp "]"; + end + +let predicate_to_string pred = + Common.format_to_string (function _ -> pp_predicate pred) + + +let pp_pred_smodif = fun (pred, smodif) -> + begin + pp_predicate pred; +(* + (match smodif with + | Ast_ctl.Modif x | Ast_ctl.UnModif x -> pp " with " + | Ast_ctl.Control -> () + ) +*) + end + + +let pp_ctlcocci show_plus inline_let_def ctl = + begin + if show_plus + then begin + Pretty_print_cocci.print_plus_flag := true; + Pretty_print_cocci.print_minus_flag := true; + end + else begin + Pretty_print_cocci.print_plus_flag := false; + Pretty_print_cocci.print_minus_flag := false; + end; + Common.pp_do_in_box (fun () -> + Pretty_print_ctl.pp_ctl (pp_pred_smodif,(fun s -> pp_meta s)) + inline_let_def ctl; + ); + end + + diff --git a/engine/pretty_print_engine.mli b/engine/pretty_print_engine.mli new file mode 100644 index 0000000..81c9536 --- /dev/null +++ b/engine/pretty_print_engine.mli @@ -0,0 +1,20 @@ +(* could be in pretty_print_c because dependent of ast_c but metavars + * are in ast_c for "bad" reason, so better put the pretty_print + * of metavars here + *) + +val pp_binding_kind : Ast_c.metavar_binding_kind -> unit +val pp_binding : Ast_c.metavars_binding -> unit + +val pp_binding_kind2 : Lib_engine.metavar_binding_kind2 -> unit +val pp_binding2_ctlsubst : + (Lib_engine.mvar, Lib_engine.metavar_binding_kind2) + Ast_ctl.generic_substitution -> + unit +val pp_predicate : Lib_engine.predicate -> unit +val predicate_to_string : Lib_engine.predicate -> string + + +val pp_ctlcocci : + bool (* show_plus *) -> bool (* inline_let *) -> Lib_engine.ctlcocci -> unit + diff --git a/engine/sgrep.ml b/engine/sgrep.ml new file mode 100644 index 0000000..1c00137 --- /dev/null +++ b/engine/sgrep.ml @@ -0,0 +1,148 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +type marker = + NoMark | BefMark of string | AftMark of string + | BefAftMark of string * string + +let extract_sgrep_marker l = + let rec inner_loop acc = function + [] -> (acc,[]) + | Ast_cocci.SgrepStartTag(s)::rest -> + (match acc with + NoMark -> inner_loop (BefMark(s)) rest + | _ -> failwith "unexpected mark") + | Ast_cocci.SgrepEndTag(s)::rest -> + (match acc with + NoMark -> inner_loop (AftMark(s)) rest + | BefMark(m) -> inner_loop (BefAftMark(m,s)) rest + | _ -> failwith "unexpected mark") + | x::rest -> + let (acc,rest) = inner_loop acc rest in + (acc,x::rest) in + let (acc,l) = + List.fold_left + (function (acc,prev) -> + function cur -> + let (acc,cur) = inner_loop acc cur in + (acc,cur::prev)) + (NoMark,[]) l in + (acc,List.rev l) + +let process_sgrep ii mck = + let file = Ast_c.file_of_info ii in + let line = Ast_c.line_of_info ii in + let col = Ast_c.col_of_info ii in + let str = Ast_c.str_of_info ii in + match mck with + Ast_cocci.MINUS(pos,repl) -> + (match extract_sgrep_marker repl with + (NoMark,_) -> mck + | (BefMark(marker),repl) -> + Printf.printf "Match on line %s starting at %s: line %d offset %d\n" + marker file line col; + Ast_cocci.MINUS(pos,repl) + | (AftMark(marker),repl) -> + Printf.printf "Match on line %s ending at %s: line %d offset %d\n" + marker file line (col + String.length str); + Ast_cocci.MINUS(pos,repl) + | (BefAftMark(bmarker,amarker),repl) -> + Printf.printf "Match on line %s starting at %s: line %d offset %d\n" + bmarker file line col; + Printf.printf "Match on line %s ending at %s: line %d offset %d\n" + amarker file line (col + String.length str); + Ast_cocci.MINUS(pos,repl)) + | Ast_cocci.CONTEXT(pos,Ast_cocci.NOTHING) -> mck + | Ast_cocci.CONTEXT(pos,Ast_cocci.BEFORE(bef)) -> + (match extract_sgrep_marker bef with + (NoMark,_) -> mck + | (BefMark(marker),[]) -> + Printf.printf "Match on line %s starting at %s: line %d offset %d\n" + marker file line col; + Ast_cocci.CONTEXT(pos,Ast_cocci.NOTHING) + | (BefMark(marker),bef) -> + Printf.printf "Match on line %s starting at %s: line %d offset %d\n" + marker file line col; + Ast_cocci.CONTEXT(pos,Ast_cocci.BEFORE(bef)) + | _ -> failwith "after not possible") + | Ast_cocci.CONTEXT(pos,Ast_cocci.AFTER(aft)) -> + (match extract_sgrep_marker aft with + (NoMark,_) -> mck + | (AftMark(marker),[]) -> + Printf.printf "Match on line %s ending at %s: line %d offset %d\n" + marker file line (col + String.length str); + Ast_cocci.CONTEXT(pos,Ast_cocci.NOTHING) + | (AftMark(marker),aft) -> + Printf.printf "Match on line %s ending at %s: line %d offset %d\n" + marker file line (col + String.length str); + Ast_cocci.CONTEXT(pos,Ast_cocci.AFTER(aft)) + | _ -> failwith "before not possible") + | Ast_cocci.CONTEXT(pos,Ast_cocci.BEFOREAFTER(bef,aft)) -> + (match extract_sgrep_marker bef with + (NoMark,_) -> + (match extract_sgrep_marker aft with + (NoMark,_) -> mck + | (AftMark(marker),[]) -> + Printf.printf + "Match on line %s ending at %s: line %d offset %d\n" + marker file line (col + String.length str); + Ast_cocci.CONTEXT(pos,Ast_cocci.BEFORE(bef)) + | (AftMark(marker),aft) -> + Printf.printf + "Match on line %s ending at %s: line %d offset %d\n" + marker file line (col + String.length str); + Ast_cocci.CONTEXT(pos,Ast_cocci.BEFOREAFTER(bef,aft)) + | _ -> failwith "before not possible") + | (BefMark(marker),[]) -> + Printf.printf "Match on line %s starting at %s: line %d offset %d\n" + marker file line col; + (match extract_sgrep_marker aft with + (NoMark,_) -> Ast_cocci.CONTEXT(pos,Ast_cocci.AFTER(aft)) + | (AftMark(marker),[]) -> + Printf.printf + "Match on line %s ending at %s: line %d offset %d\n" + marker file line (col + String.length str); + Ast_cocci.CONTEXT(pos,Ast_cocci.NOTHING) + | (AftMark(marker),aft) -> + Printf.printf + "Match on line %s ending at %s: line %d offset %d\n" + marker file line (col + String.length str); + Ast_cocci.CONTEXT(pos,Ast_cocci.AFTER(aft)) + | _ -> failwith "before not possible") + | (BefMark(marker),bef) -> + Printf.printf "Match on line %s starting at %s: line %d offset %d\n" + marker file line col; + (match extract_sgrep_marker aft with + (NoMark,_) -> Ast_cocci.CONTEXT(pos,Ast_cocci.BEFOREAFTER(bef,aft)) + | (AftMark(marker),[]) -> + Printf.printf + "Match on line %s ending at %s: line %d offset %d\n" + marker file line (col + String.length str); + Ast_cocci.CONTEXT(pos,Ast_cocci.BEFORE(bef)) + | (AftMark(marker),aft) -> + Printf.printf + "Match on line %s ending at %s: line %d offset %d\n" + marker file line (col + String.length str); + Ast_cocci.CONTEXT(pos,Ast_cocci.BEFOREAFTER(bef,aft)) + | _ -> failwith "before not possible") + | _ -> failwith "after not possible") + | _ -> failwith "unexpected plus code" diff --git a/engine/tests/Makefile b/engine/tests/Makefile new file mode 100644 index 0000000..5988c9a --- /dev/null +++ b/engine/tests/Makefile @@ -0,0 +1,10 @@ +all: test1.tex +all: test2.tex + +test1.tex: test1 ../engine + ../engine test1 test1.tex + latex test1.tex + +test2.tex: test2 ../engine + ../engine test2 test2.tex + latex test2.tex diff --git a/engine/tests/test1 b/engine/tests/test1 new file mode 100644 index 0000000..2735536 --- /dev/null +++ b/engine/tests/test1 @@ -0,0 +1,278 @@ +@@ +@@ + f(); + ... +? g(); + ... + h(); + +@@ +expression E,X,Y,Z; +local function foo; +@@ + + foo(...) { +( +- f(3,E); ++ f(3,3,E); +| +- f(E,4); ++ f(E,4,4); +| +- E; ++ g(E); +) +( +- f(3,X); ++ f(3,3,X); +| +- f(Y,4); ++ f(Y,4,4); +| +- Z; ++ g(Z); +) +( +- f(3); ++ f(3,3); +| +- f(4); ++ f(4,4); +) + } + +@@ +identifier buffer; +identifier hostptr; +@@ + p( ++ int hostptr, + char buffer) { +- int hostptr; + } + +@@ +expression X,Y; +@@ + + f(X); +- ... WHEN != h(X) + g(Y); + +@@ +expression X,Y; +@@ + + f(X); +- ... + g(Y); + +@@ +expression X,Y; +@@ + +f(X); +g(Y); +h(X); +f(Y); +g(X); +h(Y); + +@@ +expression X; +@@ + +f(X); +... +g(X); +h(X); + +@@ +expression X; +@@ + + if (X) { ... } else { ... } + f(X); + +@@ +expression X; +@@ + + if (X) { ... } + f(X); + +@@ +expression X; +@@ + + while (X) { ... } + f(X); + +@@ +expression X; +@@ + + while (X) { ... } + +@@ +expression X,Y; +@@ + + { + ... WHEN != g(Y) + f(X); + ... WHEN != h(Y) + } + +@@ +expression X,Y; +@@ + + f(X); + ... +- g(Y); ++ h(X,Y); + +@@ +expression X,Y,Z; +@@ + +- f(X); ++ f(Z); +- ... + g(Y); + h(Z); + +@@ +expression X,Y,Z; +@@ + +- f(X); ++ f(Z); + ... + g(Y); + h(Z); + + +@@ +expression X,Y,Z; +@@ + +f(X); +... +g(Y); +h(Z); + +@@ +expression X,Y,Z; +@@ + +f(X); +... WHEN != h(Z) +g(Y); +h(Z); + +@@ +expression X,Y,Z,Q; +@@ + +f(X); +... WHEN != h(Q) +g(Y); +h(Z); + +@@ +expression X,Z; +@@ + +if (X) { + ... +} +else { + g(X); +} +h(Z); + +@@ +expression X,Y; +@@ + +<... +( + h(X) +| + g(Y) +) +...> + +@@ +expression X,Y; +@@ + +<... +( + h(X) +| + g(Y) +) +...> +r(X); + +@@ +expression X,Y; +@@ + +( + h(X) +| + g(Y) +) + +@@ +expression X,Y; +@@ + + m(Y); +? h(X); + g(Y); + +@@ +struct Scsi_Host_Template sht; +!local function proc_info_func; +@@ + +sht.proc_info = proc_info_func; + +@@ +identifier buffer, start, offset, length, inout, hostptr, hostno; +@@ + + proc_info_func( + char *buffer, char **start, off_t offset, + int length, + int hostno, + int inout) { + ... + struct Scsi_Host *hostptr; + ... + hostptr = scsi_host_hn_get(hostno); + ... +? if (hostptr == NULL) { ... } + ... +? scsi_host_put(hostptr); + ... + } + +@@ +expression E; +@@ + +proc_info_func(...) { + <... +( + E->host_no == hostno +| + hostno +) + ...> + } diff --git a/engine/tests/test1.tex b/engine/tests/test1.tex new file mode 100644 index 0000000..722951c --- /dev/null +++ b/engine/tests/test1.tex @@ -0,0 +1,667 @@ +\documentclass{article} +\usepackage{fullpage} + +\newcommand{\U}{\,\mbox{\sf{U}}\,} +\newcommand{\A}{\mbox{\sf{A}}} +\newcommand{\E}{\mbox{\sf{E}}} +\newcommand{\AX}{\mbox{\sf{AX}}} +\newcommand{\EX}{\mbox{\sf{EX}}} +\newcommand{\AF}{\mbox{\sf{AF}}} +\newcommand{\EF}{\mbox{\sf{EF}}} +\newcommand{\AG}{\mbox{\sf{AG}}} +\newcommand{\EG}{\mbox{\sf{EG}}} + +\newcommand{\mita}[1]{\mbox{\it{{#1}}}} +\newcommand{\mtt}[1]{\mbox{\tt{{#1}}}} +\newcommand{\msf}[1]{\mbox{\sf{{#1}}}} +\newcommand{\mrm}[1]{\mbox{\rm{{#1}}}} +\newcommand{\mth}[1]{\({#1}\)} + +\newcommand{\ttlb}{\mbox{\tt \char'173}} +\newcommand{\ttrb}{\mbox{\tt \char'175}} + +\begin{document} + +\begin{quote}\begin{verbatim} + +@@ +@@ + +f(); +... +?g(); +... +h(); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\mita{\sf{let}} \, \mita{l9} = \mita{f();} \, \mita{\sf{in}} \, \mita{l9} \wedge (\AX(\mita{\sf{let}} \, \mita{l0} = \mita{g();} \, \mita{\sf{in}} \, \A[\neg (\mita{l0} \vee \mita{l9}) \U (\mita{\sf{let}} \, \mita{l7} = \msf{After}\\\mbox{} \vee \msf{ErrorExit} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l10} = (\mita{\sf{let}} \, \mita{l5} = \mita{h();} \, \mita{\sf{in}} \, \A[\neg (\mita{l5} \vee \mita{l0}) \U (\mita{l5} \vee \mita{l7})] + +) \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l3} = \mita{l0}\\\mbox{} \wedge (\AX\mita{l10}) \, \mita{\sf{in}} \, \mita{l3} \vee ((\neg \mita{l3}) \wedge \mita{l10}) +) +) \vee \mita{l7} +)] + +)) + +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +foo(...) { + +( + -f-(-3-, -E-)-; + >>> f(3, 3, E); + +| + -f-(-E-, -4-)-; + >>> f(E, 4, 4); + +| + -E-; + >>> g(E); + +) + +( + -f-(-3-, -X-)-; + >>> f(3, 3, X); + +| + -f-(-Y-, -4-)-; + >>> f(Y, 4, 4); + +| + -Z-; + >>> g(Z); + +) + +( + -f-(-3-)-; + >>> f(3, 3); + +| + -f-(-4-)-; + >>> f(4, 4); + +) +} +\end{verbatim}\end{quote} + +\[\begin{array}{l} +(\exists \mita{foo} . \mita{foo(...) }) \wedge (\AX(\exists \mita{p0} . (\mita{\sf{let}} \, \mita{l17} = \msf{Paren}(p0) \, \mita{\sf{in}} \, \mita{{\ttlb} + } \wedge \mita{l17} \wedge (\AX(\mita{\sf{let}} \, \mita{l32} = \AX(\mita{\sf{let}} \, \mita{l2} = \AX(\mita{\sf{let}} \, \mita{l12} = \AX(\mita{ +{\ttrb}}\\\mbox{} \wedge \mita{l17}) \, \mita{\sf{in}} \, ((\exists \mita{v0} . \mita{-f-(-3-)-; + \mth{>}\mth{>}\mth{>} f(3, 3);}_{\mita{v0}}) \wedge \mita{l12}) \vee ((\exists \mita{v0} . \mita{-f-(-4-)-; + \mth{>}\mth{>}\mth{>} f(4, 4);}_{\mita{v0}})\\\mbox{} \wedge \mita{l12}) +) \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l7} = \exists \mita{X} . \exists \mita{v0} . \mita{-f-(-3-, -X-)-; + \mth{>}\mth{>}\mth{>} f(3, 3, X);}_{\mita{v0}} \, \mita{\sf{in}} \, (\mita{l7}\\\mbox{} \wedge \mita{l2}) \vee (\mita{\sf{let}} \, \mita{l21} = \neg \mita{l7} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l6} = \exists \mita{Y} . \exists \mita{v0} . \mita{-f-(-Y-, -4-)-; + \mth{>}\mth{>}\mth{>} f(Y, 4, 4);}_{\mita{v0}}\\\mbox{} \, \mita{\sf{in}} \, (\mita{l21} \wedge \mita{l6} \wedge \mita{l2}) \vee ((\neg \mita{l6}) \wedge \mita{l21} \wedge (\exists \mita{Z} . \exists \mita{v0} . \mita{-Z-; + \mth{>}\mth{>}\mth{>} g(Z);}_{\mita{v0}}) \wedge \mita{l2}) +) +) +) +) \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l8} = \exists \mita{E}\\\mbox{} . \exists \mita{v0} . \mita{-f-(-3-, -E-)-; + \mth{>}\mth{>}\mth{>} f(3, 3, E);}_{\mita{v0}} \, \mita{\sf{in}} \, (\mita{l8} \wedge \mita{l32}) \vee (\mita{\sf{let}} \, \mita{l19} = \neg \mita{l8}\\\mbox{} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l4} = \exists \mita{E} . \exists \mita{v0} . \mita{-f-(-E-, -4-)-; + \mth{>}\mth{>}\mth{>} f(E, 4, 4);}_{\mita{v0}} \, \mita{\sf{in}} \, (\mita{l19} \wedge \mita{l4}\\\mbox{} \wedge \mita{l32}) \vee ((\neg \mita{l4}) \wedge \mita{l19} \wedge (\exists \mita{E} . \exists \mita{v0} . \mita{-E-; + \mth{>}\mth{>}\mth{>} g(E);}_{\mita{v0}}) \wedge \mita{l32}) +) +) +) +)) +))) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +p( + <<< int hostptr, + char buffer) { + -int -hostptr-; +} +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{hostptr} . ((\exists \mita{buffer} . \exists \mita{v0} . \mita{p( + <<< int hostptr, + char buffer) }_{\mita{v0}})\\\mbox{} \wedge (\AX(\exists \mita{p0} . (\mita{\sf{let}} \, \mita{l0} = \msf{Paren}(p0) \, \mita{\sf{in}} \, \mita{{\ttlb} + } \wedge \mita{l0} \wedge (\AX((\exists \mita{v0} . \mita{-int -hostptr-;}_{\mita{v0}})\\\mbox{} \wedge (\AX(\mita{ +{\ttrb}} \wedge \mita{l0})))) +)))) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +f(X); +-... WHEN != -h-(-X-) +g(Y); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{X} . (\mita{\sf{let}} \, \mita{l1} = \mita{f(X);} \, \mita{\sf{in}} \, \mita{l1} \wedge (\AX(\mita{\sf{let}} \, \mita{l0} = \exists \mita{Y} . \mita{g(Y);} \, \mita{\sf{in}} \, \A[((\exists \mita{v0} . \mita{-\_S0}_{\mita{v0}}) \wedge (\neg (\exists \mita{v0}\\\mbox{} . \mita{-h-(-X-)}_{\mita{v0}})) \wedge (\neg (\mita{l0} \vee \mita{l1}))) \U (\mita{l0} \vee \msf{After} \vee \msf{ErrorExit})] + +)) +) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +f(X); +-... +g(Y); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\mita{\sf{let}} \, \mita{l1} = \exists \mita{X} . \mita{f(X);} \, \mita{\sf{in}} \, \mita{l1} \wedge (\AX(\mita{\sf{let}} \, \mita{l2} = \exists \mita{Y} . \mita{g(Y);} \, \mita{\sf{in}} \, \A[((\exists \mita{v0} . \mita{-\_S0}_{\mita{v0}}) \wedge (\neg (\mita{l2}\\\mbox{} \vee \mita{l1}))) \U (\mita{l2} \vee \msf{After} \vee \msf{ErrorExit})] + +)) + +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +f(X); +g(Y); +h(X); +f(Y); +g(X); +h(Y); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{X} . (\mita{f(X);} \wedge (\AX(\exists \mita{Y} . (\mita{g(Y);} \wedge (\AX(\mita{h(X);} \wedge (\AX(\mita{f(Y);} \wedge (\AX(\mita{g(X);} \wedge (\AX(\mita{h(Y);})))))))))))) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +f(X); +... +g(X); +h(X); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{X} . (\mita{\sf{let}} \, \mita{l0} = \mita{f(X);} \, \mita{\sf{in}} \, \mita{l0} \wedge (\AX(\mita{\sf{let}} \, \mita{l1} = \mita{g(X);} \, \mita{\sf{in}} \, \A[\neg (\mita{l1} \vee \mita{l0}) \U ((\mita{l1} \wedge (\AX(\mita{h(X);})))\\\mbox{} \vee \msf{After} \vee \msf{ErrorExit})] + +)) +) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +if (X) { + ... +} else { + ... +} +f(X); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{X} . (\mita{\sf{let}} \, \mita{l0} = \msf{FalseBranch} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l1} = \msf{After} \, \mita{\sf{in}} \, \mita{if (X) } \wedge (\AX(\mita{\sf{let}} \, \mita{l15} = \AX(\exists \mita{p0}\\\mbox{} . (\mita{\sf{let}} \, \mita{l7} = \msf{Paren}(p0) \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l14} = \mita{{\ttlb} + } \wedge \mita{l7} \, \mita{\sf{in}} \, \mita{l14} \wedge (\AX(\mita{\sf{let}} \, \mita{l13} = \mita{ +{\ttrb}} \wedge \mita{l7}\\\mbox{} \, \mita{\sf{in}} \, \A[\neg (\mita{l13} \vee \mita{l14}) \U (\mita{l13} \vee \mita{l1} \vee \msf{ErrorExit})] + +)) +) +)) \, \mita{\sf{in}} \, (\msf{TrueBranch} \wedge \mita{l15}) \vee (\mita{l0}\\\mbox{} \wedge \mita{l15}) \vee (\mita{l1} \wedge (\AX(\mita{f(X);}))) +)) \wedge (\EX\mita{l0}) \wedge (\EX\mita{l1}) +) +) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +if (X) { + ... +} +f(X); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{X} . (\mita{\sf{let}} \, \mita{l0} = \msf{After} \, \mita{\sf{in}} \, \mita{if (X) } \wedge (\AX((\msf{TrueBranch} \wedge (\AX(\exists \mita{p0} . (\mita{\sf{let}} \, \mita{l2} = \msf{Paren}(p0)\\\mbox{} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l4} = \mita{{\ttlb} + } \wedge \mita{l2} \, \mita{\sf{in}} \, \mita{l4} \wedge (\AX(\mita{\sf{let}} \, \mita{l3} = \mita{ +{\ttrb}} \wedge \mita{l2} \, \mita{\sf{in}} \, \A[\neg (\mita{l3} \vee \mita{l4}) \U (\mita{l3} \vee \mita{l0}\\\mbox{} \vee \msf{ErrorExit})] + +)) +) +)))) \vee \msf{FallThrough} \vee (\mita{l0} \wedge (\AX(\mita{f(X);}))))) \wedge (\EX\mita{l0}) +) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +while (X) { + ... +} +f(X); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{X} . (\mita{while (X) } \wedge (\mita{\sf{let}} \, \mita{l0} = \msf{After} \, \mita{\sf{in}} \, (\AX((\msf{TrueBranch} \rightarrow (\AX(\exists \mita{p0} . (\mita{\sf{let}} \, \mita{l3} = \msf{Paren}(p0)\\\mbox{} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l5} = \mita{{\ttlb} + } \wedge \mita{l3} \, \mita{\sf{in}} \, \mita{l5} \wedge (\AX(\mita{\sf{let}} \, \mita{l4} = \mita{ +{\ttrb}} \wedge \mita{l3} \, \mita{\sf{in}} \, \A[\neg (\mita{l4} \vee \mita{l5}) \U (\mita{l4} \vee \mita{l0}\\\mbox{} \vee \msf{ErrorExit})] + +)) +) +)))) \wedge (\mita{l0} \rightarrow (\AX(\mita{f(X);}))))) \wedge (\EX\mita{l0}) +)) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +while (X) { + ... +} +\end{verbatim}\end{quote} + +\[\begin{array}{l} +(\exists \mita{X} . \mita{while (X) }) \wedge (\AX(\msf{TrueBranch} \rightarrow (\AX(\exists \mita{p0} . (\mita{\sf{let}} \, \mita{l1} = \msf{Paren}(p0) \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l4} = \mita{{\ttlb} + }\\\mbox{} \wedge \mita{l1} \, \mita{\sf{in}} \, \mita{l4} \wedge (\AX(\mita{\sf{let}} \, \mita{l3} = \mita{ +{\ttrb}} \wedge \mita{l1} \, \mita{\sf{in}} \, \A[\neg (\mita{l3} \vee \mita{l4}) \U (\mita{l3} \vee \msf{After} \vee \msf{ErrorExit})] +\\\mbox{} +)) +) +))))) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +{ + ... WHEN != g(Y) + f(X); + ... WHEN != h(Y) +} +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{p0} . (\mita{\sf{let}} \, \mita{l6} = \msf{Paren}(p0) \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l9} = \mita{{\ttlb} + } \wedge \mita{l6} \, \mita{\sf{in}} \, \mita{l9} \wedge (\AX(\exists \mita{Y} . (\mita{\sf{let}} \, \mita{l3} = \exists \mita{X} . \mita{f(X);}\\\mbox{} \, \mita{\sf{in}} \, \A[((\neg \mita{g(Y)}) \wedge (\neg (\mita{l3} \vee \mita{l9}))) \U (\mita{\sf{let}} \, \mita{l5} = \msf{After} \vee \msf{ErrorExit} \, \mita{\sf{in}} \, (\mita{l3} \wedge (\AX(\mita{\sf{let}} \, \mita{l8} = \mita{ +{\ttrb}}\\\mbox{} \wedge \mita{l6} \, \mita{\sf{in}} \, \A[((\neg \mita{h(Y)}) \wedge (\neg (\mita{l8} \vee \mita{l3}))) \U (\mita{l8} \vee \mita{l5})] + +))) \vee \mita{l5} +)] + +))) +) +) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +f(X); +... +-g-(-Y-)-; + >>> h(X, Y); + +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{X} . (\mita{\sf{let}} \, \mita{l0} = \mita{f(X);} \, \mita{\sf{in}} \, \mita{l0} \wedge (\AX\A[\neg ((\exists \mita{Y} . \mita{-g-(-Y-)-; + \mth{>}\mth{>}\mth{>} h(X, Y);}) \vee \mita{l0})\\\mbox{} \U ((\exists \mita{Y} . \exists \mita{v0} . \mita{-g-(-Y-)-; + \mth{>}\mth{>}\mth{>} h(X, Y);}_{\mita{v0}}) \vee \msf{After} \vee \msf{ErrorExit})] +) +) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +-f-(-X-)-; + >>> f(Z); + +-... +g(Y); +h(Z); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{Z} . ((\exists \mita{X} . \exists \mita{v0} . \mita{-f-(-X-)-; + \mth{>}\mth{>}\mth{>} f(Z);}_{\mita{v0}}) \wedge (\AX(\mita{\sf{let}} \, \mita{l0} = \exists \mita{Y} . \mita{g(Y);} \, \mita{\sf{in}} \, \A[((\exists \mita{v0}\\\mbox{} . \mita{-\_S0}_{\mita{v0}}) \wedge (\neg (\mita{l0} \vee (\exists \mita{X} . \mita{-f-(-X-)-; + \mth{>}\mth{>}\mth{>} f(Z);})))) \U ((\mita{l0} \wedge (\AX(\mita{h(Z);})))\\\mbox{} \vee \msf{After} \vee \msf{ErrorExit})] + +))) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +-f-(-X-)-; + >>> f(Z); + +... +g(Y); +h(Z); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{Z} . ((\exists \mita{X} . \exists \mita{v0} . \mita{-f-(-X-)-; + \mth{>}\mth{>}\mth{>} f(Z);}_{\mita{v0}}) \wedge (\AX(\mita{\sf{let}} \, \mita{l0} = \exists \mita{Y} . \mita{g(Y);} \, \mita{\sf{in}} \, \A[\neg (\mita{l0}\\\mbox{} \vee (\exists \mita{X} . \mita{-f-(-X-)-; + \mth{>}\mth{>}\mth{>} f(Z);})) \U ((\mita{l0} \wedge (\AX(\mita{h(Z);}))) \vee \msf{After} \vee \msf{ErrorExit})] +\\\mbox{} +))) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +f(X); +... +g(Y); +h(Z); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\mita{\sf{let}} \, \mita{l1} = \exists \mita{X} . \mita{f(X);} \, \mita{\sf{in}} \, \mita{l1} \wedge (\AX(\mita{\sf{let}} \, \mita{l2} = \exists \mita{Y} . \mita{g(Y);} \, \mita{\sf{in}} \, \A[\neg (\mita{l2} \vee \mita{l1}) \U ((\mita{l2} \wedge (\AX(\exists \mita{Z}\\\mbox{} . \mita{h(Z);}))) \vee \msf{After} \vee \msf{ErrorExit})] + +)) + +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +f(X); +... WHEN != h(Z) +g(Y); +h(Z); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\mita{\sf{let}} \, \mita{l1} = \exists \mita{X} . \mita{f(X);} \, \mita{\sf{in}} \, \mita{l1} \wedge (\AX(\exists \mita{Z} . (\mita{\sf{let}} \, \mita{l2} = \exists \mita{Y} . \mita{g(Y);} \, \mita{\sf{in}} \, \A[((\neg \mita{h(Z)}) \wedge (\neg (\mita{l2} \vee \mita{l1})))\\\mbox{} \U ((\mita{l2} \wedge (\AX(\mita{h(Z);}))) \vee \msf{After} \vee \msf{ErrorExit})] + +))) + +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +f(X); +... WHEN != h(Q) +g(Y); +h(Z); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\mita{\sf{let}} \, \mita{l1} = \exists \mita{X} . \mita{f(X);} \, \mita{\sf{in}} \, \mita{l1} \wedge (\AX(\mita{\sf{let}} \, \mita{l2} = \exists \mita{Y} . \mita{g(Y);} \, \mita{\sf{in}} \, \A[((\neg (\exists \mita{Q} . \mita{h(Q)})) \wedge (\neg (\mita{l2}\\\mbox{} \vee \mita{l1}))) \U ((\mita{l2} \wedge (\AX(\exists \mita{Z} . \mita{h(Z);}))) \vee \msf{After} \vee \msf{ErrorExit})] + +)) + +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +if (X) { + ... +} else { + g(X); +} +h(Z); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{X} . (\mita{\sf{let}} \, \mita{l0} = \msf{FalseBranch} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l1} = \msf{After} \, \mita{\sf{in}} \, \mita{if (X) } \wedge (\AX(\mita{\sf{let}} \, \mita{l2} = \msf{Paren}(p0)\\\mbox{} \, \mita{\sf{in}} \, (\msf{TrueBranch} \wedge (\AX(\exists \mita{p0} . (\mita{\sf{let}} \, \mita{l6} = \mita{{\ttlb} + } \wedge \mita{l2} \, \mita{\sf{in}} \, \mita{l6} \wedge (\AX(\mita{\sf{let}} \, \mita{l5} = \mita{ +{\ttrb}} \wedge \mita{l2} \, \mita{\sf{in}} \, \A[\neg (\mita{l5}\\\mbox{} \vee \mita{l6}) \U (\mita{l5} \vee \mita{l1} \vee \msf{ErrorExit})] + +)) +)))) \vee (\mita{l0} \wedge (\AX(\exists \mita{p0} . (\mita{{\ttlb} + } \wedge \mita{l2} \wedge (\AX(\mita{g(X);} \wedge (\AX(\mita{ +{\ttrb}}\\\mbox{} \wedge \mita{l2})))))))) \vee (\mita{l1} \wedge (\AX(\exists \mita{Z} . \mita{h(Z);}))) +)) \wedge (\EX\mita{l0}) \wedge (\EX\mita{l1}) +) +) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +<... + +( + h(X) +| + g(Y) +) +...> +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\AG(\mita{\sf{let}} \, \mita{l2} = \exists \mita{Y} . \exists \mita{X} . \mita{ +( +h(X) +| +g(Y) +)} \, \mita{\sf{in}} \, \mita{l2} \vee (\neg \mita{l2}) +) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +<... + +( + h(X) +| + g(Y) +) +...> +r(X); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{X} . (\mita{\sf{let}} \, \mita{l1} = \mita{r(X);} \, \mita{\sf{in}} \, \A[((\neg \mita{l1}) \wedge (\mita{\sf{let}} \, \mita{l0} = \exists \mita{Y} . \mita{ +( +h(X) +| +g(Y) +)} \, \mita{\sf{in}} \, \mita{l0} \vee (\neg \mita{l0})\\\mbox{} +)) \U (\mita{l1} \vee \msf{After} \vee \msf{ErrorExit})] + +) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + + +( +h(X) +| +g(Y) +) +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{Y} . \exists \mita{X} . \mita{ +( +h(X) +| +g(Y) +)} +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +m(Y); +?h(X); +g(Y); +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{Y} . (\mita{m(Y);} \wedge (\AX(\mita{\sf{let}} \, \mita{l0} = \mita{g(Y);} \, \mita{\sf{in}} \, ((\exists \mita{X} . \mita{h(X);}) \wedge (\AX\mita{l0})) \vee \mita{l0} +))) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +sht/*struct Scsi_Host_Template */.proc_info = proc_info_func; +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{proc\_info\_func} . \exists \mita{sht} . \mita{sht/*struct Scsi\_Host\_Template */.proc\_info = proc\_info\_func;} +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +proc_info_func(char *buffer, char **start, off_t offset, int length, + int hostno, int inout) { + ... + struct Scsi_Host *hostptr; + ... + hostptr = scsi_host_hn_get(hostno); + ... + ?if (hostptr == NULL) ?{ + ?... + ?} + ... + ?scsi_host_put(hostptr); + ... +} +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\exists \mita{hostno} . ((\exists \mita{buffer} . \exists \mita{start} . \exists \mita{offset} . \exists \mita{length} . \exists \mita{inout} . \mita{proc\_info\_func(char *buffer, char **start, off\_t offset, int length, + int hostno, int inout) })\\\mbox{} \wedge (\AX(\exists \mita{p1} . (\mita{\sf{let}} \, \mita{l33} = \msf{Paren}(p1) \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l5} = \mita{{\ttlb} + } \wedge \mita{l33} \, \mita{\sf{in}} \, \mita{l5} \wedge (\AX(\mita{\sf{let}} \, \mita{l53} = \mita{struct Scsi\_Host *hostptr;}\\\mbox{} \, \mita{\sf{in}} \, \A[\neg ((\exists \mita{hostptr} . \mita{l53}) \vee \mita{l5}) \U (\mita{\sf{let}} \, \mita{l1} = \msf{After} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l6} = \mita{l1} \vee \msf{ErrorExit}\\\mbox{} \, \mita{\sf{in}} \, (\exists \mita{hostptr} . (\mita{l53} \wedge (\AX(\mita{\sf{let}} \, \mita{l30} = \mita{hostptr = scsi\_host\_hn\_get(hostno);}\\\mbox{} \, \mita{\sf{in}} \, \A[\neg (\mita{l30} \vee \mita{l53}) \U ((\mita{l30} \wedge (\AX(\mita{\sf{let}} \, \mita{l32} = \msf{Paren}(p0) \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l50} = \mita{ +{\ttrb}} \wedge \mita{l32}\\\mbox{} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l14} = \mita{l50} \vee \mita{l6} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l2} = \msf{FallThrough} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l29} = \mita{l2} \vee \mita{l1} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l51} = \mita{{\ttlb} + }\\\mbox{} \wedge \mita{l32} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l0} = \msf{TrueBranch} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l52} = \mita{if (hostptr == NULL) } \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l20} = \mita{l52}\\\mbox{} \wedge (\AX((\mita{l0} \wedge (\AX(\exists \mita{p0} . (\mita{l51} \wedge (\AX\AF\mita{l14}))))) \vee \mita{l29})) \, \mita{\sf{in}} \, \A[\neg (\mita{l20} \vee \mita{l30}) \U ((\mita{\sf{let}} \, \mita{l8} = \mita{scsi\_host\_put(hostptr);}\\\mbox{} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l11} = \A[\neg \mita{l8} \U \mita{l6}] + \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l25} = \mita{l8} \wedge (\AX\mita{l11}) \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l39} = \neg \mita{l25} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l13} = (\mita{\sf{let}} \, \mita{l48} = (\mita{\sf{let}} \, \mita{l4} = \mita{ +{\ttrb}}\\\mbox{} \wedge \mita{l33} \, \mita{\sf{in}} \, \A[\neg (\mita{l4} \vee \mita{l8}) \U (\mita{l4} \vee \mita{l6})] + +) \, \mita{\sf{in}} \, (\mita{l8} \wedge (\AX\mita{l48})) \vee (\mita{l39} \wedge \mita{l48}) +) \vee \mita{l6} \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l36} = \neg (\mita{l8}\\\mbox{} \vee \mita{l20}) \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l34} = \mita{l0} \wedge (\AX(\exists \mita{p0} . (\mita{l51} \wedge (\AX\A[\neg (\mita{l50} \vee \mita{l51}) \U \mita{l14}] +)))) \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l16} = \EX\mita{l1}\\\mbox{} \, \mita{\sf{in}} \, (\mita{l52} \wedge (\AX(\mita{l34} \vee \mita{l2} \vee (\mita{l1} \wedge (\AX\A[\mita{l36} \U \mita{l13}] +)))) \wedge \mita{l16}) \vee ((\neg (\mita{l52} \wedge (\AX(\mita{l34}\\\mbox{} \vee \mita{l2} \vee (\mita{l1} \wedge (\AX\A[\mita{l36} \U (\mita{l25} \vee (\mita{l39} \wedge \mita{l11}) \vee \mita{l6})] +)))) \wedge \mita{l16})) \wedge (\A[\neg (\mita{l8} \vee (\mita{l52} \wedge (\AX(\mita{l34}\\\mbox{} \vee \mita{l29})))) \U \mita{l13}] +)) +) +) +) +) +) +) +) +) \vee \mita{l6})] + +) +) +) +) +) +) +) +) +))) \vee \mita{l6})] + +)))) \vee \mita{l6} +) +)] + +)) +) +)))) +\end{array}\] + +\begin{quote}\begin{verbatim} + +@@ +@@ + +proc_info_func(...) { + <... + +( + E->host_no == hostno +| + hostno +) + ...> +} +\end{verbatim}\end{quote} + +\[\begin{array}{l} +\mita{proc\_info\_func(...) } \wedge (\AX(\exists \mita{p0} . (\mita{\sf{let}} \, \mita{l3} = \msf{Paren}(p0) \, \mita{\sf{in}} \, (\mita{\sf{let}} \, \mita{l6} = \mita{{\ttlb} + } \wedge \mita{l3}\\\mbox{} \, \mita{\sf{in}} \, \mita{l6} \wedge (\AX(\mita{\sf{let}} \, \mita{l5} = \mita{ +{\ttrb}} \wedge \mita{l3} \, \mita{\sf{in}} \, \A[((\neg (\mita{l5} \vee \mita{l6})) \wedge (\mita{\sf{let}} \, \mita{l2} = \exists \mita{E} . \mita{ +( +E-\mth{>}host\_no == hostno +| +hostno +)}\\\mbox{} \, \mita{\sf{in}} \, \mita{l2} \vee (\neg \mita{l2}) +)) \U (\mita{l5} \vee \msf{After} \vee \msf{ErrorExit})] + +)) +) +))) +\end{array}\] + +\end{document} diff --git a/engine/transformation3.ml b/engine/transformation3.ml new file mode 100644 index 0000000..5691a73 --- /dev/null +++ b/engine/transformation3.ml @@ -0,0 +1,526 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Common + +module F = Control_flow_c + +(*****************************************************************************) +(* The functor argument *) +(*****************************************************************************) + +(* info passed recursively in monad in addition to binding *) +type xinfo = { + optional_storage_iso : bool; + optional_qualifier_iso : bool; + value_format_iso : bool; + current_rule_name : string; (* used for errors *) +} + +module XTRANS = struct + + (* ------------------------------------------------------------------------*) + (* Combinators history *) + (* ------------------------------------------------------------------------*) + (* + * version0: + * type ('a, 'b) transformer = + * 'a -> 'b -> Lib_engine.metavars_binding -> 'b + * exception NoMatch + * + * version1: + * type ('a, 'b) transformer = + * 'a -> 'b -> Lib_engine.metavars_binding -> 'b option + * use an exception monad + * + * version2: + * type tin = Lib_engine.metavars_binding + *) + + (* ------------------------------------------------------------------------*) + (* Standard type and operators *) + (* ------------------------------------------------------------------------*) + + type tin = { + extra: xinfo; + binding: Lib_engine.metavars_binding; + } + type 'x tout = 'x option + + type ('a, 'b) matcher = 'a -> 'b -> tin -> ('a * 'b) tout + + let (>>=) m f = fun tin -> + match m tin with + | None -> None + | Some (a,b) -> f a b tin + + let return = fun x -> fun tin -> + Some x + + (* can have fail in transform now that the process is deterministic ? *) + let fail = fun tin -> + None + + let (>||>) m1 m2 = fun tin -> + match m1 tin with + | None -> m2 tin + | Some x -> Some x (* stop as soon as have found something *) + + let (>|+|>) m1 m2 = m1 >||> m2 + + let (>&&>) f m = fun tin -> + if f tin then m tin else fail tin + + let optional_storage_flag f = fun tin -> + f (tin.extra.optional_storage_iso) tin + + let optional_qualifier_flag f = fun tin -> + f (tin.extra.optional_qualifier_iso) tin + + let value_format_flag f = fun tin -> + f (tin.extra.value_format_iso) tin + + let mode = Cocci_vs_c_3.TransformMode + + (* ------------------------------------------------------------------------*) + (* Exp *) + (* ------------------------------------------------------------------------*) + let cocciExp = fun expf expa node -> fun tin -> + + let bigf = { + Visitor_c.default_visitor_c_s with + Visitor_c.kexpr_s = (fun (k, bigf) expb -> + match expf expa expb tin with + | None -> (* failed *) k expb + | Some (x, expb) -> expb); + } + in + Some (expa, Visitor_c.vk_node_s bigf node) + + + (* same as cocciExp, but for expressions in an expression, not expressions + in a node *) + let cocciExpExp = fun expf expa expb -> fun tin -> + + let bigf = { + Visitor_c.default_visitor_c_s with + Visitor_c.kexpr_s = (fun (k, bigf) expb -> + match expf expa expb tin with + | None -> (* failed *) k expb + | Some (x, expb) -> expb); + } + in + Some (expa, Visitor_c.vk_expr_s bigf expb) + + + let cocciTy = fun expf expa node -> fun tin -> + + let bigf = { + Visitor_c.default_visitor_c_s with + Visitor_c.ktype_s = (fun (k, bigf) expb -> + match expf expa expb tin with + | None -> (* failed *) k expb + | Some (x, expb) -> expb); + } + in + Some (expa, Visitor_c.vk_node_s bigf node) + + + (* ------------------------------------------------------------------------*) + (* Tokens *) + (* ------------------------------------------------------------------------*) + let check_pos info mck pos = + match mck with + | Ast_cocci.PLUS -> raise Impossible + | Ast_cocci.CONTEXT (Ast_cocci.FixPos (i1,i2),_) + | Ast_cocci.MINUS (Ast_cocci.FixPos (i1,i2),_) -> + pos <= i2 && pos >= i1 + | Ast_cocci.CONTEXT (Ast_cocci.DontCarePos,_) + | Ast_cocci.MINUS (Ast_cocci.DontCarePos,_) -> + true + | _ -> + match info with + Some info -> + failwith + (Printf.sprintf + "wierd: dont have position info for the mcodekind in line %d column %d" + info.Ast_cocci.line info.Ast_cocci.column) + | None -> + failwith "wierd: dont have position info for the mcodekind" + + + let tag_with_mck mck ib = fun tin -> + + let cocciinforef = ib.Ast_c.cocci_tag in + let (oldmcode, oldenv) = !cocciinforef in + + let mck = + if !Flag_parsing_cocci.sgrep_mode + then Sgrep.process_sgrep ib mck + else mck + in + (match mck, Ast_c.pinfo_of_info ib with + | _, Ast_c.AbstractLineTok _ -> raise Impossible + | Ast_cocci.MINUS(_), Ast_c.ExpandedTok _ -> + failwith ("try to delete an expanded token: " ^ (Ast_c.str_of_info ib)) + | _ -> () + ); + + match (oldmcode,mck) with + | (Ast_cocci.CONTEXT(_,Ast_cocci.NOTHING), _) + | (_, Ast_cocci.CONTEXT(_,Ast_cocci.NOTHING)) + -> + cocciinforef := (mck, tin.binding); + ib + + | _ -> + if (oldmcode, oldenv) = (mck, tin.binding) + then begin + if !Flag.show_misc + then pr2 "already tagged but with same mcode, so safe"; + ib + end + else + if !Flag.sgrep_mode2 + then ib (* safe *) + else + begin + Format.set_formatter_out_channel stderr; + Common.pr2 "SP mcode "; + Pretty_print_cocci.print_mcodekind oldmcode; + Format.print_newline(); + Common.pr2 "C code mcode "; + Pretty_print_cocci.print_mcodekind mck; + Format.print_newline(); + Format.print_flush(); + failwith + (Common.sprintf "%s: already tagged token:\n%s" + tin.extra.current_rule_name + (Common.error_message (Ast_c.file_of_info ib) + (Ast_c.str_of_info ib, Ast_c.opos_of_info ib))) + end + + let tokenf ia ib = fun tin -> + let (_,i,mck,_) = ia in + let pos = Ast_c.info_to_fixpos ib in + if check_pos (Some i) mck pos + then return (ia, tag_with_mck mck ib tin) tin + else fail tin + + let tokenf_mck mck ib = fun tin -> + let pos = Ast_c.info_to_fixpos ib in + if check_pos None mck pos + then return (mck, tag_with_mck mck ib tin) tin + else fail tin + + + (* ------------------------------------------------------------------------*) + (* Distribute mcode *) + (* ------------------------------------------------------------------------*) + + (* When in the SP we attach something to a metavariable, or delete it, as in + * - S + * + foo(); + * we have to minusize all the token that compose S in the C code, and + * attach the 'foo();' to the right token, the one at the very right. + *) + + type 'a distributer = + (Ast_c.info -> Ast_c.info) * (* what to do on left *) + (Ast_c.info -> Ast_c.info) * (* what to do on middle *) + (Ast_c.info -> Ast_c.info) * (* what to do on right *) + (Ast_c.info -> Ast_c.info) -> (* what to do on both *) + 'a -> 'a + + let distribute_mck mcodekind distributef expr tin = + match mcodekind with + | Ast_cocci.MINUS (pos,any_xxs) -> + distributef ( + (fun ib -> tag_with_mck (Ast_cocci.MINUS (pos,any_xxs)) ib tin), + (fun ib -> tag_with_mck (Ast_cocci.MINUS (pos,[])) ib tin), + (fun ib -> tag_with_mck (Ast_cocci.MINUS (pos,[])) ib tin), + (fun ib -> tag_with_mck (Ast_cocci.MINUS (pos,any_xxs)) ib tin) + ) expr + | Ast_cocci.CONTEXT (pos,any_befaft) -> + (match any_befaft with + | Ast_cocci.NOTHING -> expr + + | Ast_cocci.BEFORE xxs -> + distributef ( + (fun ib -> tag_with_mck + (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFORE xxs)) ib tin), + (fun x -> x), + (fun x -> x), + (fun ib -> tag_with_mck + (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFORE xxs)) ib tin) + ) expr + | Ast_cocci.AFTER xxs -> + distributef ( + (fun x -> x), + (fun x -> x), + (fun ib -> tag_with_mck + (Ast_cocci.CONTEXT (pos,Ast_cocci.AFTER xxs)) ib tin), + (fun ib -> tag_with_mck + (Ast_cocci.CONTEXT (pos,Ast_cocci.AFTER xxs)) ib tin) + ) expr + + | Ast_cocci.BEFOREAFTER (xxs, yys) -> + distributef ( + (fun ib -> tag_with_mck + (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFORE xxs)) ib tin), + (fun x -> x), + (fun ib -> tag_with_mck + (Ast_cocci.CONTEXT (pos,Ast_cocci.AFTER yys)) ib tin), + (fun ib -> tag_with_mck + (Ast_cocci.CONTEXT (pos,Ast_cocci.BEFOREAFTER (xxs,yys))) + ib tin) + ) expr + + ) + | Ast_cocci.PLUS -> raise Impossible + + + (* use new strategy, collect ii, sort, recollect and tag *) + + let mk_bigf (maxpos, minpos) (lop,mop,rop,bop) = + let bigf = { + Visitor_c.default_visitor_c_s with + Visitor_c.kinfo_s = (fun (k,bigf) i -> + let pos = Ast_c.info_to_fixpos i in + match () with + | _ when Ast_cocci.equal_pos pos maxpos && + Ast_cocci.equal_pos pos minpos -> bop i + | _ when Ast_cocci.equal_pos pos maxpos -> rop i + | _ when Ast_cocci.equal_pos pos minpos -> lop i + | _ -> mop i + ) + } in + bigf + + let distribute_mck_expr (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> + Visitor_c.vk_expr_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x + + let distribute_mck_args (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> + Visitor_c.vk_args_splitted_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x + + let distribute_mck_type (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> + Visitor_c.vk_type_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x + + let distribute_mck_ini (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> + Visitor_c.vk_ini_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x + + let distribute_mck_param (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x -> + Visitor_c.vk_param_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x + + let distribute_mck_params (maxpos, minpos) = fun (lop,mop,rop,bop) ->fun x -> + Visitor_c.vk_params_splitted_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) + x + + let distribute_mck_node (maxpos, minpos) = fun (lop,mop,rop,bop) ->fun x -> + Visitor_c.vk_node_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) + x + + let distribute_mck_struct_fields (maxpos, minpos) = + fun (lop,mop,rop,bop) ->fun x -> + Visitor_c.vk_struct_fields_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) + x + + let distribute_mck_cst (maxpos, minpos) = + fun (lop,mop,rop,bop) ->fun x -> + Visitor_c.vk_cst_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) + x + + + let distribute_mck_define_params (maxpos, minpos) = fun (lop,mop,rop,bop) -> + fun x -> + Visitor_c.vk_define_params_splitted_s + (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) + x + + let get_pos mck = + match mck with + | Ast_cocci.PLUS -> raise Impossible + | Ast_cocci.CONTEXT (Ast_cocci.FixPos (i1,i2),_) + | Ast_cocci.MINUS (Ast_cocci.FixPos (i1,i2),_) -> + Ast_cocci.FixPos (i1,i2) + | Ast_cocci.CONTEXT (Ast_cocci.DontCarePos,_) + | Ast_cocci.MINUS (Ast_cocci.DontCarePos,_) -> + Ast_cocci.DontCarePos + | _ -> failwith "wierd: dont have position info for the mcodekind" + + let distrf (ii_of_x_f, distribute_mck_x_f) = + fun ia x -> fun tin -> + let mck = Ast_cocci.get_mcodekind ia in + let (max, min) = Lib_parsing_c.max_min_by_pos (ii_of_x_f x) + in + if + (* bug: check_pos mck max && check_pos mck min + * + * if do that then if have - f(...); and in C f(1,2); then we + * would get a "already tagged" because the '...' would sucess in + * transformaing both '1' and '1,2'. So being in the range is not + * enough. We must be equal exactly to the range! + *) + (match get_pos mck with + | Ast_cocci.DontCarePos -> true + | Ast_cocci.FixPos (i1, i2) -> + i1 = min && i2 = max + | _ -> raise Impossible + ) + + then + return ( + ia, + distribute_mck mck (distribute_mck_x_f (max,min)) x tin + ) tin + else fail tin + + + let distrf_e = distrf (Lib_parsing_c.ii_of_expr, distribute_mck_expr) + let distrf_args = distrf (Lib_parsing_c.ii_of_args, distribute_mck_args) + let distrf_type = distrf (Lib_parsing_c.ii_of_type, distribute_mck_type) + let distrf_param = distrf (Lib_parsing_c.ii_of_param, distribute_mck_param) + let distrf_params = distrf (Lib_parsing_c.ii_of_params,distribute_mck_params) + let distrf_ini = distrf (Lib_parsing_c.ii_of_ini,distribute_mck_ini) + let distrf_node = distrf (Lib_parsing_c.ii_of_node,distribute_mck_node) + let distrf_struct_fields = + distrf (Lib_parsing_c.ii_of_struct_fields, distribute_mck_struct_fields) + let distrf_cst = + distrf (Lib_parsing_c.ii_of_cst, distribute_mck_cst) + let distrf_define_params = + distrf (Lib_parsing_c.ii_of_define_params,distribute_mck_define_params) + + + (* ------------------------------------------------------------------------*) + (* Environment *) + (* ------------------------------------------------------------------------*) + let meta_name_to_str (s1, s2) = + s1 ^ "." ^ s2 + + let envf keep _inherited = fun (s, value, _) f tin -> + let s = Ast_cocci.unwrap_mcode s in + let v = + if keep = Type_cocci.Saved + then ( + try Some (List.assoc s tin.binding) + with Not_found -> + pr2(sprintf + "Don't find value for metavariable %s in the environment" + (meta_name_to_str s)); + None) + else + (* not raise Impossible! *) + Some (value) + in + match v with + | None -> fail tin + | Some (value') -> + + (* Ex: in cocci_vs_c someone wants to add a binding. Here in + * transformation3 the value for this var may be already in the + * env, because for instance its value were fixed in a previous + * SmPL rule. So here we want to check that this is the same value. + * If forget to do the check, what can happen ? Because of Exp + * and other disjunctive feature of cocci_vs_c (>||>), we + * may accept a match at a wrong position. Maybe later this + * will be detected via the pos system on tokens, but maybe + * not. So safer to keep the check. + *) + + (*f () tin*) + if Cocci_vs_c_3.equal_metavarval value value' + then f () tin + else fail tin + + + let check_constraints matcher constraints exp = fun f tin -> f () tin + + (* ------------------------------------------------------------------------*) + (* Environment, allbounds *) + (* ------------------------------------------------------------------------*) + let (all_bound : Ast_cocci.meta_name list -> tin -> bool) = fun l tin -> + true (* in transform we don't care ? *) + +end + +(*****************************************************************************) +(* Entry point *) +(*****************************************************************************) +module TRANS = Cocci_vs_c_3.COCCI_VS_C (XTRANS) + + +let transform_re_node a b tin = + match TRANS.rule_elem_node a b tin with + | None -> raise Impossible + | Some (_sp, b') -> b' + + +let (transform2: string (* rule name *) -> string list (* dropped_isos *) -> + Lib_engine.transformation_info -> F.cflow -> F.cflow) = + fun rule_name dropped_isos xs cflow -> + + let extra = { + optional_storage_iso = not(List.mem "optional_storage" dropped_isos); + optional_qualifier_iso = not(List.mem "optional_qualifier" dropped_isos); + value_format_iso = not(List.mem "value_format" dropped_isos); + current_rule_name = rule_name; + } in + + (* find the node, transform, update the node, and iter for all elements *) + + xs +> List.fold_left (fun acc (nodei, binding, rule_elem) -> + (* subtil: not cflow#nodes but acc#nodes *) + let node = acc#nodes#assoc nodei in + + if !Flag.show_misc + then pr2 "transform one node"; + + let tin = { + XTRANS.extra = extra; + XTRANS.binding = binding; + } in + + let node' = transform_re_node rule_elem node tin in + + (* assert that have done something. But with metaruleElem sometimes + dont modify fake nodes. So special case before on Fake nodes. *) + (match F.unwrap node with + | F.Enter | F.Exit | F.ErrorExit + | F.EndStatement _ | F.CaseNode _ + | F.Fake + | F.TrueNode | F.FalseNode | F.AfterNode | F.FallThroughNode + -> () + | _ -> () (* assert (not (node =*= node')); *) + ); + + (* useless, we dont go back from flow to ast now *) + (* let node' = lastfix_comma_struct node' in *) + + acc#replace_node (nodei, node'); + acc + ) cflow + + + +let transform a b c d = + Common.profile_code "Transformation3.transform" + (fun () -> transform2 a b c d) diff --git a/engine/transformation3.mli b/engine/transformation3.mli new file mode 100644 index 0000000..2126bde --- /dev/null +++ b/engine/transformation3.mli @@ -0,0 +1,5 @@ +(* note that now we do the transformation via side effect on ast *) +val transform : + string (* rule name *) -> string list (* dropped isos *) -> + Lib_engine.transformation_info -> + Control_flow_c.cflow -> Control_flow_c.cflow (* could be unit *) diff --git a/env.csh b/env.csh new file mode 100644 index 0000000..6c76161 --- /dev/null +++ b/env.csh @@ -0,0 +1,8 @@ +echo setting COCCINELLE_HOME +setenv COCCINELLE_HOME `pwd` + +echo setting LD_LIBRARY_PATH +setenv LD_LIBRARY_PATH $COCCINELLE_HOME:$LD_LIBRARY_PATH + +echo setting PYTHONPATH +setenv PYTHONPATH $COCCINELLE_HOME/python:$PYTHONPATH diff --git a/env.sh b/env.sh new file mode 100644 index 0000000..ba38c87 --- /dev/null +++ b/env.sh @@ -0,0 +1,34 @@ +# I put both stuff useful for the user and developer in this file. Could +# separate and have a env-user.sh, env-compile.sh, env-developer.sh, +# but it's not worth it. + +#!!!!You need to source me with "source env.sh" from the good directory!!!! +if [ ! -r standard.iso ] + then echo "There is no standard.iso here. +Are you sure you run this script from the coccinelle directory ? +"; +else + + +############################################################################## +# Compile +############################################################################## + +############################################################################## +# Run +############################################################################## + +# To find the data/ files such as the default standard.h file. +# Cf also globals/config.ml +echo setting COCCINELLE_HOME +export COCCINELLE_HOME=`pwd` + +# To find pycaml dynamic library +echo setting LD_LIBRARY_PATH +export LD_LIBRARY_PATH=$COCCINELLE_HOME:$LD_LIBRARY_PATH + +# To find .py files like the one in python/coccib +echo setting PYTHONPATH +export PYTHONPATH=$COCCINELLE_HOME/python:$PYTHONPATH + +fi \ No newline at end of file diff --git a/extra/.depend b/extra/.depend new file mode 100644 index 0000000..a321b42 --- /dev/null +++ b/extra/.depend @@ -0,0 +1,17 @@ +c_info.cmi: ../commons/ograph_extended.cmi ../commons/common.cmi \ + ../parsing_c/ast_c.cmo +classic_patch.cmi: ../commons/common.cmi +kbuild.cmi: ../commons/common.cmi +maintainers.cmi: ../commons/common.cmi +c_info.cmo: ../parsing_c/visitor_c.cmi ../commons/ograph_extended.cmi \ + ../globals/flag.cmo ../commons/common.cmi ../parsing_c/ast_c.cmo \ + c_info.cmi +c_info.cmx: ../parsing_c/visitor_c.cmx ../commons/ograph_extended.cmx \ + ../globals/flag.cmx ../commons/common.cmx ../parsing_c/ast_c.cmx \ + c_info.cmi +classic_patch.cmo: ../commons/common.cmi classic_patch.cmi +classic_patch.cmx: ../commons/common.cmx classic_patch.cmi +kbuild.cmo: ../commons/common.cmi kbuild.cmi +kbuild.cmx: ../commons/common.cmx kbuild.cmi +maintainers.cmo: ../commons/common.cmi maintainers.cmi +maintainers.cmx: ../commons/common.cmx maintainers.cmi diff --git a/extra/Makefile b/extra/Makefile new file mode 100644 index 0000000..1442bdb --- /dev/null +++ b/extra/Makefile @@ -0,0 +1,72 @@ +TARGET=extra + +SOURCES = classic_patch.ml kbuild.ml maintainers.ml c_info.ml + +SYSLIBS = str.cma unix.cma + +LIBS=../commons/commons.cma ../parsing_c/parsing_c.cma ../globals/globals.cma +INCLUDES= -I ../commons -I ../globals -I ../parsing_cocci -I ../parsing_c + +#for warning: -w A +#for profiling: -p -inline 0 with OCAMLOPT +OCAMLCFLAGS ?= -g -dtypes +OCAMLC =ocamlc$(OPTBIN) $(OCAMLCFLAGS) $(INCLUDES) +OCAMLOPT = ocamlopt$(OPTBIN) $(OPTFLAGS) $(INCLUDES) +OCAMLDEP = ocamldep$(OPTBIN) $(INCLUDES) +OCAMLMKTOP=ocamlmktop -g -custom $(INCLUDES) + + +OBJS = $(SOURCES:.ml=.cmo) +OPTOBJS = $(SOURCES:.ml=.cmx) + + +all: $(TARGET).cma + +all.opt: $(TARGET).cmxa + +$(TARGET).byte: $(OBJS) $(LIBS) + $(OCAMLC) -o $(TARGET).byte $(SYSLIBS) $(LIBS) $(OBJS) + +$(TARGET).opt: $(OPTOBJS) $(LIBS:.cma=.cmxa) + $(OCAMLOPT) -o $(TARGET).opt $(SYSLIBS:.cma=.cmxa) $(LIBS:.cma=.cmxa) $(OPTOBJS) + +$(TARGET).cma: $(OBJS) + $(OCAMLC) -a -o $(TARGET).cma $(OBJS) + +$(TARGET).cmxa: $(OPTOBJS) $(LIBS:.cma=.cmxa) + $(OCAMLOPT) -a -o $(TARGET).cmxa $(OPTOBJS) + +$(TARGET).top: $(OBJS) $(LIBS) + $(OCAMLMKTOP) -o $(TARGET).top $(SYSLIBS) $(LIBS) $(OBJS) + +clean:: + rm -f $(TARGET).byte $(TARGET).opt rm -f $(TARGET).top + + + +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) -c $< +.mli.cmi: + $(OCAMLC) -c $< +.ml.cmx: + $(OCAMLOPT) -c $< + +.ml.mldepend: + $(OCAMLC) -i $< + +clean:: + rm -f *.cm[ioxa] *.o *.a *.cmxa *.annot + +clean:: + rm -f *~ .*~ gmon.out #*# + +beforedepend:: + +depend:: beforedepend + $(OCAMLDEP) *.mli *.ml > .depend + +-include .depend + + diff --git a/extra/c_info.ml b/extra/c_info.ml new file mode 100644 index 0000000..9169bb5 --- /dev/null +++ b/extra/c_info.ml @@ -0,0 +1,525 @@ +open Common + +open Ast_c + + +(* used both for storing the entities 'defined' and 'used' in a file, but + * depending on the use, some fields may not be used + *) +type entities = { + macros: string hashset; (* object-like or function-like *) + variables: string hashset; + static_variables: string hashset; (* for defined only *) + functions: string hashset; + static_functions: string hashset; (* for defined only *) + structs: string hashset; (* union defs, enum defs, enum values *) + typedefs: string hashset; + include_c: filename hashset; (* for used only *) +} + +(* inverted index *) +type idx_entities = { + idx_macros: (string, (filename hashset)) Hashtbl.t; + idx_variables: (string, (filename hashset)) Hashtbl.t; + idx_functions: (string, (filename hashset)) Hashtbl.t; + idx_structs: (string, (filename hashset)) Hashtbl.t; + idx_typedefs: (string, (filename hashset)) Hashtbl.t; +} + +let empty_entities () = { + macros = Hashtbl.create 101; + variables = Hashtbl.create 101; + static_variables = Hashtbl.create 101; + functions = Hashtbl.create 101; + static_functions = Hashtbl.create 101; + structs = Hashtbl.create 101; + typedefs = Hashtbl.create 101; + include_c = Hashtbl.create 101; +} + +let empty_idx_entities () = { + idx_macros = Hashtbl.create 101; + idx_variables = Hashtbl.create 101; + idx_functions = Hashtbl.create 101; + idx_structs = Hashtbl.create 101; + idx_typedefs = Hashtbl.create 101; +} + + +let h_to_l h = Common.hashset_to_list h + +let print_entities e = + begin +(* e.macros +> h_to_l +> List.iter (fun s -> pr("MACRO: " ^ s)); *) + e.variables +> h_to_l +> List.iter (fun s -> pr("VAR: " ^ s)); + e.static_variables +> h_to_l +> List.iter (fun s -> pr("STATICVAR: " ^ s)); + e.functions +> h_to_l +> List.iter (fun s -> pr("FUNC: " ^ s)); + e.static_functions +> h_to_l +> List.iter (fun s -> pr("STATICFUNC: " ^ s)); + e.structs +> h_to_l +> List.iter (fun s -> pr("STRUCT: "^s)); + e.typedefs +> h_to_l +> List.iter (fun s -> pr("TYPEDEF: "^s)); + e.include_c +> h_to_l +> List.iter (fun s -> pr("INCLUDEC: "^s)); + end + + +(* the defined_stuff and used_stuff may not be 100% correct. They don't handle + * I think every dark corner of the C. It's possible to shadow in so many + * ways. + *) + +(* look only for toplevel definition *) +let defined_stuff xs = + let e = empty_entities() in + let add h s = Hashtbl.add h s true in + + (* look only for toplevel definition: don't recurse, don't call k *) + let bigf = { Visitor_c.default_visitor_c with + Visitor_c.ktoplevel = (fun (k,bigf) t -> + match t with + | Declaration decl -> + (match decl with + | DeclList (xs, ii) -> + xs +> List.iter (fun ((var, t, sto, _local), iicomma) -> + Visitor_c.vk_type bigf t; + match var, sto with + | None, _ -> () + | Some ((s, ini), ii_s_ini), (StoTypedef,inline) -> + add e.typedefs s; + | Some ((s, ini), ii_s_ini), (Sto Static,inline) -> + (* need add them to do the adjust_need *) + add e.static_variables s; + + | Some ((s, ini), ii_s_ini), (Sto Extern,inline) -> + () + | Some ((s, ini), ii_s_ini), (_,inline) -> + add e.variables s; + ); + | MacroDecl ((s, args),ii) -> () + ) + + | Definition def -> + let ((s, typ, sto, cp), ii) = def in + (match sto with + | Sto Static, inline -> + (* need add them to do the adjust_need *) + add e.static_functions s + | _ -> + add e.functions s + ) + + | Include includ -> () + | Define ((s,ii), body) -> add e.macros s + | MacroTop (s, args, ii) -> () + + | EmptyDef _ | NotParsedCorrectly _ | FinalDef _ -> () + ); + + Visitor_c.ktype = (fun (k, bigf) t -> + match Ast_c.unwrap_typeC t with + | StructUnion (su, sopt, fields) -> + sopt +> do_option (fun s -> + add e.structs s; + ); + + | _ -> () + ); + + } in + xs +> List.iter (fun (p, info_item) -> Visitor_c.vk_toplevel bigf p); + e + + + + + + + + +(* look only for use of external stuff. Don't consider local vars, + * typedefs, structures *) +let used_stuff xs = + + let e = empty_entities() in + let add h s = Hashtbl.replace h s true in + + let initial_env = [ + ["NULL"; + "do_gettimeofday"; + "le32_to_cpu"; + "udelay"; + "printk"; + (* !!! sometimes considered as VAR :( *) + "u8"; "u16"; "u32"; + "s32"; + ] +> List.map (fun s -> s, true); + ] + in + let regexp_macro = Str.regexp + "^[A-Z_][A-Z_0-9]*$" + in + + let (_env: (string, bool) Common.scoped_env ref) = ref initial_env in + + + let bigf = { Visitor_c.default_visitor_c with + + (* --------- handling scope of variables (and also some use) --------- *) + Visitor_c.kstatement = (fun (k, bigf) st -> + match st with + | Compound statxs, ii -> Common.do_in_new_scope _env (fun () -> k st); + | _ -> k st + ); + Visitor_c.kdecl = (fun (k, bigf) d -> + k d; (* to add possible definition in type found in Decl *) + (match d with + | (DeclList (xs, ii)) -> + xs +> List.iter (fun ((var, t, sto, _local), iicomma) -> + var +> do_option (fun ((s, ini), ii_s_ini) -> + match sto with + | StoTypedef, _inline -> + (* add_binding (TypeDef (s)) true; *) + () + | _ -> + Common.add_in_scope _env (s, true); + ); + ); + | _ -> () + ); + ); + Visitor_c.ktoplevel = (fun (k, bigf) elem -> + match elem with + | Definition def -> + let (funcs, ((returnt, (paramst, b))), sto, statxs),ii = def in + Common.do_in_new_scope _env (fun () -> + paramst +> List.iter (fun (((b, s, t), _),_) -> + match s with + | Some s -> Common.add_in_scope _env (s, true) + | None -> pr2 "no type, certainly because Void type ?" + ); + k elem + ); + | Define (s, (defkind, defval)) -> + Common.do_in_new_scope _env (fun () -> + (match defkind with + | DefineFunc (params, ii) -> + params +> List.iter (fun ((s,iis), iicomma) -> + Common.add_in_scope _env (s, true) + ); + | _ -> () + ); + k elem + ); + | Include ((inc_file,ii), posref) -> + (match inc_file with + | Local [x] when x =~ ".*\\.c$" -> + add e.include_c x + | _ -> () + ) + | _ -> k elem + ); + + + (* --------- and now looking for use --------- *) + Visitor_c.kexpr = (fun (k,bigf) x -> + match Ast_c.unwrap_expr x with + + | FunCall (((Ident f, typ), ii), args) -> + if not (Common.member_env_key f !_env) + then + if f ==~ regexp_macro + then add e.macros f + else add e.functions f + ; + args +> List.iter (fun (x,ii) -> + Visitor_c.vk_argument bigf x + ); + | Ident s -> + if not (Common.member_env_key s !_env) + then + if s ==~ regexp_macro + then add e.macros s + else add e.variables s + + | _ -> k x + ); + + Visitor_c.ktype = (fun (k,bigf) t -> + match Ast_c.unwrap_typeC t with + | StructUnionName (su, s) -> + if not (Common.member_env_key s !_env) + then + add e.structs s; + | TypeName (s,_typ) -> + if not (Common.member_env_key s !_env) + then + add e.typedefs s; + | _ -> k t + ); + + } in + xs +> List.iter (fun (p, info_item) -> Visitor_c.vk_toplevel bigf p); + e + + + + +(* for the moment, just look if it looks like a linux module file *) +let extra_stuff xs = + let is_module = ref false in + + (* look only for toplevel definition: don't recurse, don't call k *) + let bigf = { Visitor_c.default_visitor_c with + Visitor_c.ktoplevel = (fun (k,bigf) t -> + match t with + | MacroTop (s, args, ii) -> + if s = "module_init" + then is_module := true; + | Definition def -> + let ((s, typ, sto, cp), ii) = def in + if s = "init_module" + then is_module := true; + + | _ -> () + ); + } in + xs +> List.iter (fun (p, info_item) -> Visitor_c.vk_toplevel bigf p); + !is_module + + + +let adjust_used_only_external used defined = + begin + used.variables +> h_to_l +> List.iter (fun s -> + if Hashtbl.mem defined.variables s || + Hashtbl.mem defined.static_variables s || + (* sometimes functions are used as variable, when for example + * stored in a pointer variable, so look also for function here. + *) + Hashtbl.mem defined.functions s || + Hashtbl.mem defined.static_functions s + then Hashtbl.remove used.variables s + ); + used.functions +> h_to_l +> List.iter (fun s -> + if Hashtbl.mem defined.functions s || + Hashtbl.mem defined.static_functions s + then Hashtbl.remove used.functions s + ); + used.structs +> h_to_l +> List.iter (fun s -> + if Hashtbl.mem defined.structs s + then Hashtbl.remove used.structs s + ); + used.typedefs +> h_to_l +> List.iter (fun s -> + if Hashtbl.mem defined.typedefs s + then Hashtbl.remove used.typedefs s + ); + end + + + + +type file_info = { + used: entities; + defined: entities; + is_module: bool; +} +type global_definitions = idx_entities + +let mk_global_definitions_index xs = + let idx = empty_idx_entities () in + xs +> List.iter (fun (file, {defined = defined}) -> + defined.variables +> h_to_l +> List.iter (fun s -> + Common.hash_hashset_add s file idx.idx_variables; + ); + defined.functions +> h_to_l +> List.iter (fun s -> + Common.hash_hashset_add s file idx.idx_functions; + ); + defined.structs +> h_to_l +> List.iter (fun s -> + Common.hash_hashset_add s file idx.idx_structs; + ); + defined.typedefs +> h_to_l +> List.iter (fun s -> + Common.hash_hashset_add s file idx.idx_typedefs; + ); + ); + idx + +let known_duplicate = + ["init_module"; "cleanup_module"; + "main";"usage"; + ] + +let check_no_duplicate_global_definitions idx = + begin + pr2 "DUPLICATE processing:"; + idx.idx_functions +> hash_to_list +> List.iter (fun (f, set) -> + let xs = hash_to_list set in + if List.length xs <> 1 && not (List.mem f known_duplicate) + then + pr2 ("multiple def for : " ^ f ^ " in " ^ + (join " " (List.map (fun x -> basename (fst x)) xs))); + ); + end + +type dependencies_graph = + ((filename * file_info) * string, bool) Ograph_extended.ograph_mutable + + +let build_graph xs dep graphfile = + let g = ref (new Ograph_extended.ograph_mutable) in + let h = Hashtbl.create 101 in + let s_to_nodei s = Hashtbl.find h s in + + pr2 "BUILDING graph:"; + + let arrow a b c d = + (sprintf "%-20s -- %s:%25s --> %s" a b c d) + in + with_open_outfile (graphfile ^ ".graph") (fun (pr_no_nl,chan) -> + let pr_arrow a b c d = + pr2 (arrow a b c d); + pr_no_nl (arrow a b c d ^ "\n"); + in + + (* build nodes *) + xs +> List.iter (fun (file, cinfo) -> + let s = (if cinfo.is_module then "[M]" else "") ^ Filename.basename file in + let xi = !g#add_node ((file, cinfo), s) in + Hashtbl.add h file xi; + ); + + xs +> List.iter (fun (file, {used = used}) -> + + used.functions +> h_to_l +> List.iter (fun s -> + match Common.optionise (fun () -> Hashtbl.find dep.idx_functions s) with + | None -> () + | Some hset -> + hset +> h_to_l +> List.iter (fun file_defined -> + !g#add_arc ((s_to_nodei file, s_to_nodei file_defined), true); + let (file, file_defined) = basename file, basename file_defined in + pr_arrow file "f" s file_defined; + ); + ); + (* sometime use functions as variable *) + used.variables +> h_to_l +> List.iter (fun s -> + match Common.optionise (fun () -> Hashtbl.find dep.idx_functions s) with + | None -> () + | Some hset -> + hset +> h_to_l +> List.iter (fun file_defined -> + !g#add_arc ((s_to_nodei file, s_to_nodei file_defined), true); + let (file, file_defined) = basename file, basename file_defined in + pr_arrow file "f" s file_defined; + ); + ); + + used.variables +> h_to_l +> List.iter (fun s -> + match Common.optionise (fun () -> Hashtbl.find dep.idx_variables s) with + | None -> () + | Some hset -> + hset +> h_to_l +> List.iter (fun file_defined -> + !g#add_arc ((s_to_nodei file, s_to_nodei file_defined), true); + let (file, file_defined) = basename file, basename file_defined in + pr_arrow file "v" s file_defined; + ); + ); + + used.include_c +> h_to_l +> List.iter (fun local_file -> + let file_defined = Filename.concat (dirname file) local_file in + try ( + !g#add_arc ((s_to_nodei file, s_to_nodei file_defined), true); + let (file, file_defined) = basename file, basename file_defined in + pr_arrow file "I" "include" file_defined; + ) + with Not_found -> + pr2 ("can't find included C file: " ^ file_defined) + ) + +(* + used.structs +> h_to_l +> List.iter (fun s -> + match Common.optionise (fun () -> Hashtbl.find dep.idx_structs s) with + | None -> () + | Some hset -> + hset +> h_to_l +> List.iter (fun file_defined -> + !g#add_arc ((s_to_nodei file, s_to_nodei file_defined), true); + ); + ); + + used.typedefs +> h_to_l +> List.iter (fun s -> + match Common.optionise (fun () -> Hashtbl.find dep.idx_typedefs s) with + | None -> () + | Some hset -> + hset +> h_to_l +> List.iter (fun file_defined -> + !g#add_arc ((s_to_nodei file, s_to_nodei file_defined), true); + ); + ); +*) + ); + ); + Ograph_extended.print_ograph_mutable !g graphfile (!Flag.show_misc); + !g + + + + + +let generate_makefile (g: dependencies_graph) file = + pr2 "GENERATING makefile"; + with_open_outfile file (fun (pr_no_nl, chan) -> + + let nodei_to_file xi = + let ((file, cinfo ), s) = (g#nodes#assoc xi) in + file + in + let all_nodes = g#nodes#tolist +> List.map fst in + let visited_nodes_h = Hashtbl.create 101 in + + let modules = all_nodes +> List.filter (fun xi -> + let ((file, cinfo), s) = g#nodes#assoc xi in + cinfo.is_module + ) in + + pr_no_nl " # ---- modules files ---- \n"; + modules +> List.iter (fun xi -> + pr2 (nodei_to_file xi); + pr_no_nl " "; + g +> Ograph_extended.dfs_iter xi (fun yi -> + pr2 (" " ^ (Filename.basename (nodei_to_file yi))); + pr_no_nl (" " ^ (Filename.basename (nodei_to_file yi))); + Hashtbl.add visited_nodes_h yi true; + ); + pr_no_nl "\n"; + ); + let visited_nodes = Common.hashset_to_list visited_nodes_h in + let rest = all_nodes $-$ visited_nodes in + + let startfiles = rest +> List.filter (fun xi -> + (g#predecessors xi)#null + ) in + pr_no_nl " # ---- not module starting files ---- \n"; + + startfiles +> List.iter (fun xi -> + pr2 (nodei_to_file xi); + pr_no_nl " "; + g +> Ograph_extended.dfs_iter xi (fun yi -> + pr2 (" " ^ (Filename.basename (nodei_to_file yi))); + pr_no_nl (" " ^ (Filename.basename (nodei_to_file yi))); + Hashtbl.add visited_nodes_h yi true; + ); + pr_no_nl "\n"; + ); + let visited_nodes = Common.hashset_to_list visited_nodes_h in + let rest = rest $-$ visited_nodes in + + if not (null rest) then pr_no_nl " # ---- files in cycle ---- \n"; + rest +> List.iter (fun xi -> + if Hashtbl.mem visited_nodes_h xi then () (* already handled *) + else begin + pr2 (nodei_to_file xi); + pr_no_nl " "; + g +> Ograph_extended.dfs_iter xi (fun yi -> + pr2 (" " ^ (Filename.basename (nodei_to_file yi))); + pr_no_nl (" " ^ (Filename.basename (nodei_to_file yi))); + Hashtbl.add visited_nodes_h yi true; + ); + pr_no_nl "\n"; + end + ) + ) + diff --git a/extra/c_info.mli b/extra/c_info.mli new file mode 100644 index 0000000..c8e07a4 --- /dev/null +++ b/extra/c_info.mli @@ -0,0 +1,53 @@ +open Common + +type entities = { + macros : string hashset; + variables : string hashset; + static_variables : string hashset; + functions : string hashset; + static_functions : string hashset; + structs : string hashset; + typedefs : string hashset; + include_c : filename hashset; +} +val print_entities : entities -> unit + +type idx_entities = { + idx_macros : (string, filename hashset) Hashtbl.t; + idx_variables : (string, filename hashset) Hashtbl.t; + idx_functions : (string, filename hashset) Hashtbl.t; + idx_structs : (string, filename hashset) Hashtbl.t; + idx_typedefs : (string, filename hashset) Hashtbl.t; +} + +type file_info = { + used : entities; + defined : entities; + is_module : bool; +} + +type global_definitions = idx_entities + +type dependencies_graph = + ((filename * file_info) * string, bool) Ograph_extended.ograph_mutable + + +val defined_stuff : (Ast_c.toplevel * 'a) list -> entities +val used_stuff : (Ast_c.toplevel * 'a) list -> entities +(* is_module *) +val extra_stuff : (Ast_c.toplevel * 'a) list -> bool + +val adjust_used_only_external : entities -> entities -> unit + +val mk_global_definitions_index : + (filename * file_info) list -> idx_entities +val check_no_duplicate_global_definitions : + idx_entities -> unit + + +val build_graph : + (filename * file_info) list -> idx_entities -> filename (*outfile*) -> + ((filename * file_info) * string, bool) Ograph_extended.ograph_mutable + + +val generate_makefile : dependencies_graph -> filename -> unit diff --git a/extra/classic_patch.ml b/extra/classic_patch.ml new file mode 100644 index 0000000..d901df0 --- /dev/null +++ b/extra/classic_patch.ml @@ -0,0 +1,30 @@ +open Common + +type patch = patchitem list + and patchitem = File of filename * string (* header line *) * string list + +let parse_patch filename = + let xs = Common.cat filename in + let xxs = Common.split_list_regexp "^diff" xs in + xxs +> List.map (fun (s, body) -> + if s =~ "^diff --git a/\\([^ ]*\\) b/\\([^ ]*\\)" + then begin + let (a,b) = matched2 s in + assert(a =$= b); + File (a, s, body) + end + else failwith ("wrong line in git diff:" ^ s) + ) + + +let unparse_patch xs outfile = + Common.with_open_outfile outfile (fun (pr_no_nl, _chan) -> + let pr s = pr_no_nl (s ^ "\n") in + + xs +> List.iter (function (File (file, header, body)) -> + pr header; + body +> List.iter pr; + ) + ) + + diff --git a/extra/classic_patch.mli b/extra/classic_patch.mli new file mode 100644 index 0000000..58971c4 --- /dev/null +++ b/extra/classic_patch.mli @@ -0,0 +1,9 @@ +open Common + +(* used by tools/split_patch *) + +type patch = patchitem list + and patchitem = File of filename * string (* header line *) * string list + +val parse_patch : filename -> patch +val unparse_patch : patch -> filename (* outfile *) -> unit diff --git a/extra/kbuild.ml b/extra/kbuild.ml new file mode 100644 index 0000000..10c4736 --- /dev/null +++ b/extra/kbuild.ml @@ -0,0 +1,229 @@ +open Common + + + +type kbuild_info = directory list + and directory = Directory of string (*dirname*) * group list + and group = Group of filename list + +let directories_to_assoc xs = + xs +> List.map (function (Directory (s, ys)) -> s, ys) +let directories_to_hash xs = + xs +> directories_to_assoc +> Common.hash_of_list +let files_of_groups xs = + xs +> List.map (function Group ys -> ys) +> Common.union_all + + + +let adjust_dirs dirs = + dirs +> Common.map_filter (fun s -> + match s with + | s when s =~ "^\\.$" -> None + | s when s =~ "^\\./\\.git" -> None + | s when s =~ "^\\./\\.tmp_versions" -> None + | s when s =~ "^\\./include/config/" -> None + | s when s =~ "^\\./usr/include" -> None + | s when s =~ "^\\./\\(.*\\)" -> Some (matched1 s) + | s -> Some s + ) + + + +let unparse_kbuild_info xs filename = + Common.with_open_outfile filename (fun (pr_no_nl,chan) -> + let pr s = pr_no_nl (s ^ "\n") in + + xs +> List.iter (function Directory (s, ys) -> + pr s; + ys +> List.iter (function Group zs -> + pr (" " ^ (join " " zs)); + ); + pr ""; + ) + ) + +let parse_kbuild_info filename = + let xs = cat filename in + let xs = xs +> List.map (Str.global_replace (Str.regexp "#.*") "" ) in + let xs = xs +> List.filter (fun s -> not (s =~ "^[ \t]*$")) in + + (* split by header of section *) + let xs = xs +> Common.split_list_regexp "^[^ ]" in + + xs +> List.map (fun (s, xs) -> + let groups = xs +> List.map (fun s -> + assert (s =~ "^[ ]+\\(.*\\)"); + let files = matched1 s in + let cfiles = Common.split " +" files in + Group cfiles + ) in + + Directory (s, groups) + ) + +let generate_naive_kbuild_info dirs = + dirs +> List.map (fun s -> + let files = Common.readdir_to_file_list s in + let files_ext = files +> List.map Common.dbe_of_filename_safe in + let cfiles = files_ext +> Common.map_filter + (function + | Left (d,base, "c") -> + if base =~ ".*\\.mod$" then None + else Some base + | _ -> None + ) in + let ys = cfiles +> List.map (fun c -> Group [c ^ ".c"]) in + Directory (s, ys) + ) + + + + +let generate_kbuild_info_from_depcocci dirs outfile = + Common.with_open_outfile outfile (fun (pr_no_nl, chan) -> + dirs +> List.iter (fun s -> + pr_no_nl (s ^ "\n"); + let depcocci = Common.cat (Filename.concat s "depcocci.dep") in + depcocci +> List.iter (fun s -> pr_no_nl (s ^ "\n")); + pr_no_nl "\n"; + ) + ) +(* + dirs +> List.map (fun s -> + let groups = depcocci +> List.map (fun s -> Group (Common.split " +" s)) + in + Directory (s, groups) + ) +*) + + +type makefile = + { + obj_dirs : string stack ref; + obj_config: (string list) stack ref; + obj_objs: (string * (string list)) stack ref; + } +let empty_makefile () = + failwith "empty_makefile" + +let parse_makefile file = + let xs = Common.cat file in + let s = Common.unlines xs in + let s = Str.global_replace (Str.regexp "\\\\\n") "" s in + let xs = Common.lines_with_nl s in + let xs = xs +> List.map (Str.global_replace (Str.regexp "#.*") "" ) in + let xs = xs +> List.filter (fun s -> not (s =~ "^[ \t]*$")) in + let _m = empty_makefile () in + + xs +> List.iter (fun s -> + match s with + | s when s =~ "obj-\\$(CONFIG_.*)[ \t]*[\\+:]=\\(.*/\\)" -> + pr2_no_nl ("DIR: " ^ s) + | s when s =~ "obj-y[ \t]*\\+=\\(.*/\\)" -> + pr2_no_nl ("DIR: " ^ s) + | s when s =~ "obj-\\$(CONFIG_.*)[ \t]*[\\+:]=\\(.*\\)" -> + let s = matched1 s in + let objs = Common.split "[ \t]+" s in + assert(List.for_all (fun s -> thd3 (Common.dbe_of_filename s) = "o") + objs); + + pr2 ("OBJS: " ^ (join "|" objs)) + + | s when s =~ "[a-zA-Z0-9_]+-objs[ \t]*[\\+:]=\\(.*\\)" -> + let s = matched1 s in + let objs = Common.split "[ \t]+" s in + + pr2 ("OBJSMODULE: " ^ (join "|" objs)) + + | s -> + pr2_no_nl ("OTHER: " ^ s) + + ) + + +let generate_less_naive_kbuild_info dirs = + dirs +> List.map (fun s -> + let files = Common.readdir_to_file_list s in + let files_ext = files +> List.map Common.dbe_of_filename_safe in + let cfiles = files_ext +> Common.map_filter + (function + | Left (d,base, "c") -> + if base =~ ".*\\.mod$" then None + else Some base + | _ -> None + ) in + match cfiles with + | [] -> Directory (s, []) + | _::_ -> + if Common.lfile_exists (Filename.concat s "Makefile") + then + let _res = parse_makefile (Filename.concat s "Makefile") in + let ys = cfiles +> List.map (fun c -> Group [c ^ ".c"]) in + Directory (s, ys) + else + failwith ("no Makefile found in: " ^ s) + + ) + + + +(* a = current info file, in general manually extended; b = generated one *) +let check_up_to_date a b = + let das = directories_to_assoc a in + let dbs = directories_to_assoc b in + let all_dirs = (das +> List.map fst) $+$ (dbs +> List.map fst) in + all_dirs +> List.iter (fun dir -> + match + optionise (fun () -> List.assoc dir das), + optionise (fun () -> List.assoc dir dbs) + with + | None, None -> raise Impossible + | None, Some gbs -> pr2 ("new directory appeared:" ^ dir) + | Some gas, None -> pr2 ("old directory disappeared:" ^ dir) + | Some gas, Some gbs -> + let afiles = files_of_groups gas in + let bfiles = files_of_groups gbs in + let all_files = afiles $+$ bfiles in + all_files +> List.iter (fun file -> + match List.mem file afiles, List.mem file bfiles with + | false, false -> raise Impossible + | false, true -> pr2 ("new file appeared:" ^ file ^ " in " ^ dir) + | true, false -> pr2 ("old file disappeared:" ^ file ^ " in " ^ dir) + | true, true -> () + ) + ) + + +let files_in_dirs dirs kbuild_info = + dirs +> List.map (fun dir -> + let dir = Common.chop_dirsymbol dir in + (* could use assoc, but we accept "parasite" prefix *) + let gooddirs = + kbuild_info +> Common.map_filter (function (Directory (s, groups)) -> + if dir =~ ("\\(.*\\)" ^ s ^ "$") + then + let prefix = matched1 dir in + Some (prefix, s, groups) + else None + ) + in + + (match gooddirs with + | [prefix, dir, groups] -> + groups +> List.map (function (Group xs) -> + Group (xs +> List.map (fun s -> + Filename.concat (prefix ^ dir) s)) + ) + + | [] -> + pr2 ("can't find kbuild info for directory :" ^ dir); + [] + | x::y::ys -> + pr2 ("too much kbuild info candidate for directory :" ^ dir); + [] + ) + ) +> List.concat + + + + diff --git a/extra/kbuild.mli b/extra/kbuild.mli new file mode 100644 index 0000000..556864d --- /dev/null +++ b/extra/kbuild.mli @@ -0,0 +1,28 @@ +open Common + +(* used my tools/meta_files *) + + +(* correspond usually to a kernel_files.meta *) +type kbuild_info = directory list + and directory = Directory of string (*dirname*) * group list + and group = Group of filename list + +val unparse_kbuild_info : kbuild_info -> filename (*outfile*) -> unit +val parse_kbuild_info : filename -> kbuild_info + + +val generate_naive_kbuild_info : string list -> kbuild_info +val generate_less_naive_kbuild_info : string list -> kbuild_info +val generate_kbuild_info_from_depcocci : + string list -> filename (*out*) -> unit +val check_up_to_date : kbuild_info -> kbuild_info -> unit + +(* get the relevant groups from dirs given a kbuild_info *) +val files_in_dirs : string list (* dirs *) -> kbuild_info -> group list + + +(* remove the .git directory, wrong include, from the list of directories + * passed in parameter + *) +val adjust_dirs : string list -> string list diff --git a/extra/maintainers.ml b/extra/maintainers.ml new file mode 100644 index 0000000..ff5916d --- /dev/null +++ b/extra/maintainers.ml @@ -0,0 +1,106 @@ +open Common + + +type subsystem_info = subsystem list + and subsystem = Subsystem of (dir * maintainers) * + (dir * maintainers) list (* subdirs *) + and dir = string + and maintainers = string list + + +let mk_inverted_index_subsystem xs = + let h = Hashtbl.create 101 in + xs +> List.iter (function (Subsystem ((leader, emails), dirs)) -> + Hashtbl.add h leader leader; + dirs +> List.iter (fun (subdir, emails) -> + Hashtbl.add h subdir leader + )); + h + +let subsystem_to_assoc xs = + xs +> List.map (function (Subsystem ((s, emails), ys)) -> s, (emails, ys)) +let subsystem_to_hash xs = + xs +> subsystem_to_assoc +> Common.hash_of_list + +let all_dirs_from_subsystem_info xs = + xs +> List.map (function (Subsystem ((s, emails), dirs)) -> + s::(List.map fst dirs) + ) +> Common.union_all + + + +let unparse_subsystem_info xs filename = + Common.with_open_outfile filename (fun (pr_no_nl,chan) -> + let pr s = pr_no_nl (s ^ "\n") in + + xs +> List.iter (function Subsystem ((s, emails), ys) -> + pr (sprintf "%-40s : %s" s (Common.join " ," emails)); + ys +> List.iter (fun (s, emails) -> + pr (sprintf " %-40s : %s" s (Common.join " ," emails)); + ); + pr ""; + ) + ) + +let parse_subsystem_info filename = + let xs = cat filename in + let xs = xs +> List.map (Str.global_replace (Str.regexp "#.*") "" ) in + let xs = xs +> List.filter (fun s -> not (s =~ "^[ \t]*$")) in + + (* split by header of section *) + let xs = xs +> Common.split_list_regexp "^[^ ]" in + + xs +> List.map (fun (s, xs) -> + assert (s =~ "^\\([^ ]+\\) *: *\\(.*\\)"); + let (dir, email) = matched2 s in + let emails = Common.split "[ ,]+" email in + let group = xs +> List.map (fun s -> + assert (s =~ "^[ ]+\\([^ ]+\\) *: *\\(.*\\)"); + let (dir, email) = matched2 s in + let emails = Common.split "[ ,]+" email in + (dir, emails) + ) in + Subsystem ((dir, emails), group) + ) + + +let generate_naive_subsystem_info dirs = + let dirs' = dirs +> List.map (fun s -> Common.split "/" s, s ) in + + let rec aux_dirs xs = + match xs with + | [] -> [] + | (dir_elems,s)::xs -> + let cond, base = + if List.length dir_elems >= 2 then + let base = Common.take 2 dir_elems in + (fun dir_elems' -> + List.length dir_elems' >= 2 && Common.take 2 dir_elems' = base), + base + else + (fun dir_elems' -> dir_elems' = dir_elems), + dir_elems + in + + let (yes, no) = xs +> Common.partition_either (fun (dir_elems', x) -> + if cond dir_elems' + then Left (x, []) + else Right (dir_elems', x) + ) in + (Subsystem ((s, [""]), yes))::aux_dirs no + in + aux_dirs dirs' +(* old: dirs +> List.map (fun s -> Subsystem (s, "", [])) *) + + +(* a = current info file, in general manually extended; b = generated one *) +let check_up_to_date a b = + let set1 = all_dirs_from_subsystem_info a in + let set2 = all_dirs_from_subsystem_info b in + (set1 $-$ set2) +> List.iter (fun s -> + pr2 ("old directory disappeared: " ^ s) + ); + (set2 $-$ set1) +> List.iter (fun s -> + pr2 ("new directory appeared: " ^ s) + ) + diff --git a/extra/maintainers.mli b/extra/maintainers.mli new file mode 100644 index 0000000..8aaa5eb --- /dev/null +++ b/extra/maintainers.mli @@ -0,0 +1,25 @@ +open Common + +(* used my tools/meta_files and tools/split_patch *) + + +(* correspond usually to a kernel_dirs.meta *) +type subsystem_info = subsystem list + and subsystem = Subsystem of (dir * maintainers) * + (dir * maintainers) list (* subdirs *) + and dir = string + and maintainers = string list + +val mk_inverted_index_subsystem : subsystem_info -> (dir,dir) Hashtbl.t +val subsystem_to_hash : + subsystem_info -> (dir, (maintainers * (dir * maintainers) list)) Hashtbl.t + + +val unparse_subsystem_info : subsystem_info -> filename (*outfile*) -> unit +val parse_subsystem_info : filename -> subsystem_info + + +val generate_naive_subsystem_info : string list -> subsystem_info +val check_up_to_date : subsystem_info -> subsystem_info -> unit + + diff --git a/flag_cocci.ml b/flag_cocci.ml new file mode 100644 index 0000000..7c3b42c --- /dev/null +++ b/flag_cocci.ml @@ -0,0 +1,60 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* the inputs *) +let show_c = ref false +let show_cocci = ref false + +(* the output *) +let show_diff = ref true + +(* the derived inputs *) +let show_flow = ref false +let show_before_fixed_flow = ref false + +let show_ctl_tex = ref false +let show_ctl_text = ref true + +let inline_let_ctl = ref false +let show_mcodekind_in_ctl = ref false + +(* the "underived" outputs *) +let show_transinfo = ref true +let show_binding_in_out = ref false + +let windows = ref false + +let popl = ref false + +let all_includes = ref false +let include_path = ref "include" +(* if true then when have a #include "../../xx.h", we look also for xx.h in + * current directory. This is because of how works extract_c_and_res + *) + +let no_includes = ref false (* no includes at all, not even the local ones *) + +let relax_include_path = ref false + +let timeout = ref (None : int option) + +let worth_trying_opt = ref true diff --git a/globals/.depend b/globals/.depend new file mode 100644 index 0000000..e69de29 diff --git a/globals/Makefile b/globals/Makefile new file mode 100644 index 0000000..ef2cffa --- /dev/null +++ b/globals/Makefile @@ -0,0 +1,70 @@ +############################################################################## +# Variables +############################################################################## +TARGET=globals + +SRC= flag.ml config.ml + +LIBS=../commons/commons.cma +INCLUDES= -I ../commons + +############################################################################## +# Generic variables +############################################################################## +OCAMLCFLAGS ?= -g -dtypes +OCAMLC =ocamlc$(OPTBIN) $(OCAMLCFLAGS) $(INCLUDES) +OCAMLOPT = ocamlopt$(OPTBIN) $(OPTFLAGS) $(INCLUDES) +OCAMLDEP = ocamldep$(OPTBIN) $(INCLUDES) +OCAMLMKTOP=ocamlmktop -g -custom $(INCLUDES) + +OBJS= $(SRC:.ml=.cmo) +OPTOBJS= $(SRC:.ml=.cmx) + + +############################################################################## +# Top rules +############################################################################## +all: $(TARGET).cma + +all.opt: $(TARGET).cmxa + + +$(TARGET).cma: $(OBJS) $(LIBS) + $(OCAMLC) -a -o $(TARGET).cma $(OBJS) + +$(TARGET).cmxa: $(OPTOBJS) $(LIBS:.cma=.cmxa) + $(OCAMLOPT) -a -o $(TARGET).cmxa $(OPTOBJS) + + + +############################################################################## +# Developer rules +############################################################################## +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) -c $< +.mli.cmi: + $(OCAMLC) -c $< +.ml.cmx: + $(OCAMLOPT) -c $< + +.ml.mldepend: + $(OCAMLC) -i $< + +clean:: + rm -f *.cm[ioxa] *.o *.a *.cmxa *.annot + +clean:: + rm -f *~ .*~ gmon.out #*# + +beforedepend:: + +depend:: beforedepend + $(OCAMLDEP) *.mli *.ml > .depend + +-include .depend + + + + diff --git a/globals/config.ml b/globals/config.ml new file mode 100644 index 0000000..5169aa2 --- /dev/null +++ b/globals/config.ml @@ -0,0 +1,8 @@ +let version = "0.1" + +let path = + try (Sys.getenv "COCCINELLE_HOME") + with Not_found->"/usr/local/share/coccinelle" + +let std_iso = ref (Filename.concat path "standard.iso") +let std_h = ref (Filename.concat path "standard.h") diff --git a/globals/flag.ml b/globals/flag.ml new file mode 100644 index 0000000..222e4bb --- /dev/null +++ b/globals/flag.ml @@ -0,0 +1,16 @@ +let sgrep_mode2 = ref false + +let show_misc = ref true + +let show_trying = ref false + +let track_iso_usage = ref false + +let use_glimpse = ref false + +let pyoutput = ref "coccilib.output.Console" + +(*"Some" value is the path with respect to which the patch should be created*) +let patch = ref (None : string option) + +let make_hrule = ref (None : string (*dir*) option) diff --git a/install.txt b/install.txt new file mode 100644 index 0000000..b9ee270 --- /dev/null +++ b/install.txt @@ -0,0 +1,17 @@ +You must first install a recent version of + - OCaml (at least 3.09.2), + see http://caml.inria.fr/download.en.html + - the Menhir parser generator (at least 20080912), + see http://cristal.inria.fr/~fpottier/menhir/ + (unless you got a version of the coccinelle source with + the SmPL parser pre-generated) + - Python and its development files (python-dev) + (unless you run configure with the --without-python option) + + +Then simply type + ./configure + make depend + make + make install + diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..e77696a --- /dev/null +++ b/license.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/main.ml b/main.ml new file mode 100644 index 0000000..aaa0678 --- /dev/null +++ b/main.ml @@ -0,0 +1,785 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Common + +(*****************************************************************************) +(* Flags *) +(*****************************************************************************) + +(* In addition to flags that can be tweaked via -xxx options (cf the + * full list of options in "the spatch options" section below), the + * spatch program also depends on external files, described in + * globals/config.ml, mainly a standard.h and standard.iso file *) + +let cocci_file = ref "" + +let output_file = ref "" +let inplace_modif = ref false (* but keeps a .cocci_orig *) +let outplace_modif = ref false (* generates a .cocci_res *) + +(* could be avoided by using Common.files_of_dir_or_files instead *) +let dir = ref false + +let include_headers = ref false +let kbuild_info = ref "" + +(* test mode *) +let test_mode = ref false +let test_all = ref false +let test_okfailed = ref false +let test_regression_okfailed = ref false + + +(* action mode *) +let action = ref "" + +(* works with -test but also in "normal" spatch mode *) +let compare_with_expected = ref false + + +let distrib_index = ref (None : int option) +let distrib_max = ref (None : int option) +let mod_distrib = ref false + + +(*****************************************************************************) +(* Profiles *) +(*****************************************************************************) + +(* pair of (list of flags to set true, list of flags to set false *) +let quiet_profile = ( + [ + ], + [ + (* Flag_cocci.show_diff; just leave this as it is *) + + Flag.show_misc; + Flag.show_trying; + + Flag_cocci.show_c; + Flag_cocci.show_cocci; + Flag_cocci.show_flow; + Flag_cocci.show_before_fixed_flow; + Flag_cocci.show_ctl_tex; + Flag_cocci.show_ctl_text; + Flag_cocci.show_transinfo; + Flag_cocci.show_binding_in_out; + + Flag_parsing_cocci.show_SP; + Flag_parsing_cocci.show_iso_failures; + Flag_ctl.verbose_ctl_engine; + Flag_ctl.verbose_match; + Flag_engine.debug_engine; + Flag_parsing_c.debug_unparsing; + Flag_parsing_c.verbose_type; + Flag_parsing_c.verbose_parsing; + ]) + +let pad_profile = ( + [ + Flag_cocci.show_diff; + ], + [ + + Flag.show_misc; + + Flag_cocci.show_c; + Flag_cocci.show_cocci; + Flag_cocci.show_flow; + Flag_cocci.show_before_fixed_flow; + Flag_cocci.show_ctl_tex; + Flag_cocci.show_ctl_text; + Flag_cocci.show_transinfo; + Flag_cocci.show_binding_in_out; + + Flag_parsing_cocci.show_SP; + Flag_parsing_cocci.show_iso_failures; + Flag_ctl.verbose_ctl_engine; + Flag_ctl.verbose_match; + Flag_engine.debug_engine; + Flag_parsing_c.debug_unparsing; + Flag_parsing_c.verbose_type; + Flag_parsing_c.verbose_parsing; + ]) + +(*****************************************************************************) +(* The spatch options *) +(*****************************************************************************) + +let usage_msg = + "Usage: " ^ basename Sys.argv.(0) ^ + " -sp_file [-o ] [-iso_file ] [options]" ^ + "\n" ^ "Options are:" + +(* forward reference trick *) +let short_usage_func = ref (fun () -> ()) +let long_usage_func = ref (fun () -> ()) + + +(* The short_options are user-oriented. The other options are for + * the developers of coccinelle or advanced-users that know + * quite well the underlying semantics of coccinelle. + *) + + +(* will be printed when use only ./spatch. For the rest you have to + * use -longhelp to see them. + *) +let short_options = [ + "-sp_file", Arg.Set_string cocci_file, + " the semantic patch file"; + + "-o", Arg.Set_string output_file, + " the output file"; + "-inplace", Arg.Set inplace_modif, + " do the modification on the file directly"; + "-outplace", Arg.Set outplace_modif, + " store modifications in a .cocci_res file"; + + "-U", Arg.Int (fun n -> Flag_parsing_c.diff_lines := Some (i_to_s n)), + " set number of diff context lines"; + "-partial_match", Arg.Set Flag_ctl.partial_match, + " report partial matches of the SP on the C file"; + + "-iso_file", Arg.Set_string Config.std_iso, + " (default=" ^ !Config.std_iso ^")"; + "-macro_file", Arg.Set_string Config.std_h, + " (default=" ^ !Config.std_h ^ ")"; + + "-all_includes", Arg.Set Flag_cocci.all_includes, + " causes all available include files to be used"; + "-no_includes", Arg.Set Flag_cocci.no_includes, + " causes not even local include files to be used"; + "-I", Arg.Set_string Flag_cocci.include_path, + "

      containing the Linux headers (optional)"; + + + "-dir", Arg.Set dir, + " process all files in directory recursively"; + + "-include_headers", Arg.Set include_headers, + " process header files independently"; + "-use_glimpse", Arg.Set Flag.use_glimpse, + " works with -dir, use info generated by glimpseindex"; + "-patch", Arg.String (function s -> Flag.patch := Some s), + (" path name with respect to which a patch should be created\n"^ + " \"\" for a file in the current directory"); + "-kbuild_info", Arg.Set_string kbuild_info, + " improve -dir by grouping related c files"; + "-pyoutput", Arg.Set_string Flag.pyoutput, + " Sets output routine: Standard values: "; + + + "-version", Arg.Unit (fun () -> + pr2 (spf "spatch version: %s" Config.version); + exit 0; + ), + " guess what"; + + "-date", Arg.Unit (fun () -> + pr2 "version: $Date: 2008/09/26 00:44:57 $"; + raise (Common.UnixExit 0) + ), + " guess what"; + + "-shorthelp", Arg.Unit (fun () -> + !short_usage_func(); + raise (Common.UnixExit 0) + ), + " see short list of options"; + "-longhelp", Arg.Unit (fun () -> + !long_usage_func(); + raise (Common.UnixExit 0) + ), + " see all the available options in different categories"; + "-help", Arg.Unit (fun () -> + !long_usage_func(); + raise (Common.UnixExit 0) + ), + " "; + "--help", Arg.Unit (fun () -> + !long_usage_func(); + raise (Common.UnixExit 0) + ), + " "; + +] + +(* the format is a list of triples: + * (title of section * (optional) explanation of sections * option list) + *) +let other_options = [ + "aliases and obsolete options", + "", + [ + "-cocci_file", Arg.Set_string cocci_file, + " the semantic patch file"; + "-c", Arg.Set_string cocci_file, " short option of -cocci_file"; + "-iso", Arg.Set_string Config.std_iso, " short option of -iso_file"; + "-D", Arg.Set_string Config.std_h, " short option of -macro_file"; + ]; + + "most useful show options", + "", + [ + "-show_diff" , Arg.Set Flag_cocci.show_diff, " "; + "-no_show_diff" , Arg.Clear Flag_cocci.show_diff, " "; + "-show_flow" , Arg.Set Flag_cocci.show_flow, " "; + "-no_show_ctl_text" , Arg.Clear Flag_cocci.show_ctl_text, " "; + (* works in conjunction with -show_ctl *) + "-ctl_inline_let", Arg.Set Flag_cocci.inline_let_ctl, " "; + "-ctl_show_mcodekind", Arg.Set Flag_cocci.show_mcodekind_in_ctl, " "; + "-show_binding_in_out", Arg.Set Flag_cocci.show_binding_in_out, " "; + "-no_show_transinfo", Arg.Clear Flag_cocci.show_transinfo, " "; + "-no_show_misc", Arg.Clear Flag.show_misc, " "; + "-show_trying", Arg.Set Flag.show_trying, + " show the name of each function being processed"; + ]; + + "verbose subsystems options", + "", + [ + "-verbose_ctl_engine", Arg.Set Flag_ctl.verbose_ctl_engine, " "; + "-verbose_match", Arg.Set Flag_ctl.verbose_match, " "; + "-verbose_engine", Arg.Set Flag_engine.debug_engine, " "; + + "-no_parse_error_msg", Arg.Clear Flag_parsing_c.verbose_parsing, " "; + "-no_type_error_msg", Arg.Clear Flag_parsing_c.verbose_type, " "; + (* could also use Flag_parsing_c.options_verbose *) + ]; + + "other show options", + "", + [ + "-show_c" , Arg.Set Flag_cocci.show_c, " "; + "-show_cocci" , Arg.Set Flag_cocci.show_cocci, " "; + "-show_before_fixed_flow" , Arg.Set Flag_cocci.show_before_fixed_flow, " "; + "-show_ctl_tex" , Arg.Set Flag_cocci.show_ctl_tex, " "; + "-show_SP_julia" , Arg.Set Flag_parsing_cocci.show_SP, " "; + ]; + + + "debug C parsing/unparsing", + "", + [ + "-debug_cpp", Arg.Set Flag_parsing_c.debug_cpp, " "; + "-debug_lexer", Arg.Set Flag_parsing_c.debug_lexer , " "; + "-debug_etdt", Arg.Set Flag_parsing_c.debug_etdt , " "; + "-debug_typedef", Arg.Set Flag_parsing_c.debug_typedef, " "; + + "-filter_msg", Arg.Set Flag_parsing_c.filter_msg , + " filter some cpp message when the macro is a \"known\" cpp construct"; + "-filter_define_error",Arg.Set Flag_parsing_c.filter_define_error," "; + "-filter_classic_passed",Arg.Set Flag_parsing_c.filter_classic_passed," "; + + "-debug_cfg", Arg.Set Flag_parsing_c.debug_cfg , " "; + "-debug_unparsing", Arg.Set Flag_parsing_c.debug_unparsing, " "; + + ]; + (* could use Flag_parsing_c.options_debug_with_title instead *) + + + "shortcut for enabling/disabling a set of debugging options at once", + "", + [ + (* todo: other profile ? *) + "-quiet", Arg.Unit (fun () -> + let (set_to_true, set_to_false) = quiet_profile in + List.iter (fun x -> x := false) set_to_false; + List.iter (fun x -> x := true) set_to_true; + ), " "; + + "-pad", Arg.Unit (fun () -> + let (set_to_true, set_to_false) = pad_profile in + List.iter (fun x -> x := false) set_to_false; + List.iter (fun x -> x := true) set_to_true; + ), " "; + + ]; + + "bench options", + "", + [ + "-profile", Arg.Unit (function () -> Common.profile := Common.PALL) , + " gather timing information about the main coccinelle functions"; + "-bench", Arg.Int (function x -> Flag_ctl.bench := x), + " for profiling the CTL engine"; + "-timeout", Arg.Int (fun x -> Flag_cocci.timeout := Some x), + " timeout in seconds"; + "-steps", Arg.Int (fun x -> Flag_ctl.steps := Some x), + " max number of model checking steps per code unit"; + "-track_iso", Arg.Set Flag.track_iso_usage, + " gather information about isomorphism usage"; + "-profile_iso", + Arg.Unit + (function () -> + Common.profile:=PSOME ["parse cocci";"mysat";"asttoctl2";"full_engine"]), + " gather information about the cost of isomorphism usage" + ]; + + + + "change of algorithm options", + "", + [ + "-popl", Arg.Set Flag_cocci.popl, + " simplified SmPL, for the popl paper"; + + "-popl_mark_all", + Arg.Unit + (function _ -> Flag_cocci.popl := true; Flag_popl.mark_all := true), + " simplified SmPL, for the popl paper"; + + "-popl_keep_all_wits", + Arg.Unit + (function _ -> Flag_cocci.popl := true; Flag_popl.keep_all_wits := true), + " simplified SmPL, for the popl paper"; + + "-hrule", Arg.String (function s -> Flag.make_hrule := Some s), + " semantic patch generation"; + + "-loop", Arg.Set Flag_ctl.loop_in_src_code, " "; + + "-l1", Arg.Clear Flag_parsing_c.label_strategy_2, " "; + "-ifdef", Arg.Set Flag_parsing_c.ifdef_to_if, + " convert ifdef to if (buggy!)"; + "-noif0_passing", Arg.Clear Flag_parsing_c.if0_passing, + " "; + "-noadd_typedef_root", Arg.Clear Flag_parsing_c.add_typedef_root, " "; + (* could use Flag_parsing_c.options_algo instead *) + + + "-disallow_nested_exps", Arg.Set Flag_engine.disallow_nested_exps, + "disallow an expresion pattern from matching a term and its subterm"; + "-disable_worth_trying_opt", Arg.Clear Flag_cocci.worth_trying_opt, + " "; + "-only_return_is_error_exit", + Arg.Set Flag_engine.only_return_is_error_exit, + "if this flag is not set, then break and continue are also error exits"; + (* the following is a hack to make it easier to add code in sgrep-like + code, essentially to compensate for the fact that we don't have + any way of printing things out *) + "-allow_inconsistent_paths", + Arg.Set Flag_engine.allow_inconsistent_paths, + "if this flag is set don't check for inconsistent paths; dangerous"; + ]; + + "misc options", + "", + [ + "-debugger", Arg.Set Common.debugger , + " option to set if launch spatch in ocamldebug"; + "-disable_once", Arg.Set Common.disable_pr2_once, + " to print more messages"; + "-save_tmp_files", Arg.Set Common.save_tmp_files, " "; + ]; + + "concurrency", + "", + [ + "-index", Arg.Int (function x -> distrib_index := Some x) , + " the processor to use for this run of spatch"; + "-max", Arg.Int (function x -> distrib_max := Some x) , + " the number of processors available"; + "-mod_distrib", Arg.Set mod_distrib, + " use mod to distribute files among the processors"; + ]; + + "pad options", + "", + [ + "-use_cache", Arg.Set Flag_parsing_c.use_cache, + " use .ast_raw pre-parsed cached C file"; + (* could use Flag_parsing_c.options_pad instead *) + ]; + + + + "test mode and test options (works with tests/ or .ok files)", + "The test options don't work with the -sp_file and so on.", + [ + "-test", Arg.Set test_mode, + " launch spatch on tests/file.[c,cocci]"; + "-testall", Arg.Set test_all, + " launch spatch on all files in tests/ having a .res"; + "-test_okfailed", Arg.Set test_okfailed, + " generates .{ok,failed,spatch_ok} files using .res files"; + "-test_regression_okfailed", Arg.Set test_regression_okfailed, + " process the .{ok,failed,spatch_ok} files in current dir"; + + "-compare_with_expected", Arg.Set compare_with_expected, + " use also file.res"; + "-relax_include_path", Arg.Set Flag_cocci.relax_include_path, + " "; + + ]; + + "action mode", + ("The action options don't work with the -sp_file and so on." ^ "\n" ^ + "It's for the other (internal) uses of the spatch program." + ), + + (* -token_c, -parse_c, etc *) + ((Common.options_of_actions action (Test_parsing_c.actions())) ++ + [ + (let s = "-parse_cocci" in s, Arg.Unit (fun () -> action := s), + " "); + (let s = "-compare_c" in s, Arg.Unit (fun () -> action := s), + " "); + ]); +] + + +let all_options = + short_options ++ List.concat (List.map Common.thd3 other_options) + + + +(* I don't want the -help and --help that are appended by Arg.align *) +let arg_align2 xs = + Arg.align xs +> List.rev +> Common.drop 2 +> List.rev + +(* copy paste of Arg.parse. Don't want the default -help msg *) +let arg_parse2 l f msg = + (try + Arg.parse_argv Sys.argv l f msg; + with + | Arg.Bad msg -> (* eprintf "%s" msg; exit 2; *) + let xs = Common.lines msg in + (* take only head, it's where the error msg is *) + pr2 (List.hd xs); + !short_usage_func(); + raise (Common.UnixExit (2)) + | Arg.Help msg -> (* printf "%s" msg; exit 0; *) + raise Impossible (* -help is specified in speclist *) + ) + + +let short_usage () = + begin + Common.short_usage usage_msg short_options; + pr2 ""; + pr2 "Example of use:"; + pr2 " ./spatch -sp_file foo.cocci foo.c -o /tmp/newfoo.c"; + pr2 ""; + end + + +let long_usage () = + Common.long_usage usage_msg short_options other_options + +let _ = short_usage_func := short_usage +let _ = long_usage_func := long_usage + +(*****************************************************************************) +(* Helpers *) +(*****************************************************************************) + +let adjust_stdin cfile k = + if !dir + then k() + else + let newin = + let (dir, base, ext) = Common.dbe_of_filename cfile in + let varfile = Common.filename_of_dbe (dir, base, "var") in + if ext = "c" && Common.lfile_exists varfile + then Some varfile + else None in + Common.redirect_stdin_opt newin k + +let glimpse_filter (coccifile, isofile) dir = + let (astcocci,_free_var_lists,_negated_positions, + _used_after_lists,_positions_lists,_,query) = + Cocci.sp_of_file coccifile (Some isofile) in + match query with + None -> pr2 "no glimpse keyword infered from snippet"; None + | Some query -> + let suffixes = if !include_headers then ["c";"h"] else ["c"] in + pr2 ("glimpse request = " ^ query); + let command = spf "glimpse -y -H %s -N -W -w '%s'" dir query in + let (glimpse_res,stat) = Common.cmd_to_list_and_status command in + match stat with + Unix.WEXITED(0) | Unix.WEXITED(1) -> + Some + (glimpse_res +> + List.filter + (fun file -> List.mem (Common.filesuffix file) suffixes)) + | _ -> None (* error, eg due to pattern too big *) + + + + +(*****************************************************************************) +(* The coccinelle main entry point *) +(*****************************************************************************) +let main () = + begin + let args = ref [] in + + arg_parse2 (Arg.align all_options) (fun x -> args := x::!args) usage_msg; + + (if !dir && List.length !args > 1 + then + begin + let chosen = List.hd !args in + pr2 ("ignoring all but the last specified directory: "^chosen); + args := [chosen] + end); + args := List.rev !args; + + (if !Flag_cocci.all_includes && !Flag_cocci.no_includes + then failwith "cannot set both all_includes and no_includes"); + + if !cocci_file <> "" && (not (!cocci_file =~ ".*\\.\\(sgrep\\|spatch\\)$")) + then cocci_file := Common.adjust_ext_if_needed !cocci_file ".cocci"; + + if !Config.std_iso <> "" + then Config.std_iso := Common.adjust_ext_if_needed !Config.std_iso ".iso"; + if !Config.std_h <> "" + then Config.std_h := Common.adjust_ext_if_needed !Config.std_h ".h"; + + if !Config.std_h <> "" + then Parse_c.init_defs !Config.std_h; + + + (* must be done after Arg.parse, because Common.profile is set by it *) + Common.profile_code "Main total" (fun () -> + + + let all_actions = Test_parsing_c.actions() in + + (match (!args) with + + (* --------------------------------------------------------- *) + (* The test framework. Works with tests/ or .ok and .failed *) + (* --------------------------------------------------------- *) + | [x] when !test_mode -> + Flag_cocci.include_path := "tests/include"; + Testing.testone x !compare_with_expected + + | [] when !test_all -> + Flag_cocci.include_path := "tests/include"; + Testing.testall () + + | [] when !test_regression_okfailed -> + Testing.test_regression_okfailed () + + | x::xs when !test_okfailed -> + (* do its own timeout on Flag_cocci.timeout internally *) + Flag_cocci.relax_include_path := true; + adjust_stdin x (fun () -> + Testing.test_okfailed !cocci_file (x::xs) + ) + + (* --------------------------------------------------------- *) + (* Actions, useful to debug subpart of coccinelle *) + (* --------------------------------------------------------- *) + + | xs when List.mem !action (Common.action_list all_actions) -> + Common.do_action !action xs all_actions + + | [file] when !action = "-parse_cocci" -> + Testing.test_parse_cocci file + + (* I think this is used by some scripts in some Makefile for our + * big-tests. So dont remove. + *) + | [file1;file2] when !action = "-compare_c" -> + Test_parsing_c.test_compare_c file1 file2 (* result = unix code *) + + (* could add the Test_parsing_c.test_actions such as -parse_c & co *) + + + (* --------------------------------------------------------- *) + (* This is the main entry *) + (* --------------------------------------------------------- *) + | x::xs -> + adjust_stdin x (fun () -> + if !cocci_file = "" + then failwith "I need a cocci file, use -sp_file "; + + if !dir && !Flag.patch = None + then + (match xs with + | [] -> Flag.patch := Some x + | _ -> + pr2 + ("warning: patch output can only be created when only one\n"^ + "directory is specified or when the -patch flag is used") + ); + + let infiles = + Common.profile_code "Main.infiles computation" (fun () -> + match !dir, !kbuild_info, !Flag.use_glimpse with + (* glimpse *) + | false, _, true -> + failwith "-use_glimpse works only with -dir" + | true, s, true when s <> "" -> + failwith "-use_glimpse does not work with -kbuild" + | true, "", true -> + if not (null xs) + then failwith "-use_glimpse can accept only one dir"; + + let files = + match glimpse_filter (!cocci_file, !Config.std_iso) x with + None -> + Common.cmd_to_list (* same as "true, "", _" case *) + (if !include_headers + then ("find "^(join " " (x::xs))^" -name \"*.[ch]\"") + else ("find "^(join " " (x::xs))^" -name \"*.c\"")) + | Some files -> files in + files +> List.map (fun x -> [x]) + (* normal *) + | false, _, _ -> [x::xs] + | true, "", _ -> + Common.cmd_to_list + (if !include_headers + then ("find "^(join " " (x::xs))^" -name \"*.[ch]\"") + else ("find "^(join " " (x::xs))^" -name \"*.c\"")) + +> List.map (fun x -> [x]) + + (* kbuild *) + | true, kbuild_info_file,_ -> + let dirs = + Common.cmd_to_list ("find "^(join " " (x::xs))^" -type d") + in + let info = Kbuild.parse_kbuild_info kbuild_info_file in + let groups = Kbuild.files_in_dirs dirs info in + + groups +> List.map (function Kbuild.Group xs -> xs) + ) + in + + let infiles = + match (!distrib_index,!distrib_max) with + (None,None) -> infiles + | (Some index,Some max) -> + (if index >= max + then + failwith "index starts at 0, and so must be less than max"); + if !mod_distrib + then + let rec loop ct = function + [] -> [] + | x::xs -> + if (ct mod max) = index + then x::(loop (ct+1) xs) + else loop (ct+1) xs in + loop 0 infiles + else + begin + let all_files = List.length infiles in + let regions = (all_files + (max - 1)) / max in + let this_min = index * regions in + let this_max = (index+1) * regions in + let rec loop ct = function + [] -> [] + | x::xs -> + if this_min <= ct && ct < this_max + then x::(loop (ct+1) xs) + else loop (ct+1) xs in + loop 0 infiles + end + | _ -> failwith "inconsistent distribution information" in + + let outfiles = + Common.profile_code "Main.outfiles computation" (fun () -> + infiles +> List.map (fun cfiles -> + pr2 ("HANDLING: " ^ (join " " cfiles)); + Common.timeout_function_opt !Flag_cocci.timeout (fun () -> + Common.report_if_take_time 10 (join " " cfiles) (fun () -> + (* Unix.sleep 1; *) + try + (* this is the main call *) + Cocci.full_engine (!cocci_file, !Config.std_iso) cfiles + with + | Common.UnixExit x -> raise (Common.UnixExit x) + | e -> + if !dir + then begin + pr2 ("EXN:" ^ Printexc.to_string e); + [] (* *) + end + else raise e))) + ) +> List.concat + in + + Common.profile_code "Main.result analysis" (fun () -> + + Ctlcocci_integration.print_bench(); + + let outfiles = Cocci.check_duplicate_modif outfiles in + + outfiles +> List.iter (fun (infile, outopt) -> + outopt +> Common.do_option (fun outfile -> + if !inplace_modif + then begin + Common.command2 ("cp "^infile^" "^infile^".cocci_orig"); + Common.command2 ("cp "^outfile^" "^infile); + end; + + if !outplace_modif + then Common.command2 ("cp "^outfile^" "^infile^".cocci_res"); + + if !output_file = "" + then begin + let tmpfile = "/tmp/"^Common.basename infile in + pr2 (spf "One file modified. Result is here: %s" tmpfile); + Common.command2 ("cp "^outfile^" "^tmpfile); + end + )); + if !output_file <> "" then + (match outfiles with + | [infile, Some outfile] when infile = x && null xs -> + Common.command2 ("cp " ^outfile^ " " ^ !output_file); + | [infile, None] when infile = x && null xs -> + Common.command2 ("cp " ^infile^ " " ^ !output_file); + | _ -> + failwith + ("-o can not be applied because there is multiple " ^ + "modified files"); + ); + + if !compare_with_expected + then Testing.compare_with_expected outfiles)) + + (* --------------------------------------------------------- *) + (* empty entry *) + (* --------------------------------------------------------- *) + | [] -> short_usage() + + )); + if !Pycocci.initialised && (Pycocci.py_isinitialized ()) != 0 then begin + ignore(Pycocci.pyrun_simplestring "cocci.finalise()"); + if !Flag.show_misc + then Common.pr2 "Finalizing python\n"; + Pycocci.py_finalize (); + end + end + +(*****************************************************************************) +let _ = + Common.main_boilerplate (fun () -> + main (); + Ctlcocci_integration.print_bench(); + ) diff --git a/menhirlib/.depend b/menhirlib/.depend new file mode 100644 index 0000000..af43dff --- /dev/null +++ b/menhirlib/.depend @@ -0,0 +1,10 @@ +engine.cmo: engineTypes.cmo +engine.cmx: engineTypes.cmx +rowDisplacement.cmo: infiniteArray.cmo +rowDisplacement.cmx: infiniteArray.cmx +tableFormat.cmo: packedIntArray.cmo engineTypes.cmo +tableFormat.cmx: packedIntArray.cmx engineTypes.cmx +tableInterpreter.cmo: tableFormat.cmo rowDisplacement.cmo packedIntArray.cmo \ + engineTypes.cmo engine.cmo +tableInterpreter.cmx: tableFormat.cmx rowDisplacement.cmx packedIntArray.cmx \ + engineTypes.cmx engine.cmx diff --git a/menhirlib/Makefile b/menhirlib/Makefile new file mode 100644 index 0000000..71a01e8 --- /dev/null +++ b/menhirlib/Makefile @@ -0,0 +1,85 @@ +############################################################################## +# Variables +############################################################################## +TARGET=menhirLib + +SRC= infiniteArray.ml packedIntArray.ml rowDisplacement.ml engineTypes.ml \ + engine.ml tableFormat.ml tableInterpreter.ml convert.ml + +LIBS= +INCLUDES= + +# copy what the menhir authors do +EXTRAOPT=-for-pack MenhirLib + +############################################################################## +# Generic variables +############################################################################## +OCAMLCFLAGS=-g -dtypes +OPTFLAGS= + +OCAMLC=ocamlc$(OPTBIN) $(OCAMLCFLAGS) $(INCLUDES) +OCAMLOPT= ocamlopt$(OPTBIN) $(OPTFLAGS) $(EXTRAOPT) $(INCLUDES) +OCAMLOPT2=ocamlopt$(OPTBIN) $(OPTFLAGS) $(INCLUDES) +OCAMLLEX=ocamllex$(OPTBIN) +OCAMLYACC=ocamlyacc -v +OCAMLDEP=ocamldep$(OPTBIN) $(INCLUDES) +OCAMLMKTOP=ocamlmktop -g -custom $(INCLUDES) + +OBJS= $(SRC:.ml=.cmo) +OPTOBJS= $(SRC:.ml=.cmx) + + +############################################################################## +# Top rules +############################################################################## +all: $(TARGET).cma menhirLib.cmo +all.opt: $(TARGET).cmxa menhirLib.cmx +opt: all.opt + +$(TARGET).cma: $(OBJS) $(LIBS) + $(OCAMLC) -a -o $@ $(OBJS) + +$(TARGET).cmxa: $(OPTOBJS) $(LIBS:.cma=.cmxa) + $(OCAMLOPT) -a -o $@ $(OPTOBJS) + +# I thought at first that only one file menhirLib.ml +# was needed but in fact it's a wierd cos menhirLib.cmo results from multi +# files. They used the -pack ocamlc option, and for strange reason +# decided to produce a .cma instead of a classical .cma. +# So I put all the necesseray files in this directory. + +# copy what the menhir authors do in their own makefile +menhirLib.cmo: $(OBJS) + $(OCAMLC) -pack -o menhirLib.cmo $^ + +menhirLib.cmx: $(OPTOBJS) + $(OCAMLOPT2) -pack -o menhirLib.cmx $^ + +############################################################################## +# Generic rules +############################################################################## +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) -c $< +.mli.cmi: + $(OCAMLC) -c $< +.ml.cmx: + $(OCAMLOPT) -c $< + +.ml.mldepend: + $(OCAMLC) -i $< + +clean:: + rm -f *.cm[ioxa] *.o *.a *.cmxa *.annot + +clean:: + rm -f *~ .*~ gmon.out #*# + +beforedepend:: + +depend:: beforedepend + $(OCAMLDEP) *.mli *.ml > .depend + +-include .depend diff --git a/menhirlib/convert.ml b/menhirlib/convert.ml new file mode 100644 index 0000000..1ccd1cf --- /dev/null +++ b/menhirlib/convert.ml @@ -0,0 +1,122 @@ +(**************************************************************************) +(* *) +(* Menhir *) +(* *) +(* François Pottier, INRIA Rocquencourt *) +(* Yann Régis-Gianas, PPS, Université Paris Diderot *) +(* *) +(* Copyright 2005-2008 Institut National de Recherche en Informatique *) +(* et en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU Library General Public License, with the *) +(* special exception on linking described in file LICENSE. *) +(* *) +(**************************************************************************) + +(* An ocamlyacc-style, or Menhir-style, parser requires access to + the lexer, which must be parameterized with a lexing buffer, and + to the lexing buffer itself, where it reads position information. *) + +(* This traditional API is convenient when used with ocamllex, but + inelegant when used with other lexer generators. *) + +type ('token, 'semantic_value) traditional = + (Lexing.lexbuf -> 'token) -> Lexing.lexbuf -> 'semantic_value + +(* This revised API is independent of any lexer generator. Here, the + parser only requires access to the lexer, and the lexer takes no + parameters. The tokens returned by the lexer may contain position + information. *) + +type ('token, 'semantic_value) revised = + (unit -> 'token) -> 'semantic_value + +(* --------------------------------------------------------------------------- *) + +(* Converting a traditional parser, produced by ocamlyacc or Menhir, + into a revised parser. *) + +(* A token of the revised lexer is essentially a triple of a token + of the traditional lexer (or raw token), a start position, and + and end position. The three [get] functions are accessors. *) + +(* We do not require the type ['token] to actually be a triple type. + This enables complex applications where it is a record type with + more three fields. It also enables simple applications where + positions are of no interest, so ['token] is just ['raw_token] + and [get_startp] and [get_endp] return dummy positions. *) + +let traditional2revised + (get_raw_token : 'token -> 'raw_token) + (get_startp : 'token -> Lexing.position) + (get_endp : 'token -> Lexing.position) + (parser : ('raw_token, 'semantic_value) traditional) +: ('token, 'semantic_value) revised = + + (* Accept a revised lexer. *) + + fun (lexer : unit -> 'token) -> + + (* Create a dummy lexing buffer. *) + + let lexbuf : Lexing.lexbuf = + Lexing.from_string "" + in + + (* Wrap the revised lexer as a traditional lexer. A traditional + lexer returns a raw token and updates the fields of the lexing + buffer with new positions, which will be read by the parser. *) + + let lexer (lexbuf : Lexing.lexbuf) : 'raw_token = + let token : 'token = lexer() in + lexbuf.Lexing.lex_start_p <- get_startp token; + lexbuf.Lexing.lex_curr_p <- get_endp token; + get_raw_token token + in + + (* Invoke the traditional parser. *) + + parser lexer lexbuf + +(* --------------------------------------------------------------------------- *) + +(* Converting a revised parser back to a traditional parser. *) + +let revised2traditional + (make_token : 'raw_token -> Lexing.position -> Lexing.position -> 'token) + (parser : ('token, 'semantic_value) revised) +: ('raw_token, 'semantic_value) traditional = + + (* Accept a traditional lexer and a lexing buffer. *) + + fun (lexer : Lexing.lexbuf -> 'raw_token) (lexbuf : Lexing.lexbuf) -> + + (* Wrap the traditional lexer as a revised lexer. *) + + let lexer () : 'token = + let token : 'raw_token = lexer lexbuf in + make_token token lexbuf.Lexing.lex_start_p lexbuf.Lexing.lex_curr_p + in + + (* Invoke the revised parser. *) + + parser lexer + +(* --------------------------------------------------------------------------- *) + +(* Simplified versions of the above, where concrete triples are used. *) + +module Simplified = struct + + let traditional2revised parser = + traditional2revised + (fun (token, _, _) -> token) + (fun (_, startp, _) -> startp) + (fun (_, _, endp) -> endp) + parser + + let revised2traditional parser = + revised2traditional + (fun token startp endp -> (token, startp, endp)) + parser + +end diff --git a/menhirlib/engine.ml b/menhirlib/engine.ml new file mode 100644 index 0000000..f66c29c --- /dev/null +++ b/menhirlib/engine.ml @@ -0,0 +1,367 @@ +(**************************************************************************) +(* *) +(* Menhir *) +(* *) +(* François Pottier, INRIA Rocquencourt *) +(* Yann Régis-Gianas, PPS, Université Paris Diderot *) +(* *) +(* Copyright 2005-2008 Institut National de Recherche en Informatique *) +(* et en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU Library General Public License, with the *) +(* special exception on linking described in file LICENSE. *) +(* *) +(**************************************************************************) + +open EngineTypes + +(* The LR parsing engine. *) + +(* This module is used: + + - at compile time, if so requested by the user, via the --interpret options; + - at run time, in the table-based back-end. *) + +module Make (T : TABLE) = struct + + (* This propagates type and exception definitions. *) + + include T + + let _eRR : exn = + Error + + (* --------------------------------------------------------------------------- *) + + (* [discard] takes a token off the input stream, queries the lexer + for a new one, and stores it into [env.token], overwriting the + previous token. If [env.shifted] has not yet reached its limit, + it is incremented. *) + + let discard env = + let lexbuf = env.lexbuf in + let token = env.lexer lexbuf in + env.token <- token; + Log.lookahead_token lexbuf (T.token2terminal token); + let shifted = env.shifted + 1 in + if shifted >= 0 then + env.shifted <- shifted + + (* --------------------------------------------------------------------------- *) + + (* The type [void] is empty. Many of the functions below have return type + [void]. This guarantees that they never return a value. Instead, they + must stop by raising an exception: either [Accept] or [Error]. *) + + type void + + (* --------------------------------------------------------------------------- *) + + (* In the code-based back-end, the [run] function is sometimes responsible + for pushing a new cell on the stack. This is motivated by code sharing + concerns. In this interpreter, there is no such concern; [run]'s caller + is always responsible for updating the stack. *) + + (* In the code-based back-end, there is a [run] function for each state + [s]. This function can behave in two slightly different ways, depending + on when it is invoked, or (equivalently) depending on [s]. + + If [run] is invoked after shifting a terminal symbol (or, equivalently, + if [s] has a terminal incoming symbol), then [run] discards a token, + unless [s] has a default reduction on [#]. (Indeed, in that case, + requesting the next token might drive the lexer off the end of the input + stream.) + + If, on the other hand, [run] is invoked after performing a goto transition, + or invoked directly by an entry point, then there is nothing to discard. + + These two cases are reflected in [CodeBackend.gettoken]. + + Here, the code is structured in a slightly different way. It is up to + the caller of [run] to indicate whether to discard a token. *) + + let rec run env please_discard : void = + + (* Log the fact that we just entered this state. *) + + let s = env.current in + Log.state s; + + (* If [please_discard] is set, discard a token and fetch the next one. *) + + (* This flag is set when [s] is being entered by shifting a terminal + symbol and [s] does not have a default reduction on [#]. *) + + if please_discard then + discard env; + + (* Examine what situation we are in. This case analysis is analogous to + that performed in [CodeBackend.gettoken], in the sub-case where we do + not have a terminal incoming symbol. *) + + T.default_reduction + s + reduce (* there is a default reduction; perform it *) + continue (* there is none; continue below *) + env + + and continue env : void = + + (* There is no default reduction. Consult the current lookahead token + so as to determine which action should be taken. *) + + (* Peeking at the first input token, without taking it off the input + stream, is normally done by reading [env.token]. However, we check + [env.shifted] first: if it is -1, then the lookahead token is the + [error] token. *) + + (* Note that, if we just called [discard] above, then the lookahead + token cannot be [error]. *) + + if env.shifted = (-1) then begin + Log.resuming_error_handling(); + error env + end + else + action env + + (* --------------------------------------------------------------------------- *) + + (* When [action] is invoked, we know that the current state does not have + a default reduction. We also know that the current lookahead token is + not [error]: it is a real token, stored in [env.token]. *) + + and action env : void = + + (* We consult the two-dimensional action table, indexed by the + current state and the current lookahead token, in order to + determine which action should be taken. *) + + let token = env.token in + T.action + env.current (* determines a row *) + (T.token2terminal token) (* determines a column *) + (T.token2value token) + shift (* shift continuation *) + reduce (* reduce continuation *) + initiate (* failure continuation *) + env + + (* --------------------------------------------------------------------------- *) + + (* This function takes care of shift transitions along a terminal symbol. + (Goto transitions are taken care of within [reduce] below.) The symbol + can be either an actual token or the [error] pseudo-token. *) + + and shift env + (please_discard : bool) + (terminal : terminal) + (value : semantic_value) + (s' : state) + : void = + + (* Log the transition. *) + + Log.shift terminal s'; + + (* Push a new cell onto the stack, containing the identity of the + state that we are leaving. *) + + let lexbuf = env.lexbuf in + env.stack <- { + state = env.current; + semv = value; + startp = lexbuf.Lexing.lex_start_p; + endp = lexbuf.Lexing.lex_curr_p; + next = env.stack; + }; + + (* Switch to state [s']. *) + + env.current <- s'; + run env please_discard + + (* --------------------------------------------------------------------------- *) + + (* This function takes care of reductions. *) + + and reduce env (prod : production) : void = + + (* Log a reduction event. *) + + Log.reduce_or_accept prod; + + (* Invoke the semantic action. The semantic action is responsible for + truncating the stack, updating the current state, producing a cell that + contains a new semantic value, and raising [Accept] or [Error] if + appropriate. *) + + (* If the semantic action raises [Error], we catch it immediately and + initiate error handling. *) + + (* The apparently weird idiom used here is an encoding for a + [let/unless] construct, which does not exist in ocaml. *) + + if ( + try + T.semantic_action prod env; + true + with Error -> + false + ) then begin + + (* By our convention, the semantic action is responsible for updating + the stack. The state now found in the top stack cell is the return + state. *) + + (* Perform a goto transition. The target state is determined + by consulting the goto table at the return state and at + production [prod]. *) + + env.current <- T.goto env.stack.state prod; + run env false + + end + else + errorbookkeeping env + + + (* --------------------------------------------------------------------------- *) + + (* The following functions deal with errors. *) + + (* [initiate] and [errorbookkeeping] initiate error handling. See the functions + by the same names in [CodeBackend]. *) + + and initiate env : void = + assert (env.shifted >= 0); + if T.recovery && env.shifted = 0 then begin + Log.discarding_last_token (T.token2terminal env.token); + discard env; + env.shifted <- 0; + action env + end + else + errorbookkeeping env + + and errorbookkeeping env = + Log.initiating_error_handling(); + env.previouserror <- env.shifted; + env.shifted <- (-1); + error env + + (* [error] handles errors. *) + + and error env : void = + + (* Consult the column associated with the [error] pseudo-token in the + action table. *) + + T.action + env.current (* determines a row *) + T.error_terminal (* determines a column *) + T.error_value + error_shift (* shift continuation *) + error_reduce (* reduce continuation *) + error_fail (* failure continuation *) + env + + and error_shift env please_discard terminal value s' = + + (* Here, [terminal] is [T.error_terminal], and [value] is [T.error_value]. *) + + assert (terminal = T.error_terminal && value = T.error_value); + + (* This state is capable of shifting the [error] token. *) + + Log.handling_error env.current; + shift env please_discard terminal value s' + + and error_reduce env prod = + + (* This state is capable of performing a reduction on [error]. *) + + Log.handling_error env.current; + reduce env prod + + and error_fail env = + + (* This state is unable to handle errors. Attempt to pop a stack + cell. *) + + let cell = env.stack in + let next = cell.next in + if next == cell then + + (* The stack is empty. Die. *) + + raise _eRR + + else begin + + (* The stack is nonempty. Pop a cell, updating the current state + with that found in the popped cell, and try again. *) + + env.stack <- next; + env.current <- cell.state; + error env + + end + + (* --------------------------------------------------------------------------- *) + + let entry + (s : state) + (lexer : Lexing.lexbuf -> token) + (lexbuf : Lexing.lexbuf) + : semantic_value = + + (* Build an empty stack. This is a dummy cell, which is its own + successor. Its fields other than [next] contain dummy values. *) + + let rec empty = { + state = s; (* dummy *) + semv = T.error_value; (* dummy *) + startp = lexbuf.Lexing.lex_start_p; (* dummy *) + endp = lexbuf.Lexing.lex_curr_p; (* dummy *) + next = empty; + } in + + (* Perform an initial call to the lexer. *) + + let token : token = + lexer lexbuf + in + + (* Log our first lookahead token. *) + + Log.lookahead_token lexbuf (T.token2terminal token); + + (* Build an initial environment. *) + + let env = { + lexer = lexer; + lexbuf = lexbuf; + token = token; + shifted = max_int; + previouserror = max_int; + stack = empty; + current = s; + } in + + (* Run. Catch [Accept], which represents normal termination. Let [Error] + escape. *) + + try + + (* If ocaml offered a [match/with] construct with zero branches, this is + what we would use here, since the type [void] has zero cases. *) + + let (_ : void) = run env false in + assert false (* cannot fail *) + + with + | Accept v -> + v + +end + diff --git a/menhirlib/engineTypes.ml b/menhirlib/engineTypes.ml new file mode 100644 index 0000000..4203449 --- /dev/null +++ b/menhirlib/engineTypes.ml @@ -0,0 +1,331 @@ +(**************************************************************************) +(* *) +(* Menhir *) +(* *) +(* François Pottier, INRIA Rocquencourt *) +(* Yann Régis-Gianas, PPS, Université Paris Diderot *) +(* *) +(* Copyright 2005-2008 Institut National de Recherche en Informatique *) +(* et en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU Library General Public License, with the *) +(* special exception on linking described in file LICENSE. *) +(* *) +(**************************************************************************) + +(* This file defines several types and module types that are used in the + specification of module [Engine]. *) + +(* --------------------------------------------------------------------------- *) + +(* It would be nice if we could keep the structure of stacks and environments + hidden. However, stacks and environments must be accessible to semantic + actions, so the following data structure definitions must be public. *) + +(* --------------------------------------------------------------------------- *) + +(* A stack is a linked list of cells. A sentinel cell -- which is its own + successor is used to mark the bottom of the stack. The sentinel cell + itself is not significant -- it contains dummy values. *) + +type ('state, 'semantic_value) stack = { + + (* The state that we should go back to if we pop this stack cell. *) + + (* This convention means that the state contained in the top stack cell is + not the current state [env.current]. It also means that the state found + within the sentinel is a dummy -- it is never consulted. This convention + is the same as that adopted by the code-based back-end. *) + + state: 'state; + + (* The semantic value associated with the chunk of input that this cell + represents. *) + + semv: 'semantic_value; + + (* The start and end positions of the chunk of input that this cell + represents. *) + + startp: Lexing.position; + endp: Lexing.position; + + (* The next cell down in the stack. If this is a self-pointer, then this + cell is the sentinel, and the stack is conceptually empty. *) + + next: ('state, 'semantic_value) stack; + +} + +(* --------------------------------------------------------------------------- *) + +(* A parsing environment contains basically all of the automaton's state. *) + +type ('state, 'semantic_value, 'token) env = { + + (* The lexer. *) + + lexer: Lexing.lexbuf -> 'token; + + (* The lexing buffer. It is used as an argument to the lexer, and also + accessed directly when extracting positions. *) + + lexbuf: Lexing.lexbuf; + + (* The last token that was obtained from the lexer. *) + + mutable token: 'token; + + (* A count of how many tokens were shifted since the beginning, or since + the last [error] token was encountered. By convention, if [shifted] + is (-1), then the current lookahead token is [error]. *) + + mutable shifted: int; + + (* A copy of the value of [shifted] just before the most recent error + was detected. This value is not used by the automaton itself, but + is made accessible to semantic actions. *) + + mutable previouserror: int; + + (* The stack. In [CodeBackend], it is passed around on its own, + whereas, here, it is accessed via the environment. *) + + mutable stack: ('state, 'semantic_value) stack; + + (* The current state. In [CodeBackend], it is passed around on its + own, whereas, here, it is accessed via the environment. *) + + mutable current: 'state; + +} + +(* --------------------------------------------------------------------------- *) + +(* This signature describes the parameters that must be supplied to the LR + engine. *) + +module type TABLE = sig + + (* The type of automaton states. *) + + type state + + (* The type of tokens. These can be thought of as real tokens, that is, + tokens returned by the lexer. They carry a semantic value. This type + does not include the [error] pseudo-token. *) + + type token + + (* The type of terminal symbols. These can be thought of as integer codes. + They do not carry a semantic value. This type does include the [error] + pseudo-token. *) + + type terminal + + (* The type of semantic values. *) + + type semantic_value + + (* A token is conceptually a pair of a (non-[error]) terminal symbol and + a semantic value. The following two functions are the pair projections. *) + + val token2terminal: token -> terminal + val token2value: token -> semantic_value + + (* Even though the [error] pseudo-token is not a real token, it is a + terminal symbol. Furthermore, for regularity, it must have a semantic + value. *) + + val error_terminal: terminal + val error_value: semantic_value + + (* The type of productions. *) + + type production + + (* If a state [s] has a default reduction on production [prod], then, upon + entering [s], the automaton should reduce [prod] without consulting the + lookahead token. The following function allows determining which states + have default reductions. *) + + (* Instead of returning a value of a sum type -- either [DefRed prod], or + [NoDefRed] -- it accepts two continuations, and invokes just one of + them. This mechanism allows avoiding a memory allocation. *) + + val default_reduction: + state -> + ('env -> production -> 'answer) -> + ('env -> 'answer) -> + 'env -> 'answer + + (* An LR automaton can normally take three kinds of actions: shift, reduce, + or fail. (Acceptance is a particular case of reduction: it consists in + reducing a start production.) *) + + (* There are two variants of the shift action. [shift/discard s] instructs + the automaton to discard the current token, request a new one from the + lexer, and move to state [s]. [shift/nodiscard s] instructs it to move to + state [s] without requesting a new token. This instruction should be used + when [s] has a default reduction on [#]. See [CodeBackend.gettoken] for + details. *) + + (* This is the automaton's action table. It maps a pair of a state and a + terminal symbol to an action. *) + + (* Instead of returning a value of a sum type -- one of shift/discard, + shift/nodiscard, reduce, or fail -- this function accepts three + continuations, and invokes just one them. This mechanism allows avoiding + a memory allocation. *) + + (* In summary, the parameters to [action] are as follows: + + - the first two parameters, a state and a terminal symbol, are used to + look up the action table; + + - the next parameter is the semantic value associated with the above + terminal symbol; it is not used, only passed along to the shift + continuation, as explained below; + + - the shift continuation expects an environment; a flag that tells + whether to discard the current token; the terminal symbol that + is being shifted; its semantic value; and the target state of + the transition; + + - the reduce continuation expects an environment and a production; + + - the fail continuation expects an environment; + + - the last parameter is the environment; it is not used, only passed + along to the selected continuation. *) + + val action: + state -> + terminal -> + semantic_value -> + ('env -> bool -> terminal -> semantic_value -> state -> 'answer) -> + ('env -> production -> 'answer) -> + ('env -> 'answer) -> + 'env -> 'answer + + (* This is the automaton's goto table. It maps a pair of a state and a + production to a new state. + + This convention is slightly different from the textbook approach. The + goto table is usually indexed by a state and a non-terminal symbol. *) + + val goto: state -> production -> state + + (* By convention, a semantic action is responsible for: + + 1. fetching whatever semantic values and positions it needs off the stack; + + 2. popping an appropriate number of cells off the stack, as dictated + by the length of the right-hand side of the production; this involves + updating [env.stack]; + + 3. computing a new semantic value, as well as new start and end positions; + + 4. pushing a new stack cell, which contains the three values + computed in step 3; this again involves updating [env.stack] + (only one update is necessary). + + Point 1 is essentially forced upon us: if semantic values were fetched + off the stack by this interpreter, then the calling convention for + semantic actions would be variadic: not all semantic actions would have + the same number of arguments. The rest follows rather naturally. *) + + (* If production [prod] is an accepting production, then the semantic action + is responsible for raising exception [Accept], instead of returning + normally. This convention allows us to not distinguish between regular + productions and accepting productions. All we have to do is catch that + exception at top level. *) + + (* Semantic actions are allowed to raise [Error]. *) + + exception Accept of semantic_value + exception Error + + type semantic_action = + (state, semantic_value, token) env -> unit + + val semantic_action: production -> semantic_action + + (* The LR engine can attempt error recovery. This consists in discarding + tokens, just after an error has been successfully handled, until a token + that can be successfully handled is found. This mechanism is optional. + The following flag enables it. *) + + val recovery: bool + + (* The LR engine requires a number of hooks, which are used for logging. *) + + (* The comments below indicate the conventional messages that correspond + to these hooks in the code-based back-end; see [CodeBackend]. *) + + module Log : sig + + (* State %d: *) + + val state: state -> unit + + (* Shifting () to state *) + + val shift: terminal -> state -> unit + + (* Reducing a production should be logged either as a reduction + event (for regular productions) or as an acceptance event (for + start productions). *) + + (* Reducing production / Accepting *) + + val reduce_or_accept: production -> unit + + (* Lookahead token is now (-) *) + + val lookahead_token: Lexing.lexbuf -> terminal -> unit + + (* Initiating error handling *) + + val initiating_error_handling: unit -> unit + + (* Resuming error handling *) + + val resuming_error_handling: unit -> unit + + (* Handling error in state *) + + val handling_error: state -> unit + + (* Discarding last token read () *) + + val discarding_last_token: terminal -> unit + + end + +end + +(* --------------------------------------------------------------------------- *) + +(* This signature describes the LR engine. *) + +module type ENGINE = sig + + type state + + type token + + type semantic_value + + (* An entry point to the engine requires a start state, a lexer, and a lexing + buffer. It either succeeds and produces a semantic value, or fails and + raises [Error]. *) + + exception Error + + val entry: + state -> + (Lexing.lexbuf -> token) -> + Lexing.lexbuf -> + semantic_value + +end diff --git a/menhirlib/infiniteArray.ml b/menhirlib/infiniteArray.ml new file mode 100644 index 0000000..80eba6c --- /dev/null +++ b/menhirlib/infiniteArray.ml @@ -0,0 +1,64 @@ +(**************************************************************************) +(* *) +(* Menhir *) +(* *) +(* François Pottier, INRIA Rocquencourt *) +(* Yann Régis-Gianas, PPS, Université Paris Diderot *) +(* *) +(* Copyright 2005-2008 Institut National de Recherche en Informatique *) +(* et en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU Library General Public License, with the *) +(* special exception on linking described in file LICENSE. *) +(* *) +(**************************************************************************) + +(* $Id: infiniteArray.ml,v 1.1 2008/09/25 21:18:16 pad Exp $ *) + +(** This module implements infinite arrays, that is, arrays that grow + transparently upon demand. *) + +type 'a t = { + default: 'a; + mutable table: 'a array; + mutable extent: int; (* the index of the greatest [set] ever, plus one *) + } + +let default_size = + 16384 (* must be non-zero *) + +let make x = { + default = x; + table = Array.make default_size x; + extent = 0; +} + +let rec new_length length i = + if i < length then + length + else + new_length (2 * length) i + +let ensure a i = + let table = a.table in + let length = Array.length table in + if i >= length then begin + let table' = Array.make (new_length (2 * length) i) a.default in + Array.blit table 0 table' 0 length; + a.table <- table' + end + +let get a i = + ensure a i; + a.table.(i) + +let set a i x = + ensure a i; + a.table.(i) <- x; + a.extent <- max (i + 1) a.extent + +let extent a = + a.extent + +let domain a = + Array.sub a.table 0 a.extent + diff --git a/menhirlib/license.txt b/menhirlib/license.txt new file mode 100644 index 0000000..f7c1ef1 --- /dev/null +++ b/menhirlib/license.txt @@ -0,0 +1,629 @@ +In the following, "the Library" refers to the following files: + + src/standard.mly + src/infiniteArray.{ml,mli} + src/packedIntArray.{ml,mli} + src/rowDisplacement.{ml,mli} + src/engineTypes.ml + src/engine.{ml,mli} + src/tableFormat.ml + src/tableInterpreter.{ml,mli} + src/convert.{ml,mli} + +while "the Generator" refers to all other files in this archive. + +The Generator is distributed under the terms of the Q Public License +version 1.0 with a change to choice of law (included below). + +The Library is distributed under the terms of the GNU Library General +Public License version 2 (included below). + +As a special exception to the Q Public Licence, you may develop +application programs, reusable components and other software items +that link with the original or modified versions of the Generator +and are not made available to the general public, without any of the +additional requirements listed in clause 6c of the Q Public licence. + +As a special exception to the GNU Library General Public License, you +may link, statically or dynamically, a "work that uses the Library" +with a publicly distributed version of the Library to produce an +executable file containing portions of the Library, and distribute +that executable file under terms of your choice, without any of the +additional requirements listed in clause 6 of the GNU Library General +Public License. By "a publicly distributed version of the Library", +we mean either the unmodified Library as distributed by INRIA, or a +modified version of the Library that is distributed under the +conditions defined in clause 3 of the GNU Library General Public +License. This exception does not however invalidate any other reasons +why the executable file might be covered by the GNU Library General +Public License. + +---------------------------------------------------------------------- + + THE Q PUBLIC LICENSE version 1.0 + + Copyright (C) 1999 Troll Tech AS, Norway. + Everyone is permitted to copy and + distribute this license document. + +The intent of this license is to establish freedom to share and change +the software regulated by this license under the open source model. + +This license applies to any software containing a notice placed by the +copyright holder saying that it may be distributed under the terms of +the Q Public License version 1.0. Such software is herein referred to +as the Software. This license covers modification and distribution of +the Software, use of third-party application programs based on the +Software, and development of free software which uses the Software. + + Granted Rights + +1. You are granted the non-exclusive rights set forth in this license +provided you agree to and comply with any and all conditions in this +license. Whole or partial distribution of the Software, or software +items that link with the Software, in any form signifies acceptance of +this license. + +2. You may copy and distribute the Software in unmodified form +provided that the entire package, including - but not restricted to - +copyright, trademark notices and disclaimers, as released by the +initial developer of the Software, is distributed. + +3. You may make modifications to the Software and distribute your +modifications, in a form that is separate from the Software, such as +patches. The following restrictions apply to modifications: + + a. Modifications must not alter or remove any copyright notices + in the Software. + + b. When modifications to the Software are released under this + license, a non-exclusive royalty-free right is granted to the + initial developer of the Software to distribute your + modification in future versions of the Software provided such + versions remain available under these terms in addition to any + other license(s) of the initial developer. + +4. You may distribute machine-executable forms of the Software or +machine-executable forms of modified versions of the Software, +provided that you meet these restrictions: + + a. You must include this license document in the distribution. + + b. You must ensure that all recipients of the machine-executable + forms are also able to receive the complete machine-readable + source code to the distributed Software, including all + modifications, without any charge beyond the costs of data + transfer, and place prominent notices in the distribution + explaining this. + + c. You must ensure that all modifications included in the + machine-executable forms are available under the terms of this + license. + +5. You may use the original or modified versions of the Software to +compile, link and run application programs legally developed by you or +by others. + +6. You may develop application programs, reusable components and other +software items that link with the original or modified versions of the +Software. These items, when distributed, are subject to the following +requirements: + + a. You must ensure that all recipients of machine-executable + forms of these items are also able to receive and use the + complete machine-readable source code to the items without any + charge beyond the costs of data transfer. + + b. You must explicitly license all recipients of your items to + use and re-distribute original and modified versions of the + items in both machine-executable and source code forms. The + recipients must be able to do so without any charges whatsoever, + and they must be able to re-distribute to anyone they choose. + + c. If the items are not available to the general public, and the + initial developer of the Software requests a copy of the items, + then you must supply one. + + Limitations of Liability + +In no event shall the initial developers or copyright holders be +liable for any damages whatsoever, including - but not restricted to - +lost revenue or profits or other direct, indirect, special, incidental +or consequential damages, even if they have been advised of the +possibility of such damages, except to the extent invariable law, if +any, provides otherwise. + + No Warranty + +The Software and this license document are provided AS IS with NO +WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + Choice of Law + +This license is governed by the Laws of France. + +---------------------------------------------------------------------- + + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/menhirlib/packedIntArray.ml b/menhirlib/packedIntArray.ml new file mode 100644 index 0000000..b31c744 --- /dev/null +++ b/menhirlib/packedIntArray.ml @@ -0,0 +1,199 @@ +(**************************************************************************) +(* *) +(* Menhir *) +(* *) +(* François Pottier, INRIA Rocquencourt *) +(* Yann Régis-Gianas, PPS, Université Paris Diderot *) +(* *) +(* Copyright 2005-2008 Institut National de Recherche en Informatique *) +(* et en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU Library General Public License, with the *) +(* special exception on linking described in file LICENSE. *) +(* *) +(**************************************************************************) + +(* A packed integer array is represented as a pair of an integer [k] and + a string [s]. The integer [k] is the number of bits per integer that we + use. The string [s] is just an array of bits, which is read in 8-bit + chunks. *) + +(* The ocaml programming language treats string literals and array literals + in slightly different ways: the former are statically allocated, while + the latter are dynamically allocated. (This is rather arbitrary.) In the + context of Menhir's table-based back-end, where compact, immutable + integer arrays are needed, ocaml strings are preferable to ocaml arrays. *) + +type t = + int * string + +(* The magnitude [k] of an integer [v] is the number of bits required + to represent [v]. It is rounded up to the nearest power of two, so + that [k] divides [Sys.word_size]. *) + +let magnitude (v : int) = + if v < 0 then + Sys.word_size + else + let rec check k max = (* [max] equals [2^k] *) + if (max <= 0) || (v < max) then + k + (* if [max] just overflew, then [v] requires a full ocaml + integer, and [k] is the number of bits in an ocaml integer + plus one, that is, [Sys.word_size]. *) + else + check (2 * k) (max * max) + in + check 1 2 + +(* [pack a] turns an array of integers into a packed integer array. *) + +(* Because the sign bit is the most significant bit, the magnitude of + any negative number is the word size. In other words, [pack] does + not achieve any space savings as soon as [a] contains any negative + numbers, even if they are ``small''. *) + +let pack (a : int array) : t = + + let m = Array.length a in + + (* Compute the maximum magnitude of the array elements. This tells + us how many bits per element we are going to use. *) + + let k = + Array.fold_left (fun k v -> + max k (magnitude v) + ) 1 a + in + + (* Because access to ocaml strings is performed on an 8-bit basis, + two cases arise. If [k] is less than 8, then we can pack multiple + array entries into a single character. If [k] is greater than 8, + then we must use multiple characters to represent a single array + entry. *) + + if k <= 8 then begin + + (* [w] is the number of array entries that we pack in a character. *) + + assert (8 mod k = 0); + let w = 8 / k in + + (* [n] is the length of the string that we allocate. *) + + let n = + if m mod w = 0 then + m / w + else + m / w + 1 + in + + let s = + String.create n + in + + (* Define a reader for the source array. The reader might run off + the end if [w] does not divide [m]. *) + + let i = ref 0 in + let next () = + let ii = !i in + if ii = m then + 0 (* ran off the end, pad with zeroes *) + else + let v = a.(ii) in + i := ii + 1; + v + in + + (* Fill up the string. *) + + for j = 0 to n - 1 do + let c = ref 0 in + for x = 1 to w do + c := (!c lsl k) lor next() + done; + s.[j] <- Char.chr !c + done; + + (* Done. *) + + k, s + + end + else begin (* k > 8 *) + + (* [w] is the number of characters that we use to encode an array entry. *) + + assert (k mod 8 = 0); + let w = k / 8 in + + (* [n] is the length of the string that we allocate. *) + + let n = + m * w + in + + let s = + String.create n + in + + (* Fill up the string. *) + + for i = 0 to m - 1 do + let v = ref a.(i) in + for x = 1 to w do + s.[(i + 1) * w - x] <- Char.chr (!v land 255); + v := !v lsr 8 + done + done; + + (* Done. *) + + k, s + + end + +(* Access to a string. *) + +let read (s : string) (i : int) : int = + Char.code (String.unsafe_get s i) + +(* [get1 t i] returns the integer stored in the packed array [t] at index [i]. + It assumes (and does not check) that the array's bit width is [1]. The + parameter [t] is just a string. *) + +let get1 (s : string) (i : int) : int = + let c = read s (i lsr 3) in + let c = c lsr ((lnot i) land 0b111) in + let c = c land 0b1 in + c + +(* [get t i] returns the integer stored in the packed array [t] at index [i]. *) + +(* Together, [pack] and [get] satisfy the following property: if the index [i] + is within bounds, then [get (pack a) i] equals [a.(i)]. *) + +let get ((k, s) : t) (i : int) : int = + match k with + | 1 -> + get1 s i + | 2 -> + let c = read s (i lsr 2) in + let c = c lsr (2 * ((lnot i) land 0b11)) in + let c = c land 0b11 in + c + | 4 -> + let c = read s (i lsr 1) in + let c = c lsr (4 * ((lnot i) land 0b1)) in + let c = c land 0b1111 in + c + | 8 -> + read s i + | 16 -> + let j = 2 * i in + (read s j) lsl 8 + read s (j + 1) + | _ -> + assert (k = 32); (* 64 bits unlikely, not supported *) + let j = 4 * i in + (((read s j lsl 8) + read s (j + 1)) lsl 8 + read s (j + 2)) lsl 8 + read s (j + 3) + diff --git a/menhirlib/readme.txt b/menhirlib/readme.txt new file mode 100644 index 0000000..09068aa --- /dev/null +++ b/menhirlib/readme.txt @@ -0,0 +1,7 @@ +To make it easier to install coccinelle, to not have to bother about +where some of menhir object files are, we simply have copied some +files from the menhir distribution. Those files are needed for the +parsers generated with the --table menhir option. The files in this +directory are thus copyrighted by the menhir authors, François Pottier +and Yann Régis-Gianas, and covered by the GNU Library General Public +License version 2. diff --git a/menhirlib/rowDisplacement.ml b/menhirlib/rowDisplacement.ml new file mode 100644 index 0000000..640c1ac --- /dev/null +++ b/menhirlib/rowDisplacement.ml @@ -0,0 +1,272 @@ +(**************************************************************************) +(* *) +(* Menhir *) +(* *) +(* François Pottier, INRIA Rocquencourt *) +(* Yann Régis-Gianas, PPS, Université Paris Diderot *) +(* *) +(* Copyright 2005-2008 Institut National de Recherche en Informatique *) +(* et en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU Library General Public License, with the *) +(* special exception on linking described in file LICENSE. *) +(* *) +(**************************************************************************) + +(* This module compresses a two-dimensional table, where some values + are considered insignificant, via row displacement. *) + +(* This idea reportedly appears in Aho and Ullman's ``Principles + of Compiler Design'' (1977). It is evaluated in Tarjan and Yao's + ``Storing a Sparse Table'' (1979) and in Dencker, Dürre, and Heuft's + ``Optimization of Parser Tables for Portable Compilers'' (1984). *) + +(* A compressed table is represented as a pair of arrays. The + displacement array is an array of offsets into the data array. *) + +type 'a table = + int array * (* displacement *) + 'a array (* data *) + +(* In a natural version of this algorithm, displacements would be greater + than (or equal to) [-n]. However, in the particular setting of Menhir, + both arrays are intended to be compressed with [PackedIntArray], which + does not efficiently support negative numbers. For this reason, we are + careful not to produce negative displacements. *) + +(* In order to avoid producing negative displacements, we simply use the + least significant bit as the sign bit. This is implemented by [encode] + and [decode] below. *) + +(* One could also think, say, of adding [n] to every displacement, so as + to ensure that all displacements are nonnegative. This would work, but + would require [n] to be published, for use by the decoder. *) + +let encode (displacement : int) : int = + if displacement >= 0 then + displacement lsl 1 + else + (-displacement) lsl 1 + 1 + +let decode (displacement : int) : int = + if displacement land 1 = 0 then + displacement lsr 1 + else + -(displacement lsr 1) + +(* It is reasonable to assume that, as matrices grow large, their + density becomes low, i.e., they have many insignificant entries. + As a result, it is important to work with a sparse data structure + for rows. We internally represent a row as a list of its + significant entries, where each entry is a pair of a [j] index and + an element. *) + +type 'a row = + (int * 'a) list + +(* [compress equal insignificant dummy m n t] turns the two-dimensional table + [t] into a compressed table. The parameter [equal] is equality of data + values. The parameter [wildcard] tells which data values are insignificant, + and can thus be overwritten with other values. The parameter [dummy] is + used to fill holes in the data array. [m] and [n] are the integer + dimensions of the table [t]. *) + +let compress + (equal : 'a -> 'a -> bool) + (insignificant : 'a -> bool) + (dummy : 'a) + (m : int) (n : int) + (t : 'a array array) + : 'a table = + + (* Be defensive. *) + + assert (Array.length t = m); + assert begin + for i = 0 to m - 1 do + assert (Array.length t.(i) = n) + done; + true + end; + + (* This turns a row-as-array into a row-as-sparse-list. *) + + let sparse (line : 'a array) : 'a row = + + let rec loop (j : int) (row : 'a row) = + if j < 0 then + row + else + let x = line.(j) in + loop + (j - 1) + (if insignificant x then row else (j, x) :: row) + in + + loop (n - 1) [] + + in + + (* Define the rank of a row as its number of significant entries. *) + + let rank (row : 'a row) : int = + List.length row + in + + (* Construct a list of all rows, together with their index and rank. *) + + let rows : (int * int * 'a row) list = (* index, rank, row *) + Array.to_list ( + Array.mapi (fun i line -> + let row = sparse line in + i, rank row, row + ) t + ) + in + + (* Sort this list by decreasing rank. This does not have any impact + on correctness, but reportedly improves compression. The + intuitive idea is that rows with few significant elements are + easy to fit, so they should be inserted last, after the problem + has become quite constrained by fitting the heavier rows. This + heuristic is attributed to Ziegler. *) + + let rows = + List.sort (fun (_, rank1, _) (_, rank2, _) -> + compare rank2 rank1 + ) rows + in + + (* Allocate a one-dimensional array of displacements. *) + + let displacement : int array = + Array.make m 0 + in + + (* Allocate a one-dimensional, infinite array of values. Indices + into this array are written [k]. *) + + let data : 'a InfiniteArray.t = + InfiniteArray.make dummy + in + + (* Determine whether [row] fits at offset [k] within the current [data] + array, up to extension of this array. *) + + (* Note that this check always succeeds when [k] equals the length of + the [data] array. Indeed, the loop is then skipped. This property + guarantees the termination of the recursive function [fit] below. *) + + let fits k (row : 'a row) : bool = + + let d = InfiniteArray.extent data in + + let rec loop = function + | [] -> + true + | (j, x) :: row -> + + (* [x] is a significant element. *) + + (* By hypothesis, [k + j] is nonnegative. If it is greater than or + equal to the current length of the data array, stop -- the row + fits. *) + + assert (k + j >= 0); + + if k + j >= d then + true + + (* We now know that [k + j] is within bounds of the data + array. Check whether it is compatible with the element [y] found + there. If it is, continue. If it isn't, stop -- the row does not + fit. *) + + else + let y = InfiniteArray.get data (k + j) in + if insignificant y || equal x y then + loop row + else + false + + in + loop row + + in + + (* Find the leftmost position where a row fits. *) + + (* If the leftmost significant element in this row is at offset [j], + then we can hope to fit as far left as [-j] -- so this element + lands at offset [0] in the data array. *) + + (* Note that displacements may be negative. This means that, for + insignificant elements, accesses to the data array could fail: they could + be out of bounds, either towards the left or towards the right. This is + not a problem, as long as [get] is invoked only at significant + elements. *) + + let rec fit k row : int = + if fits k row then + k + else + fit (k + 1) row + in + + let fit row = + match row with + | [] -> + 0 (* irrelevant *) + | (j, _) :: _ -> + fit (-j) row + in + + (* Write [row] at (compatible) offset [k]. *) + + let rec write k = function + | [] -> + () + | (j, x) :: row -> + InfiniteArray.set data (k + j) x; + write k row + in + + (* Iterate over the sorted list of rows. Fit and write each row at + the leftmost compatible offset. Update the displacement table. *) + + let () = + List.iter (fun (i, _, row) -> + let k = fit row in (* if [row] has leading insignificant elements, then [k] can be negative *) + write k row; + displacement.(i) <- encode k + ) rows + in + + (* Return the compressed tables. *) + + displacement, InfiniteArray.domain data + +(* [get ct i j] returns the value found at indices [i] and [j] in the + compressed table [ct]. This function call is permitted only if the + value found at indices [i] and [j] in the original table is + significant -- otherwise, it could fail abruptly. *) + +(* Together, [compress] and [get] have the property that, if the value + found at indices [i] and [j] in an uncompressed table [t] is + significant, then [get (compress t) i j] is equal to that value. *) + +let get (displacement, data) i j = + assert (0 <= i && i < Array.length displacement); + let k = decode displacement.(i) in + assert (0 <= k + j && k + j < Array.length data); + (* failure of this assertion indicates an attempt to access an + insignificant element that happens to be mapped out of the bounds + of the [data] array. *) + data.(k + j) + +(* [getget] is a variant of [get] which only requires read access, + via accessors, to the two components of the table. *) + +let getget get_displacement get_data (displacement, data) i j = + let k = decode (get_displacement displacement i) in + get_data data (k + j) + diff --git a/menhirlib/tableFormat.ml b/menhirlib/tableFormat.ml new file mode 100644 index 0000000..8e94d5b --- /dev/null +++ b/menhirlib/tableFormat.ml @@ -0,0 +1,134 @@ +(**************************************************************************) +(* *) +(* Menhir *) +(* *) +(* François Pottier, INRIA Rocquencourt *) +(* Yann Régis-Gianas, PPS, Université Paris Diderot *) +(* *) +(* Copyright 2005-2008 Institut National de Recherche en Informatique *) +(* et en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU Library General Public License, with the *) +(* special exception on linking described in file LICENSE. *) +(* *) +(**************************************************************************) + +(* This signature defines the format of the parse tables. It is used as + an argument to [TableInterpreter]. *) + +module type TABLES = sig + + (* This is the parser's type of tokens. *) + + type token + + (* This maps a token to its internal (generation-time) integer code. *) + + val token2terminal: token -> int + + (* This is the integer code for the error pseudo-token. *) + + val error_terminal: int + + (* This maps a token to its semantic value. *) + + val token2value: token -> Obj.t + + (* Traditionally, an LR automaton is described by two tables, namely, an + action table and a goto table. See, for instance, the Dragon book. + + The action table is a two-dimensional matrix that maps a state and a + lookahead token to an action. An action is one of: shift to a certain + state, reduce a certain production, accept, or fail. + + The goto table is a two-dimensional matrix that maps a state and a + non-terminal symbol to either a state or undefined. By construction, this + table is sparse: its undefined entries are never looked up. A compression + technique is free to overlap them with other entries. + + In Menhir, things are slightly different. If a state has a default + reduction on token [#], then that reduction must be performed without + consulting the lookahead token. As a result, we must first determine + whether that is the case, before we can obtain a lookahead token and use it + as an index in the action table. + + Thus, Menhir's tables are as follows. + + A one-dimensional default reduction table maps a state to either ``no + default reduction'' (encoded as: 0) or ``by default, reduce prod'' + (encoded as: 1 + prod). The action table is looked up only when there + is no default reduction. *) + + val default_reduction: PackedIntArray.t + + (* Menhir follows Dencker, Dürre and Heuft, who point out that, although the + action table is not sparse by nature (i.e., the error entries are + significant), it can be made sparse by first factoring out a binary error + matrix, then replacing the error entries in the action table with undefined + entries. Thus: + + A two-dimensional error bitmap maps a state and a terminal to either + ``fail'' (encoded as: 0) or ``do not fail'' (encoded as: 1). The action + table, which is now sparse, is looked up only in the latter case. *) + + (* The error bitmap is flattened into a one-dimensional table; its width is + recorded so as to allow indexing. The table is then compressed via + [PackedIntArray]. The bit width of the resulting packed array must be + [1], so it is not explicitly recorded. *) + + (* The error bitmap does not contain a column for the [#] pseudo-terminal. + Thus, its width is [Terminal.n - 1]. We exploit the fact that the integer + code assigned to [#] is greatest: the fact that the right-most column + in the bitmap is missing does not affect the code for accessing it. *) + + val error: int (* width of the bitmap *) * string (* second component of [PackedIntArray.t] *) + + (* A two-dimensional action table maps a state and a terminal to one of + ``shift to state s and discard the current token'' (encoded as: s | 10), + ``shift to state s without discarding the current token'' (encoded as: s | + 11), or ``reduce prod'' (encoded as: prod | 01). *) + + (* The action table is first compressed via [RowDisplacement], then packed + via [PackedIntArray]. *) + + (* Like the error bitmap, the action table does not contain a column for the + [#] pseudo-terminal. *) + + val action: PackedIntArray.t * PackedIntArray.t + + (* A one-dimensional lhs table maps a production to its left-hand side (a + non-terminal symbol). *) + + val lhs: PackedIntArray.t + + (* A two-dimensional goto table maps a state and a non-terminal symbol to + either undefined (encoded as: 0) or a new state s (encoded as: 1 + s). *) + + (* The goto table is first compressed via [RowDisplacement], then packed + via [PackedIntArray]. *) + + val goto: PackedIntArray.t * PackedIntArray.t + + (* A one-dimensional semantic action table maps productions to semantic + actions. The calling convention for semantic actions is described in + [EngineTypes]. *) + + val semantic_action: ((int, Obj.t, token) EngineTypes.env -> unit) array + + (* The parser defines its own [Error] exception. This exception can be + raised by semantic actions and caught by the engine, and raised by the + engine towards the final user. *) + + exception Error + + (* The parser indicates whether to perform error recovery. *) + + val recovery: bool + + (* The parser indicates whether to generate a trace. Generating a + trace requires two extra tables, which respectively map a + terminal symbol and a production to a string. *) + + val trace: (string array * string array) option + +end + diff --git a/menhirlib/tableInterpreter.ml b/menhirlib/tableInterpreter.ml new file mode 100644 index 0000000..3dae3aa --- /dev/null +++ b/menhirlib/tableInterpreter.ml @@ -0,0 +1,186 @@ +(**************************************************************************) +(* *) +(* Menhir *) +(* *) +(* François Pottier, INRIA Rocquencourt *) +(* Yann Régis-Gianas, PPS, Université Paris Diderot *) +(* *) +(* Copyright 2005-2008 Institut National de Recherche en Informatique *) +(* et en Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU Library General Public License, with the *) +(* special exception on linking described in file LICENSE. *) +(* *) +(**************************************************************************) + +(* This module instantiates the generic [Engine] with a thin decoding layer + for the generated tables. Like [Engine], it is part of [MenhirLib]. *) + +(* The exception [Accept] is pre-declared here: this obviates the need + for generating its definition. The exception [Error] is declared + within the generated parser. This is preferable to pre-declaring it + here, as it ensures that each parser gets its own, distinct [Error] + exception. This is consistent with the code-based back-end. *) + +exception Accept of Obj.t + +(* This functor is invoked by the generated parser. *) + +module Make (T : TableFormat.TABLES) + += Engine.Make (struct + + type state = + int + + type token = + T.token + + type terminal = + int + + type semantic_value = + Obj.t + + let token2terminal = + T.token2terminal + + let token2value = + T.token2value + + let error_terminal = + T.error_terminal + + let error_value = + Obj.repr () + + type production = + int + + let default_reduction state defred nodefred env = + let code = PackedIntArray.get T.default_reduction state in + if code = 0 then + nodefred env + else + defred env (code - 1) + + (* This auxiliary function helps access a compressed, two-dimensional + matrix, like the action and goto tables. *) + + let unmarshal2 table i j = + RowDisplacement.getget + PackedIntArray.get + PackedIntArray.get + table + i j + + (* This auxiliary function helps access a flattened, two-dimensional + matrix, like the error bitmap. *) + + let unflatten (n, data) i j = + PackedIntArray.get1 data (n * i + j) + + let action state terminal value shift reduce fail env = + match unflatten T.error state terminal with + | 1 -> + let action = unmarshal2 T.action state terminal in + let opcode = action land 0b11 + and param = action lsr 2 in + if opcode >= 0b10 then + (* 0b10 : shift/discard *) + (* 0b11 : shift/nodiscard *) + let please_discard = (opcode = 0b10) in + shift env please_discard terminal value param + else + (* 0b01 : reduce *) + (* 0b00 : cannot happen *) + reduce env param + | c -> + assert (c = 0); + fail env + + let goto state prod = + let code = unmarshal2 T.goto state (PackedIntArray.get T.lhs prod) in + (* code = 1 + state *) + code - 1 + + exception Accept = + Accept + + exception Error = + T.Error + + type semantic_action = + (state, semantic_value, token) EngineTypes.env -> unit + + let semantic_action prod = + T.semantic_action.(prod) + + let recovery = + T.recovery + + module Log = struct + + open Printf + + let state state = + match T.trace with + | Some _ -> + fprintf stderr "State %d:\n%!" state + | None -> + () + + let shift terminal state = + match T.trace with + | Some (terminals, _) -> + fprintf stderr "Shifting (%s) to state %d\n%!" terminals.(terminal) state + | None -> + () + + let reduce_or_accept prod = + match T.trace with + | Some (_, productions) -> + fprintf stderr "%s\n%!" productions.(prod) + | None -> + () + + let lookahead_token lexbuf token = + match T.trace with + | Some (terminals, _) -> + fprintf stderr "Lookahead token is now %s (%d-%d)\n%!" + terminals.(token) + lexbuf.Lexing.lex_start_p.Lexing.pos_cnum + lexbuf.Lexing.lex_curr_p.Lexing.pos_cnum + | None -> + () + + let initiating_error_handling () = + match T.trace with + | Some _ -> + fprintf stderr "Initiating error handling\n%!" + | None -> + () + + let resuming_error_handling () = + match T.trace with + | Some _ -> + fprintf stderr "Resuming error handling\n%!" + | None -> + () + + let handling_error state = + match T.trace with + | Some _ -> + fprintf stderr "Handling error in state %d\n%!" state + | None -> + () + + let discarding_last_token token = + match T.trace with + | Some (terminals, _) -> + fprintf stderr "Discarding last token read (%s)\n%!" terminals.(token) + | None -> + () + + end + +end) diff --git a/parsing_c/.depend b/parsing_c/.depend new file mode 100644 index 0000000..70d620d --- /dev/null +++ b/parsing_c/.depend @@ -0,0 +1,98 @@ +ast_to_flow.cmi: control_flow_c.cmi ../commons/common.cmi ast_c.cmo +compare_c.cmi: ../commons/common.cmi +control_flow_c.cmi: ../commons/ograph_extended.cmi ast_c.cmo +lexer_parser.cmi: ../commons/common.cmi +parse_c.cmi: parsing_hacks.cmi parser_c.cmi ../commons/common.cmi ast_c.cmo +parser_c.cmi: ast_c.cmo +parsing_hacks.cmi: parser_c.cmi ../commons/common.cmi +pretty_print_c.cmi: ast_c.cmo +test_parsing_c.cmi: ../commons/common.cmi +token_helpers.cmi: parser_c.cmi ../commons/common.cmi ast_c.cmo +type_annoter_c.cmi: ../commons/common.cmi ast_c.cmo +unparse_c2.cmi: parse_c.cmi ../commons/common.cmi +unparse_cocci2.cmi: pretty_print_c.cmi ../parsing_cocci/ast_cocci.cmi \ + ast_c.cmo +unparse_hrule.cmi: parse_c.cmi ../commons/common.cmi +visitor_c.cmi: control_flow_c.cmi ../commons/common.cmi ast_c.cmo +ast_c.cmo: ../commons/common.cmi ../parsing_cocci/ast_cocci.cmi +ast_c.cmx: ../commons/common.cmx ../parsing_cocci/ast_cocci.cmx +ast_to_flow.cmo: visitor_c.cmi ../commons/ograph_extended.cmi \ + ../commons/oassocb.cmo ../commons/oassoc.cmi flag_parsing_c.cmo \ + control_flow_c.cmi ../commons/common.cmi ast_c.cmo ast_to_flow.cmi +ast_to_flow.cmx: visitor_c.cmx ../commons/ograph_extended.cmx \ + ../commons/oassocb.cmx ../commons/oassoc.cmx flag_parsing_c.cmx \ + control_flow_c.cmx ../commons/common.cmx ast_c.cmx ast_to_flow.cmi +compare_c.cmo: visitor_c.cmi token_helpers.cmi parser_c.cmi parse_c.cmi \ + lib_parsing_c.cmo flag_parsing_c.cmo ../commons/common.cmi ast_c.cmo \ + compare_c.cmi +compare_c.cmx: visitor_c.cmx token_helpers.cmx parser_c.cmx parse_c.cmx \ + lib_parsing_c.cmx flag_parsing_c.cmx ../commons/common.cmx ast_c.cmx \ + compare_c.cmi +control_flow_c.cmo: ../commons/ograph_extended.cmi flag_parsing_c.cmo \ + ../commons/common.cmi ast_c.cmo control_flow_c.cmi +control_flow_c.cmx: ../commons/ograph_extended.cmx flag_parsing_c.cmx \ + ../commons/common.cmx ast_c.cmx control_flow_c.cmi +flag_parsing_c.cmo: ../commons/common.cmi +flag_parsing_c.cmx: ../commons/common.cmx +lexer_c.cmo: parser_c.cmi flag_parsing_c.cmo ../commons/common.cmi ast_c.cmo +lexer_c.cmx: parser_c.cmx flag_parsing_c.cmx ../commons/common.cmx ast_c.cmx +lexer_parser.cmo: flag_parsing_c.cmo ../commons/common.cmi lexer_parser.cmi +lexer_parser.cmx: flag_parsing_c.cmx ../commons/common.cmx lexer_parser.cmi +lib_parsing_c.cmo: visitor_c.cmi ../commons/common.cmi \ + ../parsing_cocci/ast_cocci.cmi ast_c.cmo +lib_parsing_c.cmx: visitor_c.cmx ../commons/common.cmx \ + ../parsing_cocci/ast_cocci.cmx ast_c.cmx +parse_c.cmo: visitor_c.cmi token_helpers.cmi semantic_c.cmo parsing_hacks.cmi \ + parser_c.cmi lexer_parser.cmi lexer_c.cmo flag_parsing_c.cmo \ + ../globals/config.cmo ../commons/common.cmi ast_c.cmo parse_c.cmi +parse_c.cmx: visitor_c.cmx token_helpers.cmx semantic_c.cmx parsing_hacks.cmx \ + parser_c.cmx lexer_parser.cmx lexer_c.cmx flag_parsing_c.cmx \ + ../globals/config.cmx ../commons/common.cmx ast_c.cmx parse_c.cmi +parser_c.cmo: semantic_c.cmo lexer_parser.cmi flag_parsing_c.cmo \ + ../commons/common.cmi ast_c.cmo parser_c.cmi +parser_c.cmx: semantic_c.cmx lexer_parser.cmx flag_parsing_c.cmx \ + ../commons/common.cmx ast_c.cmx parser_c.cmi +parsing_hacks.cmo: token_helpers.cmi parser_c.cmi lexer_parser.cmi \ + flag_parsing_c.cmo ../commons/common.cmi ast_c.cmo parsing_hacks.cmi +parsing_hacks.cmx: token_helpers.cmx parser_c.cmx lexer_parser.cmx \ + flag_parsing_c.cmx ../commons/common.cmx ast_c.cmx parsing_hacks.cmi +pretty_print_c.cmo: flag_parsing_c.cmo ../commons/common.cmi ast_c.cmo \ + pretty_print_c.cmi +pretty_print_c.cmx: flag_parsing_c.cmx ../commons/common.cmx ast_c.cmx \ + pretty_print_c.cmi +semantic_c.cmo: ../commons/common.cmi +semantic_c.cmx: ../commons/common.cmx +test_parsing_c.cmo: unparse_c2.cmi type_annoter_c.cmi parse_c.cmi \ + ../commons/ograph_extended.cmi flag_parsing_c.cmo compare_c.cmi \ + ../commons/common.cmi ast_to_flow.cmi ast_c.cmo test_parsing_c.cmi +test_parsing_c.cmx: unparse_c2.cmx type_annoter_c.cmx parse_c.cmx \ + ../commons/ograph_extended.cmx flag_parsing_c.cmx compare_c.cmx \ + ../commons/common.cmx ast_to_flow.cmx ast_c.cmx test_parsing_c.cmi +token_helpers.cmo: parser_c.cmi ../commons/common.cmi ast_c.cmo \ + token_helpers.cmi +token_helpers.cmx: parser_c.cmx ../commons/common.cmx ast_c.cmx \ + token_helpers.cmi +type_annoter_c.cmo: visitor_c.cmi parse_c.cmi lib_parsing_c.cmo \ + flag_parsing_c.cmo ../commons/common.cmi ast_c.cmo type_annoter_c.cmi +type_annoter_c.cmx: visitor_c.cmx parse_c.cmx lib_parsing_c.cmx \ + flag_parsing_c.cmx ../commons/common.cmx ast_c.cmx type_annoter_c.cmi +unparse_c2.cmo: visitor_c.cmi unparse_cocci2.cmi token_helpers.cmi \ + pretty_print_c.cmi parser_c.cmi flag_parsing_c.cmo ../commons/common.cmi \ + ../parsing_cocci/ast_cocci.cmi ast_c.cmo unparse_c2.cmi +unparse_c2.cmx: visitor_c.cmx unparse_cocci2.cmx token_helpers.cmx \ + pretty_print_c.cmx parser_c.cmx flag_parsing_c.cmx ../commons/common.cmx \ + ../parsing_cocci/ast_cocci.cmx ast_c.cmx unparse_c2.cmi +unparse_cocci2.cmo: pretty_print_c.cmi ../commons/common.cmi \ + ../parsing_cocci/ast_cocci.cmi ast_c.cmo unparse_cocci2.cmi +unparse_cocci2.cmx: pretty_print_c.cmx ../commons/common.cmx \ + ../parsing_cocci/ast_cocci.cmx ast_c.cmx unparse_cocci2.cmi +unparse_hrule.cmo: unparse_c2.cmi token_helpers.cmi pretty_print_c.cmi \ + parser_c.cmi ../commons/common.cmi ../parsing_cocci/ast_cocci.cmi \ + ast_c.cmo unparse_hrule.cmi +unparse_hrule.cmx: unparse_c2.cmx token_helpers.cmx pretty_print_c.cmx \ + parser_c.cmx ../commons/common.cmx ../parsing_cocci/ast_cocci.cmx \ + ast_c.cmx unparse_hrule.cmi +visitor_c.cmo: control_flow_c.cmi ../commons/common.cmi ast_c.cmo \ + visitor_c.cmi +visitor_c.cmx: control_flow_c.cmx ../commons/common.cmx ast_c.cmx \ + visitor_c.cmi diff --git a/parsing_c/Makefile b/parsing_c/Makefile new file mode 100644 index 0000000..c0d1df0 --- /dev/null +++ b/parsing_c/Makefile @@ -0,0 +1,109 @@ +############################################################################## +# Variables +############################################################################## +TARGET=parsing_c + +SRC= \ + flag_parsing_c.ml ast_c.ml control_flow_c.ml semantic_c.ml \ + visitor_c.ml lib_parsing_c.ml \ + ast_to_flow.ml \ + lexer_parser.ml parser_c.ml lexer_c.ml \ + token_helpers.ml parsing_hacks.ml parse_c.ml \ + compare_c.ml type_annoter_c.ml pretty_print_c.ml \ + unparse_cocci2.ml unparse_c2.ml unparse_hrule.ml \ + test_parsing_c.ml + + +SYSLIBS= str.cma unix.cma + +# parsing_c now depends on cocci_parser because in addition to decorate the +# token in Ast_c with some parse info, we now also make some place to +# welcome some mcodekind of Ast_cocci. +LIBS=../commons/commons.cma ../globals/globals.cma \ + ../parsing_cocci/cocci_parser.cma + +INCLUDES= -I ../commons -I ../commons/ocamlextra \ + -I ../globals -I ../parsing_cocci + + +############################################################################## +# Generic variables +############################################################################## + +#for warning: -w A +#for profiling: -p -inline 0 with OCAMLOPT +OCAMLCFLAGS ?= -g -dtypes + +OCAMLC=ocamlc$(OPTBIN) $(OCAMLCFLAGS) $(INCLUDES) +OCAMLOPT=ocamlopt$(OPTBIN) $(OPTFLAGS) $(INCLUDES) +OCAMLLEX=ocamllex$(OPTBIN) #-ml +OCAMLYACC=ocamlyacc -v +OCAMLDEP=ocamldep$(OPTBIN) $(INCLUDES) +OCAMLMKTOP=ocamlmktop -g -custom $(INCLUDES) + + +OBJS = $(SRC:.ml=.cmo) +OPTOBJS = $(SRC:.ml=.cmx) + + +############################################################################## +# Top rules +############################################################################## +all: $(TARGET).cma +all.opt: $(TARGET).cmxa + +$(TARGET).cma: $(OBJS) + $(OCAMLC) -a -o $(TARGET).cma $(OBJS) + +$(TARGET).cmxa: $(OPTOBJS) $(LIBS:.cma=.cmxa) + $(OCAMLOPT) -a -o $(TARGET).cmxa $(OPTOBJS) + +$(TARGET).top: $(OBJS) $(LIBS) + $(OCAMLMKTOP) -o $(TARGET).top $(SYSLIBS) $(LIBS) $(OBJS) + +clean:: + rm -f $(TARGET).top + + + +lexer_c.ml: lexer_c.mll + $(OCAMLLEX) $< +clean:: + rm -f lexer_c.ml +beforedepend:: lexer_c.ml + + +parser_c.ml parser_c.mli: parser_c.mly + $(OCAMLYACC) $< +clean:: + rm -f parser_c.ml parser_c.mli parser_c.output +beforedepend:: parser_c.ml parser_c.mli + + +############################################################################## +# Generic rules +############################################################################## + +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) -c $< +.mli.cmi: + $(OCAMLC) -c $< +.ml.cmx: + $(OCAMLOPT) -c $< + +.ml.mldepend: + $(OCAMLC) -i $< + +clean:: + rm -f *.cm[ioxa] *.o *.a *.cmxa *.annot +clean:: + rm -f *~ .*~ gmon.out #*# + +beforedepend:: + +depend:: beforedepend + $(OCAMLDEP) *.mli *.ml > .depend + +-include .depend diff --git a/parsing_c/ast_c.ml b/parsing_c/ast_c.ml new file mode 100644 index 0000000..877cb51 --- /dev/null +++ b/parsing_c/ast_c.ml @@ -0,0 +1,790 @@ +(* Copyright (C) 2002-2008 Yoann Padioleau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License (GPL) + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * file license.txt for more details. + *) +open Common + +(*****************************************************************************) +(* The AST C related types *) +(*****************************************************************************) + +(* Cocci: Each token will be decorated in the future by the mcodekind + * of cocci. It is the job of the pretty printer to look at this + * information and decide to print or not the token (and also the + * pending '+' associated sometimes with the token). + * + * The first time that we parse the original C file, the mcodekind is + * empty, or more precisely all is tagged as a CONTEXT with NOTHING + * associated. This is what I call a "clean" expr/statement/.... + * + * Each token will also be decorated in the future with an environment, + * because the pending '+' may contain metavariables that refer to some + * C code. + * + * Update: Now I use a ref! so take care. + * + * Sometimes we want to add someting at the beginning or at the end + * of a construct. For 'function' and 'decl' we want add something + * to their left and for 'if' 'while' et 'for' and so on at their right. + * We want some kinds of "virtual placeholders" that represent the start or + * end of a construct. We use fakeInfo for that purpose. + * To identify those cases I have added a fakestart/fakeend comment. + * + * convention: I often use 'ii' for the name of a list of info. + * + *) + +(* forunparser: *) + +type posl = int * int (* lin-col, for MetaPosValList, for position variables *) +type virtual_position = Common.parse_info * int (* character offset *) +type parse_info = + (* Present both in ast and list of tokens *) + | OriginTok of Common.parse_info + (* Present only in ast and generated after parsing. Used mainly + * by Julia, to add stuff at virtual places, beginning of func or decl *) + | FakeTok of string * virtual_position + (* Present both in ast and list of tokens. *) + | ExpandedTok of Common.parse_info * virtual_position + (* Present neither in ast nor in list of tokens + * but only in the '+' of the mcode of some tokens. Those kind of tokens + * are used to be able to use '=' to compare big ast portions. + *) + | AbstractLineTok of Common.parse_info (* local to the abstracted thing *) + +type info = { + pinfo : parse_info; + cocci_tag: (Ast_cocci.mcodekind * metavars_binding) ref; + comments_tag: comments_around ref; (* set in comment_annotater.ml *) + (* todo? token_info : sometimes useful to know what token it was *) + } +and il = info list + +(* wrap2 is like wrap, except that I use it often for separator such + * as ','. In that case the info is associated to the argument that + * follows, so in 'a,b' I will have in the list [(a,[]); (b,[','])]. *) +and 'a wrap = 'a * il +and 'a wrap2 = 'a * il + +(* ------------------------------------------------------------------------- *) +(* C Type *) +(* ------------------------------------------------------------------------- *) +(* Could have more precise type in fullType, in expression, etc, but + * it requires to do too much things in parsing such as checking no + * conflicting structname, computing value, etc. Better to separate + * concern, so I put '=>' to mean what we would really like. In fact + * what we really like is defining another fullType, expression, etc + * from scratch, because many stuff are just sugar. + * + * invariant: Array and FunctionType have also typeQualifier but they + * dont have sense. I put this to factorise some code. If you look in + * grammar, you see that we can never specify const for the array + * himself (but we can do it for pointer). + * + * + * Because of ExprStatement, we can have more 'new scope' events, but + * rare I think. For instance with 'array of constExpression' there can + * have an exprStatement and a new (local) struct defined. Same for + * Constructor. + * + * Some stuff are tagged semantic: which means that they are computed + * after parsing. *) + + +and fullType = typeQualifier * typeC +and typeC = typeCbis wrap + +and typeCbis = + | BaseType of baseType + + | Pointer of fullType + | Array of constExpression option * fullType + | FunctionType of functionType + + | Enum of string option * enumType + | StructUnion of structUnion * string option * structType (* new scope *) + + | EnumName of string + | StructUnionName of structUnion * string + + | TypeName of string * fullType option (* semantic: filled later *) + + | ParenType of fullType (* forunparser: *) + + (* gccext: TypeOfType may seems useless, why declare a __typeof__(int) + * x; ? But when used with macro, it allows to fix a problem of C which + * is that type declaration can be spread around the ident. Indeed it + * may be difficult to have a macro such as '#define macro(type, + * ident) type ident;' because when you want to do a macro(char[256], + * x), then it will generate invalid code, but with a '#define + * macro(type, ident) __typeof(type) ident;' it will work. *) + | TypeOfExpr of expression + | TypeOfType of fullType + +(* -------------------------------------- *) + and baseType = Void + | IntType of intType + | FloatType of floatType + + (* stdC: type section + * add a | SizeT ? + * note: char and signed char are semantically different!! + *) + and intType = CChar (* obsolete? | CWchar *) + | Si of signed + + and signed = sign * base + and base = CChar2 | CShort | CInt | CLong | CLongLong (* gccext: *) + and sign = Signed | UnSigned + + and floatType = CFloat | CDouble | CLongDouble + + + (* -------------------------------------- *) + and structUnion = Struct | Union + and structType = (field wrap) list (* ; *) + + (* before unparser, I didn't have a FieldDeclList but just a Field. *) + and field = FieldDeclList of fieldkind wrap2 list (* , *) + | EmptyField (* gccext: *) + + (* At first I thought that a bitfield could be only Signed/Unsigned. + * But it seems that gcc allow char i:4. C rule must say that you + * can cast into int so enum too, ... + *) + and fieldkind = fieldkindbis wrap (* s : *) + and fieldkindbis = + | Simple of string option * fullType + | BitField of string option * fullType * constExpression + (* fullType => BitFieldInt | BitFieldUnsigned *) + + + (* -------------------------------------- *) + and enumType = (string * constExpression option) wrap (* s = *) + wrap2 (* , *) list + (* => string * int list *) + + + (* -------------------------------------- *) + (* return * (params * has "...") *) + and functionType = fullType * (parameterType wrap2 list * bool wrap) + and parameterType = (bool * string option * fullType) wrap (* reg s *) + (* => (bool (register) * fullType) list * bool *) + + +and typeQualifier = typeQualifierbis wrap +and typeQualifierbis = {const: bool; volatile: bool} + + +(* ------------------------------------------------------------------------- *) +(* C expression *) +(* ------------------------------------------------------------------------- *) +and expression = (expressionbis * exp_info ref (* semantic: *)) wrap +and local = LocalVar of parse_info | NotLocalVar +and test = Test | NotTest +and exp_type = fullType * local +and exp_info = exp_type option * test +and expressionbis = + + (* Ident can be a enumeration constant, a simple variable, a name of a func. + * With cppext, Ident can also be the name of a macro. Sparse says + * "an identifier with a meaning is a symbol". + *) + | Ident of string (* todo? more semantic info such as LocalFunc *) + | Constant of constant + | FunCall of expression * argument wrap2 (* , *) list + (* gccext: x ? /* empty */ : y <=> x ? x : y; *) + | CondExpr of expression * expression option * expression + + (* should be considered as statements, bad C langage *) + | Sequence of expression * expression + | Assignment of expression * assignOp * expression + + | Postfix of expression * fixOp + | Infix of expression * fixOp + | Unary of expression * unaryOp + | Binary of expression * binaryOp * expression + + | ArrayAccess of expression * expression + | RecordAccess of expression * string + | RecordPtAccess of expression * string + (* redundant normally, could replace it by DeRef RecordAcces *) + + | SizeOfExpr of expression + | SizeOfType of fullType + | Cast of fullType * expression + + (* gccext: *) + | StatementExpr of compound wrap (* ( ) new scope *) + | Constructor of fullType * initialiser wrap2 (* , *) list + + (* forunparser: *) + | ParenExpr of expression + + (* cppext: normmally just expression *) + and argument = (expression, wierd_argument) either + and wierd_argument = + | ArgType of parameterType + | ArgAction of action_macro + and action_macro = + | ActMisc of il + + + (* I put string for Int and Float because int would not be enough because + * OCaml int are 31 bits. So simpler to do string. Same reason to have + * string instead of int list for the String case. + * + * note: that -2 is not a constant, it is the unary operator '-' + * applied to constant 2. So the string must represent a positive + * integer only. *) + + and constant = + | String of (string * isWchar) + | MultiString (* can contain MacroString *) + | Char of (string * isWchar) (* normally it is equivalent to Int *) + | Int of (string (* * intType*)) + | Float of (string * floatType) + + and isWchar = IsWchar | IsChar + + (* gccext: GetRefLabel, via &&label notation *) + and unaryOp = GetRef | DeRef | UnPlus | UnMinus | Tilde | Not | GetRefLabel + and assignOp = SimpleAssign | OpAssign of arithOp + and fixOp = Dec | Inc + + and binaryOp = Arith of arithOp | Logical of logicalOp + + and arithOp = + | Plus | Minus | Mul | Div | Mod + | DecLeft | DecRight + | And | Or | Xor + + and logicalOp = + | Inf | Sup | InfEq | SupEq + | Eq | NotEq + | AndLog | OrLog + + and constExpression = expression (* => int *) + + +(* ------------------------------------------------------------------------- *) +(* C statement *) +(* ------------------------------------------------------------------------- *) +(* note: that assignement is not a statement but an expression; + * wonderful C langage. + * + * note: I use 'and' for type definition cos gccext allow statement as + * expression, so need mutual recursive type definition. *) + +and statement = statementbis wrap +and statementbis = + | Labeled of labeled + | Compound of compound (* new scope *) + | ExprStatement of exprStatement + | Selection of selection (* have fakeend *) + | Iteration of iteration (* have fakeend *) + | Jump of jump + + (* simplify cocci: only at the beginning of a compound normally *) + | Decl of declaration + + (* gccext: *) + | Asm of asmbody + | NestedFunc of definition + + (* cppext: *) + | MacroStmt + + + + and labeled = Label of string * statement + | Case of expression * statement + | CaseRange of expression * expression * statement (* gccext: *) + | Default of statement + + (* cppext: + * old: compound = (declaration list * statement list) + * old: (declaration, statement) either list + * Simplify cocci to just have statement list, by integrating Decl in stmt. + *) + and compound = statement list + + and exprStatement = expression option + + (* for Switch, need check that all elements in the compound start + * with a case:, otherwise unreachable code. + *) + and selection = + | If of expression * statement * statement + | Switch of expression * statement + | Ifdef of statement list * statement list (* cppext: *) + + and iteration = + | While of expression * statement + | DoWhile of statement * expression + | For of exprStatement wrap * exprStatement wrap * exprStatement wrap * + statement + | MacroIteration of string * argument wrap2 list * statement + + and jump = Goto of string + | Continue | Break + | Return | ReturnExpr of expression + | GotoComputed of expression (* gccext: goto *exp ';' *) + + + (* gccext: *) + and asmbody = il (* string list *) * colon wrap (* : *) list + and colon = Colon of colon_option wrap2 list + and colon_option = colon_option_bis wrap + and colon_option_bis = ColonMisc | ColonExpr of expression + + +(* ------------------------------------------------------------------------- *) +(* Declaration *) +(* ------------------------------------------------------------------------- *) +(* (string * ...) option cos can have empty declaration or struct tag + * declaration. + * + * Before I had Typedef constructor, but why make this special case and not + * have StructDef, EnumDef, ... so that 'struct t {...} v' will generate 2 + * declarations ? So I try to generalise and not have not Typedef too. This + * requires more work in parsing. Better to separate concern. + * + * Before the need for unparser, I didn't have a DeclList but just a Decl. + * + * I am not sure what it means to declare a prototype inline, but gcc + * accepts it. + *) + +and local_decl = LocalDecl | NotLocalDecl + +and declaration = + | DeclList of onedecl wrap2 (* , *) list wrap (* ; fakestart sto *) + (* cppext: *) + | MacroDecl of (string * argument wrap2 list) wrap + + and onedecl = + ((string * initialiser option) wrap (* s = *) option) * + fullType * storage * local_decl + and storage = storagebis * bool (* inline or not, gccext: *) + and storagebis = NoSto | StoTypedef | Sto of storageClass + and storageClass = Auto | Static | Register | Extern + + and initialiser = initialiserbis wrap + and initialiserbis = + | InitExpr of expression + | InitList of initialiser wrap2 (* , *) list + (* gccext: *) + | InitDesignators of designator list * initialiser + | InitFieldOld of string * initialiser + | InitIndexOld of expression * initialiser + + (* ex: [2].y = x, or .y[2] or .y.x. They can be nested *) + and designator = designatorbis wrap + and designatorbis = + | DesignatorField of string + | DesignatorIndex of expression + | DesignatorRange of expression * expression + +(* ------------------------------------------------------------------------- *) +(* Function definition *) +(* ------------------------------------------------------------------------- *) +(* Normally we should define another type functionType2 because there + * are more restrictions on what can define a function than a pointer + * function. For instance a function declaration can omit the name of the + * parameter wheras a function definition can not. But, in some cases such + * as 'f(void) {', there is no name too, so I simplified and reused the + * same functionType type for both declaration and function definition. + *) +and definition = (string * functionType * storage * compound) + wrap (* s ( ) { } fakestart sto *) + +(* ------------------------------------------------------------------------- *) +(* #define and #include body *) +(* ------------------------------------------------------------------------- *) + +(* cppext *) +and define = string wrap * define_body (* #define s *) + and define_body = define_kind * define_val + and define_kind = + | DefineVar + | DefineFunc of ((string wrap) wrap2 list) wrap + and define_val = + | DefineExpr of expression + | DefineStmt of statement + | DefineType of fullType + | DefineDoWhileZero of statement wrap (* do { } while(0) *) + | DefineFunction of definition + | DefineText of string wrap + | DefineEmpty + + + +and includ = inc_file wrap (* #include s *) * + (include_rel_pos option ref * bool (* is in ifdef, cf -test incl *) ) + and inc_file = + | Local of inc_elem list + | NonLocal of inc_elem list + | Wierd of string (* ex: #include SYSTEM_H *) + and inc_elem = string + +(* Cocci: to tag the first of #include and last of #include + * + * The first_of and last_of store the list of prefixes that was + * introduced by the include. On #include , if the include was + * the first in the file, it would give in first_of the following + * prefixes a/b/c; a/b/; a/ ; + * + * This is set after parsing, in cocci.ml, in update_rel_pos. + *) + and include_rel_pos = { + first_of : string list list; + last_of : string list list; + } + +(* ------------------------------------------------------------------------- *) +(* The toplevels elements *) +(* ------------------------------------------------------------------------- *) +and toplevel = + | Declaration of declaration + | Definition of definition + + (* cppext: *) + | Include of includ + | Define of define + (* cppext: *) + | MacroTop of string * argument wrap2 list * il + + | EmptyDef of il (* gccext: allow redundant ';' *) + | NotParsedCorrectly of il + + + | FinalDef of info (* EOF *) + +(* ------------------------------------------------------------------------- *) +and program = toplevel list + + +(*****************************************************************************) +(* Cocci Bindings *) +(*****************************************************************************) +(* Was previously in pattern.ml, but because of the transformer, + * we need to decorate each token with some cocci code AND the environment + * for this cocci code. + *) +and metavars_binding = (Ast_cocci.meta_name, metavar_binding_kind) assoc + and metavar_binding_kind = + | MetaIdVal of string + | MetaFuncVal of string + | MetaLocalFuncVal of string + + | MetaExprVal of expression (* a "clean expr" *) + | MetaExprListVal of argument wrap2 list + | MetaParamVal of parameterType + | MetaParamListVal of parameterType wrap2 list + + | MetaTypeVal of fullType + | MetaStmtVal of statement + + (* Could also be in Lib_engine.metavars_binding2 with the ParenVal, + * because don't need to have the value for a position in the env of + * a '+'. But ParenVal or LabelVal are used only by CTL, they are not + * variables accessible via SmPL whereas the position can be one day + * so I think it's better to put MetaPosVal here *) + | MetaPosVal of (Ast_cocci.fixpos * Ast_cocci.fixpos) (* max, min *) + | MetaPosValList of (Common.filename * posl * posl) list (* min, max *) + | MetaListlenVal of int + + +(*****************************************************************************) +(* C comments *) +(*****************************************************************************) + +(* I often use m for comments as I can not use c (already use for c stuff) + * and com is too long. + *) + +(* this type will be associated to each token *) +and comments_around = { + mbefore: comment_and_relative_pos list; + mafter: comment_and_relative_pos list; +} + and comment_and_relative_pos = { + + minfo: Common.parse_info; + (* the int represent the number of lines of difference between the + * current token and the comment. When on same line, this number is 0. + * When previous line, -1. In some way the after/before in previous + * record is useless because the sign of the integer can helps + * do the difference too, but I keep it that way. + *) + mpos: int; + (* todo? + * cppbetween: bool; touse? if false positive + * is_alone_in_line: bool; (*for labels, to avoid false positive*) + *) + } + +and comment = Common.parse_info +and com = comment list ref + + +(*****************************************************************************) +(* Cpp constructs, put it comments in lexer *) +(*****************************************************************************) + +(* This type is not in the Ast but is associated with the TCommentCpp token. + * I put this enum here because parser_c.mly need it. I could have put + * it also in lexer_parser. + *) +type cppcommentkind = + CppDirective | CppAttr | CppMacro | CppOther + + + + +(*****************************************************************************) +(* Some constructors *) +(*****************************************************************************) +let nullQualif = ({const=false; volatile= false}, []) +let nQ = nullQualif + +let defaultInt = (BaseType (IntType (Si (Signed, CInt)))) + +let noType () = ref (None,NotTest) +let noInstr = (ExprStatement (None), []) +let noTypedefDef () = None + +let emptyMetavarsBinding = + ([]: metavars_binding) + +let emptyAnnot = + (Ast_cocci.CONTEXT (Ast_cocci.NoPos,Ast_cocci.NOTHING), + emptyMetavarsBinding) + +let emptyComments= { + mbefore = []; + mafter = []; +} + + +(* for include, some meta information needed by cocci *) +let noRelPos () = + ref (None: include_rel_pos option) +let noInIfdef () = + ref false + + +(* When want add some info in ast that does not correspond to + * an existing C element. + * old: or when don't want 'synchronize' on it in unparse_c.ml + * (now have other mark for tha matter). + *) +let no_virt_pos = ({str="";charpos=0;line=0;column=0;file=""},-1) + +let fakeInfo pi = + { pinfo = FakeTok ("",no_virt_pos); + cocci_tag = ref emptyAnnot; + comments_tag = ref emptyComments; + } + + +(*****************************************************************************) +(* Wrappers *) +(*****************************************************************************) +let unwrap = fst + + +let unwrap_expr ((unwrap_e, typ), iie) = unwrap_e +let rewrap_expr ((_old_unwrap_e, typ), iie) newe = ((newe, typ), iie) + +let get_type_expr ((unwrap_e, typ), iie) = !typ +let set_type_expr ((unwrap_e, oldtyp), iie) newtyp = + oldtyp := newtyp + (* old: (unwrap_e, newtyp), iie *) + + +let unwrap_typeC (qu, (typeC, ii)) = typeC +let rewrap_typeC (qu, (typeC, ii)) newtypeC = (qu, (newtypeC, ii)) + + +let rewrap_str s ii = + {ii with pinfo = + (match ii.pinfo with + OriginTok pi -> OriginTok { pi with Common.str = s;} + | ExpandedTok (pi,vpi) -> ExpandedTok ({ pi with Common.str = s;},vpi) + | FakeTok (_,vpi) -> FakeTok (s,vpi) + | AbstractLineTok pi -> OriginTok { pi with Common.str = s;})} + +let rewrap_pinfo pi ii = + {ii with pinfo = pi} + +(* info about the current location *) +let get_pi = function + OriginTok pi -> pi + | ExpandedTok (_,(pi,_)) -> pi + | FakeTok (_,(pi,_)) -> pi + | AbstractLineTok pi -> pi + +(* original info *) +let get_opi = function + OriginTok pi -> pi + | ExpandedTok (pi,_) -> pi + | FakeTok (_,_) -> failwith "no position information" + | AbstractLineTok pi -> pi + +let is_fake ii = + match ii.pinfo with + FakeTok (_,_) -> true + | _ -> false + +let str_of_info ii = + match ii.pinfo with + OriginTok pi -> pi.Common.str + | ExpandedTok (pi,_) -> pi.Common.str + | FakeTok (s,_) -> s + | AbstractLineTok pi -> pi.Common.str + +let get_info f ii = + match ii.pinfo with + OriginTok pi -> f pi + | ExpandedTok (_,(pi,_)) -> f pi + | FakeTok (_,(pi,_)) -> f pi + | AbstractLineTok pi -> f pi + +let get_orig_info f ii = + match ii.pinfo with + OriginTok pi -> f pi + | ExpandedTok (pi,_) -> f pi + | FakeTok (_,(pi,_)) -> f pi + | AbstractLineTok pi -> f pi + +let make_expanded ii = + {ii with pinfo = ExpandedTok (get_opi ii.pinfo,no_virt_pos)} + +let pos_of_info ii = get_info (function x -> x.Common.charpos) ii +let opos_of_info ii = get_orig_info (function x -> x.Common.charpos) ii +let line_of_info ii = get_orig_info (function x -> x.Common.line) ii +let col_of_info ii = get_orig_info (function x -> x.Common.column) ii +let file_of_info ii = get_orig_info (function x -> x.Common.file) ii +let mcode_of_info ii = fst (!(ii.cocci_tag)) +let pinfo_of_info ii = ii.pinfo +let parse_info_of_info ii = get_pi ii.pinfo + +type posrv = Real of Common.parse_info | Virt of virtual_position +let compare_pos ii1 ii2 = + let get_pos = function + OriginTok pi -> Real pi + | FakeTok (s,vpi) -> Virt vpi + | ExpandedTok (pi,vpi) -> Virt vpi + | AbstractLineTok pi -> Real pi in (* used for printing *) + let pos1 = get_pos (pinfo_of_info ii1) in + let pos2 = get_pos (pinfo_of_info ii2) in + match (pos1,pos2) with + (Real p1, Real p2) -> compare p1.Common.charpos p2.Common.charpos + | (Virt (p1,_), Real p2) -> + if (compare p1.Common.charpos p2.Common.charpos) = (-1) then (-1) else 1 + | (Real p1, Virt (p2,_)) -> + if (compare p1.Common.charpos p2.Common.charpos) = 1 then 1 else (-1) + | (Virt (p1,o1), Virt (p2,o2)) -> + let poi1 = p1.Common.charpos in + let poi2 = p2.Common.charpos in + match compare poi1 poi2 with + -1 -> -1 + | 0 -> compare o1 o2 + | x -> x + +let equal_posl (l1,c1) (l2,c2) = + (l1 =|= l2) && (c1 =|= c2) + +let info_to_fixpos ii = + match pinfo_of_info ii with + OriginTok pi -> Ast_cocci.Real pi.Common.charpos + | ExpandedTok (_,(pi,offset)) -> + Ast_cocci.Virt (pi.Common.charpos,offset) + | FakeTok (_,(pi,offset)) -> + Ast_cocci.Virt (pi.Common.charpos,offset) + | AbstractLineTok pi -> failwith "unexpected abstract" + +let is_test (e : expression) = + let (_,info) = unwrap e in + let (_,test) = !info in + test = Test + +(*****************************************************************************) +(* Abstract line *) +(*****************************************************************************) + +(* When we have extended the C Ast to add some info to the tokens, + * such as its line number in the file, we can not use anymore the + * ocaml '=' to compare Ast elements. To overcome this problem, to be + * able to use again '=', we just have to get rid of all those extra + * information, to "abstract those line" (al) information. + *) + +let al_info tokenindex x = + { pinfo = + (AbstractLineTok + {charpos = tokenindex; + line = tokenindex; + column = tokenindex; + file = ""; + str = str_of_info x}); + cocci_tag = ref emptyAnnot; + comments_tag = ref emptyComments; + } + +let semi_al_info x = + { x with + cocci_tag = ref emptyAnnot; + comments_tag = ref emptyComments; + } + +(*****************************************************************************) +(* Views *) +(*****************************************************************************) + +(* Transform a list of arguments (or parameters) where the commas are + * represented via the wrap2 and associated with an element, with + * a list where the comma are on their own. f(1,2,2) was + * [(1,[]); (2,[,]); (2,[,])] and become [1;',';2;',';2]. + * + * Used in cocci_vs_c.ml, to have a more direct correspondance between + * the ast_cocci of julia and ast_c. + *) +let rec (split_comma: 'a wrap2 list -> ('a, il) either list) = + function + | [] -> [] + | (e, ii)::xs -> + if null ii + then (Left e)::split_comma xs + else Right ii::Left e::split_comma xs + +let rec (unsplit_comma: ('a, il) either list -> 'a wrap2 list) = + function + | [] -> [] + | Right ii::Left e::xs -> + (e, ii)::unsplit_comma xs + | Left e::xs -> + let empty_ii = [] in + (e, empty_ii)::unsplit_comma xs + | Right ii::_ -> + raise Impossible + + + + +let split_register_param = fun (hasreg, idb, ii_b_s) -> + match hasreg, idb, ii_b_s with + | false, Some s, [i1] -> Left (s, [], i1) + | true, Some s, [i1;i2] -> Left (s, [i1], i2) + | _, None, ii -> Right ii + | _ -> raise Impossible + diff --git a/parsing_c/ast_to_flow.ml b/parsing_c/ast_to_flow.ml new file mode 100644 index 0000000..608d3f3 --- /dev/null +++ b/parsing_c/ast_to_flow.ml @@ -0,0 +1,1320 @@ +open Common + +open Ast_c +open Control_flow_c + +open Ograph_extended +open Oassoc +open Oassocb + + +(*****************************************************************************) +(* todo?: compute target level with goto (but rare that different I think) + * ver1: just do init, + * ver2: compute depth of label (easy, intercept compound in the visitor) + * + * checktodo: after a switch, need check that all the st in the + * compound start with a case: ? + * + * checktodo: how ensure that when we call aux_statement recursivly, we + * pass it xi_lbl and not just auxinfo ? how enforce that ? + * in fact we must either pass a xi_lbl or a newxi + * + * todo: can have code (and so nodes) in many places, in the size of an + * array, in the init of initializer, but also in StatementExpr, ... + * + * todo?: steal code from CIL ? (but seems complicated ... again) *) +(*****************************************************************************) + +type error = + | DeadCode of Common.parse_info option + | CaseNoSwitch of Common.parse_info + | OnlyBreakInSwitch of Common.parse_info + | NoEnclosingLoop of Common.parse_info + | GotoCantFindLabel of string * Common.parse_info + | NoExit of Common.parse_info + | DuplicatedLabel of string + | NestedFunc + | ComputedGoto + +exception Error of error + +(*****************************************************************************) +(* Helpers *) +(*****************************************************************************) + +let add_node node labels nodestr g = + g#add_node (Control_flow_c.mk_node node labels [] nodestr) +let add_bc_node node labels parent_labels nodestr g = + g#add_node (Control_flow_c.mk_node node labels parent_labels nodestr) +let add_arc_opt (starti, nodei) g = + starti +> do_option (fun starti -> g#add_arc ((starti, nodei), Direct)) + + +let lbl_0 = [] + +let pinfo_of_ii ii = Ast_c.get_opi (List.hd ii).Ast_c.pinfo + + + +(*****************************************************************************) +(* Contextual information passed in aux_statement *) +(*****************************************************************************) + +(* Sometimes have a continue/break and we must know where we must jump. + * + * ctl_brace: The node list in context_info record the number of '}' at the + * context point, for instance at the switch point. So that when deeper, + * we can compute the difference between the number of '}' from root to + * the context point to close the good number of '}' . For instance + * where there is a 'continue', we must close only until the for. + *) +type context_info = + | NoInfo + | LoopInfo of nodei * nodei (* start, end *) * node list * int list + | SwitchInfo of nodei * nodei (* start, end *) * node list * int list + +(* for the Compound case I need to do different things depending if + * the compound is the compound of the function definition, the compound of + * a switch, so this type allows to specify this and enable to factorize + * code for the Compound + *) +and compound_caller = + FunctionDef | Statement | Switch of (nodei -> xinfo -> xinfo) + +(* other information used internally in ast_to_flow and passed recursively *) +and xinfo = { + + ctx: context_info; (* cf above *) + ctx_stack: context_info list; + + (* are we under a ifthen[noelse]. Used for ErrorExit *) + under_ifthen: bool; + compound_caller: compound_caller; + + (* does not change recursively. Some kind of globals. *) + labels_assoc: (string, nodei) oassoc; + exiti: nodei option; + errorexiti: nodei option; + + (* ctl_braces: the nodei list is to handle current imbrication depth. + * It contains the must-close '}'. + * update: now it is instead a node list. + *) + braces: node list; + + (* ctl: *) + labels: int list; + } + + +let initial_info = { + ctx = NoInfo; + ctx_stack = []; + under_ifthen = false; + compound_caller = Statement; + braces = []; + labels = []; + + (* don't change when recurse *) + labels_assoc = new oassocb []; + exiti = None; + errorexiti = None; +} + + +(*****************************************************************************) +(* (Semi) Globals, Julia's style. *) +(*****************************************************************************) +(* global graph *) +let g = ref (new ograph_mutable) + +let counter_for_labels = ref 0 +let counter_for_braces = ref 0 + +(* For switch we use compteur too (or pass int ref) cos need know order of the + * case if then later want to go from CFG to (original) AST. + * update: obsolete now I think + *) +let counter_for_switch = ref 0 + + +(*****************************************************************************) +(* helpers *) +(*****************************************************************************) + +(* alt: do via a todo list, so can do all in one pass (but more complex) + * todo: can also count the depth level and associate it to the node, for + * the ctl_braces: + *) +let compute_labels_and_create_them st = + + (* map C label to index number in graph *) + let (h: (string, nodei) oassoc ref) = ref (new oassocb []) in + + begin + st +> Visitor_c.vk_statement { Visitor_c.default_visitor_c with + Visitor_c.kstatement = (fun (k, bigf) st -> + match st with + | Labeled (Ast_c.Label (s, _st)),ii -> + (* at this point I put a lbl_0, but later I will put the + * good labels. *) + let newi = !g +> add_node (Label (st,(s,ii))) lbl_0 (s^":") in + begin + (* the C label already exists ? *) + if (!h#haskey s) then raise (Error (DuplicatedLabel s)); + h := !h#add (s, newi); + (* not k _st !!! otherwise in lbl1: lbl2: i++; we miss lbl2 *) + k st; + end + | st -> k st + ) + }; + !h; + end + + +(* ctl_braces: *) +let insert_all_braces xs starti = + xs +> List.fold_left (fun acc node -> + (* Have to build a new node (clone), cos cant share it. + * update: This is now done by the caller. The clones are in xs. + *) + let newi = !g#add_node node in + !g#add_arc ((acc, newi), Direct); + newi + ) starti + +(*****************************************************************************) +(* Statement *) +(*****************************************************************************) + +(* Take in a (optional) start node, return an (optional) end node. + * + * history: + * + * ver1: old code was returning an nodei, but goto has no end, so + * aux_statement should return nodei option. + * + * ver2: old code was taking a nodei, but should also take nodei + * option. + * + * ver3: deadCode detection. What is dead code ? When there is no + * starti to start from ? So make starti an option too ? Si on arrive + * sur un label: au moment d'un deadCode, on peut verifier les + * predecesseurs de ce label, auquel cas si y'en a, ca veut dire + * qu'en fait c'est pas du deadCode et que donc on peut se permettre + * de partir d'un starti à None. Mais si on a xx; goto far:; near: + * yy; zz; far: goto near:. Bon ca doit etre un cas tres tres rare, + * mais a cause de notre parcours, on va rejeter ce programme car au + * moment d'arriver sur near: on n'a pas encore de predecesseurs pour + * ce label. De meme, meme le cas simple ou la derniere instruction + * c'est un return, alors ca va generer un DeadCode :( + * + * So make a first pass where dont launch exn at all. Create nodes, + * if starti is None then dont add arc. Then make a second pass that + * just checks that all nodes (except enter) have predecessors. + * So make starti an option too. So type is now + * + * nodei option -> statement -> nodei option. + * + * todo?: if the pb is at a fake node, then try first successos that + * is non fake. + * + * ver4: because of special needs of coccinelle, need pass more info, cf + * type additionnal_info defined above. + * + * - to complete (break, continue (and enclosing loop), switch (and + * associated case, casedefault)) we need to pass additionnal info. + * The start/exit when enter in a loop, to know the current 'for'. + * + * - to handle the braces, need again pass additionnal info. + * + * - need pass the labels. + * + * convention: xi for the auxinfo passed recursively + * + *) + +let rec (aux_statement: (nodei option * xinfo) -> statement -> nodei option) = + fun (starti, xi) stmt -> + + if not !Flag_parsing_c.label_strategy_2 + then incr counter_for_labels; + + let lbl = + if !Flag_parsing_c.label_strategy_2 + then xi.labels + else xi.labels @ [!counter_for_labels] + in + + (* Normally the new auxinfo to pass recursively to the next aux_statement. + * But in some cases we add additionnal stuff in which case we don't use + * this 'xi_lbl' but a 'newxi' specially built. + *) + let xi_lbl = + if !Flag_parsing_c.label_strategy_2 + then { xi with + compound_caller = Statement; + } + else { xi with + labels = xi.labels @ [ !counter_for_labels ]; + compound_caller = Statement; + } + in + + (* ------------------------- *) + match stmt with + + (* coupling: the Switch case copy paste parts of the Compound case *) + | Ast_c.Compound statxs, ii -> + (* flow_to_ast: *) + let (i1, i2) = tuple_of_list2 ii in + + (* ctl_braces: *) + incr counter_for_braces; + let brace = !counter_for_braces in + + let s1 = "{" ^ i_to_s brace in + let s2 = "}" ^ i_to_s brace in + + let lbl = match xi.compound_caller with + | FunctionDef -> xi.labels (* share label with function header *) + | Statement -> xi.labels @ [!counter_for_labels] + | Switch _ -> xi.labels + in + + let newi = !g +> add_node (SeqStart (stmt, brace, i1)) lbl s1 in + let endnode = mk_node (SeqEnd (brace, i2)) lbl [] s2 in + let endnode_dup = mk_fake_node (SeqEnd (brace, i2)) lbl [] s2 in +(* + let _endnode_dup = + mk_node (SeqEnd (brace, Ast_c.fakeInfo())) lbl [] s2 in +*) + + let newxi = { xi_lbl with braces = endnode_dup:: xi_lbl.braces } in + + let newxi = match xi.compound_caller with + | Switch todo_in_compound -> + (* note that side effect in todo_in_compound *) + todo_in_compound newi newxi + | FunctionDef | Statement -> newxi + in + + !g +> add_arc_opt (starti, newi); + let starti = Some newi in + + statxs +> List.fold_left (fun starti statement -> + if !Flag_parsing_c.label_strategy_2 + then incr counter_for_labels; + + let newxi' = + if !Flag_parsing_c.label_strategy_2 + then { newxi with labels = xi.labels @ [ !counter_for_labels ] } + else newxi + in + aux_statement (starti, newxi') statement + ) starti + + (* braces: *) + +> Common.fmap (fun starti -> + (* subtil: not always return a Some. + * Note that if starti is None, alors forcement ca veut dire + * qu'il y'a eu un return (ou goto), et donc forcement les + * braces auront au moins ete crée une fois, et donc flow_to_ast + * marchera. + * Sauf si le goto revient en arriere ? mais dans ce cas + * ca veut dire que le programme boucle. Pour qu'il boucle pas + * il faut forcement au moins un return. + *) + let endi = !g#add_node endnode in + !g#add_arc ((starti, endi), Direct); + endi + ) + + + (* ------------------------- *) + | Labeled (Ast_c.Label (s, st)), ii -> + let ilabel = xi.labels_assoc#find s in + let node = mk_node (unwrap (!g#nodes#find ilabel)) lbl [] (s ^ ":") in + !g#replace_node (ilabel, node); + !g +> add_arc_opt (starti, ilabel); + aux_statement (Some ilabel, xi_lbl) st + + + | Jump (Ast_c.Goto s), ii -> + (* special_cfg_ast: *) + let newi = !g +> add_node (Goto (stmt, (s,ii))) lbl ("goto " ^ s ^ ":") in + !g +> add_arc_opt (starti, newi); + + let ilabel = + try xi.labels_assoc#find s + with Not_found -> + (* jump vers ErrorExit a la place ? + * pourquoi tant de "cant jump" ? pas detecté par gcc ? + *) + raise (Error (GotoCantFindLabel (s, pinfo_of_ii ii))) + in + (* !g +> add_arc_opt (starti, ilabel); + * todo: special_case: suppose that always goto to toplevel of function, + * hence the Common.init + * todo?: can perhaps report when a goto is not a classic error_goto ? + * that is when it does not jump to the toplevel of the function. + *) + let newi = insert_all_braces (Common.list_init xi.braces) newi in + !g#add_arc ((newi, ilabel), Direct); + None + + | Jump (Ast_c.GotoComputed e), ii -> + raise (Error (ComputedGoto)) + + (* ------------------------- *) + | Ast_c.ExprStatement opte, ii -> + (* flow_to_ast: old: when opte = None, then do not add in CFG. *) + let s = + match opte with + | None -> "empty;" + | Some e -> + let ((unwrap_e, typ), ii) = e in + (match unwrap_e with + | FunCall (((Ident f, _typ), _ii), _args) -> + f ^ "(...)" + | Assignment (((Ident var, _typ), _ii), SimpleAssign, e) -> + var ^ " = ... ;" + | Assignment + (((RecordAccess (((Ident var, _typ), _ii), field), _typ2), + _ii2), + SimpleAssign, + e) -> + var ^ "." ^ field ^ " = ... ;" + + | _ -> "statement" + ) + in + let newi = !g +> add_node (ExprStatement (stmt, (opte, ii))) lbl s in + !g +> add_arc_opt (starti, newi); + Some newi + + + (* ------------------------- *) + | Selection (Ast_c.If (e, st1, (Ast_c.ExprStatement (None), []))), ii -> + (* sometome can have ExprStatement None but it is a if-then-else, + * because something like if() xx else ; + * so must force to have [] in the ii associated with ExprStatement + *) + + let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in + let ii = [i1;i2;i3] in + (* starti -> newi ---> newfakethen -> ... -> finalthen --> lasti + * | | + * |-> newfakeelse -> ... -> finalelse -| + * update: there is now also a link directly to lasti. + * + * because of CTL, now do different things if we are in a ifthen or + * ifthenelse. + *) + let newi = !g +> add_node (IfHeader (stmt, (e, ii))) lbl ("if") in + !g +> add_arc_opt (starti, newi); + let newfakethen = !g +> add_node TrueNode lbl "[then]" in + let newfakeelse = !g +> add_node FallThroughNode lbl "[fallthrough]" in + let afteri = !g +> add_node AfterNode lbl "[after]" in + let lasti = !g +> add_node (EndStatement (Some iifakeend)) lbl "[endif]" + in + + (* for ErrorExit heuristic *) + let newxi = { xi_lbl with under_ifthen = true; } in + + !g#add_arc ((newi, newfakethen), Direct); + !g#add_arc ((newi, newfakeelse), Direct); + !g#add_arc ((newi, afteri), Direct); + !g#add_arc ((afteri, lasti), Direct); + !g#add_arc ((newfakeelse, lasti), Direct); + + let finalthen = aux_statement (Some newfakethen, newxi) st1 in + !g +> add_arc_opt (finalthen, lasti); + Some lasti + + + | Selection (Ast_c.If (e, st1, st2)), ii -> + (* starti -> newi ---> newfakethen -> ... -> finalthen --> lasti + * | | + * |-> newfakeelse -> ... -> finalelse -| + * update: there is now also a link directly to lasti. + *) + let (iiheader, iielse, iifakeend) = + match ii with + | [i1;i2;i3;i4;i5] -> [i1;i2;i3], i4, i5 + | _ -> raise Impossible + in + let newi = !g +> add_node (IfHeader (stmt, (e, iiheader))) lbl "if" in + !g +> add_arc_opt (starti, newi); + let newfakethen = !g +> add_node TrueNode lbl "[then]" in + let newfakeelse = !g +> add_node FalseNode lbl "[else]" in + let elsenode = !g +> add_node (Else iielse) lbl "else" in + + + !g#add_arc ((newi, newfakethen), Direct); + !g#add_arc ((newi, newfakeelse), Direct); + + !g#add_arc ((newfakeelse, elsenode), Direct); + + let finalthen = aux_statement (Some newfakethen, xi_lbl) st1 in + let finalelse = aux_statement (Some elsenode, xi_lbl) st2 in + + (match finalthen, finalelse with + | (None, None) -> None + | _ -> + let lasti = + !g +> add_node (EndStatement(Some iifakeend)) lbl "[endif]" in + let afteri = + !g +> add_node AfterNode lbl "[after]" in + !g#add_arc ((newi, afteri), Direct); + !g#add_arc ((afteri, lasti), Direct); + begin + !g +> add_arc_opt (finalthen, lasti); + !g +> add_arc_opt (finalelse, lasti); + Some lasti + end) + + + | Selection (Ast_c.Ifdef (st1s, st2s)), ii -> + let (ii,iifakeend) = + match ii with + | [i1;i2;i3;i4] -> [i1;i2;i3], i4 + | [i1;i2;i3] -> [i1;i2], i3 + | _ -> raise Impossible + in + + let newi = !g +> add_node (Ifdef (stmt, ((), ii))) lbl "ifcpp" in + !g +> add_arc_opt (starti, newi); + let newfakethen = !g +> add_node TrueNode lbl "[then]" in + let newfakeelse = !g +> add_node FalseNode lbl "[else]" in + + !g#add_arc ((newi, newfakethen), Direct); + !g#add_arc ((newi, newfakeelse), Direct); + + let aux_statement_list (starti, newxi) statxs = + statxs +> List.fold_left (fun starti statement -> + aux_statement (starti, newxi) statement + ) starti + in + + + let finalthen = aux_statement_list (Some newfakethen, xi_lbl) st1s in + let finalelse = aux_statement_list (Some newfakeelse, xi_lbl) st2s in + + (match finalthen, finalelse with + | (None, None) -> None + | _ -> + let lasti = + !g +> add_node (EndStatement (Some iifakeend)) lbl "[endifcpp]" + in + begin + !g +> add_arc_opt (finalthen, lasti); + !g +> add_arc_opt (finalelse, lasti); + Some lasti + end + ) + + + (* ------------------------- *) + | Selection (Ast_c.Switch (e, st)), ii -> + let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in + let ii = [i1;i2;i3] in + + (* The newswitchi is for the labels to know where to attach. + * The newendswitch (endi) is for the 'break'. *) + let newswitchi= + !g+> add_node (SwitchHeader(stmt,(e,ii))) lbl "switch" in + let newendswitch = + !g +> add_node (EndStatement (Some iifakeend)) lbl "[endswitch]" in + + !g +> add_arc_opt (starti, newswitchi); + + (* call compound case. Need special info to pass to compound case + * because we need to build a context_info that need some of the + * information build inside the compound case: the nodei of { + *) + let finalthen = + match st with + | Ast_c.Compound statxs, ii -> + + (* todo? we should not allow to match a stmt that corresponds + * to a compound of a switch, so really SeqStart (stmt, ...) + * here ? so maybe should change the SeqStart labeling too. + * So need pass a todo_in_compound2 function. + *) + let todo_in_compound newi newxi = + let newxi' = { newxi with + ctx = SwitchInfo (newi(*!!*), newendswitch, xi.braces, lbl); + ctx_stack = newxi.ctx::newxi.ctx_stack + } + in + !g#add_arc ((newswitchi, newi), Direct); + (* new: if have not a default case, then must add an edge + * between start to end. + * todo? except if the case[range] coverthe whole spectrum + *) + if not (statxs +> List.exists (function + | (Labeled (Ast_c.Default _), _) -> true + | _ -> false + )) + then begin + (* when there is no default, then a valid path is + * from the switchheader to the end. In between we + * add a Fallthrough. + *) + + let newafter = !g+>add_node FallThroughNode lbl "[switchfall]" + in + !g#add_arc ((newafter, newendswitch), Direct); + !g#add_arc ((newswitchi, newafter), Direct); + (* old: + !g#add_arc ((newswitchi, newendswitch), Direct) +> adjust_g; + *) + end; + newxi' + in + let newxi = { xi with compound_caller = + Switch todo_in_compound + } + in + aux_statement (None (* no starti *), newxi) st + | x -> raise Impossible + in + !g +> add_arc_opt (finalthen, newendswitch); + + + (* what if has only returns inside. We must try to see if the + * newendswitch has been used via a 'break;' or because no + * 'default:') + *) + let res = + (match finalthen with + | Some finalthen -> + + let afteri = !g +> add_node AfterNode lbl "[after]" in + !g#add_arc ((newswitchi, afteri), Direct); + !g#add_arc ((afteri, newendswitch), Direct); + + + !g#add_arc ((finalthen, newendswitch), Direct); + Some newendswitch + | None -> + if (!g#predecessors newendswitch)#null + then begin + assert ((!g#successors newendswitch)#null); + !g#del_node newendswitch; + None + end + else begin + + let afteri = !g +> add_node AfterNode lbl "[after]" in + !g#add_arc ((newswitchi, afteri), Direct); + !g#add_arc ((afteri, newendswitch), Direct); + + + Some newendswitch + end + ) + in + res + + + | Labeled (Ast_c.Case (_, _)), ii + | Labeled (Ast_c.CaseRange (_, _, _)), ii -> + + incr counter_for_switch; + let switchrank = !counter_for_switch in + let node, st = + match stmt with + | Labeled (Ast_c.Case (e, st)), ii -> + (Case (stmt, (e, ii))), st + | Labeled (Ast_c.CaseRange (e, e2, st)), ii -> + (CaseRange (stmt, ((e, e2), ii))), st + | _ -> raise Impossible + in + + let newi = !g +> add_node node lbl "case:" in + + (match Common.optionise (fun () -> + (* old: xi.ctx *) + (xi.ctx::xi.ctx_stack) +> Common.find_some (function + | SwitchInfo (a, b, c, _) -> Some (a, b, c) + | _ -> None + )) + with + | Some (startbrace, switchendi, _braces) -> + (* no need to attach to previous for the first case, cos would be + * redundant. *) + starti +> do_option (fun starti -> + if starti <> startbrace + then !g +> add_arc_opt (Some starti, newi); + ); + + let s = ("[casenode] " ^ i_to_s switchrank) in + let newcasenodei = !g +> add_node (CaseNode switchrank) lbl s in + !g#add_arc ((startbrace, newcasenodei), Direct); + !g#add_arc ((newcasenodei, newi), Direct); + | None -> raise (Error (CaseNoSwitch (pinfo_of_ii ii))) + ); + aux_statement (Some newi, xi_lbl) st + + + | Labeled (Ast_c.Default st), ii -> + incr counter_for_switch; + let switchrank = !counter_for_switch in + + let newi = !g +> add_node (Default(stmt, ((),ii))) lbl "case default:" in + !g +> add_arc_opt (starti, newi); + + (match xi.ctx with + | SwitchInfo (startbrace, switchendi, _braces, _parent_lbl) -> + let s = ("[casenode] " ^ i_to_s switchrank) in + let newcasenodei = !g +> add_node (CaseNode switchrank) lbl s in + !g#add_arc ((startbrace, newcasenodei), Direct); + !g#add_arc ((newcasenodei, newi), Direct); + | _ -> raise (Error (CaseNoSwitch (pinfo_of_ii ii))) + ); + aux_statement (Some newi, xi_lbl) st + + + + + + + (* ------------------------- *) + | Iteration (Ast_c.While (e, st)), ii -> + (* starti -> newi ---> newfakethen -> ... -> finalthen - + * |---|-----------------------------------| + * |-> newfakelse + *) + + let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in + let ii = [i1;i2;i3] in + + let newi = !g +> add_node (WhileHeader (stmt, (e,ii))) lbl "while" in + !g +> add_arc_opt (starti, newi); + let newfakethen = !g +> add_node InLoopNode lbl "[whiletrue]" in + (* let newfakeelse = !g +> add_node FalseNode lbl "[endwhile]" in *) + let newafter = !g +> add_node FallThroughNode lbl "[whilefall]" in + let newfakeelse = + !g +> add_node (EndStatement (Some iifakeend)) lbl "[endwhile]" in + + let newxi = { xi_lbl with + ctx = LoopInfo (newi, newfakeelse, xi_lbl.braces, lbl); + ctx_stack = xi_lbl.ctx::xi_lbl.ctx_stack + } + in + + !g#add_arc ((newi, newfakethen), Direct); + !g#add_arc ((newafter, newfakeelse), Direct); + !g#add_arc ((newi, newafter), Direct); + let finalthen = aux_statement (Some newfakethen, newxi) st in + !g +> add_arc_opt (finalthen, newi); + Some newfakeelse + + + (* This time, may return None, for instance if goto in body of dowhile + * (whereas While cant return None). But if return None, certainly + * some deadcode. + *) + | Iteration (Ast_c.DoWhile (st, e)), ii -> + (* starti -> doi ---> ... ---> finalthen (opt) ---> whiletaili + * |--------- newfakethen ---------------| |---> newfakelse + *) + let is_zero = + match Ast_c.unwrap_expr e with + | Constant (Int "0") -> true + | _ -> false + in + + let (iido, iiwhiletail, iifakeend) = + match ii with + | [i1;i2;i3;i4;i5;i6] -> i1, [i2;i3;i4;i5], i6 + | _ -> raise Impossible + in + let doi = !g +> add_node (DoHeader (stmt, iido)) lbl "do" in + !g +> add_arc_opt (starti, doi); + let taili = !g +> add_node (DoWhileTail (e, iiwhiletail)) lbl "whiletail" + in + + + (*let newfakeelse = !g +> add_node FalseNode lbl "[enddowhile]" in *) + let newafter = !g +> add_node FallThroughNode lbl "[dowhilefall]" in + let newfakeelse = + !g +> add_node (EndStatement (Some iifakeend)) lbl "[enddowhile]" in + + let newxi = { xi_lbl with + ctx = LoopInfo (taili, newfakeelse, xi_lbl.braces, lbl); + ctx_stack = xi_lbl.ctx::xi_lbl.ctx_stack + } + in + + if not is_zero + then begin + let newfakethen = !g +> add_node InLoopNode lbl "[dowhiletrue]" in + !g#add_arc ((taili, newfakethen), Direct); + !g#add_arc ((newfakethen, doi), Direct); + end; + + !g#add_arc ((newafter, newfakeelse), Direct); + !g#add_arc ((taili, newafter), Direct); + + + let finalthen = aux_statement (Some doi, newxi) st in + (match finalthen with + | None -> + if (!g#predecessors taili)#null + then raise (Error (DeadCode (Some (pinfo_of_ii ii)))) + else Some newfakeelse + | Some finali -> + !g#add_arc ((finali, taili), Direct); + Some newfakeelse + ) + + + + | Iteration (Ast_c.For (e1opt, e2opt, e3opt, st)), ii -> + let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in + let ii = [i1;i2;i3] in + + let newi = + !g+>add_node(ForHeader(stmt,((e1opt,e2opt,e3opt),ii))) lbl "for" in + !g +> add_arc_opt (starti, newi); + let newfakethen = !g +> add_node InLoopNode lbl "[fortrue]" in + (*let newfakeelse = !g +> add_node FalseNode lbl "[endfor]" in*) + let newafter = !g +> add_node FallThroughNode lbl "[forfall]" in + let newfakeelse = + !g +> add_node (EndStatement (Some iifakeend)) lbl "[endfor]" in + + let newxi = { xi_lbl with + ctx = LoopInfo (newi, newfakeelse, xi_lbl.braces, lbl); + ctx_stack = xi_lbl.ctx::xi_lbl.ctx_stack + } + in + + !g#add_arc ((newi, newfakethen), Direct); + !g#add_arc ((newafter, newfakeelse), Direct); + !g#add_arc ((newi, newafter), Direct); + let finalthen = aux_statement (Some newfakethen, newxi) st in + !g +> add_arc_opt (finalthen, newi); + Some newfakeelse + + + (* to generate less exception with the breakInsideLoop, analyse + * correctly the loop deguisé comme list_for_each. Add a case ForMacro + * in ast_c (and in lexer/parser), and then do code that imitates the + * code for the For. + * update: the list_for_each was previously converted into Tif by the + * lexer, now they are returned as Twhile so less pbs. But not perfect. + * update: now I recognize the list_for_each macro so no more problems. + *) + | Iteration (Ast_c.MacroIteration (s, es, st)), ii -> + let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in + let ii = [i1;i2;i3] in + + let newi = + !g+>add_node(MacroIterHeader(stmt,((s,es),ii))) lbl "foreach" in + !g +> add_arc_opt (starti, newi); + let newfakethen = !g +> add_node InLoopNode lbl "[fortrue]" in + (*let newfakeelse = !g +> add_node FalseNode lbl "[endfor]" in*) + let newafter = !g +> add_node FallThroughNode lbl "[foreachfall]" in + let newfakeelse = + !g +> add_node (EndStatement (Some iifakeend)) lbl "[endforeach]" in + + let newxi = { xi_lbl with + ctx = LoopInfo (newi, newfakeelse, xi_lbl.braces, lbl); + ctx_stack = xi_lbl.ctx::xi_lbl.ctx_stack + } + in + + !g#add_arc ((newi, newfakethen), Direct); + !g#add_arc ((newafter, newfakeelse), Direct); + !g#add_arc ((newi, newafter), Direct); + let finalthen = aux_statement (Some newfakethen, newxi) st in + !g +> add_arc_opt (finalthen, newi); + Some newfakeelse + + + + (* ------------------------- *) + | Jump ((Ast_c.Continue|Ast_c.Break) as x),ii -> + let context_info = + match xi.ctx with + SwitchInfo (startbrace, loopendi, braces, parent_lbl) -> + if x = Ast_c.Break + then xi.ctx + else + (try + xi.ctx_stack +> Common.find_some (function + LoopInfo (_,_,_,_) as c -> Some c + | _ -> None) + with Not_found -> + raise (Error (OnlyBreakInSwitch (pinfo_of_ii ii)))) + | LoopInfo (loopstarti, loopendi, braces, parent_lbl) -> xi.ctx + | NoInfo -> raise (Error (NoEnclosingLoop (pinfo_of_ii ii))) in + + let parent_label = + match context_info with + LoopInfo (loopstarti, loopendi, braces, parent_lbl) -> parent_lbl + | SwitchInfo (startbrace, loopendi, braces, parent_lbl) -> parent_lbl + | NoInfo -> raise Impossible in + + (* flow_to_ast: *) + let (node_info, string) = + let parent_string = + String.concat "," (List.map string_of_int parent_label) in + (match x with + | Ast_c.Continue -> + (Continue (stmt, ((), ii)), + Printf.sprintf "continue; [%s]" parent_string) + | Ast_c.Break -> + (Break (stmt, ((), ii)), + Printf.sprintf "break; [%s]" parent_string) + | _ -> raise Impossible + ) in + + (* idea: break or continue records the label of its parent loop or + switch *) + let newi = !g +> add_bc_node node_info lbl parent_label string in + !g +> add_arc_opt (starti, newi); + + (* let newi = some starti in *) + + (match context_info with + | LoopInfo (loopstarti, loopendi, braces, parent_lbl) -> + let desti = + (match x with + | Ast_c.Break -> loopendi + | Ast_c.Continue -> loopstarti + | x -> raise Impossible + ) in + let difference = List.length xi.braces - List.length braces in + assert (difference >= 0); + let toend = take difference xi.braces in + let newi = insert_all_braces toend newi in + !g#add_arc ((newi, desti), Direct); + None + + | SwitchInfo (startbrace, loopendi, braces, parent_lbl) -> + assert (x = Ast_c.Break); + let difference = List.length xi.braces - List.length braces in + assert (difference >= 0); + let toend = take difference xi.braces in + let newi = insert_all_braces toend newi in + !g#add_arc ((newi, loopendi), Direct); + None + | NoInfo -> raise Impossible + ) + + | Jump ((Ast_c.Return | Ast_c.ReturnExpr _) as kind), ii -> + (match xi.exiti, xi.errorexiti with + | None, None -> raise (Error (NoExit (pinfo_of_ii ii))) + | Some exiti, Some errorexiti -> + + (* flow_to_ast: *) + let s = + match kind with + | Ast_c.Return -> "return" + | Ast_c.ReturnExpr _ -> "return ..." + | _ -> raise Impossible + in + let newi = + !g +> add_node + (match kind with + | Ast_c.Return -> Return (stmt, ((),ii)) + | Ast_c.ReturnExpr e -> ReturnExpr (stmt, (e, ii)) + | _ -> raise Impossible + ) + lbl s + in + !g +> add_arc_opt (starti, newi); + let newi = insert_all_braces xi.braces newi in + + if xi.under_ifthen + then !g#add_arc ((newi, errorexiti), Direct) + else !g#add_arc ((newi, exiti), Direct) + ; + None + | _ -> raise Impossible + ) + + + (* ------------------------- *) + | Ast_c.Decl decl, ii -> + let s = + match decl with + | (Ast_c.DeclList ([(Some ((s, _),_), typ, sto, _), _], _)) -> + "decl:" ^ s + | _ -> "decl_novar_or_multivar" + in + + let newi = !g +> add_node (Decl (decl)) lbl s in + !g +> add_arc_opt (starti, newi); + Some newi + + (* ------------------------- *) + | Ast_c.Asm body, ii -> + let newi = !g +> add_node (Asm (stmt, ((body,ii)))) lbl "asm;" in + !g +> add_arc_opt (starti, newi); + Some newi + + | Ast_c.MacroStmt, ii -> + let newi = !g +> add_node (MacroStmt (stmt, ((),ii))) lbl "macro;" in + !g +> add_arc_opt (starti, newi); + Some newi + + + (* ------------------------- *) + | Ast_c.NestedFunc def, ii -> + raise (Error NestedFunc) + + + + +(*****************************************************************************) +(* Definition of function *) +(*****************************************************************************) + +let (aux_definition: nodei -> definition -> unit) = fun topi funcdef -> + + let lbl_start = [!counter_for_labels] in + + let ((funcs, functype, sto, compound), ii) = funcdef in + let iifunheader, iicompound = + (match ii with + | is::ioparen::icparen::iobrace::icbrace::iifake::isto -> + is::ioparen::icparen::iifake::isto, + [iobrace;icbrace] + | _ -> raise Impossible + ) + in + + let topstatement = Ast_c.Compound compound, iicompound in + + let headi = !g +> add_node (FunHeader ((funcs, functype, sto), iifunheader)) + lbl_start ("function " ^ funcs) in + let enteri = !g +> add_node Enter lbl_0 "[enter]" in + let exiti = !g +> add_node Exit lbl_0 "[exit]" in + let errorexiti = !g +> add_node ErrorExit lbl_0 "[errorexit]" in + + !g#add_arc ((topi, headi), Direct); + !g#add_arc ((headi, enteri), Direct); + + (* ---------------------------------------------------------------- *) + (* todocheck: assert ? such as we have "consommer" tous les labels *) + let info = + { initial_info with + labels = lbl_start; + labels_assoc = compute_labels_and_create_them topstatement; + exiti = Some exiti; + errorexiti = Some errorexiti; + compound_caller = FunctionDef; + } + in + + let lasti = aux_statement (Some enteri, info) topstatement in + !g +> add_arc_opt (lasti, exiti) + +(*****************************************************************************) +(* Entry point *) +(*****************************************************************************) + +(* Helpers for SpecialDeclMacro. + * + * could also force the coccier to define + * the toplevel macro statement as in @@ toplevel_declarator MACRO_PARAM;@@ + * and so I would not need this hack and instead I would to a cleaner + * match in cocci_vs_c_3.ml of a A.MacroTop vs B.MacroTop + *) +let specialdeclmacro_to_stmt (s, args, ii) = + let (iis, iiopar, iicpar, iiptvirg) = tuple_of_list4 ii in + let ident = (Ast_c.Ident s, Ast_c.noType()), [iis] in + let f = (Ast_c.FunCall (ident, args), Ast_c.noType()), [iiopar;iicpar] in + let stmt = Ast_c.ExprStatement (Some f), [iiptvirg] in + stmt, (f, [iiptvirg]) + + + +let ast_to_control_flow e = + + (* globals (re)initialialisation *) + g := (new ograph_mutable); + counter_for_labels := 1; + counter_for_braces := 0; + counter_for_switch := 0; + + let topi = !g +> add_node TopNode lbl_0 "[top]" in + + match e with + | Ast_c.Definition (((funcs, _, _, c),_) as def) -> + (* if !Flag.show_misc then pr2 ("build info function " ^ funcs); *) + aux_definition topi def; + Some !g + + | Ast_c.Declaration _ + | Ast_c.Include _ + | Ast_c.MacroTop _ + -> + let (elem, str) = + match e with + | Ast_c.Declaration decl -> + (Control_flow_c.Decl decl), "decl" + | Ast_c.Include (a,b) -> + (Control_flow_c.Include (a,b)), "#include" + | Ast_c.MacroTop (s, args, ii) -> + let (st, (e, ii)) = specialdeclmacro_to_stmt (s, args, ii) in + (Control_flow_c.ExprStatement (st, (Some e, ii))), "macrotoplevel" + (*(Control_flow_c.MacroTop (s, args,ii), "macrotoplevel") *) + | _ -> raise Impossible + in + let ei = !g +> add_node elem lbl_0 str in + let endi = !g +> add_node EndNode lbl_0 "[end]" in + + !g#add_arc ((topi, ei),Direct); + !g#add_arc ((ei, endi),Direct); + Some !g + + | Ast_c.Define ((id,ii), (defkind, defval)) -> + let s = ("#define " ^ id) in + let headeri = !g+>add_node (DefineHeader ((id, ii), defkind)) lbl_0 s in + !g#add_arc ((topi, headeri),Direct); + + (match defval with + | Ast_c.DefineExpr e -> + let ei = !g +> add_node (DefineExpr e) lbl_0 "defexpr" in + let endi = !g +> add_node EndNode lbl_0 "[end]" in + !g#add_arc ((headeri, ei) ,Direct); + !g#add_arc ((ei, endi) ,Direct); + + | Ast_c.DefineType ft -> + let ei = !g +> add_node (DefineType ft) lbl_0 "deftyp" in + let endi = !g +> add_node EndNode lbl_0 "[end]" in + !g#add_arc ((headeri, ei) ,Direct); + !g#add_arc ((ei, endi) ,Direct); + + | Ast_c.DefineStmt st -> + + (* can have some return; inside the statement *) + let exiti = !g +> add_node Exit lbl_0 "[exit]" in + let errorexiti = !g +> add_node ErrorExit lbl_0 "[errorexit]" in + let goto_labels = compute_labels_and_create_them st in + + let info = { initial_info with + labels_assoc = goto_labels; + exiti = Some exiti; + errorexiti = Some errorexiti; + } + in + + let lasti = aux_statement (Some headeri , info) st in + lasti +> do_option (fun lasti -> + (* todo? if don't have a lasti ? no EndNode ? CTL will work ? *) + let endi = !g +> add_node EndNode lbl_0 "[end]" in + !g#add_arc ((lasti, endi), Direct) + ) + + + | Ast_c.DefineDoWhileZero (st, ii) -> + let headerdoi = + !g +> add_node (DefineDoWhileZeroHeader ((),ii)) lbl_0 "do0" in + !g#add_arc ((headeri, headerdoi), Direct); + let info = initial_info in + let lasti = aux_statement (Some headerdoi , info) st in + lasti +> do_option (fun lasti -> + let endi = !g +> add_node EndNode lbl_0 "[end]" in + !g#add_arc ((lasti, endi), Direct) + ) + + | Ast_c.DefineFunction def -> + aux_definition headeri def; + + | Ast_c.DefineText (s, ii) -> + raise Todo + | Ast_c.DefineEmpty -> + let endi = !g +> add_node EndNode lbl_0 "[end]" in + !g#add_arc ((headeri, endi),Direct); + ); + + Some !g + + + | _ -> None + + +(*****************************************************************************) +(* CFG loop annotation *) +(*****************************************************************************) + +let annotate_loop_nodes g = + let firsti = Control_flow_c.first_node g in + + (* just for opti a little *) + let already = Hashtbl.create 101 in + + g +> Ograph_extended.dfs_iter_with_path firsti (fun xi path -> + Hashtbl.add already xi true; + let succ = g#successors xi in + let succ = succ#tolist in + succ +> List.iter (fun (yi,_edge) -> + if Hashtbl.mem already yi && List.mem yi (xi::path) + then + let node = g#nodes#find yi in + let ((node2, nodeinfo), nodestr) = node in + let node' = ((node2, {nodeinfo with is_loop = true}), (nodestr ^ "*")) + in + g#replace_node (yi, node'); + ); + ); + + + g + + +(*****************************************************************************) +(* CFG checks *) +(*****************************************************************************) + +(* the second phase, deadcode detection. Old code was raising DeadCode if + * lasti = None, but maybe not. In fact if have 2 return in the then + * and else of an if ? + * + * alt: but can assert that at least there exist + * a node to exiti, just check #pred of exiti. + * + * Why so many deadcode in Linux ? Ptet que le label est utilisé + * mais dans le corps d'une macro et donc on le voit pas :( + * + *) +let deadcode_detection g = + + g#nodes#iter (fun (k, node) -> + let pred = g#predecessors k in + if pred#null then + (match unwrap node with + (* old: + * | Enter -> () + * | EndStatement _ -> pr2 "deadcode sur fake node, pas grave"; + *) + | TopNode -> () + | FunHeader _ -> () + | ErrorExit -> () + | Exit -> () (* if have 'loop: if(x) return; i++; goto loop' *) + | SeqEnd _ -> () (* todo?: certaines '}' deviennent orphelins *) + | x -> + (match Control_flow_c.extract_fullstatement node with + | Some (st, ii) -> raise (Error (DeadCode (Some (pinfo_of_ii ii)))) + | _ -> pr2 "CFG: orphelin nodes, maybe something wierd happened" + ) + ) + ) + +(*------------------------------------------------------------------------*) +(* special_cfg_braces: the check are really specific to the way we + * have build our control_flow, with the { } in the graph so normally + * all those checks here are useless. + * + * ver1: to better error reporting, to report earlier the message, pass + * the list of '{' (containing morover a brace_identifier) instead of + * just the depth. + *) + +let (check_control_flow: cflow -> unit) = fun g -> + + let nodes = g#nodes in + let starti = first_node g in + let visited = ref (new oassocb []) in + + let print_trace_error xs = pr2 "PB with flow:"; Common.pr2_gen xs; in + + let rec dfs (nodei, (* Depth depth,*) startbraces, trace) = + let trace2 = nodei::trace in + if !visited#haskey nodei + then + (* if loop back, just check that go back to a state where have same depth + number *) + let (*(Depth depth2)*) startbraces2 = !visited#find nodei in + if (*(depth = depth2)*) startbraces <> startbraces2 + then + begin + pr2 (sprintf "PB with flow: the node %d has not same braces count" + nodei); + print_trace_error trace2 + end + else + let children = g#successors nodei in + let _ = visited := !visited#add (nodei, (* Depth depth*) startbraces) in + + (* old: good, but detect a missing } too late, only at the end + let newdepth = + (match fst (nodes#find nodei) with + | StartBrace i -> Depth (depth + 1) + | EndBrace i -> Depth (depth - 1) + | _ -> Depth depth + ) + in + *) + let newdepth = + (match unwrap (nodes#find nodei), startbraces with + | SeqStart (_,i,_), xs -> i::xs + | SeqEnd (i,_), j::xs -> + if i = j + then xs + else + begin + pr2 (sprintf ("PB with flow: not corresponding match between }%d and excpeted }%d at node %d") i j nodei); + print_trace_error trace2; + xs + end + | SeqEnd (i,_), [] -> + pr2 (sprintf "PB with flow: too much } at }%d " i); + print_trace_error trace2; + [] + | _, xs -> xs + ) + in + + + if children#tolist = [] + then + if (* (depth = 0) *) startbraces <> [] + then print_trace_error trace2 + else + children#tolist +> List.iter (fun (nodei,_) -> + dfs (nodei, newdepth, trace2) + ) + in + + dfs (starti, (* Depth 0*) [], []) + +(*****************************************************************************) +(* Error report *) +(*****************************************************************************) + +let report_error error = + let error_from_info info = + Common.error_message_short info.file ("", info.charpos) + in + match error with + | DeadCode infoopt -> + (match infoopt with + | None -> pr2 "FLOW: deadcode detected, but cant trace back the place" + | Some info -> pr2 ("FLOW: deadcode detected: " ^ error_from_info info) + ) + | CaseNoSwitch info -> + pr2 ("FLOW: case without corresponding switch: " ^ error_from_info info) + | OnlyBreakInSwitch info -> + pr2 ("FLOW: only break are allowed in switch: " ^ error_from_info info) + | NoEnclosingLoop (info) -> + pr2 ("FLOW: can't find enclosing loop: " ^ error_from_info info) + | GotoCantFindLabel (s, info) -> + pr2 ("FLOW: cant jump to " ^ s ^ ": because we can't find this label") + | NoExit info -> + pr2 ("FLOW: can't find exit or error exit: " ^ error_from_info info) + | DuplicatedLabel s -> + pr2 ("FLOW: duplicate label" ^ s) + | NestedFunc -> + pr2 ("FLOW: not handling yet nested function") + | ComputedGoto -> + pr2 ("FLOW: not handling computed goto yet") diff --git a/parsing_c/ast_to_flow.mli b/parsing_c/ast_to_flow.mli new file mode 100644 index 0000000..56d6109 --- /dev/null +++ b/parsing_c/ast_to_flow.mli @@ -0,0 +1,22 @@ + +val ast_to_control_flow : Ast_c.toplevel -> Control_flow_c.cflow option + +val deadcode_detection : Control_flow_c.cflow -> unit +val check_control_flow : Control_flow_c.cflow -> unit + +val annotate_loop_nodes : Control_flow_c.cflow -> Control_flow_c.cflow + +type error = + | DeadCode of Common.parse_info option + | CaseNoSwitch of Common.parse_info + | OnlyBreakInSwitch of Common.parse_info + | NoEnclosingLoop of Common.parse_info + | GotoCantFindLabel of string * Common.parse_info + | NoExit of Common.parse_info + | DuplicatedLabel of string + | NestedFunc + | ComputedGoto + +exception Error of error + +val report_error : error -> unit diff --git a/parsing_c/authors.txt b/parsing_c/authors.txt new file mode 100644 index 0000000..06e6b26 --- /dev/null +++ b/parsing_c/authors.txt @@ -0,0 +1 @@ +Yoann Padioleau diff --git a/parsing_c/compare_c.ml b/parsing_c/compare_c.ml new file mode 100644 index 0000000..efea7d1 --- /dev/null +++ b/parsing_c/compare_c.ml @@ -0,0 +1,361 @@ +open Common + +open Ast_c + + +type compare_result = + | Correct + | Pb of string + | PbOnlyInNotParsedCorrectly of string + + +(*****************************************************************************) +(* Normalise before comparing *) +(*****************************************************************************) + +(* List taken from CVS manual, 'Keyword substitution' chapter. Note + * that I do not put "Log" because it is used only in comment, and it + * is not enough to substituate until the end of the line. *) +let cvs_keyword_list = [ + "Id";"Date"; "Revision"; (* the common one *) + "Name";"Author";"CVSHeader";"Header";"Locker";"RCSfile";"Source";"State"; + "Rev"; +] + +(* Can also have just dollarIDdollar but it is only when you have not + * yet committed the file. After the commit it would be a dollarIddollar:. + * If reput Id:, do not join the regexp!! otherwise CVS will modify it :) + *) +let cvs_keyword_regexp = Str.regexp + ("\\$\\([A-Za-z_]+\\):[^\\$]*\\$") + + +let cvs_compute_newstr s = + Str.global_substitute cvs_keyword_regexp (fun _s -> + let substr = Str.matched_string s in + assert (substr ==~ cvs_keyword_regexp); (* use its side-effect *) + let tag = matched1 substr in + + if not (List.mem tag cvs_keyword_list) + then failwith ("unknown CVS keyword: " ^ tag); + + "CVS_MAGIC_STRING" + ) s + + + + +(* todo: get rid of the type for expressions ? *) +let normal_form_program xs = + let bigf = { Visitor_c.default_visitor_c_s with + + Visitor_c.kini_s = (fun (k,bigf) ini -> + match ini with + | InitList xs, [i1;i2;iicommaopt] -> + k (InitList xs, [i1;i2]) + | _ -> k ini + ); + Visitor_c.kexpr_s = (fun (k,bigf) e -> + match e with + (* todo: should also do something for multistrings *) + | (Constant (String (s,kind)), typ), [ii] + when Common.string_match_substring cvs_keyword_regexp s -> + let newstr = cvs_compute_newstr s in + (Constant (String (newstr,kind)), typ), [rewrap_str newstr ii] + | _ -> k e + + ); + Visitor_c.ktoplevel_s = (fun (k,bigf) p -> + match p with + | Define _ -> + raise Todo + (* + let (i1, i2, i3) = Common.tuple_of_list3 ii in + if Common.string_match_substring cvs_keyword_regexp body + then + let newstr = cvs_compute_newstr body in + Define ((s, newstr), [i1;i2;rewrap_str newstr i3]) + else p + *) + | _ -> k p + ); + +(* + Visitor_c.kinfo_s = (fun (k,bigf) i -> + let s = Ast_c.get_str_of_info i in + if Common.string_match_substring cvs_keyword_regexp s + then + let newstr = cvs_compute_newstr s in + rewrap_str newstr i + else i + ); +*) + + } + in + xs +> List.map (fun p -> Visitor_c.vk_toplevel_s bigf p) + + + + + + +let normal_form_token x = + let x' = + match x with + | Parser_c.TString ((s, kind),i1) -> Parser_c.TString (("",kind), i1) + | x -> x + in + x' +> Token_helpers.visitor_info_of_tok (fun info -> + let info = Ast_c.al_info 0 info in + let str = Ast_c.str_of_info info in + if Common.string_match_substring cvs_keyword_regexp str + then + let newstr = cvs_compute_newstr str in + rewrap_str newstr info + else info + ) + + +(*****************************************************************************) +(* Compare at Ast level *) +(*****************************************************************************) + +(* Note that I do a (simple) astdiff to know if there is a difference, but + * then I use diff to print the differences. So sometimes you have to dig + * a little to find really where the real difference (one not involving + * just spacing difference) was. + * Note also that the astdiff is not very accurate. As I skip comments, + * macro definitions, those are not in the Ast and if there is a diff + * between 2 files regarding macro def, then I will not be able to report it :( + * update: I now put the toplevel #define at least in the Ast. + * update: You can use token_compare for more precise diff. + * + * todo?: finer grain astdiff, better report, more precise. + * + * todo: do iso between if() S and if() { S } + *) +let compare_ast filename1 filename2 = + + let xs = + match !Flag_parsing_c.diff_lines with + None -> + Common.cmd_to_list ("diff -u -b -B "^filename1^ " " ^ filename2) + | Some n -> + Common.cmd_to_list ("diff -U "^n^" -b -B "^filename1^" "^filename2) in + + (* get rid of the --- and +++ lines *) + let xs = + if null xs + then xs + else Common.drop 2 xs + in + + + let process_filename filename = + let (c, _stat) = Parse_c.parse_print_error_heuristic filename in + let c = List.map fst c in + c +> Lib_parsing_c.al_program +> normal_form_program + in + + let c1 = process_filename filename1 in + let c2 = process_filename filename2 in + + let error = ref 0 in + let pb_notparsed = ref 0 in + + let res = + if List.length c1 <> List.length c2 + then Pb "not same number of entities (func, decl, ...)" + else + begin + zip c1 c2 +> List.iter (function + | Declaration a, Declaration b -> if not (a =*= b) then incr error + | Definition a, Definition b -> if not (a =*= b) then incr error + | EmptyDef a, EmptyDef b -> if not (a =*= b) then incr error + | MacroTop (a1,b1,c1), MacroTop (a2,b2,c2) -> + if not ((a1,b1,c1) =*= (a2,b2,c2)) then incr error + | Include (a,_), Include (b,_) -> if not (a =*= b) then incr error + | Define _, Define _ -> + raise Todo + (* if not (a =*= b) then incr error *) + | NotParsedCorrectly a, NotParsedCorrectly b -> + if not (a =*= b) then incr pb_notparsed + | NotParsedCorrectly a, _ -> + (* Pb only in generated file *) + incr error; + + | _, NotParsedCorrectly b -> + incr pb_notparsed + | FinalDef a, FinalDef b -> if not (a =*= b) then incr error + | _, _ -> incr error + ); + (match () with + | _ when !pb_notparsed > 0 && !error = 0 -> + PbOnlyInNotParsedCorrectly "" + | _ when !error > 0 -> Pb "" + | _ -> Correct + ) + end + in + res, xs + + + +(*****************************************************************************) +(* Compare at token level *) +(*****************************************************************************) + +(* Because I now commentize more in parsing, with parsing_hacks, + * compare_ast may say that 2 programs are equal whereas they are not. + * Here I compare token, and so have still the TCommentCpp and TCommentMisc + * so at least detect such differences. + * + * Morover compare_ast is not very precise in his report when it + * detects a difference. So token_diff is better. + * + * I do token_diff but I use programCelement2, so that + * I know if I am in a "notparsable" zone. The tokens are + * in (snd programCelement2). + * + * Faire aussi un compare_token qui se moque des TCommentMisc, + * TCommentCPP et TIfdef ? Normalement si fait ca retrouvera + * les meme resultats que compare_ast. + * + *) + + +(* Pass only "true" comments, dont pass TCommentMisc and TCommentCpp *) +let is_normal_space_or_comment = function + | Parser_c.TComment _ + | Parser_c.TCommentSpace _ + | Parser_c.TCommentNewline _ + +(* | Parser_c.TComma _ *) (* UGLY, because of gcc_opt_comma isomorphism *) + -> true + | _ -> false + + +(* convetion: compare_token generated_file expected_res + * because when there is a notparsablezone in generated_file, I + * don't issue a PbOnlyInNotParsedCorrectly + *) +let compare_token filename1 filename2 = + + + let rec loop xs ys = + match xs, ys with + | [], [] -> None + + (* UGLY, because of gcc_opt_comma isomorphism *) + | (Parser_c.TComma _::Parser_c.TCBrace _::xs), (Parser_c.TCBrace _::ys) -> + loop xs ys + | (Parser_c.TCBrace _::xs), (Parser_c.TComma _::Parser_c.TCBrace _::ys) -> + loop xs ys + + | [], x::xs -> + Some "not same number of tokens inside C elements" + | x::xs, [] -> + Some "not same number of tokens inside C elements" + + | x::xs, y::ys -> + let x' = normal_form_token x in + let y' = normal_form_token y in + if x' = y' + then loop xs ys + else + let str1, pos1 = + Token_helpers.str_of_tok x, Token_helpers.pos_of_tok x in + let str2, pos2 = + Token_helpers.str_of_tok y, Token_helpers.pos_of_tok y in + Some ("diff token: " ^ str1 ^" VS " ^ str2 ^ "\n" ^ + Common.error_message filename1 (str1, pos1) ^ "\n" ^ + Common.error_message filename2 (str2, pos2) ^ "\n" + ) + + in + let final_loop xs ys = + loop + (xs +> List.filter (fun x -> not (is_normal_space_or_comment x))) + (ys +> List.filter (fun x -> not (is_normal_space_or_comment x))) + in + + (* + let toks1 = Parse_c.tokens filename1 in + let toks2 = Parse_c.tokens filename2 in + loop toks1 toks2 in + *) + + let (c1, _stat) = Parse_c.parse_print_error_heuristic filename1 in + let (c2, _stat) = Parse_c.parse_print_error_heuristic filename2 in + + let res = + if List.length c1 <> List.length c2 + then Pb "not same number of entities (func, decl, ...)" + else + zip c1 c2 +> Common.fold_k (fun acc ((a,infoa),(b,infob)) k -> + match a, b with + | NotParsedCorrectly a, NotParsedCorrectly b -> + (match final_loop (snd infoa) (snd infob) with + | None -> k acc + | Some s -> PbOnlyInNotParsedCorrectly s + ) + + | NotParsedCorrectly a, _ -> + Pb "PB parsing only in generated-file" + | _, NotParsedCorrectly b -> + PbOnlyInNotParsedCorrectly "PB parsing only in expected-file" + | _, _ -> + (match final_loop (snd infoa) (snd infob) with + | None -> k acc + | Some s -> Pb s + ) + ) (fun acc -> acc) + (Correct) + in + + let xs = + match !Flag_parsing_c.diff_lines with + None -> + Common.cmd_to_list ("diff -u -b -B "^filename1^ " " ^ filename2) + | Some n -> + Common.cmd_to_list ("diff -U "^n^" -b -B "^filename1^" "^filename2) in + + (* get rid of the --- and +++ lines *) + let xs = + if null xs + then xs + else Common.drop 2 xs + in + + if null xs && (res <> Correct) + then failwith + "Impossible: How can diff be null and have not Correct in compare_c?"; + + res, xs + + + + +(*****************************************************************************) + +let compare_default = compare_token + + +let compare_result_to_string (correct, diffxs) = + match correct with + | Correct -> + "seems correct" ^ "\n" + | Pb s -> + ("seems incorrect: " ^ s) ^ "\n" ^ + "diff (result(-) vs expected_result(+)) = " ^ "\n" ^ + (diffxs +> Common.join "\n") ^ "\n" + | PbOnlyInNotParsedCorrectly s -> + "seems incorrect, but only because of code that was not parsable" ^ "\n"^ + ("explanation:" ^ s) ^ "\n" ^ + "diff (result(-) vs expected_result(+)) = " ^ "\n" ^ + (diffxs +> Common.join "\n") ^ "\n" + + +let compare_result_to_bool correct = + correct = Correct diff --git a/parsing_c/compare_c.mli b/parsing_c/compare_c.mli new file mode 100644 index 0000000..fdf388d --- /dev/null +++ b/parsing_c/compare_c.mli @@ -0,0 +1,21 @@ +open Common + +type compare_result = + | Correct + | Pb of string + | PbOnlyInNotParsedCorrectly of string + + +(* the string list is the output of diff *) + +val compare_ast : + filename -> filename -> compare_result * string list + +val compare_token : + filename -> filename -> compare_result * string list + +val compare_default : filename -> filename -> compare_result * string list + + +val compare_result_to_string : compare_result * string list -> string +val compare_result_to_bool : compare_result -> bool diff --git a/parsing_c/control_flow_c.ml b/parsing_c/control_flow_c.ml new file mode 100644 index 0000000..7c6d07f --- /dev/null +++ b/parsing_c/control_flow_c.ml @@ -0,0 +1,362 @@ +open Common + +open Ast_c + +(*****************************************************************************) +(* + * There is more information in the CFG we build that in the CFG usually built + * in a compiler. This is because: + * + * - We need later to go back from flow to original ast, because we are + * doing a refactoring tool, so different context. So we have to add + * some nodes for '{' or '}' or goto that normally disapear in a CFG. + * We must keep those entities, in the same way that we must keep the parens + * (ParenExpr, ParenType) in the Ast_c during parsing. + * + * Moreover, the coccier can mention in his semantic patch those entities, + * so we must keep those entities in the CFG. + * + * We also have to add some extra nodes to make the process that goes from + * flow to ast deterministic with for instance the CaseNode, or easier + * with for instance the Fake node. + * + * - The coccinelle engine later transforms some nodes, and we need to rebuild + * the ast from a statement now defined and altered in different nodes. + * So we can't just put all the parsing info (Ast_c.il) in the top node of + * a statement. We have to split those Ast_c.il in different nodes, to + * later reconstruct a full Ast_c.il from different nodes. This is why + * we need the Else node, ... + * + * Note that at the same time, we also need to store the fullstatement + * in the top node, because the CTL engine need to get that information + * when dealing with MetaStatement (statement S; in a Semantic Patch). + * + * + * - The CTL engine needs more information than just the CFG, and we use + * tricks to encode those informations in the nodes: + * + * - We have some TrueNode, FalseNode to know in what branch we are. + * Normally we could achieve this by putting this information in the + * edges, but CTL engine know nothing about edges, it must do + * everything with only nodes information. + * + * - We need to mark each braces with an identifier so that the CTL + * can know if one specific '}' correspond to a specific '{'. + * + * - We add some labels to each node to handle the MetaRuleElem and + * MetaStatement. It allows to groups nodes that belong to the same + * statement. Normally CFG are there to abstract from this, but in + * Coccinelle we need sometimes the CFG view, and sometimes the Ast + * view and the labels allow that. + * + * - We even add nodes. We add '}', not only to be able to go back to AST + * but also because of the CTL engine. So one '}' may in fact be + * represented by multiple nodes, one in each CFG path. + * + * - need After, + * - need FallThrough. + * - Need know if ErrorExit, + * + * choice: Julia proposed that the flow is in fact just + * a view through the Ast, which means just Ocaml ref, so that when we + * modify some nodes, in fact it modifies the ast. But I prefer do it + * the functionnal way. + * + * The node2 type should be as close as possible to Ast_cocci.rule_elem to + * facilitate the job of cocci_vs_c. + * + *) + +(*****************************************************************************) + + +(* The string is for debugging. Used by Ograph_extended.print_graph. + * The int list are Labels. Trick used for CTL engine. Must not + * transform that in a triple or record because print_graph would + * not work. + *) +type node = node1 * string + and node1 = node2 * nodeinfo + and nodeinfo = { + labels: int list; + bclabels: int list; (* parent of a break or continue node *) + is_loop: bool; + is_fake: bool; + } + and node2 = + + (* For CTL to work, we need that some nodes loop over itself. We + * need that every nodes have a successor. Julia also want to go back + * indefinitely. So must tag some nodes as the beginning and end of + * the graph so that some fix_ctl function can easily find those + * nodes. + * + * If have a function, then no need for EndNode; Exit and ErrorExit + * will play that role. + * + * When everything we analyze was a function there was no pb. We used + * FunHeader as a Topnode and Exit for EndNode but now that we also + * analyse #define body, so we need those nodes. + *) + | TopNode + | EndNode + + | FunHeader of (string * functionType * storage) wrap + + | Decl of declaration + + (* flow_to_ast: cocci: Need the { and } in the control flow graph also + * because the coccier can express patterns containing such { }. + * + * ctl: to make possible the forall (AX, A[...]), have to add more than + * one node sometimes for the same '}' (one in each CFG path) in the graph. + * + * ctl: Morover, the int in the type is here to indicate to what { } + * they correspond. Two pairwise { } share the same number. kind of + * "brace_identifier". Used for debugging or for checks and more importantly, + * needed by CTL engine. + * + * Because of those nodes, there is no equivalent for Compound. + * + * There was a problem with SeqEnd. Some info can be tagged on it + * but there is multiple SeqEnd that correspond to the same '}' even + * if they are in different nodes. Solved by using shared ref + * and allow the "already-tagged" token. + *) + | SeqStart of statement * int * info + | SeqEnd of int * info + + + | ExprStatement of statement * (expression option) wrap + + + | IfHeader of statement * expression wrap + | Else of info + | WhileHeader of statement * expression wrap + | DoHeader of statement * info + | DoWhileTail of expression wrap + | ForHeader of statement * + (exprStatement wrap * exprStatement wrap * exprStatement wrap) + wrap + | SwitchHeader of statement * expression wrap + | MacroIterHeader of statement * (string * argument wrap2 list) wrap + + (* Used to mark the end of if, while, dowhile, for, switch. Later we + * will be able to "tag" some cocci code on this node. + * + * This is because in + * + * - S + foo(); + * + * the S can be anything, including an if, and this is internally + * translated in a series of MetaRuleElem, and the last element is a + * EndStatement, and we must tag foo() to this EndStatement. + * Otherwise, without this last common node, we would tag foo() to 2 + * nodes :( So having a unique node makes it correct, and in + * flow_to_ast we must propagate back this + foo() to the last token + * of an if (maybe a '}', maybe a ';') + * + * The problem is that this stuff should be in transformation.ml, + * but need information available in flow_to_ast, but we dont want + * to polluate both files. + * + * So the choices are + * + * - soluce julia1, extend Ast_c by adding a fake token to the if + * + * - extend Ast with a Skip, and add this next to EndStatement node, + * and do special case in flow_to_ast to start from this node + * (not to get_next EndStatement, but from EndStatement directly) + * and so add a case when have directly a EndStatement node an extract + * the statement from it. + * + * - remonter dans le graphe pour accrocher le foo() non plus au + * EndStatement (qui n'a pas d'equivalent niveau token dans l'ast_c), + * mais au dernier token de la branche Else (ou Then si y'a pas de else). + * + * I first did solution 2 and then when we decided to use ref, + * I use julia'as solution. Have virtual-placeholders, the fakeInfo + * for the if, while, and put this shared ref in the EndStatement. + *) + | EndStatement of info option (* fake_info *) + + | Return of statement * unit wrap + | ReturnExpr of statement * expression wrap + + + (* ------------------------ *) + | DefineHeader of string wrap * define_kind + + | DefineExpr of expression + | DefineType of fullType + | DefineDoWhileZeroHeader of unit wrap + + | Include of inc_file wrap * (include_rel_pos option ref * bool) + + (* obsolete? *) + | MacroTop of string * argument wrap2 list * il + + (* ------------------------ *) + | Case of statement * expression wrap + | Default of statement * unit wrap + + | Continue of statement * unit wrap + | Break of statement * unit wrap + + (* no counter part in cocci *) + | CaseRange of statement * (expression * expression) wrap + | Label of statement * string wrap + | Goto of statement * string wrap + + + | Asm of statement * asmbody wrap + | MacroStmt of statement * unit wrap + + | Ifdef of statement * unit wrap + + (* ------------------------ *) + (* some control nodes *) + | Enter + | Exit + + + (* Redundant nodes, often to mark the end of an if/switch. + * That makes it easier to do later the flow_to_ast. + * update: no more used for the end. see Endstatement. Just used + * to mark the start of the function, as required by julia. + * Maybe would be better to use instead a Enter2. + *) + | Fake + + (* flow_to_ast: In this case, I need to know the order between the children + * of the switch in the graph. + *) + | CaseNode of int + + (* ------------------------ *) + (* for ctl: *) + | TrueNode + | FalseNode + | InLoopNode (* almost equivalent to TrueNode but just for loops *) + + | AfterNode + | FallThroughNode + + | ErrorExit + +type edge = Direct (* Normal | Shadow *) + +type cflow = (node, edge) Ograph_extended.ograph_mutable + + +(* ------------------------------------------------------------------------ *) +let unwrap ((node, info), nodestr) = node +let rewrap ((_node, info), nodestr) node = (node, info), nodestr +let extract_labels ((node, info), nodestr) = info.labels +let extract_bclabels ((node, info), nodestr) = info.bclabels +let extract_is_loop ((node, info), nodestr) = info.is_loop +let extract_is_fake ((node, info), nodestr) = info.is_fake + +let mk_any_node is_fake node labels bclabels nodestr = + let nodestr = + if !Flag_parsing_c.show_flow_labels + then nodestr ^ ("[" ^ (labels +> List.map i_to_s +> join ",") ^ "]") + else nodestr + in + ((node, {labels = labels;is_loop=false;bclabels=bclabels;is_fake=is_fake}), + nodestr) + +let mk_node = mk_any_node false +let mk_fake_node = mk_any_node true (* for duplicated braces *) + +(* ------------------------------------------------------------------------ *) +let first_node g = + g#nodes#tolist +> List.find (fun (i, node) -> + match unwrap node with TopNode -> true | _ -> false + ) +> fst + +let find_node f g = + g#nodes#tolist +> List.find (fun (nodei, node) -> + f (unwrap node)) + +> fst + + +(* remove an intermediate node and redirect the connexion *) +let remove_one_node nodei g = + let preds = (g#predecessors nodei)#tolist in + let succs = (g#successors nodei)#tolist in + assert (not (null preds)); + + preds +> List.iter (fun (predi, Direct) -> + g#del_arc ((predi, nodei), Direct); + ); + succs +> List.iter (fun (succi, Direct) -> + g#del_arc ((nodei, succi), Direct); + ); + + g#del_node nodei; + + (* connect in-nodes to out-nodes *) + preds +> List.iter (fun (pred, Direct) -> + succs +> List.iter (fun (succ, Direct) -> + g#add_arc ((pred, succ), Direct); + ); + ) + + + +(* ------------------------------------------------------------------------ *) + +let extract_fullstatement node = + match unwrap node with + | Decl decl -> + (* new policy. no more considered as a statement *) + (* old: Some (Ast_c.Decl decl, []) *) + None + | MacroStmt (st, _) -> Some st + | MacroIterHeader (st, _) -> Some st + + | Ifdef _ -> None (* other ? *) + + | Include _ + | DefineHeader _ | DefineType _ | DefineExpr _ | DefineDoWhileZeroHeader _ + | MacroTop _ + -> None + + | SeqStart (st,_,_) + | ExprStatement (st, _) + | IfHeader (st, _) + | WhileHeader (st, _) + | DoHeader (st, _) + | ForHeader (st, _) + | SwitchHeader (st, _) + | Return (st, _) + | ReturnExpr (st, _) + (* no counter part in cocci *) + | Label (st, _) + | Case (st,_) + | CaseRange (st, _) + | Default (st, _) + | Goto (st, _) + | Continue (st, _) + | Break (st, _) + | Asm (st,_) + -> Some st + + | TopNode|EndNode + | FunHeader _ + | SeqEnd _ + | Else _ + | EndStatement _ + | DoWhileTail _ + | Enter + | Exit + | Fake + | CaseNode _ + | TrueNode + | FalseNode + | InLoopNode + | AfterNode + | FallThroughNode + | ErrorExit + -> None diff --git a/parsing_c/control_flow_c.mli b/parsing_c/control_flow_c.mli new file mode 100644 index 0000000..0bd1ecf --- /dev/null +++ b/parsing_c/control_flow_c.mli @@ -0,0 +1,104 @@ +open Ast_c + +type node = node1 * string (* For debugging. Used by print_graph *) + and node1 = node2 * nodeinfo + and nodeinfo = { + labels: int list; (* Labels. Trick used for CTL engine *) + bclabels: int list; (* parent of a break or continue node *) + is_loop: bool; + is_fake: bool; + } + and node2 = + | TopNode + | EndNode + + | FunHeader of (string * functionType * storage) wrap + | Decl of declaration + + | SeqStart of statement * int * info + | SeqEnd of int * info + + | ExprStatement of statement * (expression option) wrap + + | IfHeader of statement * expression wrap + | Else of info + | WhileHeader of statement * expression wrap + | DoHeader of statement * info + | DoWhileTail of expression wrap + | ForHeader of statement * + (exprStatement wrap * exprStatement wrap * exprStatement wrap) + wrap + | SwitchHeader of statement * expression wrap + | MacroIterHeader of statement * (string * argument wrap2 list) wrap + + | EndStatement of info option + + | Return of statement * unit wrap + | ReturnExpr of statement * expression wrap + + + (* ------------------------ *) + | DefineHeader of string wrap * define_kind + + | DefineExpr of expression + | DefineType of fullType + | DefineDoWhileZeroHeader of unit wrap + + | Include of inc_file wrap * (include_rel_pos option ref * bool) + + | MacroTop of string * argument wrap2 list * il + + (* ------------------------ *) + | Case of statement * expression wrap + | Default of statement * unit wrap + + | Continue of statement * unit wrap + | Break of statement * unit wrap + + (* no counter part in cocci *) + | CaseRange of statement * (expression * expression) wrap + | Label of statement * string wrap + | Goto of statement * string wrap + + + | Asm of statement * asmbody wrap + | MacroStmt of statement * unit wrap + + | Ifdef of statement * unit wrap + + + (* ------------------------ *) + | Enter + | Exit + | Fake + | CaseNode of int + + (* ------------------------ *) + (* for ctl: *) + | TrueNode + | FalseNode + | InLoopNode + | AfterNode + | FallThroughNode + | ErrorExit + +type edge = Direct + +type cflow = (node, edge) Ograph_extended.ograph_mutable + +val unwrap : node -> node2 +val rewrap : node -> node2 -> node + +val extract_labels : node -> int list +val extract_bclabels : node -> int list +val extract_fullstatement : node -> Ast_c.statement option +val extract_is_loop : node -> bool +val extract_is_fake : node -> bool + +val mk_node: node2 -> int list -> int list -> string -> node +val mk_fake_node: node2 -> int list -> int list -> string -> node + +val first_node : cflow -> Ograph_extended.nodei +val find_node : (node2 -> bool) -> cflow -> Ograph_extended.nodei +(* remove an intermediate node and redirect the connexion *) +val remove_one_node : Ograph_extended.nodei -> cflow -> unit diff --git a/parsing_c/copyright.txt b/parsing_c/copyright.txt new file mode 100644 index 0000000..6a6a6be --- /dev/null +++ b/parsing_c/copyright.txt @@ -0,0 +1,18 @@ +parsing_c library - Yoann Padioleau + +Copyright (C) 2002-2008 Yoann Padioleau + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License (GPL) + version 2 as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + file license.txt for more details. + + +The contents of some files in this directory was derived from external +sources with compatible licenses. The original copyright and license +notice was preserved in the affected files. + diff --git a/parsing_c/credits.txt b/parsing_c/credits.txt new file mode 100644 index 0000000..29a9218 --- /dev/null +++ b/parsing_c/credits.txt @@ -0,0 +1,10 @@ +Thanks to Julia Lawall for the idea to better parse C+CPP by using +indentation information for heuristic-based parsing. Thanks to Julia +again for many other things too long to enumerate. + +Inspiration: + - C grammar found on the web + - FrontC of hughes casse ? + - CIL ? + - EDG ? + diff --git a/parsing_c/flag_parsing_c.ml b/parsing_c/flag_parsing_c.ml new file mode 100644 index 0000000..c1b1b54 --- /dev/null +++ b/parsing_c/flag_parsing_c.ml @@ -0,0 +1,116 @@ +(*****************************************************************************) +(* convenient globals to pass to parse_c.init_defs *) +(*****************************************************************************) +let path = Filename.concat (Sys.getenv "HOME") "coccinelle" +let std_h = ref (Filename.concat path "standard.h") + +let cmdline_flags_macrofile () = + [ + "-macro_file", Arg.Set_string std_h, + " (default=" ^ !std_h ^ ")"; + "-D", Arg.Set_string std_h, + " short option of -macro_file"; + ] + +(*****************************************************************************) +(* verbose *) +(*****************************************************************************) + +let verbose_lexing = ref true +let verbose_parsing = ref true +let verbose_type = ref true + +let filter_msg = ref false +let filter_define_error = ref false +let filter_classic_passed = ref false + +let pretty_print_type_info = ref false + +(* cocci specific *) +let show_flow_labels = ref true + + +let cmdline_flags_verbose () = + [ + "-no_parse_error_msg", Arg.Clear verbose_parsing, " "; + "-no_verbose_parsing", Arg.Clear verbose_parsing , " "; + "-no_verbose_lexing", Arg.Clear verbose_lexing , " "; + "-no_type_error_msg", Arg.Clear verbose_type, " "; + + + "-filter_msg", Arg.Set filter_msg , + " filter some cpp message when the macro is a \"known\" cpp construct"; + "-filter_define_error",Arg.Set filter_define_error," "; + "-filter_classic_passed",Arg.Set filter_classic_passed," "; + ] + + +(*****************************************************************************) +(* debugging *) +(*****************************************************************************) + +let debug_lexer = ref false +let debug_etdt = ref false +let debug_typedef = ref false +let debug_cpp = ref false + +let debug_unparsing = ref false + +let debug_cfg = ref false + +(* "debug C parsing/unparsing", "" *) +let cmdline_flags_debugging () = + [ + "-debug_cpp", Arg.Set debug_cpp, " "; + "-debug_lexer", Arg.Set debug_lexer , " "; + "-debug_etdt", Arg.Set debug_etdt , " "; + "-debug_typedef", Arg.Set debug_typedef, " "; + + "-debug_cfg", Arg.Set debug_cfg , " "; + "-debug_unparsing", Arg.Set debug_unparsing, " "; + ] + +(*****************************************************************************) +(* change algo *) +(*****************************************************************************) + +let ifdef_to_if = ref false +let if0_passing = ref true +let add_typedef_root = ref true + +(* cocci specific *) +let label_strategy_2 = ref false + +let cmdline_flags_algos () = + [ + "-ifdef", Arg.Set ifdef_to_if, + " convert ifdef to if (buggy!)"; + "-noif0_passing", Arg.Clear if0_passing, + " "; + "-noadd_typedef_root", Arg.Clear add_typedef_root, " "; + + "-l1", Arg.Clear label_strategy_2, " "; + ] + +(*****************************************************************************) +(* other *) +(*****************************************************************************) + +(* for compare_c *) +let diff_lines = ref (None : string option) (* number of lines of context *) + +(* for parse_c *) +let use_cache = ref false + +let cmdline_flags_other () = + [ + "-U", Arg.Int (fun n -> diff_lines := Some (Common.i_to_s n)), + " set number of diff context lines"; + + "-use_cache", Arg.Set use_cache, + " use .ast_raw pre-parsed cached C file"; + ] + + +(*****************************************************************************) + diff --git a/parsing_c/lexer_c.mll b/parsing_c/lexer_c.mll new file mode 100644 index 0000000..12727e5 --- /dev/null +++ b/parsing_c/lexer_c.mll @@ -0,0 +1,719 @@ +{ +(* Copyright (C) 2002-2008 Yoann Padioleau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License (GPL) + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * file license.txt for more details. + *) +open Common + +open Parser_c + +open Ast_c (* to factorise tokens, OpAssign, ... *) + +(*****************************************************************************) +(* + * subtil: ocamllex use side effect on lexbuf, so must take care. + * For instance must do + * + * let info = tokinfo lexbuf in + * TComment (info +> tok_add_s (comment lexbuf)) + * + * and not + * + * TComment (tokinfo lexbuf +> tok_add_s (comment lexbuf)) + * + * because of the "wierd" order of evaluation of OCaml. + * + * note: can't use Lexer_parser._lexer_hint here to do different + * things, because now we call the lexer to get all the tokens + * (tokens_all), and then we parse. So we can't have the _lexer_hint + * info here. We can have it only in parse_c. For the same reason, the + * typedef handling here is now useless. + *) +(*****************************************************************************) + +(*****************************************************************************) +(* Wrappers *) +(*****************************************************************************) +let pr2 s = + if !Flag_parsing_c.verbose_lexing + then Common.pr2 s + +(*****************************************************************************) + + +exception Lexical of string + +let tok lexbuf = Lexing.lexeme lexbuf + +let tokinfo lexbuf = + { + pinfo = Ast_c.OriginTok { + Common.charpos = Lexing.lexeme_start lexbuf; + Common.str = Lexing.lexeme lexbuf; + (* info filled in a post-lexing phase *) + Common.line = -1; + Common.column = -1; + Common.file = ""; + }; + (* must generate a new ref each time, otherwise share *) + cocci_tag = ref Ast_c.emptyAnnot; + comments_tag = ref Ast_c.emptyComments; + } + +let tok_add_s s ii = Ast_c.rewrap_str ((Ast_c.str_of_info ii) ^ s) ii + + +(* opti: less convenient, but using a hash is faster than using a match *) +let keyword_table = Common.hash_of_list [ + + "void", (fun ii -> Tvoid ii); + "char", (fun ii -> Tchar ii); + "short", (fun ii -> Tshort ii); + "int", (fun ii -> Tint ii); + "long", (fun ii -> Tlong ii); + "float", (fun ii -> Tfloat ii); + "double", (fun ii -> Tdouble ii); + + "unsigned", (fun ii -> Tunsigned ii); + "signed", (fun ii -> Tsigned ii); + + "auto", (fun ii -> Tauto ii); + "register", (fun ii -> Tregister ii); + "extern", (fun ii -> Textern ii); + "static", (fun ii -> Tstatic ii); + + "const", (fun ii -> Tconst ii); + "volatile", (fun ii -> Tvolatile ii); + + "struct", (fun ii -> Tstruct ii); + "union", (fun ii -> Tunion ii); + "enum", (fun ii -> Tenum ii); + "typedef", (fun ii -> Ttypedef ii); + + "if", (fun ii -> Tif ii); + "else", (fun ii -> Telse ii); + "break", (fun ii -> Tbreak ii); + "continue", (fun ii -> Tcontinue ii); + "switch", (fun ii -> Tswitch ii); + "case", (fun ii -> Tcase ii); + "default", (fun ii -> Tdefault ii); + "for", (fun ii -> Tfor ii); + "do", (fun ii -> Tdo ii); + "while", (fun ii -> Twhile ii); + "return", (fun ii -> Treturn ii); + "goto", (fun ii -> Tgoto ii); + + "sizeof", (fun ii -> Tsizeof ii); + + + (* gccext: cppext: linuxext: synonyms *) + "asm", (fun ii -> Tasm ii); + "__asm__", (fun ii -> Tasm ii); + "__asm", (fun ii -> Tasm ii); + + "inline", (fun ii -> Tinline ii); + "__inline__", (fun ii -> Tinline ii); + "__inline", (fun ii -> Tinline ii); + "INLINE", (fun ii -> Tinline ii); + "_INLINE_", (fun ii -> Tinline ii); + "__INLINE__", (fun ii -> Tinline ii); + + "__attribute__", (fun ii -> Tattribute ii); + "__attribute", (fun ii -> Tattribute ii); + + "typeof", (fun ii -> Ttypeof ii); + "__typeof__", (fun ii -> Ttypeof ii); + + "__signed__", (fun ii -> Tsigned ii); + + "__const__", (fun ii -> Tconst ii); + "__const", (fun ii -> Tconst ii); + + "__volatile__", (fun ii -> Tvolatile ii); + "__volatile", (fun ii -> Tvolatile ii); + + ] + +let error_radix s = + ("numeric " ^ s ^ " constant contains digits beyond the radix:") + +} + +(*****************************************************************************) +let letter = ['A'-'Z' 'a'-'z' '_'] +let digit = ['0'-'9'] + +(* not used for the moment *) +let punctuation = ['!' '"' '#' '%' '&' '\'' '(' ')' '*' '+' ',' '-' '.' '/' ':' + ';' '<' '=' '>' '?' '[' '\\' ']' '^' '{' '|' '}' '~'] +let space = [' ' '\t' '\n' '\r' '\011' '\012' ] +let additionnal = [ ' ' '\b' '\t' '\011' '\n' '\r' '\007' ] +(* 7 = \a = bell in C. this is not the only char allowed !! + * ex @ and $ ` are valid too + *) + +let cchar = (letter | digit | punctuation | additionnal) + +let sp = [' ' '\t']+ +let spopt = [' ' '\t']* + +let dec = ['0'-'9'] +let oct = ['0'-'7'] +let hex = ['0'-'9' 'a'-'f' 'A'-'F'] + +let decimal = ('0' | (['1'-'9'] dec*)) +let octal = ['0'] oct+ +let hexa = ("0x" |"0X") hex+ + + +let pent = dec+ +let pfract = dec+ +let sign = ['-' '+'] +let exp = ['e''E'] sign? dec+ +let real = pent exp | ((pent? '.' pfract | pent '.' pfract? ) exp?) + +let id = letter (letter | digit) * + +(*****************************************************************************) +rule token = parse + + (* ----------------------------------------------------------------------- *) + (* spacing/comments *) + (* ----------------------------------------------------------------------- *) + + (* note: this lexer generate tokens for comments!! so can not give + * this lexer as-is to the parsing function. Must preprocess it, hence + * use techniques like cur_tok ref in parse_c.ml + *) + + | ['\n'] [' ' '\t' '\r' '\011' '\012' ]* + (* starting a new line; the newline character followed by whitespace *) + { TCommentNewline (tokinfo lexbuf) } + | [' ' '\t' '\r' '\011' '\012' ]+ + { TCommentSpace (tokinfo lexbuf) } + | "/*" + { let info = tokinfo lexbuf in + let com = comment lexbuf in + TComment(info +> tok_add_s com) + } + + + (* C++ comment are allowed via gccext, but normally they are deleted by cpp. + * So need this here only when dont call cpp before. + *) + | "//" [^'\r' '\n' '\011']* { TComment (tokinfo lexbuf) } + + (* ----------------------------------------------------------------------- *) + (* cpp *) + (* ----------------------------------------------------------------------- *) + + (* old: + * | '#' { endline lexbuf} // should be line, and not endline + * and endline = parse | '\n' { token lexbuf} + * | _ { endline lexbuf} + *) + + (* todo?: + * have found a # #else in "newfile-2.6.c", legal ? and also a #/* ... + * => just "#" -> token {lexbuf} (that is ignore) + * il y'a 1 #elif sans rien apres + * il y'a 1 #error sans rien apres + * il y'a 2 mov dede, #xxx qui genere du coup exn car + * entouré par des #if 0 + * => make as for comment, call a comment_cpp that when #endif finish the + * comment and if other cpp stuff raise exn + * il y'a environ 10 #if(xxx) ou le ( est collé direct + * il y'a des include"" et include< + * il y'a 1 ` (derriere un #ifndef linux) + *) + + + + (* ---------------------- *) + (* misc *) + (* ---------------------- *) + + (* #pragma pack + * #pragma GCC set_debug_pwd + * #pragma alloc_text + * #pragma options align=packed + * #pragma options align=reset + * #pragma options align=power + * #pragma pack(2) + * etc + *) + | "#pragma" sp [^'\n']* '\n' + { TCommentCpp (CppDirective, tokinfo lexbuf) } + + | "#" [' ' '\t']* "ident" [' ' '\t']+ [^'\n']+ '\n' + + | "#" [' ' '\t']* "line" [' ' '\t']+ [^'\n']+ '\n' + + | "#" [' ' '\t']* "error" [' ' '\t']+ [^'\n']* '\n' + | "#" [' ' '\t']* "warning" [' ' '\t']+ [^'\n']* '\n' + | "#" [' ' '\t']* "abort" [' ' '\t']+ [^'\n']* '\n' + + { TCommentCpp (CppDirective, tokinfo lexbuf) } + + (* only after cpp, ex: # 1 "include/linux/module.h" 1 *) + | "#" sp pent sp '"' [^ '"']* '"' (spopt pent)* spopt '\n' + { TCommentCpp (CppDirective, tokinfo lexbuf) } + + + (* in drivers/char/tpqic02.c, in old version of the kernel *) + | "#" [' ' '\t']* "error" { TCommentCpp (CppDirective,tokinfo lexbuf) } + + + | "#" [' ' '\t']* '\n' { TCommentCpp (CppDirective,tokinfo lexbuf) } + + + (* ---------------------- *) + (* #define, #undef *) + (* ---------------------- *) + + (* the rest of the lexing/parsing of define is done in fix_tokens_define + * where we parse until a TCppEscapedNewline and generate a TDefEol + *) + | "#" [' ' '\t']* "define" { TDefine (tokinfo lexbuf) } + + | "#" [' ' '\t']* "undef" [' ' '\t']+ id + { let info = tokinfo lexbuf in + TCommentCpp (CppDirective,info +> tok_add_s (cpp_eat_until_nl lexbuf)) + } + + + (* could generate separate token for #, ## and then exten grammar, + * but there can be ident in many different places, in expression + * but also in declaration, in function name. So having 3 tokens + * for an ident does not work well with how we add info in + * ast_c. So better to generate just one token, just one info, + * even if have later to reanalyse those tokens and unsplit. + *) + + | ((id as s) "...") + { TDefParamVariadic (s, tokinfo lexbuf) } + + (* cppext: string concatenation *) + | id ([' ''\t']* "##" [' ''\t']* id)+ + { let info = tokinfo lexbuf in + TIdent (tok lexbuf, info) + } + + (* cppext: stringification *) + | "#" id + { let info = tokinfo lexbuf in + TIdent (tok lexbuf, info) + } + + (* cppext: gccext: ##args for variadic macro *) + | "##" [' ''\t']* id + { let info = tokinfo lexbuf in + TIdent (tok lexbuf, info) + } + + (* only in cpp directives normally *) + | "\\" '\n' { TCppEscapedNewline (tokinfo lexbuf) } + + + (* ---------------------- *) + (* #include *) + (* ---------------------- *) + + (* The difference between a local "" and standard <> include is computed + * later in parser_c.mly. So redo a little bit of lexing there. Ugly but + * simpler to generate a single token here. *) + | (("#" [' ''\t']* "include" [' ' '\t']*) as includes) + (('"' ([^ '"']+) '"' | + '<' [^ '>']+ '>' | + ['A'-'Z''_']+ + ) as filename) + { + let info = tokinfo lexbuf in + TInclude (includes, filename, Ast_c.noInIfdef(), info) + } + + (* linuxext: special_for_no_exn: in atm/ambassador.c *) + | "#include UCODE(" [^'\n']+ '\n' + { TCommentCpp (CppDirective, tokinfo lexbuf) } + + + (* ---------------------- *) + (* #ifdef *) + (* ---------------------- *) + + (* '0'+ because sometimes it is a #if 000 *) + | "#" [' ' '\t']* "if" [' ' '\t']* '0'+ (* [^'\n']* '\n' *) + { let info = tokinfo lexbuf in + TIfdefBool (false, info +> tok_add_s (cpp_eat_until_nl lexbuf)) + } + + | "#" [' ' '\t']* "if" [' ' '\t']* '1' [^'\n']* '\n' + { let info = tokinfo lexbuf in + TIfdefBool (true, info) + + } + + | "#" [' ' '\t']* "ifdef" [' ' '\t']* "__cplusplus" [^'\n']* '\n' + { let info = tokinfo lexbuf in + TIfdefMisc (false, info) + } + + + (* linuxext: different possible variations (we not manage all of them): + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2) + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) + #if LINUX_VERSION_CODE < 0x020600 + #if LINUX_VERSION_CODE >= 0x2051c + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + #if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) + #if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \ + # if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) + #if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12) + #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) + #ifndef LINUX_VERSION_CODE + #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,2,0) || \ + (LINUX_VERSION_CODE > ASC_LINUX_VERSION(2,3,0) && \ + LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0)) + #if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE) + #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + # if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) + + *) + + (* linuxext: *) + | "#" spopt "if" sp "("? "LINUX_VERSION_CODE" sp (">=" | ">") sp + { let info = tokinfo lexbuf in + TIfdefVersion (true, info +> tok_add_s (cpp_eat_until_nl lexbuf)) + } + (* linuxext: *) + | "#" spopt "if" sp "!" "("? "LINUX_VERSION_CODE" sp (">=" | ">") sp + | "#" spopt "if" sp ['(']? "LINUX_VERSION_CODE" sp ("<=" | "<") sp + + { let info = tokinfo lexbuf in + TIfdefVersion (false, info +> tok_add_s (cpp_eat_until_nl lexbuf)) + } + + + (* can have some ifdef 0 hence the letter|digit even at beginning of word *) + | "#" [' ''\t']* "ifdef" [' ''\t']+ (letter|digit) ((letter|digit)*) [' ''\t']* + { TIfdef (tokinfo lexbuf) } + | "#" [' ''\t']* "ifndef" [' ''\t']+ (letter|digit) ((letter|digit)*) [' ''\t']* + { TIfdef (tokinfo lexbuf) } + | "#" [' ''\t']* "if" [' ' '\t']+ + { let info = tokinfo lexbuf in + TIfdef (info +> tok_add_s (cpp_eat_until_nl lexbuf)) + } + | "#" [' ' '\t']* "if" '(' + { let info = tokinfo lexbuf in + TIfdef (info +> tok_add_s (cpp_eat_until_nl lexbuf)) + } + + | "#" [' ' '\t']* "elif" [' ' '\t']+ + { let info = tokinfo lexbuf in + TIfdefelif (info +> tok_add_s (cpp_eat_until_nl lexbuf)) + } + + + (* can have #endif LINUX *) + | "#" [' ' '\t']* "endif" [^'\n']* '\n' { TEndif (tokinfo lexbuf) } + (* can be at eof *) + | "#" [' ' '\t']* "endif" { TEndif (tokinfo lexbuf) } + + | "#" [' ' '\t']* "else" [' ' '\t' '\n'] { TIfdefelse (tokinfo lexbuf) } + (* there is a file in 2.6 that have this *) + | "##" [' ' '\t']* "else" [' ' '\t' '\n'] { TIfdefelse (tokinfo lexbuf) } + + + + + (* ----------------------------------------------------------------------- *) + (* C symbols *) + (* ----------------------------------------------------------------------- *) + (* stdC: + ... && -= >= ~ + ; ] + <<= &= -> >> % , < ^ + >>= *= /= ^= & - = { + != ++ << |= ( . > | + %= += <= || ) / ? } + -- == ! * : [ + recent addition: <: :> <% %> + only at processing: %: %:%: # ## + *) + + + | '[' { TOCro(tokinfo lexbuf) } | ']' { TCCro(tokinfo lexbuf) } + | '(' { TOPar(tokinfo lexbuf) } | ')' { TCPar(tokinfo lexbuf) } + | '{' { TOBrace(tokinfo lexbuf) } | '}' { TCBrace(tokinfo lexbuf) } + + | '+' { TPlus(tokinfo lexbuf) } | '*' { TMul(tokinfo lexbuf) } + | '-' { TMinus(tokinfo lexbuf) } | '/' { TDiv(tokinfo lexbuf) } + | '%' { TMod(tokinfo lexbuf) } + + | "++"{ TInc(tokinfo lexbuf) } | "--"{ TDec(tokinfo lexbuf) } + + | "=" { TEq(tokinfo lexbuf) } + + | "-=" { TAssign (OpAssign Minus, (tokinfo lexbuf))} + | "+=" { TAssign (OpAssign Plus, (tokinfo lexbuf))} + | "*=" { TAssign (OpAssign Mul, (tokinfo lexbuf))} + | "/=" { TAssign (OpAssign Div, (tokinfo lexbuf))} + | "%=" { TAssign (OpAssign Mod, (tokinfo lexbuf))} + | "&=" { TAssign (OpAssign And, (tokinfo lexbuf))} + | "|=" { TAssign (OpAssign Or, (tokinfo lexbuf)) } + | "^=" { TAssign(OpAssign Xor, (tokinfo lexbuf))} + | "<<=" {TAssign (OpAssign DecLeft, (tokinfo lexbuf)) } + | ">>=" {TAssign (OpAssign DecRight, (tokinfo lexbuf))} + + | "==" { TEqEq(tokinfo lexbuf) } | "!=" { TNotEq(tokinfo lexbuf) } + | ">=" { TSupEq(tokinfo lexbuf) } | "<=" { TInfEq(tokinfo lexbuf) } + | "<" { TInf(tokinfo lexbuf) } | ">" { TSup(tokinfo lexbuf) } + + | "&&" { TAndLog(tokinfo lexbuf) } | "||" { TOrLog(tokinfo lexbuf) } + | ">>" { TShr(tokinfo lexbuf) } | "<<" { TShl(tokinfo lexbuf) } + | "&" { TAnd(tokinfo lexbuf) } | "|" { TOr(tokinfo lexbuf) } + | "^" { TXor(tokinfo lexbuf) } + | "..." { TEllipsis(tokinfo lexbuf) } + | "->" { TPtrOp(tokinfo lexbuf) } | '.' { TDot(tokinfo lexbuf) } + | ',' { TComma(tokinfo lexbuf) } + | ";" { TPtVirg(tokinfo lexbuf) } + | "?" { TWhy(tokinfo lexbuf) } | ":" { TDotDot(tokinfo lexbuf) } + | "!" { TBang(tokinfo lexbuf) } | "~" { TTilde(tokinfo lexbuf) } + + | "<:" { TOCro(tokinfo lexbuf) } | ":>" { TCCro(tokinfo lexbuf) } + | "<%" { TOBrace(tokinfo lexbuf) } | "%>" { TCBrace(tokinfo lexbuf) } + + + + (* ----------------------------------------------------------------------- *) + (* C keywords and ident *) + (* ----------------------------------------------------------------------- *) + + (* StdC: must handle at least name of length > 509, but can + * truncate to 31 when compare and truncate to 6 and even lowerise + * in the external linkage phase + *) + | letter (letter | digit) * + { let info = tokinfo lexbuf in + let s = tok lexbuf in + Common.profile_code "C parsing.lex_ident" (fun () -> + match Common.optionise (fun () -> Hashtbl.find keyword_table s) + with + | Some f -> f info + + (* parse_typedef_fix. note: now this is no more useful, cos + * as we use tokens_all, it first parse all as an ident and + * later transform an indent in a typedef. so this job is + * now done in parse_c.ml. + * + * if Lexer_parser.is_typedef s + * then TypedefIdent (s, info) + * else TIdent (s, info) + *) + + | None -> TIdent (s, info) + ) + } + + (* ----------------------------------------------------------------------- *) + (* C constant *) + (* ----------------------------------------------------------------------- *) + + | "'" + { let info = tokinfo lexbuf in + let s = char lexbuf in + TChar ((s, IsChar), (info +> tok_add_s (s ^ "'"))) + } + | '"' + { let info = tokinfo lexbuf in + let s = string lexbuf in + TString ((s, IsChar), (info +> tok_add_s (s ^ "\""))) + } + (* wide character encoding, TODO L'toto' valid ? what is allowed ? *) + | 'L' "'" + { let info = tokinfo lexbuf in + let s = char lexbuf in + TChar ((s, IsWchar), (info +> tok_add_s (s ^ "'"))) + } + | 'L' '"' + { let info = tokinfo lexbuf in + let s = string lexbuf in + TString ((s, IsWchar), (info +> tok_add_s (s ^ "\""))) + } + + + (* Take care of the order ? No because lex try the longest match. The + * strange diff between decimal and octal constant semantic is not + * understood too by refman :) refman:11.1.4, and ritchie. + *) + + | (( decimal | hexa | octal) + ( ['u' 'U'] + | ['l' 'L'] + | (['l' 'L'] ['u' 'U']) + | (['u' 'U'] ['l' 'L']) + | (['u' 'U'] ['l' 'L'] ['l' 'L']) + | (['l' 'L'] ['l' 'L']) + )? + ) as x { TInt (x, tokinfo lexbuf) } + + + | (real ['f' 'F']) as x { TFloat ((x, CFloat), tokinfo lexbuf) } + | (real ['l' 'L']) as x { TFloat ((x, CLongDouble), tokinfo lexbuf) } + | (real as x) { TFloat ((x, CDouble), tokinfo lexbuf) } + + | ['0'] ['0'-'9']+ + { pr2 ("LEXER: " ^ error_radix "octal" ^ tok lexbuf); + TCommentMisc (tokinfo lexbuf) + } + | ("0x" |"0X") ['0'-'9' 'a'-'z' 'A'-'Z']+ + { pr2 ("LEXER: " ^ error_radix "hexa" ^ tok lexbuf); + TCommentMisc (tokinfo lexbuf) + } + + + (* !!! to put after other rules !!! otherwise 0xff + * will be parsed as an ident. + *) + | ['0'-'9']+ letter (letter | digit) * + { pr2 ("LEXER: ZARB integer_string, certainly a macro:" ^ tok lexbuf); + TIdent (tok lexbuf, tokinfo lexbuf) + } + +(* gccext: http://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html *) +(* + | "0b" ['0'-'1'] { TInt (((tok lexbuf)(??,??)) +> int_of_stringbits) } + | ['0'-'1']+'b' { TInt (((tok lexbuf)(0,-2)) +> int_of_stringbits) } +*) + + + (*------------------------------------------------------------------------ *) + | eof { EOF (tokinfo lexbuf +> Ast_c.rewrap_str "") } + + | _ + { + if !Flag_parsing_c.verbose_lexing + then pr2_once ("LEXER:unrecognised symbol, in token rule:"^tok lexbuf); + TUnknown (tokinfo lexbuf) + } + + + +(*****************************************************************************) +and char = parse + | (_ as x) "'" { String.make 1 x } + (* todo?: as for octal, do exception beyond radix exception ? *) + | (("\\" (oct | oct oct | oct oct oct)) as x "'") { x } + (* this rule must be after the one with octal, lex try first longest + * and when \7 we want an octal, not an exn. + *) + | (("\\x" ((hex | hex hex))) as x "'") { x } + | (("\\" (_ as v)) as x "'") + { + (match v with (* Machine specific ? *) + | 'n' -> () | 't' -> () | 'v' -> () | 'b' -> () | 'r' -> () + | 'f' -> () | 'a' -> () + | '\\' -> () | '?' -> () | '\'' -> () | '"' -> () + | 'e' -> () (* linuxext: ? *) + | _ -> + pr2 ("LEXER: unrecognised symbol in char:"^tok lexbuf); + ); + x + } + | _ + { pr2 ("LEXER: unrecognised symbol in char:"^tok lexbuf); + tok lexbuf + } + + + +(*****************************************************************************) + +(* todo? factorise code with char ? but not same ending token so hard. *) +and string = parse + | '"' { "" } + | (_ as x) { string_of_char x^string lexbuf} + | ("\\" (oct | oct oct | oct oct oct)) as x { x ^ string lexbuf } + | ("\\x" (hex | hex hex)) as x { x ^ string lexbuf } + | ("\\" (_ as v)) as x + { + (match v with (* Machine specific ? *) + | 'n' -> () | 't' -> () | 'v' -> () | 'b' -> () | 'r' -> () + | 'f' -> () | 'a' -> () + | '\\' -> () | '?' -> () | '\'' -> () | '"' -> () + | 'e' -> () (* linuxext: ? *) + + (* old: "x" -> 10 gccext ? todo ugly, I put a fake value *) + + (* cppext: can have \ for multiline in string too *) + | '\n' -> () + | _ -> pr2 ("LEXER: unrecognised symbol in string:"^tok lexbuf); + ); + x ^ string lexbuf + } + + (* Bug if add following code, cos match also the '"' that is needed + * to finish the string, and so go until end of file. + *) + (* + | [^ '\\']+ + { let cs = lexbuf +> tok +> list_of_string +> List.map Char.code in + cs ++ string lexbuf + } + *) + + + +(*****************************************************************************) + +(* less: allow only char-'*' ? *) +and comment = parse + | "*/" { tok lexbuf } + (* noteopti: *) + | [^ '*']+ { let s = tok lexbuf in s ^ comment lexbuf } + | [ '*'] { let s = tok lexbuf in s ^ comment lexbuf } + | _ + { let s = tok lexbuf in + pr2 ("LEXER: unrecognised symbol in comment:"^s); + s ^ comment lexbuf + } + + + +(*****************************************************************************) + +(* cpp recognize C comments, so when #define xx (yy) /* comment \n ... */ + * then he has already erased the /* comment. So: + * - dont eat the start of the comment otherwiseafterwards we are in the middle + * of a comment and so will problably get a parse error somewhere. + * - have to recognize comments in cpp_eat_until_nl. + *) + +and cpp_eat_until_nl = parse + (* bugfix: *) + | "/*" + { let s = tok lexbuf in + let s2 = comment lexbuf in + let s3 = cpp_eat_until_nl lexbuf in + s ^ s2 ^ s3 + } + | '\\' "\n" { let s = tok lexbuf in s ^ cpp_eat_until_nl lexbuf } + + | "\n" { tok lexbuf } + (* noteopti: + * update: need also deal with comments chars now + *) + | [^ '\n' '\\' '/' '*' ]+ + { let s = tok lexbuf in s ^ cpp_eat_until_nl lexbuf } + | eof { pr2 "LEXER: end of file in cpp_eat_until_nl"; ""} + | _ { let s = tok lexbuf in s ^ cpp_eat_until_nl lexbuf } diff --git a/parsing_c/lexer_parser.ml b/parsing_c/lexer_parser.ml new file mode 100644 index 0000000..1c6eee4 --- /dev/null +++ b/parsing_c/lexer_parser.ml @@ -0,0 +1,111 @@ +(* Copyright (C) 2002-2008 Yoann Padioleau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License (GPL) + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * file license.txt for more details. + *) +open Common + +(* Tricks used to handle the ambiguity in the grammar with the typedef + * which impose a cooperation between the lexer and the parser. + * + * An example by hughes casse: "in the symbol table, local + * definition must replace type definition in order to correctly parse + * local variable in functions body. This is the only way to correctly + * handle this kind of exception, that is, + * + * typedef ... ID; int f(int *p) {int ID; return (ID) * *p;} If ID + * isn't overload, last expression is parsed as a type cast, if it + * isn't, this a multiplication." + * + * Why parse_typedef_fix2 ? Cos when introduce new variable, for + * instance when declare parameters for a function such as int var_t, + * then the var_t must not be lexed as a typedef, so we must disable + * temporaly the typedef mechanism to allow variable with same name as + * a typedef. *) + +(* parse_typedef_fix *) +let _handle_typedef = ref true + +(* parse_typedef_fix2 *) +let enable_typedef () = _handle_typedef := true +let disable_typedef () = _handle_typedef := false + +let is_enabled_typedef () = !_handle_typedef + + + + +type identkind = TypeDefI | IdentI + +(* Ca marche ce code ? on peut avoir un typedef puis un ident puis + * un typedef nested ? oui car Hashtbl (dans scoped_h_env) gere l'historique. + * + * oldsimple: but slow, take 2 secondes on some C files + * let (typedef: typedef list list ref) = ref [[]] + *) +let (_typedef : (string, identkind) Common.scoped_h_env ref) = + ref (Common.empty_scoped_h_env ()) + +let is_typedef s = if !_handle_typedef then + (match (Common.optionise (fun () -> Common.lookup_h_env s !_typedef)) with + | Some TypeDefI -> true + | Some IdentI -> false + | None -> false + ) + else false + +let new_scope() = Common.new_scope_h _typedef +let del_scope() = Common.del_scope_h _typedef + +let add_typedef s = Common.add_in_scope_h _typedef (s, TypeDefI) +let add_ident s = Common.add_in_scope_h _typedef (s, IdentI) + +let add_typedef_root s = + if !Flag_parsing_c.add_typedef_root + then + Hashtbl.add !_typedef.scoped_h s TypeDefI + else add_typedef s (* have far more .failed without this *) + + +(* Used by parse_c when do some error recovery. The parse error may + * have some bad side effects on typedef hash, so recover this. + *) +let _old_state = ref (Common.clone_scoped_h_env !_typedef) + +let save_typedef_state () = + _old_state := Common.clone_scoped_h_env !_typedef + +let restore_typedef_state () = + _typedef := !_old_state + + + + +type lexer_hint = { + mutable parameterDeclaration: bool; + mutable structDefinition: int; (* depth in struct def, 0 = not in struct *) + mutable toplevel: bool; + } + +let default_hint () = { + parameterDeclaration = false; + structDefinition = 0; + toplevel = false; +} + +let _lexer_hint = ref (default_hint()) + + +let lexer_reset_typedef () = + begin + _handle_typedef := true; + _typedef := Common.empty_scoped_h_env (); + _lexer_hint := { (default_hint ()) with toplevel = true; } ; + end + diff --git a/parsing_c/lexer_parser.mli b/parsing_c/lexer_parser.mli new file mode 100644 index 0000000..2f6287f --- /dev/null +++ b/parsing_c/lexer_parser.mli @@ -0,0 +1,39 @@ + +val _handle_typedef : bool ref + +val enable_typedef : unit -> unit +val disable_typedef : unit -> unit +val is_enabled_typedef : unit -> bool + + + +(* private *) +type identkind = TypeDefI | IdentI +val _typedef : (string, identkind) Common.scoped_h_env ref + +val add_ident : string -> unit +val add_typedef : string -> unit +val add_typedef_root : string -> unit + +val new_scope : unit -> unit +val del_scope : unit -> unit + +val is_typedef : string -> bool + +val lexer_reset_typedef : unit -> unit + +val _old_state : (string, identkind) Common.scoped_h_env ref +val save_typedef_state : unit -> unit +val restore_typedef_state : unit -> unit + + +type lexer_hint = { + mutable parameterDeclaration: bool; + mutable structDefinition: int; (* depth in struct def, 0 = not in struct *) +(* mutable statements: bool; *) + mutable toplevel: bool; + } + +val _lexer_hint : lexer_hint ref + +val default_hint : unit -> lexer_hint diff --git a/parsing_c/lib_parsing_c.ml b/parsing_c/lib_parsing_c.ml new file mode 100644 index 0000000..6e3c26e --- /dev/null +++ b/parsing_c/lib_parsing_c.ml @@ -0,0 +1,143 @@ +(* Copyright (C) 2002-2008 Yoann Padioleau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License (GPL) + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * file license.txt for more details. + *) +open Common + +(*****************************************************************************) +(* Abstract line *) +(*****************************************************************************) + +(* todo?: al_expr doit enlever les infos de type ? et doit remettre en + * emptyAnnot ? + *) + +(* drop all info information *) + +let strip_info_visitor _ = + { Visitor_c.default_visitor_c_s with + Visitor_c.kinfo_s = + (* traversal should be deterministic... *) + (let ctr = ref 0 in + (function (k,_) -> + function i -> ctr := !ctr + 1; Ast_c.al_info !ctr i)); + + Visitor_c.kexpr_s = (fun (k,_) e -> + let (e', ty),ii' = k e in + (e', Ast_c.noType()(*ref !ty*)), ii' (* keep type - jll *) + ); + +(* + Visitor_c.ktype_s = (fun (k,_) ft -> + let ft' = k ft in + match Ast_c.unwrap_typeC ft' with + | Ast_c.TypeName (s,_typ) -> + Ast_c.TypeName (s, Ast_c.noTypedefDef()) +> Ast_c.rewrap_typeC ft' + | _ -> ft' + + ); +*) + + } + +let al_expr x = Visitor_c.vk_expr_s (strip_info_visitor()) x +let al_statement x = Visitor_c.vk_statement_s (strip_info_visitor()) x +let al_type x = Visitor_c.vk_type_s (strip_info_visitor()) x +let al_param x = Visitor_c.vk_param_s (strip_info_visitor()) x +let al_params x = Visitor_c.vk_params_s (strip_info_visitor()) x +let al_arguments x = Visitor_c.vk_arguments_s (strip_info_visitor()) x + +let al_program x = List.map (Visitor_c.vk_toplevel_s (strip_info_visitor())) x + +let semi_strip_info_visitor = (* keep position information *) + { Visitor_c.default_visitor_c_s with + Visitor_c.kinfo_s = (fun (k,_) i -> Ast_c.semi_al_info i); + + Visitor_c.kexpr_s = (fun (k,_) e -> + let (e', ty),ii' = k e in + (e', Ast_c.noType()(*ref !ty*)), ii' (* keep type - jll *) + ); + + } + +let semi_al_expr = Visitor_c.vk_expr_s semi_strip_info_visitor +let semi_al_statement = Visitor_c.vk_statement_s semi_strip_info_visitor +let semi_al_type = Visitor_c.vk_type_s semi_strip_info_visitor +let semi_al_param = Visitor_c.vk_param_s semi_strip_info_visitor +let semi_al_params = Visitor_c.vk_params_s semi_strip_info_visitor +let semi_al_arguments = Visitor_c.vk_arguments_s semi_strip_info_visitor + +let semi_al_program = List.map (Visitor_c.vk_toplevel_s semi_strip_info_visitor) + +(*****************************************************************************) +(* Extract infos *) +(*****************************************************************************) + +let extract_info_visitor recursor x = + let globals = ref [] in + let visitor = + { + Visitor_c.default_visitor_c with + Visitor_c.kinfo = (fun (k, _) i -> Common.push2 i globals) + } in + begin + recursor visitor x; + !globals + end + +let ii_of_decl = extract_info_visitor Visitor_c.vk_decl +let ii_of_node = extract_info_visitor Visitor_c.vk_node +let ii_of_expr = extract_info_visitor Visitor_c.vk_expr +let ii_of_stmt = extract_info_visitor Visitor_c.vk_statement +let ii_of_args = extract_info_visitor Visitor_c.vk_args_splitted +let ii_of_type = extract_info_visitor Visitor_c.vk_type +let ii_of_ini = extract_info_visitor Visitor_c.vk_ini +let ii_of_param = extract_info_visitor Visitor_c.vk_param +let ii_of_params = extract_info_visitor Visitor_c.vk_params_splitted +let ii_of_struct_fields = extract_info_visitor Visitor_c.vk_struct_fields +let ii_of_struct_field = extract_info_visitor Visitor_c.vk_struct_field +let ii_of_cst = extract_info_visitor Visitor_c.vk_cst +let ii_of_define_params = + extract_info_visitor Visitor_c.vk_define_params_splitted + +let max_min_ii_by_pos xs = + match xs with + | [] -> failwith "empty list, max_min_ii_by_pos" + | [x] -> (x, x) + | x::xs -> + let pos_leq p1 p2 = (Ast_c.compare_pos p1 p2) = (-1) in + xs +> List.fold_left (fun (maxii,minii) e -> + let maxii' = if pos_leq maxii e then e else maxii in + let minii' = if pos_leq e minii then e else minii in + maxii', minii' + ) (x,x) + +let info_to_fixpos ii = + match Ast_c.pinfo_of_info ii with + Ast_c.OriginTok pi -> Ast_cocci.Real pi.Common.charpos + | Ast_c.ExpandedTok (_,(pi,offset)) -> + Ast_cocci.Virt (pi.Common.charpos,offset) + | Ast_c.FakeTok (_,(pi,offset)) -> + Ast_cocci.Virt (pi.Common.charpos,offset) + | Ast_c.AbstractLineTok pi -> failwith "unexpected abstract" + +let max_min_by_pos xs = + let (i1, i2) = max_min_ii_by_pos xs in + (info_to_fixpos i1, info_to_fixpos i2) + +let lin_col_by_pos xs = + (* put min before max; no idea why they are backwards above *) + let (i2, i1) = max_min_ii_by_pos xs in + let posf x = Ast_c.col_of_info x in + let mposf x = Ast_c.col_of_info x + String.length (Ast_c.str_of_info x) in + (Ast_c.file_of_info i1, + (Ast_c.line_of_info i1, posf i1), (Ast_c.line_of_info i2, mposf i2)) + + diff --git a/parsing_c/license.txt b/parsing_c/license.txt new file mode 100644 index 0000000..c443b8d --- /dev/null +++ b/parsing_c/license.txt @@ -0,0 +1,341 @@ +GPL + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/parsing_c/parse_c.ml b/parsing_c/parse_c.ml new file mode 100644 index 0000000..6450692 --- /dev/null +++ b/parsing_c/parse_c.ml @@ -0,0 +1,1060 @@ +(* Copyright (C) 2002-2008 Yoann Padioleau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License (GPL) + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * file license.txt for more details. + *) + +open Common + +module TH = Token_helpers +module LP = Lexer_parser + +(*****************************************************************************) +(* Wrappers *) +(*****************************************************************************) +let pr2 s = + if !Flag_parsing_c.verbose_parsing + then Common.pr2 s + +(*****************************************************************************) +(* Helpers *) +(*****************************************************************************) + +let lexbuf_to_strpos lexbuf = + (Lexing.lexeme lexbuf, Lexing.lexeme_start lexbuf) + +let token_to_strpos tok = + (TH.str_of_tok tok, TH.pos_of_tok tok) + + +let error_msg_tok tok = + let file = TH.file_of_tok tok in + if !Flag_parsing_c.verbose_parsing + then Common.error_message file (token_to_strpos tok) + else ("error in " ^ file ^ "set verbose_parsing for more info") + + +let print_bad line_error (start_line, end_line) filelines = + if !Flag_parsing_c.verbose_parsing + then + begin + pr2 ("badcount: " ^ i_to_s (end_line - start_line)); + for i = start_line to end_line do + if i = line_error + then pr2 ("BAD:!!!!!" ^ " " ^ filelines.(i)) + else pr2 ("bad:" ^ " " ^ filelines.(i)) + done + end + + + +let mk_info_item2 filename toks = + let buf = Buffer.create 100 in + let s = + (* old: get_slice_file filename (line1, line2) *) + begin + toks +> List.iter (fun tok -> + match TH.pinfo_of_tok tok with + | Ast_c.OriginTok _ -> Buffer.add_string buf (TH.str_of_tok tok) + | Ast_c.AbstractLineTok _ -> raise Impossible + | _ -> () + ); + Buffer.contents buf + end + in + (s, toks) + +let mk_info_item a b = + Common.profile_code "C parsing.mk_info_item" + (fun () -> mk_info_item2 a b) + + + +(*****************************************************************************) +(* Stat *) +(*****************************************************************************) +type parsing_stat = { + filename: filename; + mutable have_timeout: bool; + + mutable correct: int; + mutable bad: int; + + mutable commentized: int; (* by our cpp commentizer *) + + (* if want to know exactly what was passed through, uncomment: + * + * mutable passing_through_lines: int; + * + * it differs from bad by starting from the error to + * the synchro point instead of starting from start of + * function to end of function. + *) + + } + +let default_stat file = { + filename = file; + have_timeout = false; + correct = 0; bad = 0; + commentized = 0; + } + +(* todo: stat per dir ? give in terms of func_or_decl numbers: + * nbfunc_or_decl pbs / nbfunc_or_decl total ?/ + * + * note: cela dit si y'a des fichiers avec des #ifdef dont on connait pas les + * valeurs alors on parsera correctement tout le fichier et pourtant y'aura + * aucune def et donc aucune couverture en fait. + * ==> TODO evaluer les parties non parsé ? + *) + +let print_parsing_stat_list = fun statxs -> + let total = (List.length statxs) in + let perfect = + statxs + +> List.filter (function + {have_timeout = false; bad = 0} -> true | _ -> false) + +> List.length + in + pr2 "\n\n\n---------------------------------------------------------------"; + pr2 "pbs with files:"; + statxs + +> List.filter (function + | {have_timeout = true} -> true + | {bad = n} when n > 0 -> true + | _ -> false) + +> List.iter (function + {filename = file; have_timeout = timeout; bad = n} -> + pr2 (file ^ " " ^ (if timeout then "TIMEOUT" else i_to_s n)); + ); + + pr2 "\n\n\n"; + pr2 "files with lots of tokens passed/commentized:"; + let threshold_passed = 100 in + statxs + +> List.filter (function + | {commentized = n} when n > threshold_passed -> true + | _ -> false) + +> List.iter (function + {filename = file; commentized = n} -> + pr2 (file ^ " " ^ (i_to_s n)); + ); + + pr2 "\n\n\n---------------------------------------------------------------"; + pr2 ( + (sprintf "NB total files = %d; " total) ^ + (sprintf "perfect = %d; " perfect) ^ + (sprintf "pbs = %d; " (statxs +> List.filter (function + {have_timeout = b; bad = n} when n > 0 -> true | _ -> false) + +> List.length)) ^ + (sprintf "timeout = %d; " (statxs +> List.filter (function + {have_timeout = true; bad = n} -> true | _ -> false) + +> List.length)) ^ + (sprintf "=========> %d" ((100 * perfect) / total)) ^ "%" + + ); + let good = statxs +> List.fold_left (fun acc {correct = x} -> acc+x) 0 in + let bad = statxs +> List.fold_left (fun acc {bad = x} -> acc+x) 0 in + let passed = statxs +> List.fold_left (fun acc {commentized = x} -> acc+x) 0 + in + let gf, badf = float_of_int good, float_of_int bad in + let passedf = float_of_int passed in + pr2 ( + (sprintf "nb good = %d, nb passed = %d " good passed) ^ + (sprintf "=========> %f" (100.0 *. (passedf /. gf)) ^ "%") + ); + pr2 ( + (sprintf "nb good = %d, nb bad = %d " good bad) ^ + (sprintf "=========> %f" (100.0 *. (gf /. (gf +. badf))) ^ "%" + ) + ) + + +(*****************************************************************************) +(* Stats on what was passed/commentized *) +(*****************************************************************************) + +let commentized xs = xs +> Common.map_filter (function + | Parser_c.TCommentCpp (cppkind, ii) -> + if !Flag_parsing_c.filter_classic_passed + then + (match cppkind with + | Ast_c.CppOther -> + let s = Ast_c.str_of_info ii in + (match s with + | s when s =~ "KERN_.*" -> None + | s when s =~ "__.*" -> None + | _ -> Some (ii.Ast_c.pinfo) + ) + + | Ast_c.CppDirective | Ast_c.CppAttr | Ast_c.CppMacro + -> None + ) + else Some (ii.Ast_c.pinfo) + + | Parser_c.TCommentMisc ii + | Parser_c.TAction ii + -> + Some (ii.Ast_c.pinfo) + | _ -> + None + ) + +let count_lines_commentized xs = + let line = ref (-1) in + let count = ref 0 in + begin + commentized xs +> + List.iter + (function + Ast_c.OriginTok pinfo | Ast_c.ExpandedTok (_,(pinfo,_)) -> + let newline = pinfo.Common.line in + if newline <> !line + then begin + line := newline; + incr count + end + | _ -> ()); + !count + end + + + +let print_commentized xs = + let line = ref (-1) in + begin + let ys = commentized xs in + ys +> + List.iter + (function + Ast_c.OriginTok pinfo | Ast_c.ExpandedTok (_,(pinfo,_)) -> + let newline = pinfo.Common.line in + let s = pinfo.Common.str in + let s = Str.global_substitute + (Str.regexp "\n") (fun s -> "") s + in + if newline = !line + then prerr_string (s ^ " ") + else begin + if !line = -1 + then pr2_no_nl "passed:" + else pr2_no_nl "\npassed:"; + line := newline; + pr2_no_nl (s ^ " "); + end + | _ -> ()); + if not (null ys) then pr2 ""; + end + + + + +(*****************************************************************************) +(* Lexing only *) +(*****************************************************************************) + +(* called by parse_print_error_heuristic *) +let tokens2 file = + let table = Common.full_charpos_to_pos file in + + Common.with_open_infile file (fun chan -> + let lexbuf = Lexing.from_channel chan in + try + let rec tokens_aux acc = + let tok = Lexer_c.token lexbuf in + (* fill in the line and col information *) + let tok = tok +> TH.visitor_info_of_tok (fun ii -> + { ii with Ast_c.pinfo= + (* could assert pinfo.filename = file ? *) + match Ast_c.pinfo_of_info ii with + Ast_c.OriginTok pi -> + Ast_c.OriginTok (Common.complete_parse_info file table pi) + | Ast_c.ExpandedTok (pi,vpi) -> + Ast_c.ExpandedTok((Common.complete_parse_info file table pi),vpi) + | Ast_c.FakeTok (s,vpi) -> Ast_c.FakeTok (s,vpi) + | Ast_c.AbstractLineTok pi -> failwith "should not occur" + }) + in + + if TH.is_eof tok + then List.rev (tok::acc) + else tokens_aux (tok::acc) + in + tokens_aux [] + with + | Lexer_c.Lexical s -> + failwith ("lexical error " ^ s ^ "\n =" ^ + (Common.error_message file (lexbuf_to_strpos lexbuf))) + | e -> raise e + ) + +let tokens a = + Common.profile_code "C parsing.tokens" (fun () -> tokens2 a) + + +let tokens_string string = + let lexbuf = Lexing.from_string string in + try + let rec tokens_s_aux () = + let tok = Lexer_c.token lexbuf in + if TH.is_eof tok + then [tok] + else tok::(tokens_s_aux ()) + in + tokens_s_aux () + with + | Lexer_c.Lexical s -> failwith ("lexical error " ^ s ^ "\n =" ) + | e -> raise e + + +(*****************************************************************************) +(* Parsing, but very basic, no more used *) +(*****************************************************************************) + +(* + * !!!Those function use refs, and are not reentrant !!! so take care. + * It use globals defined in Lexer_parser. + * + * update: because now lexer return comments tokens, those functions + * may not work anymore. + *) + +let parse file = + let lexbuf = Lexing.from_channel (open_in file) in + let result = Parser_c.main Lexer_c.token lexbuf in + result + + +let parse_print_error file = + let chan = (open_in file) in + let lexbuf = Lexing.from_channel chan in + + let error_msg () = Common.error_message file (lexbuf_to_strpos lexbuf) in + try + lexbuf +> Parser_c.main Lexer_c.token + with + | Lexer_c.Lexical s -> + failwith ("lexical error " ^s^ "\n =" ^ error_msg ()) + | Parsing.Parse_error -> + failwith ("parse error \n = " ^ error_msg ()) + | Semantic_c.Semantic (s, i) -> + failwith ("semantic error " ^ s ^ "\n =" ^ error_msg ()) + | e -> raise e + + + + +(*****************************************************************************) +(* Parsing subelements, useful to debug parser *) +(*****************************************************************************) + +(* + * !!!Those function use refs, and are not reentrant !!! so take care. + * It use globals defined in Lexer_parser. + *) + + +(* old: + * let parse_gen parsefunc s = + * let lexbuf = Lexing.from_string s in + * let result = parsefunc Lexer_c.token lexbuf in + * result + *) + +let parse_gen parsefunc s = + let toks = tokens_string s +> List.filter TH.is_not_comment in + + + (* Why use this lexing scheme ? Why not classically give lexer func + * to parser ? Because I now keep comments in lexer. Could + * just do a simple wrapper that when comment ask again for a token, + * but maybe simpler to use cur_tok technique. + *) + let all_tokens = ref toks in + let cur_tok = ref (List.hd !all_tokens) in + + let lexer_function = + (fun _ -> + if TH.is_eof !cur_tok + then (pr2 "LEXER: ALREADY AT END"; !cur_tok) + else + let v = Common.pop2 all_tokens in + cur_tok := v; + !cur_tok + ) + in + let lexbuf_fake = Lexing.from_function (fun buf n -> raise Impossible) in + let result = parsefunc lexer_function lexbuf_fake in + result + + +let type_of_string = parse_gen Parser_c.type_name +let statement_of_string = parse_gen Parser_c.statement +let expression_of_string = parse_gen Parser_c.expr + +(* ex: statement_of_string "(struct us_data* )psh->hostdata = NULL;" *) + + + + + +(*****************************************************************************) +(* Consistency checking *) +(*****************************************************************************) + +type class_ident = + | CIdent (* can be var, func, field, tag, enum constant *) + | CTypedef + +let str_of_class_ident = function + | CIdent -> "Ident" + | CTypedef -> "Typedef" + +(* + | CMacro + | CMacroString + | CMacroStmt + | CMacroDecl + | CMacroIterator + | CAttr + +(* but take care that must still be able to use '=' *) +type context = InFunction | InEnum | InStruct | InInitializer | InParams +type class_token = + | CIdent of class_ident + + | CComment + | CSpace + | CCommentCpp of cppkind + | CCommentMisc + | CCppDirective + + | COPar + | CCPar + | COBrace + | CCBrace + + | CSymbol + | CReservedKwd (type | decl | qualif | flow | misc | attr) +*) + +(* parse_typedef_fix4 *) +let consistency_checking2 xs = + + (* first phase, gather data *) + let stat = Hashtbl.create 101 in + + (* default value for hash *) + let v1 () = Hashtbl.create 101 in + let v2 () = ref 0 in + + let bigf = { Visitor_c.default_visitor_c with + + Visitor_c.kexpr = (fun (k,bigf) x -> + match Ast_c.unwrap_expr x with + | Ast_c.Ident s -> + stat +> + Common.hfind_default s v1 +> Common.hfind_default CIdent v2 +> + (fun aref -> incr aref) + + | _ -> k x + ); + Visitor_c.ktype = (fun (k,bigf) t -> + match Ast_c.unwrap_typeC t with + | Ast_c.TypeName (s,_typ) -> + stat +> + Common.hfind_default s v1 +> Common.hfind_default CTypedef v2 +> + (fun aref -> incr aref) + + | _ -> k t + ); + } + in + xs +> List.iter (fun (p, info_item) -> Visitor_c.vk_toplevel bigf p); + + + let ident_to_type = ref [] in + + + (* second phase, analyze data *) + stat +> Hashtbl.iter (fun k v -> + let xs = Common.hash_to_list v in + if List.length xs >= 2 + then begin + pr2 ("CONFLICT:" ^ k); + let sorted = xs +> List.sort (fun (ka,va) (kb,vb) -> + if !va = !vb then + (match ka, kb with + | CTypedef, _ -> 1 (* first is smaller *) + | _, CTypedef -> -1 + | _ -> 0 + ) + else compare !va !vb + ) in + let sorted = List.rev sorted in + match sorted with + | [CTypedef, i1;CIdent, i2] -> + pr2 ("transforming some ident in typedef"); + push2 k ident_to_type; + | _ -> + pr2 ("TODO:other transforming?"); + + end + ); + + (* third phase, update ast *) + if (null !ident_to_type) + then xs + else + let bigf = { Visitor_c.default_visitor_c_s with + Visitor_c.kdefineval_s = (fun (k,bigf) x -> + match x with + | Ast_c.DefineExpr e -> + (match e with + | (Ast_c.Ident s, _), ii when List.mem s !ident_to_type -> + let t = (Ast_c.nQ, + (Ast_c.TypeName (s, Ast_c.noTypedefDef()), ii)) in + + Ast_c.DefineType t + | _ -> k x + ) + | _ -> k x + ); + Visitor_c.kexpr_s = (fun (k, bigf) x -> + match x with + | (Ast_c.SizeOfExpr e, tref), isizeof -> + let i1 = tuple_of_list1 isizeof in + (match e with + | (Ast_c.ParenExpr e, _), iiparen -> + (match e with + | (Ast_c.Ident s, _), ii when List.mem s !ident_to_type -> + let (i2, i3) = tuple_of_list2 iiparen in + let t = (Ast_c.nQ, + (Ast_c.TypeName (s, Ast_c.noTypedefDef()), ii)) in + (Ast_c.SizeOfType t, tref), [i1;i2;i3] + + | _ -> k x + ) + | _ -> k x + ) + | _ -> k x + ); + } in + xs +> List.map (fun (p, info_item) -> + Visitor_c.vk_toplevel_s bigf p, info_item + ) + + +let consistency_checking a = + Common.profile_code "C consistencycheck" (fun () -> consistency_checking2 a) + + + +(*****************************************************************************) +(* Error recovery *) +(*****************************************************************************) + +(* todo: do something if find Parser_c.Eof ? *) +let rec find_next_synchro next already_passed = + + (* Maybe because not enough }, because for example an ifdef contains + * in both branch some opening {, we later eat too much, "on deborde + * sur la fonction d'apres". So already_passed may be too big and + * looking for next synchro point starting from next may not be the + * best. So maybe we can find synchro point inside already_passed + * instead of looking in next. + * + * But take care! must progress. We must not stay in infinite loop! + * For instance now I have as a error recovery to look for + * a "start of something", corresponding to start of function, + * but must go beyond this start otherwise will loop. + * So look at premier(external_declaration2) in parser.output and + * pass at least those first tokens. + * + * I have chosen to start search for next synchro point after the + * first { I found, so quite sure we will not loop. *) + + let last_round = List.rev already_passed in + let is_define = + let xs = last_round +> List.filter TH.is_not_comment in + match xs with + | Parser_c.TDefine _::_ -> true + | _ -> false + in + if is_define + then find_next_synchro_define (last_round ++ next) [] + else + + let (before, after) = + last_round +> Common.span (fun tok -> + match tok with + (* by looking at TOBrace we are sure that the "start of something" + * will not arrive too early + *) + | Parser_c.TOBrace _ -> false + | Parser_c.TDefine _ -> false + | _ -> true + ) + in + find_next_synchro_orig (after ++ next) (List.rev before) + + + +and find_next_synchro_define next already_passed = + match next with + | [] -> + pr2 "ERROR-RECOV: end of file while in recovery mode"; + already_passed, [] + | (Parser_c.TDefEOL i as v)::xs -> + pr2 ("ERROR-RECOV: found sync end of #define "^i_to_s(TH.line_of_tok v)); + v::already_passed, xs + | v::xs -> + find_next_synchro_define xs (v::already_passed) + + + + +and find_next_synchro_orig next already_passed = + match next with + | [] -> + pr2 "ERROR-RECOV: end of file while in recovery mode"; + already_passed, [] + + | (Parser_c.TCBrace i as v)::xs when TH.col_of_tok v = 0 -> + pr2 ("ERROR-RECOV: found sync '}' at line "^i_to_s (TH.line_of_tok v)); + + (match xs with + | [] -> raise Impossible (* there is a EOF token normally *) + + (* still useful: now parser.mly allow empty ';' so normally no pb *) + | Parser_c.TPtVirg iptvirg::xs -> + pr2 "ERROR-RECOV: found sync bis, eating } and ;"; + (Parser_c.TPtVirg iptvirg)::v::already_passed, xs + + | Parser_c.TIdent x::Parser_c.TPtVirg iptvirg::xs -> + pr2 "ERROR-RECOV: found sync bis, eating ident, }, and ;"; + (Parser_c.TPtVirg iptvirg)::(Parser_c.TIdent x)::v::already_passed, + xs + + | Parser_c.TCommentSpace sp::Parser_c.TIdent x::Parser_c.TPtVirg iptvirg + ::xs -> + pr2 "ERROR-RECOV: found sync bis, eating ident, }, and ;"; + (Parser_c.TCommentSpace sp):: + (Parser_c.TPtVirg iptvirg):: + (Parser_c.TIdent x):: + v:: + already_passed, + xs + + | Parser_c.TCommentNewline sp::Parser_c.TIdent x::Parser_c.TPtVirg iptvirg + ::xs -> + pr2 "ERROR-RECOV: found sync bis, eating ident, }, and ;"; + (Parser_c.TCommentNewline sp):: + (Parser_c.TPtVirg iptvirg):: + (Parser_c.TIdent x):: + v:: + already_passed, + xs + + | _ -> + v::already_passed, xs + ) + | v::xs when TH.col_of_tok v = 0 && TH.is_start_of_something v -> + pr2 ("ERROR-RECOV: found sync col 0 at line "^ i_to_s(TH.line_of_tok v)); + already_passed, v::xs + + | v::xs -> + find_next_synchro_orig xs (v::already_passed) + + +(*****************************************************************************) +(* Include/Define hacks *) +(*****************************************************************************) + +(* ------------------------------------------------------------------------- *) +(* helpers *) +(* ------------------------------------------------------------------------- *) + +(* used to generate new token from existing one *) +let new_info posadd str ii = + { Ast_c.pinfo = + Ast_c.OriginTok { (Ast_c.parse_info_of_info ii) with + charpos = Ast_c.pos_of_info ii + posadd; + str = str; + column = Ast_c.col_of_info ii + posadd; + }; + (* must generate a new ref each time, otherwise share *) + cocci_tag = ref Ast_c.emptyAnnot; + comments_tag = ref Ast_c.emptyComments; + } + + +let rec comment_until_defeol xs = + match xs with + | [] -> failwith "cant find end of define token TDefEOL" + | x::xs -> + (match x with + | Parser_c.TDefEOL i -> + Parser_c.TCommentCpp (Ast_c.CppDirective, TH.info_of_tok x) + ::xs + | _ -> + Parser_c.TCommentCpp (Ast_c.CppOther, TH.info_of_tok x) + ::comment_until_defeol xs + ) + +let drop_until_defeol xs = + List.tl + (Common.drop_until (function Parser_c.TDefEOL _ -> true | _ -> false) xs) + + + +(* ------------------------------------------------------------------------- *) +(* returns a pair (replaced token, list of next tokens) *) +(* ------------------------------------------------------------------------- *) + +let tokens_include (info, includes, filename, inifdef) = + Parser_c.TIncludeStart (Ast_c.rewrap_str includes info, inifdef), + [Parser_c.TIncludeFilename + (filename, (new_info (String.length includes) filename info)) + ] + +(*****************************************************************************) +(* Parsing default define, standard.h *) +(*****************************************************************************) + +let parse_cpp_define_file file = + let toks = tokens file in + let toks = Parsing_hacks.fix_tokens_define toks in + Parsing_hacks.extract_cpp_define toks + + +(*****************************************************************************) +(* Main entry point *) +(*****************************************************************************) + +type info_item = string * Parser_c.token list + +type program2 = toplevel2 list + and toplevel2 = Ast_c.toplevel * info_item + + +(* The use of local refs (remaining_tokens, passed_tokens, ...) makes + * possible error recovery. Indeed, they allow to skip some tokens and + * still be able to call again the ocamlyacc parser. It is ugly code + * because we cant modify ocamllex and ocamlyacc. As we want some + * extended lexing tricks, we have to use such refs. + * + * Those refs are now also used for my lalr(k) technique. Indeed They + * store the futur and previous tokens that were parsed, and so + * provide enough context information for powerful lex trick. + * + * - passed_tokens_last_ckp stores the passed tokens since last + * checkpoint. Used for NotParsedCorrectly and also for build the + * info_item attached to each program_element. + * - passed_tokens_clean is used for lookahead, in fact for lookback. + * - remaining_tokens_clean is used for lookahead. Now remaining_tokens + * contain some comments and so would make pattern matching difficult + * in lookahead. Hence this variable. We would like also to get rid + * of cpp instruction because sometimes a cpp instruction is between + * two tokens and makes a pattern matching fail. But lookahead also + * transform some cpp instruction (in comment) so can't remove them. + * + * So remaining_tokens, passed_tokens_last_ckp contain comment-tokens, + * whereas passed_tokens_clean and remaining_tokens_clean does not contain + * comment-tokens. + * + * Normally we have: + * toks = (reverse passed_tok) ++ cur_tok ++ remaining_tokens + * after the call to pop2. + * toks = (reverse passed_tok) ++ remaining_tokens + * at the and of the lexer_function call. + * At the very beginning, cur_tok and remaining_tokens overlap, but not after. + * At the end of lexer_function call, cur_tok overlap with passed_tok. + * + * convention: I use "tr" for "tokens refs" + *) + +type tokens_state = { + mutable rest : Parser_c.token list; + mutable rest_clean : Parser_c.token list; + mutable current : Parser_c.token; + (* it's passed since last "checkpoint", not passed from the beginning *) + mutable passed : Parser_c.token list; + mutable passed_clean : Parser_c.token list; +} + +(* Hacked lex. This function use refs passed by parse_print_error_heuristic *) +let rec lexer_function tr = fun lexbuf -> + match tr.rest with + | [] -> pr2 "ALREADY AT END"; tr.current + | v::xs -> + tr.rest <- xs; + tr.current <- v; + + if !Flag_parsing_c.debug_lexer then Common.pr2_gen v; + + if TH.is_comment v + then begin + tr.passed <- v::tr.passed; + lexer_function tr lexbuf + end + else begin + let x = List.hd tr.rest_clean in + tr.rest_clean <- List.tl tr.rest_clean; + assert (x = v); + + (match v with + | Parser_c.TDefine (tok) -> + if not !LP._lexer_hint.LP.toplevel + then begin + pr2_once ("CPP-DEFINE: inside function, I treat it as comment"); + let v' = Parser_c.TCommentCpp (Ast_c.CppDirective,TH.info_of_tok v) + in + tr.passed <- v'::tr.passed; + tr.rest <- comment_until_defeol tr.rest; + tr.rest_clean <- drop_until_defeol tr.rest_clean; + lexer_function tr lexbuf + end + else begin + tr.passed <- v::tr.passed; + tr.passed_clean <- v::tr.passed_clean; + v + end + + | Parser_c.TInclude (includes, filename, inifdef, info) -> + if not !LP._lexer_hint.LP.toplevel + then begin + pr2_once ("CPP-INCLUDE: inside function, I treat it as comment"); + let v = Parser_c.TCommentCpp(Ast_c.CppDirective, info) in + tr.passed <- v::tr.passed; + lexer_function tr lexbuf + end + else begin + let (v,new_tokens) = + tokens_include (info, includes, filename, inifdef) in + let new_tokens_clean = + new_tokens +> List.filter TH.is_not_comment in + + tr.passed <- v::tr.passed; + tr.passed_clean <- v::tr.passed_clean; + tr.rest <- new_tokens ++ tr.rest; + tr.rest_clean <- new_tokens_clean ++ tr.rest_clean; + v + end + + | _ -> + + (* typedef_fix1 *) + let v = match v with + | Parser_c.TIdent (s, ii) -> + if LP.is_typedef s + then Parser_c.TypedefIdent (s, ii) + else Parser_c.TIdent (s, ii) + | x -> x + in + + let v = Parsing_hacks.lookahead (v::tr.rest_clean) tr.passed_clean in + + tr.passed <- v::tr.passed; + + (* the lookahead may have change the status of the token and + * consider it as a comment, for instance some #include are + * turned into comments hence this code. *) + match v with + | Parser_c.TCommentCpp _ -> lexer_function tr lexbuf + | v -> + tr.passed_clean <- v::tr.passed_clean; + v + ) + end + + + +(* note: as now we go in 2 passes, there is first all the error message of + * the lexer, and then the error of the parser. It is no more + * interwinded. + * + * !!!This function use refs, and is not reentrant !!! so take care. + * It use globals defined in Lexer_parser and also the _defs global + * in parsing_hack.ml. + *) + +let parse_print_error_heuristic2 file = + + (* -------------------------------------------------- *) + (* call lexer and get all the tokens *) + (* -------------------------------------------------- *) + LP.lexer_reset_typedef(); + let toks = tokens file in + + let toks = Parsing_hacks.fix_tokens_define toks in + let toks = Parsing_hacks.fix_tokens_cpp toks in + + let filelines = (""::Common.cat file) +> Array.of_list in + let stat = default_stat file in + + let tr = { + rest = toks; + rest_clean = (toks +> List.filter TH.is_not_comment); + current = (List.hd toks); + passed = []; + passed_clean = []; + } in + let lexbuf_fake = Lexing.from_function (fun buf n -> raise Impossible) in + + let rec loop () = + + if not (LP.is_enabled_typedef()) && !Flag_parsing_c.debug_typedef + then pr2 "TYPEDEF:_handle_typedef=false. Not normal if dont come from exn"; + + (* normally have to do that only when come from an exception in which + * case the dt() may not have been done + * TODO but if was in scoped scope ? have to let only the last scope + * so need do a LP.lexer_reset_typedef (); + *) + LP.enable_typedef(); + LP._lexer_hint := { (LP.default_hint ()) with LP.toplevel = true; }; + LP.save_typedef_state(); + + (* todo?: I am not sure that it represents current_line, cos maybe + * tr.current partipated in the previous parsing phase, so maybe tr.current + * is not the first token of the next parsing phase. Same with checkpoint2. + * It would be better to record when we have a } or ; in parser.mly, + * cos we know that they are the last symbols of external_declaration2. + *) + let checkpoint = TH.line_of_tok tr.current in + + tr.passed <- []; + let was_define = ref false in + + let elem = + (try + (* -------------------------------------------------- *) + (* Call parser *) + (* -------------------------------------------------- *) + Parser_c.celem (lexer_function tr) lexbuf_fake + with e -> + begin + (match e with + (* Lexical is no more launched I think *) + | Lexer_c.Lexical s -> + pr2 ("lexical error " ^s^ "\n =" ^ error_msg_tok tr.current) + | Parsing.Parse_error -> + pr2 ("parse error \n = " ^ error_msg_tok tr.current) + | Semantic_c.Semantic (s, i) -> + pr2 ("semantic error " ^s^ "\n ="^ error_msg_tok tr.current) + | e -> raise e + ); + LP.restore_typedef_state(); + let line_error = TH.line_of_tok tr.current in + + (* error recovery, go to next synchro point *) + let (passed', rest') = find_next_synchro tr.rest tr.passed in + tr.rest <- rest'; + tr.passed <- passed'; + + tr.current <- List.hd passed'; + tr.passed_clean <- []; (* enough ? *) + (* with error recovery, rest and rest_clean may not be in sync *) + tr.rest_clean <- (tr.rest +> List.filter TH.is_not_comment); + + let checkpoint2 = TH.line_of_tok tr.current in (* <> line_error *) + + (* was a define ? *) + let xs = tr.passed +> List.rev +> List.filter TH.is_not_comment in + if List.length xs >= 2 + then + (match Common.head_middle_tail xs with + | Parser_c.TDefine _, _, Parser_c.TDefEOL _ -> + was_define := true + | _ -> () + ) + else pr2 "WIERD: lenght list of error recovery tokens < 2 "; + + if !was_define && !Flag_parsing_c.filter_define_error + then () + else print_bad line_error (checkpoint, checkpoint2) filelines; + + + let info_of_bads = Common.map_eff_rev TH.info_of_tok tr.passed in + Ast_c.NotParsedCorrectly info_of_bads + end + ) + in + + (* again not sure if checkpoint2 corresponds to end of bad region *) + let checkpoint2 = TH.line_of_tok tr.current in + let diffline = (checkpoint2 - checkpoint) in + let info = mk_info_item file (List.rev tr.passed) in + + stat.commentized <- stat.commentized + count_lines_commentized (snd info); + (match elem with + | Ast_c.NotParsedCorrectly xs -> + if !was_define && !Flag_parsing_c.filter_define_error + then stat.correct <- stat.correct + diffline + else stat.bad <- stat.bad + diffline + | _ -> stat.correct <- stat.correct + diffline + ); + + (match elem with + | Ast_c.FinalDef x -> [(Ast_c.FinalDef x, info)] + | xs -> (xs, info):: loop () (* recurse *) + ) + in + let v = loop() in + let v = consistency_checking v in + (v, stat) + + +let parse_print_error_heuristic a = + Common.profile_code "C parsing" (fun () -> parse_print_error_heuristic2 a) + +(* alias *) +let parse_c_and_cpp a = parse_print_error_heuristic a + +(*****************************************************************************) +(* Same but faster cos memoize stuff *) +(*****************************************************************************) +let parse_cache file = + if not !Flag_parsing_c.use_cache then parse_print_error_heuristic file + else + let need_no_changed_files = + (* should use Sys.argv.(0), would be safer. *) + [Config.path ^ "/parsing_c/c_parser.cma"; + (* we may also depend now on the semantic patch because + the SP may use macro and so we will disable some of the + macro expansions from standard.h. + *) + !Config.std_h; + ] + in + let need_no_changed_variables = + (* could add some of the flags of flag_parsing_c.ml *) + [] + in + Common.cache_computation_robust + file ".ast_raw" + (need_no_changed_files, need_no_changed_variables) ".depend_raw" + (fun () -> parse_print_error_heuristic file) + + + +(*****************************************************************************) +(*****************************************************************************) + +(* can not be put in parsing_hack, cos then mutually recursive problem as + * we also want to parse the standard.h file. + *) +let init_defs std_h = + if not (Common.lfile_exists std_h) + then pr2 ("warning: Can't find default macro file: " ^ std_h) + else + Parsing_hacks._defs := Common.hash_of_list (parse_cpp_define_file std_h) + ; diff --git a/parsing_c/parse_c.mli b/parsing_c/parse_c.mli new file mode 100644 index 0000000..ef896b5 --- /dev/null +++ b/parsing_c/parse_c.mli @@ -0,0 +1,70 @@ +(* Copyright (C) 2002-2008 Yoann Padioleau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License (GPL) + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * file license.txt for more details. + *) +open Common + +(* The main function is parse_c_and_cpp. It uses globals in Lexer_Parser and + * Parsing_hacks. Especially Parsing_hacks._defs which often comes + * from a standard.h macro file. Cf also init_defs below. + *) + +(* the token list contains now also the comment-tokens *) +type info_item = (string * Parser_c.token list) + +type program2 = toplevel2 list + and toplevel2 = Ast_c.toplevel * info_item + +type parsing_stat = { + filename: filename; + mutable have_timeout: bool; + mutable correct: int; + mutable bad: int; + mutable commentized: int; + } + +(* This is the main function *) +val parse_print_error_heuristic: + filename (*cfile*) -> (program2 * parsing_stat) +val parse_c_and_cpp : (* alias of previous func *) + filename (*cfile*) -> (program2 * parsing_stat) + +val parse_cpp_define_file : + filename -> (string, Parsing_hacks.define_body) assoc + +val init_defs : filename -> unit + + + + + + +val tokens: filename -> Parser_c.token list +val tokens_string: string -> Parser_c.token list + +val parse: filename -> Ast_c.program +val parse_print_error: filename -> Ast_c.program +val parse_gen: + ((Lexing.lexbuf -> Parser_c.token) -> Lexing.lexbuf -> 'a) -> string -> 'a + +(* easy way to build complex Ast elements from simple strings *) +val type_of_string : string -> Ast_c.fullType +val statement_of_string : string -> Ast_c.statement + + +(* use some .ast_raw memoized version, and take care if obsolete *) +val parse_cache: + filename (*cfile*) -> (program2 * parsing_stat) + + +val print_parsing_stat_list: parsing_stat list -> unit +val print_commentized : Parser_c.token list -> unit + + diff --git a/parsing_c/parser_c.mly b/parsing_c/parser_c.mly new file mode 100644 index 0000000..6153e26 --- /dev/null +++ b/parsing_c/parser_c.mly @@ -0,0 +1,1475 @@ +%{ +(* Copyright (C) 2002-2008 Yoann Padioleau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License (GPL) + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * file license.txt for more details. + *) +open Common + +open Ast_c + +module LP = Lexer_parser +open Lexer_parser (* for the fields *) + +open Semantic_c (* Semantic exn *) + + +(*****************************************************************************) +(* Wrappers *) +(*****************************************************************************) +let warning s v = + if !Flag_parsing_c.verbose_parsing + then Common.warning ("PARSING: " ^ s) v + else v + + +let pr2 s = + if !Flag_parsing_c.verbose_parsing + then Common.pr2 s + +(*****************************************************************************) +(* Parse helpers functions *) +(*****************************************************************************) + +(*-------------------------------------------------------------------------- *) +(* Type related *) +(*-------------------------------------------------------------------------- *) + +type shortLong = Short | Long | LongLong + +type decl = { + storageD: storagebis wrap; + typeD: ((sign option) * (shortLong option) * (typeCbis option)) wrap; + qualifD: typeQualifierbis wrap; + inlineD: bool wrap; + (* note: have a full_info: parse_info list; to remember ordering + * between storage, qualifier, type ? well this info is already in + * the Ast_c.info, just have to sort them to get good order *) +} + +let nullDecl = { + storageD = NoSto, []; + typeD = (None, None, None), []; + qualifD = nullQualif; + inlineD = false, []; +} +let fake_pi = Common.fake_parse_info + +let addStorageD = function + | ((x,ii), ({storageD = (NoSto,[])} as v)) -> { v with storageD = (x, [ii]) } + | ((x,ii), ({storageD = (y, ii2)} as v)) -> + if x = y then warning "duplicate storage classes" v + else raise (Semantic ("multiple storage classes", fake_pi)) + +let addInlineD = function + | ((true,ii), ({inlineD = (false,[])} as v)) -> { v with inlineD=(true,[ii])} + | ((true,ii), ({inlineD = (true, ii2)} as v)) -> warning "duplicate inline" v + | _ -> raise Impossible + + +let addTypeD = function + | ((Left3 Signed,ii) ,({typeD = ((Some Signed, b,c),ii2)} as v)) -> + warning "duplicate 'signed'" v + | ((Left3 UnSigned,ii) ,({typeD = ((Some UnSigned,b,c),ii2)} as v)) -> + warning "duplicate 'unsigned'" v + | ((Left3 _,ii), ({typeD = ((Some _,b,c),ii2)} as _v)) -> + raise (Semantic ("both signed and unsigned specified", fake_pi)) + | ((Left3 x,ii), ({typeD = ((None,b,c),ii2)} as v)) -> + {v with typeD = (Some x,b,c),ii ++ ii2} + + | ((Middle3 Short,ii), ({typeD = ((a,Some Short,c),ii2)} as v)) -> + warning "duplicate 'short'" v + + + (* gccext: long long allowed *) + | ((Middle3 Long,ii), ({typeD = ((a,Some Long ,c),ii2)} as v)) -> + { v with typeD = (a, Some LongLong, c),ii++ii2 } + | ((Middle3 Long,ii), ({typeD = ((a,Some LongLong ,c),ii2)} as v)) -> + warning "triplicate 'long'" v + + | ((Middle3 _,ii), ({typeD = ((a,Some _,c),ii2)} as _v)) -> + raise (Semantic ("both long and short specified", fake_pi)) + | ((Middle3 x,ii), ({typeD = ((a,None,c),ii2)} as v)) -> + {v with typeD = (a, Some x,c),ii++ii2} + + | ((Right3 t,ii), ({typeD = ((a,b,Some _),ii2)} as _v)) -> + raise (Semantic ("two or more data types", fake_pi)) + | ((Right3 t,ii), ({typeD = ((a,b,None),ii2)} as v)) -> + {v with typeD = (a,b, Some t),ii++ii2} + + +let addQualif = function + | ({const=true}, ({const=true} as x)) -> warning "duplicate 'const'" x + | ({volatile=true},({volatile=true} as x))-> warning "duplicate 'volatile'" x + | ({const=true}, v) -> {v with const=true} + | ({volatile=true}, v) -> {v with volatile=true} + | _ -> internal_error "there is no noconst or novolatile keyword" + +let addQualifD ((qu,ii), ({qualifD = (v,ii2)} as x)) = + { x with qualifD = (addQualif (qu, v),ii::ii2) } + + +(*-------------------------------------------------------------------------- *) +(* Declaration/Function related *) +(*-------------------------------------------------------------------------- *) + + +(* stdC: type section, basic integer types (and ritchie) + * To understand the code, just look at the result (right part of the PM) + * and go back. + *) +let (fixDeclSpecForDecl: decl -> (fullType * (storage wrap))) = function + {storageD = (st,iist); + qualifD = (qu,iiq); + typeD = (ty,iit); + inlineD = (inline,iinl); + } -> + ( + ((qu, iiq), + (match ty with + | (None,None,None) -> warning "type defaults to 'int'" (defaultInt, []) + | (None, None, Some t) -> (t, iit) + + | (Some sign, None, (None| Some (BaseType (IntType (Si (_,CInt)))))) -> + BaseType(IntType (Si (sign, CInt))), iit + | ((None|Some Signed),Some x,(None|Some(BaseType(IntType (Si (_,CInt)))))) -> + BaseType(IntType (Si (Signed, [Short,CShort; Long, CLong; LongLong, CLongLong] +> List.assoc x))), iit + | (Some UnSigned, Some x, (None| Some (BaseType (IntType (Si (_,CInt))))))-> + BaseType(IntType (Si (UnSigned, [Short,CShort; Long, CLong; LongLong, CLongLong] +> List.assoc x))), iit + | (Some sign, None, (Some (BaseType (IntType CChar)))) -> BaseType(IntType (Si (sign, CChar2))), iit + | (None, Some Long,(Some(BaseType(FloatType CDouble)))) -> BaseType (FloatType (CLongDouble)), iit + + | (Some _,_, Some _) -> + (*mine*) + raise (Semantic ("signed, unsigned valid only for char and int", fake_pi)) + | (_,Some _,(Some(BaseType(FloatType (CFloat|CLongDouble))))) -> + raise (Semantic ("long or short specified with floatint type", fake_pi)) + | (_,Some Short,(Some(BaseType(FloatType CDouble)))) -> + raise (Semantic ("the only valid combination is long double", fake_pi)) + + | (_, Some _, Some _) -> + (* mine *) + raise (Semantic ("long, short valid only for int or float", fake_pi)) + + (* if do short uint i, then gcc say parse error, strange ? it is + * not a parse error, it is just that we dont allow with typedef + * either short/long or signed/unsigned. In fact, with + * parse_typedef_fix2 (with et() and dt()) now I say too parse + * error so this code is executed only when do short struct + * {....} and never with a typedef cos now we parse short uint i + * as short ident ident => parse error (cos after first short i + * pass in dt() mode) *) + )) + ,((st, inline),iist++iinl) + ) + +let fixDeclSpecForParam = function ({storageD = (st,iist)} as r) -> + let ((qu,ty) as v,_st) = fixDeclSpecForDecl r in + match st with + | (Sto Register) -> (v, true), iist + | NoSto -> (v, false), iist + | _ -> + raise + (Semantic ("storage class specified for parameter of function", + fake_pi)) + +let fixDeclSpecForFuncDef x = + let (returnType,storage) = fixDeclSpecForDecl x in + (match fst (unwrap storage) with + | StoTypedef -> + raise (Semantic ("function definition declared 'typedef'", fake_pi)) + | x -> (returnType, storage) + ) + +(* parameter: (this is the context where we give parameter only when + * in func DEFINITION not in funct DECLARATION) We must have a name. + * This function ensure that we give only parameterTypeDecl with well + * formed Classic constructor todo?: do we accept other declaration + * in ? so I must add them to the compound of the deffunc. I dont + * have to handle typedef pb here cos C forbid to do VF f { ... } + * with VF a typedef of func cos here we dont see the name of the + * argument (in the typedef) + *) +let (fixOldCDecl: fullType -> fullType) = fun ty -> + match snd ty with + | ((FunctionType (fullt, (params, (b, iib)))),iifunc) -> + + (* stdC: If the prototype declaration declares a parameter for a + * function that you are defining (it is part of a function + * definition), then you must write a name within the declarator. + * Otherwise, you can omit the name. *) + (match params with + | [((reg, None, ((_qua, (BaseType Void,_)))),_), _] -> + ty + | params -> + (params +> List.iter (function + | (((b, None, _), ii1),ii2) -> + (* if majuscule, then certainly macro-parameter *) + pr2 ("SEMANTIC:parameter name omitted, but I continue"); + | _ -> () + ); + ty) + ) + (* todo? can we declare prototype in the decl or structdef, + ... => length <> but good kan meme *) + | _ -> + (* gcc say parse error but dont see why *) + raise (Semantic ("seems this is not a function", fake_pi)) + + +let fixFunc = function + | (( + (s,iis), + (nQ, (FunctionType (fullt, (params,bool)),iifunc)), + (st,iist) + ), + (cp,iicp)) -> + let iistart = Ast_c.fakeInfo () in + assert (nQ =*= nullQualif); + (match params with + | [((reg, None, ((_qua, (BaseType Void,_)))),_), _] -> () + | params -> + params +> List.iter (function + | (((bool, Some s, fullt), _), _) -> () + | _ -> () + (* failwith "internal errror: fixOldCDecl not good" *) + )); + (* it must be nullQualif,cos parser construct only this*) + (s, (fullt, (params, bool)), st, cp), + ([iis]++iifunc++iicp++[iistart]++iist) + | _ -> + raise + (Semantic + ("you are trying to do a function definition but you dont give " ^ + "any parameter", fake_pi)) + + +(*-------------------------------------------------------------------------- *) +(* parse_typedef_fix2 *) +(*-------------------------------------------------------------------------- *) + +let dt s () = + if !Flag_parsing_c.debug_etdt then pr2 ("<" ^ s); + LP.disable_typedef () + +let et s () = + if !Flag_parsing_c.debug_etdt then pr2 (">" ^ s); + LP.enable_typedef () + + +let fix_add_params_ident = function + | ((s, (nQ, (FunctionType (fullt, (params, bool)),_)), st)) -> + + (match params with + | [((reg, None, ((_qua, (BaseType Void,_)))),_), _] -> () + | params -> + params +> List.iter (function + | (((bool, Some s, fullt), _), _) -> + LP.add_ident s + | _ -> + () + (* failwith "internal errror: fixOldCDecl not good" *) + )) + | _ -> () + +(*-------------------------------------------------------------------------- *) +(* shortcuts *) +(*-------------------------------------------------------------------------- *) + +let mk_e e ii = ((e, Ast_c.noType()), ii) + +%} + +/*(*****************************************************************************)*/ + +/* +(* + * Some tokens are not even used in this file because they are filtered + * in some intermediate phase. But they still must be declared because + * ocamllex may generate them, or some intermediate phase may also + * generate them (like some functions in parsing_hacks.ml) + *) +*/ + +%token TUnknown /*(* unrecognized token *)*/ + +/*(* coupling: Token_helpers.is_real_comment *)*/ +%token TComment TCommentSpace TCommentNewline + +/*(* cppext: extra tokens *)*/ + +%token TDefine +%token <(string * Ast_c.info)> TDefParamVariadic +/*(* disappear after fix_tokens_define *)*/ +%token TCppEscapedNewline +/*(* appear after fix_tokens_define *)*/ +%token TOParDefine +%token <(string * Ast_c.info)> TIdentDefine /*(* same *)*/ +%token TDefEOL /*(* same *)*/ + +/*(* used only in lexer_c, then transformed in comment or splitted in tokens *)*/ +%token <(string * string * bool ref * Ast_c.info)> TInclude +/*(* tokens coming from above, generated in parse_c from TInclude, etc *)*/ +%token <(Ast_c.info * bool ref)> TIncludeStart +%token <(string * Ast_c.info)> TIncludeFilename + + +/*(* coupling: Token_helpers.is_cpp_instruction *)*/ +%token TIfdef TIfdefelse TIfdefelif TEndif +%token <(bool * Ast_c.info)> TIfdefBool TIfdefMisc TIfdefVersion + + +%token TCommentMisc +%token <(Ast_c.cppcommentkind * Ast_c.info)> TCommentCpp + +/*(* appear after fix_tokens_cpp *)*/ + +%token TMacroStmt +/*(* no need value for the moment *)*/ +%token TMacroString +%token <(string * Ast_c.info)> TMacroDecl +%token TMacroDeclConst +%token <(string * Ast_c.info)> TMacroIterator +/*(* %token <(string * Ast_c.info)> TMacroTop *)*/ +/*(* appear after parsing_hack *)*/ +%token TCParEOL + +%token TAction + + +/*(* the normal tokens *)*/ + +%token TInt +%token <(string * Ast_c.floatType) * Ast_c.info> TFloat +%token <(string * Ast_c.isWchar) * Ast_c.info> TChar +%token <(string * Ast_c.isWchar) * Ast_c.info> TString + +%token TIdent TypedefIdent + + +/* +(* Some tokens like TOPar and TCPar are used as synchronisation stuff, + * in parsing_hack.ml. So if define special tokens like TOParDefine and + * TCParEOL, then take care to also modify in Token_helpers + *) +*/ + +%token TOPar TCPar TOBrace TCBrace TOCro TCCro +%token TDot TComma TPtrOp +%token TInc TDec +%token TAssign +%token TEq +%token TWhy TTilde TBang +%token TEllipsis +%token TDotDot + +%token TPtVirg +%token + TOrLog TAndLog TOr TXor TAnd TEqEq TNotEq TInf TSup TInfEq TSupEq + TShl TShr + TPlus TMinus TMul TDiv TMod + +%token + Tchar Tshort Tint Tdouble Tfloat Tlong Tunsigned Tsigned Tvoid + Tauto Tregister Textern Tstatic + Ttypedef + Tconst Tvolatile + Tstruct Tunion Tenum + Tbreak Telse Tswitch Tcase Tcontinue Tfor Tdo Tif Twhile Treturn + Tgoto Tdefault + Tsizeof + +/*(* gccext: extra tokens *)*/ +%token Tasm +%token Tattribute +%token Tinline +%token Ttypeof + + +%token EOF + + +/* operator precedence */ +%nonassoc Tif +%nonassoc Telse + +%left TOrLog +%left TAndLog +%left TOr +%left TXor +%left TAnd +%left TEqEq TNotEq +%left TInf TSup TInfEq TSupEq +%left TShl TShr +%left TPlus TMinus +%left TMul TDiv TMod + +%start main celem statement expr type_name +%type main +%type celem + +%type statement +%type expr +%type type_name + +%% +/*(*************************************************************************)*/ +/* +(* TOC: + * expression + * statement + * declaration, types, initializers, struct, enum + * xxx_list, xxx_opt + * cpp directives + * celem (=~ main) + *) +*/ +/*(*************************************************************************)*/ + +/*(* no more used; now that use error recovery *)*/ + +main: translation_unit EOF { $1 } + +translation_unit: + | external_declaration + { !LP._lexer_hint.toplevel <- true; [$1] } + | translation_unit external_declaration + { !LP._lexer_hint.toplevel <- true; $1 ++ [$2] } + + + +/*(*************************************************************************)*/ +/*(* expr *)*/ +/*(*************************************************************************)*/ + +expr: + | assign_expr { $1 } + | expr TComma assign_expr { mk_e (Sequence ($1,$3)) [$2] } + +/*(* bugfix: in C grammar they put unary_expr, but in fact it must be + * cast_expr, otherwise (int * ) xxx = &yy; is not allowed + *)*/ +assign_expr: + | cond_expr { $1 } + | cast_expr TAssign assign_expr { mk_e(Assignment ($1,fst $2,$3)) [snd $2]} + | cast_expr TEq assign_expr { mk_e(Assignment ($1,SimpleAssign,$3)) [$2]} + +/*(* gccext: allow optional then part hence gcc_opt_expr + * bugfix: in C grammar they put TDotDot cond_expr, but in fact it must be + * assign_expr, otherwise pnp ? x : x = 0x388 is not allowed + *)*/ +cond_expr: + | arith_expr + { $1 } + | arith_expr TWhy gcc_opt_expr TDotDot assign_expr + { mk_e (CondExpr ($1,$3,$5)) [$2;$4] } + + +arith_expr: + | cast_expr { $1 } + | arith_expr TMul arith_expr { mk_e(Binary ($1, Arith Mul, $3)) [$2] } + | arith_expr TDiv arith_expr { mk_e(Binary ($1, Arith Div, $3)) [$2] } + | arith_expr TMod arith_expr { mk_e(Binary ($1, Arith Mod, $3)) [$2] } + | arith_expr TPlus arith_expr { mk_e(Binary ($1, Arith Plus, $3)) [$2] } + | arith_expr TMinus arith_expr { mk_e(Binary ($1, Arith Minus, $3)) [$2] } + | arith_expr TShl arith_expr { mk_e(Binary ($1, Arith DecLeft, $3)) [$2] } + | arith_expr TShr arith_expr { mk_e(Binary ($1, Arith DecRight, $3)) [$2] } + | arith_expr TInf arith_expr { mk_e(Binary ($1, Logical Inf, $3)) [$2] } + | arith_expr TSup arith_expr { mk_e(Binary ($1, Logical Sup, $3)) [$2] } + | arith_expr TInfEq arith_expr { mk_e(Binary ($1, Logical InfEq, $3)) [$2] } + | arith_expr TSupEq arith_expr { mk_e(Binary ($1, Logical SupEq, $3)) [$2] } + | arith_expr TEqEq arith_expr { mk_e(Binary ($1, Logical Eq, $3)) [$2] } + | arith_expr TNotEq arith_expr { mk_e(Binary ($1, Logical NotEq, $3)) [$2] } + | arith_expr TAnd arith_expr { mk_e(Binary ($1, Arith And, $3)) [$2] } + | arith_expr TOr arith_expr { mk_e(Binary ($1, Arith Or, $3)) [$2] } + | arith_expr TXor arith_expr { mk_e(Binary ($1, Arith Xor, $3)) [$2] } + | arith_expr TAndLog arith_expr { mk_e(Binary ($1, Logical AndLog, $3)) [$2] } + | arith_expr TOrLog arith_expr { mk_e(Binary ($1, Logical OrLog, $3)) [$2] } + +cast_expr: + | unary_expr { $1 } + | topar2 type_name tcpar2 cast_expr { mk_e(Cast ($2, $4)) [$1;$3] } + +unary_expr: + | postfix_expr { $1 } + | TInc unary_expr { mk_e(Infix ($2, Inc)) [$1] } + | TDec unary_expr { mk_e(Infix ($2, Dec)) [$1] } + | unary_op cast_expr { mk_e(Unary ($2, fst $1)) [snd $1] } + | Tsizeof unary_expr { mk_e(SizeOfExpr ($2)) [$1] } + | Tsizeof topar2 type_name tcpar2 { mk_e(SizeOfType ($3)) [$1;$2;$4] } + +unary_op: + | TAnd { GetRef, $1 } + | TMul { DeRef, $1 } + | TPlus { UnPlus, $1 } + | TMinus { UnMinus, $1 } + | TTilde { Tilde, $1 } + | TBang { Not, $1 } + /*(* gccext: have that a lot in old kernel to get address of local label. + * cf gcc manual "local labels as values". + *)*/ + | TAndLog { GetRefLabel, $1 } + + + +postfix_expr: + | primary_expr { $1 } + | postfix_expr TOCro expr TCCro + { mk_e(ArrayAccess ($1, $3)) [$2;$4] } + | postfix_expr TOPar argument_list_ne TCPar + { mk_e(FunCall ($1, $3)) [$2;$4] } + | postfix_expr TOPar TCPar { mk_e(FunCall ($1, [])) [$2;$3] } + | postfix_expr TDot ident { mk_e(RecordAccess ($1,fst $3)) [$2;snd $3] } + | postfix_expr TPtrOp ident { mk_e(RecordPtAccess ($1,fst $3)) [$2;snd $3] } + | postfix_expr TInc { mk_e(Postfix ($1, Inc)) [$2] } + | postfix_expr TDec { mk_e(Postfix ($1, Dec)) [$2] } + + /*(* gccext: also called compound literals *)*/ + | topar2 type_name tcpar2 TOBrace TCBrace + { mk_e(Constructor ($2, [])) [$1;$3;$4;$5] } + | topar2 type_name tcpar2 TOBrace initialize_list gcc_comma_opt TCBrace + { mk_e(Constructor ($2, List.rev $5)) ([$1;$3;$4;$7] ++ $6) } + +primary_expr: + | TIdent { mk_e(Ident (fst $1)) [snd $1] } + | TInt { mk_e(Constant (Int (fst $1))) [snd $1] } + | TFloat { mk_e(Constant (Float (fst $1))) [snd $1] } + | TString { mk_e(Constant (String (fst $1))) [snd $1] } + | TChar { mk_e(Constant (Char (fst $1))) [snd $1] } + | TOPar expr TCPar { mk_e(ParenExpr ($2)) [$1;$3] } /*(* forunparser: *)*/ + + /*(* gccext: cppext: *)*/ + | string_elem string_list { mk_e(Constant (MultiString)) ($1 ++ $2) } + + /*(* gccext: allow statement as expressions via ({ statement }) *)*/ + | TOPar compound TCPar { mk_e(StatementExpr ($2)) [$1;$3] } + + + + +/*(* cppext: *)*/ +argument_ne: + | assign_expr { Left $1 } + | parameter_decl { Right (ArgType $1) } + | action_higherordermacro_ne { Right (ArgAction $1) } + +argument: + | assign_expr { Left $1 } + | parameter_decl { Right (ArgType $1) } + | action_higherordermacro { Right (ArgAction $1) } + +action_higherordermacro_ne: + | taction_list_ne + { if null $1 + then ActMisc [Ast_c.fakeInfo()] + else ActMisc $1 + } + +action_higherordermacro: + | taction_list + { if null $1 + then ActMisc [Ast_c.fakeInfo()] + else ActMisc $1 + } + + +/*(*----------------------------*)*/ +/*(* workarounds *)*/ +/*(*----------------------------*)*/ + +/*(* Why this ? Why not s/ident/TIdent ? cos there is multiple namespaces in C, + * so a label can have the same name that a typedef, same for field and tags + * hence sometimes the use of ident instead of TIdent. + *)*/ +ident: + | TIdent { $1 } + | TypedefIdent { $1 } + +identifier: + | TIdent { $1 } + +/*(* would like evalInt $1 but require too much info *)*/ +const_expr: cond_expr { $1 } + + +topar2: TOPar { et "topar2" (); $1 } +tcpar2: TCPar { et "tcpar2" (); $1 (*TODO? et ? sure ? c pas dt plutot ? *) } + + + +/*(*************************************************************************)*/ +/*(* statement *)*/ +/*(*************************************************************************)*/ + +statement: + | labeled { Labeled (fst $1), snd $1 } + | compound { Compound (fst $1), snd $1 } + | expr_statement { ExprStatement(fst $1), snd $1 } + | selection { Selection (fst $1), snd $1 ++ [fakeInfo()] } + | iteration { Iteration (fst $1), snd $1 ++ [fakeInfo()] } + | jump TPtVirg { Jump (fst $1), snd $1 ++ [$2] } + + /*(* gccext: *)*/ + | Tasm TOPar asmbody TCPar TPtVirg { Asm $3, [$1;$2;$4;$5] } + | Tasm Tvolatile TOPar asmbody TCPar TPtVirg { Asm $4, [$1;$2;$3;$5;$6] } + + /*(* cppext: *)*/ + | TMacroStmt { MacroStmt, [$1] } + | TMacroStmt TPtVirg { MacroStmt, [$1;$2] } + + + + +/*(* note that case 1: case 2: i++; would be correctly parsed, but with + * a Case (1, (Case (2, i++))) :( + *)*/ +labeled: + | ident TDotDot statement { Label (fst $1, $3), [snd $1; $2] } + | Tcase const_expr TDotDot statement { Case ($2, $4), [$1; $3] } + | Tcase const_expr TEllipsis const_expr TDotDot statement + { CaseRange ($2, $4, $6), [$1;$3;$5] } /*(* gccext: allow range *)*/ + | Tdefault TDotDot statement { Default $3, [$1; $2] } + +end_labeled: + /*(* gccext: allow toto: } + * generate each 30 shift/Reduce conflicts, mais ca va, ca fait ce qu'il + * faut + *)*/ + | ident TDotDot + { Label (fst $1, (ExprStatement None, [])), [snd $1; $2] } + | Tcase const_expr TDotDot { Case ($2, (ExprStatement None, [])), [$1;$3] } + | Tdefault TDotDot { Default (ExprStatement None, []), [$1; $2] } + + + + + +compound: tobrace compound2 tcbrace { $2, [$1; $3] } + +tobrace: TOBrace { LP.new_scope (); $1 } +tcbrace: TCBrace { LP.del_scope (); $1 } + +/*(* old: +compound2: + | { ([],[]) } + | statement_list { ([], $1) } + | decl_list { ($1, []) } + | decl_list statement_list { ($1,$2) } + +statement_list: stat_or_decl_list { $1 } +*)*/ + + +/* +(* cppext: because of cpp, some stuff looks like declaration but are in + * fact statement but too hard to figure out, and if parse them as + * expression, then we force to have first decls and then exprs, then + * will have a parse error. So easier to let mix decl/statement. + * Moreover it helps to not make such a difference between decl and + * statement for further coccinelle phases to factorize code. +*)*/ +compound2: + | { ([]) } + | stat_or_decl_list { $1 } + +stat_or_decl: + | decl { Decl ($1 Ast_c.LocalDecl), [] } + | statement { $1 } + + /*(* cppext: if -ifdef_to_if is enabled for parsing_hack *)*/ + | TIfdef stat_or_decl_list TIfdefelse stat_or_decl_list TEndif + { Selection (Ifdef ($2, $4)), [$1;$3;$5;fakeInfo()] } + | TIfdef stat_or_decl_list TEndif + { Selection (Ifdef ($2, [])), [$1;$3;fakeInfo()] } + + /*(* gccext: *)*/ + | function_definition { NestedFunc $1, [] } + + + + + + +expr_statement: + | TPtVirg { None, [$1] } + | expr TPtVirg { Some $1, [$2] } + +selection: + | Tif TOPar expr TCPar statement %prec Tif + { If ($3, $5, (ExprStatement None, [])), [$1;$2;$4] } + | Tif TOPar expr TCPar statement Telse statement + { If ($3, $5, $7), [$1;$2;$4;$6] } + | Tswitch TOPar expr TCPar statement + { Switch ($3,$5), [$1;$2;$4] } + +iteration: + | Twhile TOPar expr TCPar statement + { While ($3,$5), [$1;$2;$4] } + | Tdo statement Twhile TOPar expr TCPar TPtVirg + { DoWhile ($2,$5), [$1;$3;$4;$6;$7] } + | Tfor TOPar expr_statement expr_statement TCPar statement + { For ($3,$4,(None, []),$6), [$1;$2;$5]} + | Tfor TOPar expr_statement expr_statement expr TCPar statement + { For ($3,$4,(Some $5, []),$7), [$1;$2;$6] } +/*(* c++ext: for(int i = 0; i < n; i++) + | Tfor TOPar decl expr_statement expr TCPar statement + { pr2 "DECL in for"; + While ($5, $7), [] (* fake ast *) + } +*)*/ + /*(* cppext: *)*/ + | TMacroIterator TOPar argument_list_ne TCPar statement + { MacroIteration (fst $1, $3, $5), [snd $1;$2;$4] } + | TMacroIterator TOPar TCPar statement + { MacroIteration (fst $1, [], $4), [snd $1;$2;$3] } + +/*(* the ';' in the caller grammar rule will be appended to the infos *)*/ +jump: + | Tgoto ident { Goto (fst $2), [$1;snd $2] } + | Tcontinue { Continue, [$1] } + | Tbreak { Break, [$1] } + | Treturn { Return, [$1] } + | Treturn expr { ReturnExpr $2, [$1] } + | Tgoto TMul expr { GotoComputed $3, [$1;$2] } + + + +/*(*----------------------------*)*/ +/*(* gccext: *)*/ +/*(*----------------------------*)*/ +string_elem: + | TString { [snd $1] } + /*(* cppext: ex= printk (KERN_INFO "xxx" UTS_RELEASE) *)*/ + | TMacroString { [$1] } + + +asmbody: + | string_list colon_asm_list { $1, $2 } + | string_list { $1, [] } /*(* in old kernel *)*/ + + +colon_asm: TDotDot colon_option_list { Colon $2, [$1] } + +colon_option: + | TString { ColonMisc, [snd $1] } + | TString TOPar asm_expr TCPar { ColonExpr $3, [snd $1; $2;$4] } + /*(* cppext: certainly a macro *)*/ + | TOCro identifier TCCro TString TOPar asm_expr TCPar + { ColonExpr $6, [$1;snd $2;$3;snd $4; $5; $7 ] } + | identifier { ColonMisc, [snd $1] } + | /*(* empty *)*/ { ColonMisc, [] } + +asm_expr: assign_expr { $1 } + + + +/*(*************************************************************************)*/ +/*(* declaration, types, initializers *)*/ +/*(*************************************************************************)*/ + +decl2: + | decl_spec TPtVirg + { function local -> + let (returnType,storage) = fixDeclSpecForDecl $1 in + let iistart = Ast_c.fakeInfo () in + DeclList ([(None, returnType, unwrap storage, local),[]], + ($2::iistart::snd storage)) + } + | decl_spec init_declarator_list TPtVirg + { function local -> + let (returnType,storage) = fixDeclSpecForDecl $1 in + let iistart = Ast_c.fakeInfo () in + DeclList ( + ($2 +> List.map (fun ((((s,iis),f), ini), iivirg) -> + let ini, iini = + match ini with + | None -> None, [] + | Some (ini, iini) -> Some ini, [iini] + in + if fst (unwrap storage) = StoTypedef + then LP.add_typedef s; + (Some ((s, ini), iis::iini), f returnType, unwrap storage, local), + iivirg + ) + ), ($3::iistart::snd storage)) + } + /*(* cppext: *)*/ + + | TMacroDecl TOPar argument_list TCPar TPtVirg + { function _ -> + MacroDecl ((fst $1, $3), [snd $1;$2;$4;$5;fakeInfo()]) } + | Tstatic TMacroDecl TOPar argument_list TCPar TPtVirg + { function _ -> + MacroDecl ((fst $2, $4), [snd $2;$3;$5;$6;fakeInfo();$1]) } + | Tstatic TMacroDeclConst TMacroDecl TOPar argument_list TCPar TPtVirg + { function _ -> + MacroDecl ((fst $3, $5), [snd $3;$4;$6;$7;fakeInfo();$1;$2])} + + + +decl_spec2: + | storage_class_spec { {nullDecl with storageD = (fst $1, [snd $1]) } } + | type_spec { addTypeD ($1,nullDecl) } + | type_qualif { {nullDecl with qualifD = (fst $1, [snd $1]) } } + | Tinline { {nullDecl with inlineD = (true, [$1]) } } + | storage_class_spec decl_spec2 { addStorageD ($1, $2) } + | type_spec decl_spec2 { addTypeD ($1, $2) } + | type_qualif decl_spec2 { addQualifD ($1, $2) } + | Tinline decl_spec2 { addInlineD ((true, $1), $2) } + +/*(* can simplify by putting all in _opt ? must have at least one otherwise + * decl_list is ambiguous ? (no cos have ';' between decl) + *)*/ + + +storage_class_spec: + | Tstatic { Sto Static, $1 } + | Textern { Sto Extern, $1 } + | Tauto { Sto Auto, $1 } + | Tregister { Sto Register,$1 } + | Ttypedef { StoTypedef, $1 } + +type_spec2: + | Tvoid { Right3 (BaseType Void), [$1] } + | Tchar { Right3 (BaseType (IntType CChar)), [$1]} + | Tint { Right3 (BaseType (IntType (Si (Signed,CInt)))), [$1]} + | Tfloat { Right3 (BaseType (FloatType CFloat)), [$1]} + | Tdouble { Right3 (BaseType (FloatType CDouble)), [$1] } + | Tshort { Middle3 Short, [$1]} + | Tlong { Middle3 Long, [$1]} + | Tsigned { Left3 Signed, [$1]} + | Tunsigned { Left3 UnSigned, [$1]} + | struct_or_union_spec { Right3 (fst $1), snd $1 } + | enum_spec { Right3 (fst $1), snd $1 } + + /* + (* parse_typedef_fix1: cant put: TIdent {} cos it make the grammar + * ambiguous, generates lots of conflicts => we must + * use some tricks: we make the lexer and parser cooperate, cf lexerParser.ml. + * + * parse_typedef_fix2: this is not enough, and you must use + * parse_typedef_fix2 to fully manage typedef problems in grammar. + * + * parse_typedef_fix3: + * + * parse_typedef_fix4: try also to do now some consistency checking in + * Parse_c + *)*/ + | TypedefIdent { Right3 (TypeName (fst $1,Ast_c.noTypedefDef())), [snd $1]} + + | Ttypeof TOPar assign_expr TCPar { Right3 (TypeOfExpr ($3)), [$1;$2;$4] } + | Ttypeof TOPar type_name TCPar { Right3 (TypeOfType ($3)), [$1;$2;$4] } + + +type_qualif: + | Tconst { {const=true ; volatile=false}, $1 } + | Tvolatile { {const=false ; volatile=true}, $1 } + + + +/*(*----------------------------*)*/ +/*(* workarounds *)*/ +/*(*----------------------------*)*/ + +decl: decl2 { et "decl" (); $1 } +decl_spec: decl_spec2 { dt "declspec" (); $1 } +type_spec: type_spec2 { dt "type" (); $1 } + + + + + + +/*(*-----------------------------------------------------------------------*)*/ +/*(* for struct and also typename *)*/ +/*(* cant put decl_spec cos no storage is allowed for field struct *)*/ +spec_qualif_list2: + | type_spec { addTypeD ($1, nullDecl) } + | type_qualif { {nullDecl with qualifD = (fst $1,[snd $1])}} + | type_spec spec_qualif_list { addTypeD ($1,$2) } + | type_qualif spec_qualif_list { addQualifD ($1,$2) } + +spec_qualif_list: spec_qualif_list2 { dt "spec_qualif" (); $1 } + +/*(*-----------------------------------------------------------------------*)*/ +init_declarator: init_declarator2 { dt "init" (); $1 } + +init_declarator2: + | declaratori { ($1, None) } + | declaratori teq initialize { ($1, Some ($3, $2)) } + + + +/*(*----------------------------*)*/ +/*(* workarounds *)*/ +/*(*----------------------------*)*/ +declaratori: + | declarator + { LP.add_ident (fst (fst $1)); $1 } + /*(* gccext: *)*/ + | declarator gcc_asm_decl + { LP.add_ident (fst (fst $1)); $1 } + +teq: TEq { et "teq" (); $1 } + + + +/*(*----------------------------*)*/ +/*(* gccext: *)*/ +/*(*----------------------------*)*/ + +gcc_asm_decl: + | Tasm TOPar asmbody TCPar { } + | Tasm Tvolatile TOPar asmbody TCPar { } + + + + + +/*(*-----------------------------------------------------------------------*)*/ + +/* +(* declarator return a couple: + * (name, partial type (a function to be applied to return type)) + * + * when int* f(int) we must return Func(Pointer int,int) and not + * Pointer (Func(int,int) + *)*/ + +declarator: + | pointer direct_d { (fst $2, fun x -> x +> $1 +> (snd $2) ) } + | direct_d { $1 } + +/*(* so must do int * const p; if the pointer is constant, not the pointee *)*/ +pointer: + | TMul { fun x ->(nQ, (Pointer x, [$1]))} + | TMul type_qualif_list { fun x ->($2.qualifD, (Pointer x, [$1]))} + | TMul pointer { fun x ->(nQ, (Pointer ($2 x),[$1]))} + | TMul type_qualif_list pointer { fun x ->($2.qualifD, (Pointer ($3 x),[$1]))} + +type_qualif_list: + | type_qualif { {nullDecl with qualifD = (fst $1,[snd $1])} } + | type_qualif_list type_qualif { addQualifD ($2,$1) } + +direct_d: + | identifier + { ($1, fun x -> x) } + | TOPar declarator TCPar /*(* forunparser: old: $2 *)*/ + { (fst $2, fun x -> (nQ, (ParenType ((snd $2) x), [$1;$3]))) } + | direct_d tocro tccro + { (fst $1,fun x->(snd $1) (nQ,(Array (None,x), [$2;$3]))) } + | direct_d tocro const_expr tccro + { (fst $1,fun x->(snd $1) (nQ,(Array (Some $3,x), [$2;$4])))} + | direct_d topar tcpar + { (fst $1, + fun x->(snd $1) + (nQ,(FunctionType (x,(([],(false, [])))),[$2;$3]))) + } + | direct_d topar parameter_type_list tcpar + { (fst $1,fun x->(snd $1) (nQ,(FunctionType (x, $3), [$2;$4]))) } + + +parameter_type_list: + | parameter_list { ($1, (false, []))} + | parameter_list TComma TEllipsis { ($1, (true, [$2;$3])) } + + +parameter_decl2: + | decl_spec declaratorp + { let ((returnType,hasreg),iihasreg) = fixDeclSpecForParam $1 + in + (hasreg, Some (fst (fst $2)), ((snd $2) returnType)), + (iihasreg ++ [snd (fst $2)]) + } + | decl_spec abstract_declarator + { let ((returnType,hasreg), iihasreg) = fixDeclSpecForParam $1 + in (hasreg, None, ($2 returnType)), (iihasreg ++ []) + } + | decl_spec + { let ((returnType,hasreg), iihasreg) = fixDeclSpecForParam $1 + in (hasreg, None, returnType), (iihasreg ++ []) + } + + +/*(*----------------------------*)*/ +/*(* workarounds *)*/ +/*(*----------------------------*)*/ + +tocro: TOCro { et "tocro" ();$1 } +tccro: TCCro { dt "tccro" ();$1 } + +topar: TOPar + { LP.new_scope ();et "topar" (); + !LP._lexer_hint.parameterDeclaration <- true; $1 + } +tcpar: TCPar + { LP.del_scope ();dt "tcpar" (); + !LP._lexer_hint.parameterDeclaration <- false; $1 + } + +parameter_decl: parameter_decl2 { et "param" (); $1 } + +declaratorp: declarator + { LP.add_ident (fst (fst $1)); $1 } + + +/*(*-----------------------------------------------------------------------*)*/ +type_name: + | spec_qualif_list + { let (returnType, _) = fixDeclSpecForDecl $1 in returnType } + | spec_qualif_list abstract_declarator + { let (returnType, _) = fixDeclSpecForDecl $1 in $2 returnType } + + +abstract_declarator: + | pointer { $1 } + | direct_abstract_declarator { $1 } + | pointer direct_abstract_declarator { fun x -> x +> $2 +> $1 } + +direct_abstract_declarator: + | TOPar abstract_declarator TCPar /*(* forunparser: old: $2 *)*/ + { (fun x -> (nQ, (ParenType ($2 x), [$1;$3]))) } + + | TOCro TCCro + { fun x -> (nQ, (Array (None, x), [$1;$2]))} + | TOCro const_expr TCCro + { fun x -> (nQ, (Array (Some $2, x), [$1;$3]))} + | direct_abstract_declarator TOCro TCCro + { fun x ->$1 (nQ, (Array (None, x), [$2;$3])) } + | direct_abstract_declarator TOCro const_expr TCCro + { fun x ->$1 (nQ, (Array (Some $3,x), [$2;$4])) } + | TOPar TCPar + { fun x -> (nQ, (FunctionType (x, ([], (false, []))), [$1;$2])) } + | TOPar parameter_type_list TCPar + { fun x -> (nQ, (FunctionType (x, $2), [$1;$3]))} + | direct_abstract_declarator TOPar TCPar + { fun x ->$1 (nQ, (FunctionType (x, (([], (false, [])))),[$2;$3])) } + | direct_abstract_declarator TOPar parameter_type_list TCPar + { fun x -> $1 (nQ, (FunctionType (x, $3), [$2;$4])) } + +/*(*-----------------------------------------------------------------------*)*/ +initialize: + | assign_expr + { InitExpr $1, [] } + | tobrace_ini initialize_list gcc_comma_opt_struct TCBrace + { InitList (List.rev $2), [$1;$4]++$3 } + | tobrace_ini TCBrace + { InitList [], [$1;$2] } /*(* gccext: *)*/ + + +/* +(* opti: This time we use the weird order of non-terminal which requires in + * the "caller" to do a List.rev cos quite critical. With this wierd order it + * allows yacc to use a constant stack space instead of exploding if we would + * do a 'initialize2 Tcomma initialize_list'. + *) +*/ +initialize_list: + | initialize2 { [$1, []] } + | initialize_list TComma initialize2 { ($3, [$2])::$1 } + + +/*(* gccext: condexpr and no assign_expr cos can have ambiguity with comma *)*/ +initialize2: + | cond_expr + { InitExpr $1, [] } + | tobrace_ini initialize_list gcc_comma_opt_struct TCBrace + { InitList (List.rev $2), [$1;$4]++$3 } + | tobrace_ini TCBrace + { InitList [], [$1;$2] } + + /*(* gccext: labeled elements, a.k.a designators *)*/ + | designator_list TEq initialize2 + { InitDesignators ($1, $3), [$2] } + + /*(* gccext: old format *)*/ + | ident TDotDot initialize2 + { InitFieldOld (fst $1, $3), [snd $1; $2] } /*(* in old kernel *)*/ + | TOCro const_expr TCCro initialize2 + { InitIndexOld ($2, $4), [$1;$3] } + +/*(* they can be nested, can have a .x.[3].y *)*/ +designator: + | TDot ident + { DesignatorField (fst $2), [$1;snd $2] } + | TOCro const_expr TCCro + { DesignatorIndex ($2), [$1;$3] } + | TOCro const_expr TEllipsis const_expr TCCro + { DesignatorRange ($2, $4), [$1;$3;$5] } + + +/*(*----------------------------*)*/ +/*(* workarounds *)*/ +/*(*----------------------------*)*/ + +gcc_comma_opt_struct: + | TComma { [$1] } + | /*(* empty *)*/ { [Ast_c.fakeInfo() +> Ast_c.rewrap_str ","] } + + +tobrace_ini: TOBrace { !LP._lexer_hint.toplevel <- false; $1 } + + + + + + +/*(*-----------------------------------------------------------------------*)*/ +s_or_u_spec2: + | struct_or_union ident tobrace_struct struct_decl_list_gcc tcbrace_struct + { StructUnion (fst $1, Some (fst $2), $4), [snd $1;snd $2;$3;$5] } + | struct_or_union tobrace_struct struct_decl_list_gcc tcbrace_struct + { StructUnion (fst $1, None, $3), [snd $1;$2;$4] } + | struct_or_union ident + { StructUnionName (fst $1, fst $2), [snd $1;snd $2] } + +struct_or_union2: + | Tstruct { Struct, $1 } + | Tunion { Union, $1 } + + + +struct_decl2: + | spec_qualif_list struct_declarator_list TPtVirg + { + let (returnType,storage) = fixDeclSpecForDecl $1 in + if fst (unwrap storage) <> NoSto + then internal_error "parsing dont allow this"; + + FieldDeclList ($2 +> (List.map (fun (f, iivirg) -> + f returnType, iivirg)) + ), [$3] + (* dont need to check if typedef or func initialised cos + * grammar dont allow typedef nor initialiser in struct + *) + } + + + | spec_qualif_list TPtVirg + { + (* gccext: allow empty elements if it is a structdef or enumdef *) + let (returnType,storage) = fixDeclSpecForDecl $1 in + if fst (unwrap storage) <> NoSto + then internal_error "parsing dont allow this"; + + FieldDeclList [(Simple (None, returnType), []) , []], [$2] + } + | TPtVirg { EmptyField, [$1] } + + + +struct_declarator: + | declaratorsd + { (fun x -> Simple (Some (fst (fst $1)), (snd $1) x), [snd (fst $1)]) } + | dotdot const_expr2 + { (fun x -> BitField (None, x, $2), [$1]) } + | declaratorsd dotdot const_expr2 + { (fun x -> BitField (Some (fst(fst $1)), + ((snd $1) x), + $3), + [snd (fst $1);$2]) + } + + +/*(*----------------------------*)*/ +/*(* workarounds *)*/ +/*(*----------------------------*)*/ +tobrace_struct: TOBrace + { !LP._lexer_hint.toplevel <- false; + !LP._lexer_hint.structDefinition <- !LP._lexer_hint.structDefinition +1; + $1 + } +tcbrace_struct: TCBrace + { + !LP._lexer_hint.structDefinition <- !LP._lexer_hint.structDefinition -1; + $1 + } + +declaratorsd: declarator + { (*also ? LP.add_ident (fst (fst $1)); *) $1 } + + + +struct_or_union_spec: s_or_u_spec2 { dt "su" (); $1 } +struct_or_union: struct_or_union2 { et "su" (); $1 } +struct_decl: struct_decl2 { et "struct" (); $1 } + +dotdot: TDotDot { et "dotdot" (); $1 } +const_expr2: const_expr { dt "const_expr2" (); $1 } + +struct_decl_list_gcc: + | struct_decl_list { $1 } + | /*(* empty *)*/ { [] } /*(* gccext: allow empty struct *)*/ + + +/*(*-----------------------------------------------------------------------*)*/ +enum_spec: + | Tenum tobrace_enum enumerator_list gcc_comma_opt TCBrace + { Enum (None, $3), [$1;$2;$5] ++ $4 } + | Tenum ident tobrace_enum enumerator_list gcc_comma_opt TCBrace + { Enum (Some (fst $2), $4), [$1; snd $2; $3;$6] ++ $5 } + | Tenum ident + { EnumName (fst $2), [$1; snd $2] } + +enumerator: + | idente { (fst $1, None), [snd $1] } + | idente TEq const_expr { (fst $1, Some $3), [snd $1; $2] } + + + +/*(*----------------------------*)*/ +/*(* workarounds *)*/ +/*(*----------------------------*)*/ + +idente: ident { LP.add_ident (fst $1); $1 } + +tobrace_enum: TOBrace { !LP._lexer_hint.toplevel <- false; $1 } + + + +/*(*************************************************************************)*/ +/*(* xxx_list, xxx_opt *)*/ +/*(*************************************************************************)*/ + + +/*(* +decl_list: + | decl { [$1] } + | decl_list decl { $1 ++ [$2] } + +statement_list: + | statement { [$1] } + | statement_list statement { $1 ++ [$2] } +*)*/ + +stat_or_decl_list: + | stat_or_decl { [$1] } + | end_labeled { [Labeled (fst $1), snd $1] } + | stat_or_decl stat_or_decl_list { $1 :: $2 } + + + + +string_list: + | string_elem { $1 } + | string_list string_elem { $1 ++ $2 } + +colon_asm_list: + | colon_asm { [$1] } + | colon_asm_list colon_asm { $1 ++ [$2] } + +colon_option_list: + | colon_option { [$1, []] } + | colon_option_list TComma colon_option { $1 ++ [$3, [$2]] } + + + +argument_list_ne: + | argument_ne { [$1, []] } + | argument_list_ne TComma argument { $1 ++ [$3, [$2]] } + +argument_list: + | argument { [$1, []] } + | argument_list TComma argument { $1 ++ [$3, [$2]] } + +/*(* +expression_list: + | assign_expr { [$1, []] } + | expression_list TComma assign_expr { $1 ++ [$3, [$2]] } +*)*/ + + +struct_decl_list: + | struct_decl { [$1] } + | struct_decl_list struct_decl { $1 ++ [$2] } + + +struct_declarator_list: + | struct_declarator { [$1, []] } + | struct_declarator_list TComma struct_declarator { $1 ++ [$3, [$2]] } + + +enumerator_list: + | enumerator { [$1, []] } + | enumerator_list TComma enumerator { $1 ++ [$3, [$2]] } + + +init_declarator_list: + | init_declarator { [$1, []] } + | init_declarator_list TComma init_declarator { $1 ++ [$3, [$2]] } + + +parameter_list: + | parameter_decl { [$1, []] } + | parameter_list TComma parameter_decl { $1 ++ [$3, [$2]] } + +taction_list_ne: + | TAction { [$1] } + | TAction taction_list_ne { $1 :: $2 } + +taction_list: + | { [] } + | TAction taction_list { $1 :: $2 } + +param_define_list: + | /*(* empty *)*/ { [] } + | param_define { [$1, []] } + | param_define_list TComma param_define { $1 ++ [$3, [$2]] } + +designator_list: + | designator { [$1] } + | designator_list designator { $1 ++ [$2] } + + +/*(* gccext: which allow a trailing ',' in enum, as in perl *)*/ +gcc_comma_opt: + | TComma { [$1] } + | /*(* empty *)*/ { [] } + +/*(* +gcc_opt_virg: + | TPtVirg { } + | { } +*)*/ + +gcc_opt_expr: + | expr { Some $1 } + | /*(* empty *)*/ { None } + +/*(* +opt_ptvirg: + | TPtVirg { [$1] } + | { [] } +*)*/ + + +/*(*************************************************************************)*/ +/*(* cpp directives *)*/ +/*(*************************************************************************)*/ + +/*(* cppext: *)*/ +cpp_directive: + + | identifier TOPar argument_list TCPar TPtVirg + { MacroTop (fst $1, $3, [snd $1;$2;$4;$5]) } + + /*(* TCParEOL to fix the end-of-stream bug of ocamlyacc *)*/ + | identifier TOPar argument_list TCParEOL + { MacroTop (fst $1, $3, [snd $1;$2;$4;fakeInfo()]) } + + /*(* ex: EXPORT_NO_SYMBOLS; *)*/ + | identifier TPtVirg { EmptyDef [snd $1;$2] } + + | TIncludeStart TIncludeFilename + { + let (i1, in_ifdef) = $1 in + let (s, i2) = $2 in + + (* redo some lexing work :( *) + let inc_file = + match () with + | _ when s =~ "^\"\\(.*\\)\"$" -> + Local (Common.split "/" (matched1 s)) + | _ when s =~ "^\\<\\(.*\\)\\>$" -> + NonLocal (Common.split "/" (matched1 s)) + | _ -> + Wierd s + in + Include ((inc_file, [i1;i2]), (Ast_c.noRelPos(), !in_ifdef)) + } + + | TDefine TIdentDefine define_val TDefEOL + { Define ((fst $2, [$1; snd $2;$4]), (DefineVar, $3)) } + + /* + (* The TOParDefine is introduced to avoid ambiguity with previous rules. + * A TOParDefine is a TOPar that was just next to the ident. + *)*/ + | TDefine TIdentDefine TOParDefine param_define_list TCPar define_val TDefEOL + { Define + ((fst $2, [$1; snd $2;$7]), + (DefineFunc ($4, [$3;$5]), $6)) + } + + +/*(* perhaps better to use assign_expr ? but in that case need + * do a assign_expr_of_string in parse_c + *)*/ +define_val: + | expr { DefineExpr $1 } + | statement { DefineStmt $1 } + | decl { DefineStmt (Decl ($1 Ast_c.NotLocalDecl), []) } + | TypedefIdent { DefineType (nQ,(TypeName(fst $1,noTypedefDef()),[snd $1]))} + | function_definition { DefineFunction $1 } + + | Tdo statement Twhile TOPar TInt TCPar + { + if fst $5 <> "0" + then pr2 "WIERD: in macro and have not a while(0)"; + DefineDoWhileZero ($2, [$1;$3;$4;snd $5;$6]) + } + | /*(* empty *)*/ { DefineEmpty } + +param_define: + | identifier { fst $1, [snd $1] } + | TypedefIdent { fst $1, [snd $1] } + | TDefParamVariadic { fst $1, [snd $1] } + | TEllipsis { "...", [$1] } + /*(* they reuse keywords :( *)*/ + | Tregister { "register", [$1] } + + +/*(*************************************************************************)*/ +/*(* celem *)*/ +/*(*************************************************************************)*/ + +external_declaration: + | function_definition { Definition $1 } + | decl { Declaration ($1 Ast_c.NotLocalDecl) } + +function_definition: function_def { fixFunc $1 } + +function_def: start_fun compound { LP.del_scope(); ($1, $2) } + +start_fun: start_fun2 + { LP.new_scope(); + fix_add_params_ident $1; + !LP._lexer_hint.toplevel <- false; + $1 + } + +start_fun2: decl_spec declaratorfd + { let (returnType,storage) = fixDeclSpecForFuncDef $1 in + (fst $2, fixOldCDecl ((snd $2) returnType) , storage) + } + +celem: + | external_declaration { $1 } + | cpp_directive { $1 } + + /*(* can have asm declaration at toplevel *)*/ + | Tasm TOPar asmbody TCPar TPtVirg { EmptyDef [] } + + /* + (* in ~/kernels/src/linux-2.5.2/drivers/isdn/hisax/isdnl3.c sometimes + * the function ends with }; instead of just } + * can also remove this rule and report "parse error" pb to morton + *)*/ + | TPtVirg { EmptyDef [$1] } + + + | EOF { FinalDef $1 } + + +/*(*----------------------------*)*/ +/*(* workarounds *)*/ +/*(*----------------------------*)*/ +declaratorfd: declarator { et "declaratorfd" (); $1 } + + diff --git a/parsing_c/parsing_hacks.ml b/parsing_c/parsing_hacks.ml new file mode 100644 index 0000000..af59c37 --- /dev/null +++ b/parsing_c/parsing_hacks.ml @@ -0,0 +1,2149 @@ +(* Copyright (C) 2002-2008 Yoann Padioleau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License (GPL) + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * file license.txt for more details. + *) + +open Common + +module TH = Token_helpers +module LP = Lexer_parser + +open Parser_c + +let acc_map f l = + let rec loop acc = function + [] -> List.rev acc + | x::xs -> loop ((f x)::acc) xs in + loop [] l + +(*****************************************************************************) +(* Some debugging functions *) +(*****************************************************************************) + +let pr2 s = + if !Flag_parsing_c.verbose_parsing + then Common.pr2 s + +let pr2_cpp s = + if !Flag_parsing_c.debug_cpp + then Common.pr2_once ("CPP-" ^ s) + + +(* In the following, there are some harcoded names of types or macros + * but they are not used by our heuristics! They are just here to + * enable to detect false positive by printing only the typedef/macros + * that we don't know yet. If we print everything, then we can easily + * get lost with too much verbose tracing information. So those + * functions "filter" some messages. So our heuristics are still good, + * there is no more (or not that much) hardcoded linux stuff. + *) + +let msg_gen cond is_known printer s = + if cond + then + if not (!Flag_parsing_c.filter_msg) + then printer s + else + if not (is_known s) + then printer s + + + + + +(* note: cant use partial application with let msg_typedef = + * because it would compute msg_typedef at compile time when + * the flag debug_typedef is always false + *) +let msg_typedef s = + msg_gen (!Flag_parsing_c.debug_typedef) + (fun s -> + (match s with + | "u_char" | "u_short" | "u_int" | "u_long" + | "u8" | "u16" | "u32" | "u64" + | "s8" | "s16" | "s32" | "s64" + | "__u8" | "__u16" | "__u32" | "__u64" + -> true + + | "acpi_handle" + | "acpi_status" + -> true + + | "FILE" + | "DIR" + -> true + + | s when s =~ ".*_t$" -> true + | _ -> false + ) + ) + (fun s -> + pr2_cpp ("TYPEDEF: promoting: " ^ s) + ) + s + + + + +let msg_declare_macro s = + msg_gen (!Flag_parsing_c.debug_cpp) + (fun s -> + (match s with + | "DECLARE_MUTEX" | "DECLARE_COMPLETION" | "DECLARE_RWSEM" + | "DECLARE_WAITQUEUE" | "DECLARE_WAIT_QUEUE_HEAD" + | "DEFINE_SPINLOCK" | "DEFINE_TIMER" + | "DEVICE_ATTR" | "CLASS_DEVICE_ATTR" | "DRIVER_ATTR" + | "SENSOR_DEVICE_ATTR" + | "LIST_HEAD" + | "DECLARE_WORK" | "DECLARE_TASKLET" + | "PORT_ATTR_RO" | "PORT_PMA_ATTR" + | "DECLARE_BITMAP" + + -> true + (* + | s when s =~ "^DECLARE_.*" -> true + | s when s =~ ".*_ATTR$" -> true + | s when s =~ "^DEFINE_.*" -> true + *) + + | _ -> false + ) + ) + (fun s -> pr2_cpp ("MACRO: found declare-macro: " ^ s)) + s + + +let msg_foreach s = + pr2_cpp ("MACRO: found foreach: " ^ s) + + +let msg_debug_macro s = + pr2_cpp ("MACRO: found debug-macro: " ^ s) + + +let msg_macro_noptvirg s = + pr2_cpp ("MACRO: found macro with param noptvirg: " ^ s) + +let msg_macro_toplevel_noptvirg s = + pr2_cpp ("MACRO: found toplevel macro noptvirg: " ^ s) + + +let msg_macro_noptvirg_single s = + pr2_cpp ("MACRO: found single-macro noptvirg: " ^ s) + + +let msg_macro_higher_order s = + msg_gen (!Flag_parsing_c.debug_cpp) + (fun s -> + (match s with + | "DBGINFO" + | "DBGPX" + | "DFLOW" + -> true + | _ -> false + ) + ) + (fun s -> pr2_cpp ("MACRO: found higher ordre macro : " ^ s)) + s + + +let msg_stringification s = + msg_gen (!Flag_parsing_c.debug_cpp) + (fun s -> + (match s with + | "REVISION" + | "UTS_RELEASE" + | "SIZE_STR" + | "DMA_STR" + -> true + (* s when s =~ ".*STR.*" -> true *) + | _ -> false + ) + ) + (fun s -> pr2_cpp ("MACRO: found string-macro " ^ s)) + s + + + +(*****************************************************************************) +(* CPP handling: macros, ifdefs, macros defs *) +(*****************************************************************************) + +(* opti: better to built then once and for all, especially regexp_foreach *) + +let regexp_macro = Str.regexp + "^[A-Z_][A-Z_0-9]*$" + +(* linuxext: *) +let regexp_annot = Str.regexp + "^__.*$" + +(* linuxext: *) +let regexp_declare = Str.regexp + ".*DECLARE.*" + +(* linuxext: *) +let regexp_foreach = Str.regexp_case_fold + ".*\\(for_?each\\|for_?all\\|iterate\\|loop\\|walk\\|scan\\|each\\|for\\)" + +let regexp_typedef = Str.regexp + ".*_t$" + + +let false_typedef = [ + "printk"; + ] + +type define_body = (unit,string list) either * Parser_c.token list + +let (_defs : (string, define_body) Hashtbl.t ref) = + ref (Hashtbl.create 101) + + +(* ------------------------------------------------------------------------- *) +(* fuzzy parsing, different "views" over the same program *) +(* ------------------------------------------------------------------------- *) + + +(* Normally I should not use ref/mutable in the token_extended type + * and I should have a set of functions taking a list of tokens and + * returning a list of tokens. The problem is that to make easier some + * functions, it is better to work on better representation, on "views" + * over this list of tokens. But then modifying those views and get + * back from those views to the original simple list of tokens is + * tedious. One way is to maintain next to the view a list of "actions" + * (I was using a hash storing the charpos of the token and associating + * the action) but it is tedious too. Simpler to use mutable/ref. We + * use the same idea that we use when working on the Ast_c. *) + +(* old: when I was using the list of "actions" next to the views, the hash + * indexed by the charpos, there could have been some problems: + * how my fake_pos interact with the way I tag and adjust token ? + * because I base my tagging on the position of the token ! so sometimes + * could tag another fakeInfo that should not be tagged ? + * fortunately I don't use anymore this technique. + *) + +(* update: quite close to the Place_c.Inxxx *) +type context = + InFunction | InEnum | InStruct | InInitializer | NoContext + +type token_extended = { + mutable tok: Parser_c.token; + mutable where: context; + + (* less: need also a after ? *) + mutable new_tokens_before : Parser_c.token list; + + (* line x col cache, more easily accessible, of the info in the token *) + line: int; + col : int; +} + +let set_as_comment cppkind x = + if TH.is_eof x.tok + then () (* otherwise parse_c will be lost if don't find a EOF token *) + else + x.tok <- TCommentCpp (cppkind, TH.info_of_tok x.tok) + +let mk_token_extended x = + let (line, col) = TH.linecol_of_tok x in + { tok = x; + line = line; col = col; + where = NoContext; + new_tokens_before = []; + } + + +(* x list list, because x list separated by ',' *) +type paren_grouped = + | Parenthised of paren_grouped list list * token_extended list + | PToken of token_extended + +type brace_grouped = + | Braceised of + brace_grouped list list * token_extended * token_extended option + | BToken of token_extended + +(* Far better data structure than doing hacks in the lexer or parser + * because in lexer we don't know to which ifdef a endif is related + * and so when we want to comment a ifdef, we don't know which endif + * we must also comment. Especially true for the #if 0 which sometimes + * have a #else part. + * + * x list list, because x list separated by #else or #elif + *) +type ifdef_grouped = + | Ifdef of ifdef_grouped list list * token_extended list + | Ifdefbool of bool * ifdef_grouped list list * token_extended list + | NotIfdefLine of token_extended list + + +type 'a line_grouped = + Line of 'a list + + +type body_function_grouped = + | BodyFunction of token_extended list + | NotBodyLine of token_extended list + + +(* ------------------------------------------------------------------------- *) +(* view builders *) +(* ------------------------------------------------------------------------- *) + +(* todo: synchro ! use more indentation + * if paren not closed and same indentation level, certainly because + * part of a mid-ifdef-expression. +*) +let rec mk_parenthised xs = + match xs with + | [] -> [] + | x::xs -> + (match x.tok with + | TOPar _ | TOParDefine _ -> + let body, extras, xs = mk_parameters [x] [] xs in + Parenthised (body,extras)::mk_parenthised xs + | _ -> + PToken x::mk_parenthised xs + ) + +(* return the body of the parenthised expression and the rest of the tokens *) +and mk_parameters extras acc_before_sep xs = + match xs with + | [] -> + (* maybe because of #ifdef which "opens" '(' in 2 branches *) + pr2 "PB: not found closing paren in fuzzy parsing"; + [List.rev acc_before_sep], List.rev extras, [] + | x::xs -> + (match x.tok with + (* synchro *) + | TOBrace _ when x.col = 0 -> + pr2 "PB: found synchro point } in paren"; + [List.rev acc_before_sep], List.rev (extras), (x::xs) + + | TCPar _ | TCParEOL _ -> + [List.rev acc_before_sep], List.rev (x::extras), xs + | TOPar _ | TOParDefine _ -> + let body, extrasnest, xs = mk_parameters [x] [] xs in + mk_parameters extras + (Parenthised (body,extrasnest)::acc_before_sep) + xs + | TComma _ -> + let body, extras, xs = mk_parameters (x::extras) [] xs in + (List.rev acc_before_sep)::body, extras, xs + | _ -> + mk_parameters extras (PToken x::acc_before_sep) xs + ) + + + + +let rec mk_braceised xs = + match xs with + | [] -> [] + | x::xs -> + (match x.tok with + | TOBrace _ -> + let body, endbrace, xs = mk_braceised_aux [] xs in + Braceised (body, x, endbrace)::mk_braceised xs + | TCBrace _ -> + pr2 "PB: found closing brace alone in fuzzy parsing"; + BToken x::mk_braceised xs + | _ -> + BToken x::mk_braceised xs + ) + +(* return the body of the parenthised expression and the rest of the tokens *) +and mk_braceised_aux acc xs = + match xs with + | [] -> + (* maybe because of #ifdef which "opens" '(' in 2 branches *) + pr2 "PB: not found closing brace in fuzzy parsing"; + [List.rev acc], None, [] + | x::xs -> + (match x.tok with + | TCBrace _ -> [List.rev acc], Some x, xs + | TOBrace _ -> + let body, endbrace, xs = mk_braceised_aux [] xs in + mk_braceised_aux (Braceised (body,x, endbrace)::acc) xs + | _ -> + mk_braceised_aux (BToken x::acc) xs + ) + + + + +let rec mk_ifdef xs = + match xs with + | [] -> [] + | x::xs -> + (match x.tok with + | TIfdef _ -> + let body, extra, xs = mk_ifdef_parameters [x] [] xs in + Ifdef (body, extra)::mk_ifdef xs + | TIfdefBool (b,_) -> + let body, extra, xs = mk_ifdef_parameters [x] [] xs in + + (* if not passing, then consider a #if 0 as an ordinary #ifdef *) + if !Flag_parsing_c.if0_passing + then Ifdefbool (b, body, extra)::mk_ifdef xs + else Ifdef(body, extra)::mk_ifdef xs + + | TIfdefMisc (b,_) | TIfdefVersion (b,_) -> + let body, extra, xs = mk_ifdef_parameters [x] [] xs in + Ifdefbool (b, body, extra)::mk_ifdef xs + + + | _ -> + (* todo? can have some Ifdef in the line ? *) + let line, xs = Common.span (fun y -> y.line = x.line) (x::xs) in + NotIfdefLine line::mk_ifdef xs + ) + +and mk_ifdef_parameters extras acc_before_sep xs = + match xs with + | [] -> + (* Note that mk_ifdef is assuming that CPP instruction are alone + * on their line. Because I do a span (fun x -> is_same_line ...) + * I might take with me a #endif if this one is mixed on a line + * with some "normal" tokens. + *) + pr2 "PB: not found closing ifdef in fuzzy parsing"; + [List.rev acc_before_sep], List.rev extras, [] + | x::xs -> + (match x.tok with + | TEndif _ -> + [List.rev acc_before_sep], List.rev (x::extras), xs + | TIfdef _ -> + let body, extrasnest, xs = mk_ifdef_parameters [x] [] xs in + mk_ifdef_parameters + extras (Ifdef (body, extrasnest)::acc_before_sep) xs + + | TIfdefBool (b,_) -> + let body, extrasnest, xs = mk_ifdef_parameters [x] [] xs in + + if !Flag_parsing_c.if0_passing + then + mk_ifdef_parameters + extras (Ifdefbool (b, body, extrasnest)::acc_before_sep) xs + else + mk_ifdef_parameters + extras (Ifdef (body, extrasnest)::acc_before_sep) xs + + + | TIfdefMisc (b,_) | TIfdefVersion (b,_) -> + let body, extrasnest, xs = mk_ifdef_parameters [x] [] xs in + mk_ifdef_parameters + extras (Ifdefbool (b, body, extrasnest)::acc_before_sep) xs + + | TIfdefelse _ + | TIfdefelif _ -> + let body, extras, xs = mk_ifdef_parameters (x::extras) [] xs in + (List.rev acc_before_sep)::body, extras, xs + | _ -> + let line, xs = Common.span (fun y -> y.line = x.line) (x::xs) in + mk_ifdef_parameters extras (NotIfdefLine line::acc_before_sep) xs + ) + +(* --------------------------------------- *) + +let line_of_paren = function + | PToken x -> x.line + | Parenthised (xxs, info_parens) -> + (match info_parens with + | [] -> raise Impossible + | x::xs -> x.line + ) + + +let rec span_line_paren line = function + | [] -> [],[] + | x::xs -> + (match x with + | PToken tok when TH.is_eof tok.tok -> + [], x::xs + | _ -> + if line_of_paren x = line + then + let (l1, l2) = span_line_paren line xs in + (x::l1, l2) + else ([], x::xs) + ) + + +let rec mk_line_parenthised xs = + match xs with + | [] -> [] + | x::xs -> + let line_no = line_of_paren x in + let line, xs = span_line_paren line_no xs in + Line (x::line)::mk_line_parenthised xs + + +(* --------------------------------------- *) +let rec mk_body_function_grouped xs = + match xs with + | [] -> [] + | x::xs -> + (match x with + | {tok = TOBrace _; col = 0} -> + let is_closing_brace = function + | {tok = TCBrace _; col = 0 } -> true + | _ -> false + in + let body, xs = Common.span (fun x -> not (is_closing_brace x)) xs in + (match xs with + | ({tok = TCBrace _; col = 0 })::xs -> + BodyFunction body::mk_body_function_grouped xs + | [] -> + pr2 "PB:not found closing brace in fuzzy parsing"; + [NotBodyLine body] + | _ -> raise Impossible + ) + + | _ -> + let line, xs = Common.span (fun y -> y.line = x.line) (x::xs) in + NotBodyLine line::mk_body_function_grouped xs + ) + + +(* ------------------------------------------------------------------------- *) +(* view iterators *) +(* ------------------------------------------------------------------------- *) + +let rec iter_token_paren f xs = + xs +> List.iter (function + | PToken tok -> f tok; + | Parenthised (xxs, info_parens) -> + info_parens +> List.iter f; + xxs +> List.iter (fun xs -> iter_token_paren f xs) + ) + +let rec iter_token_brace f xs = + xs +> List.iter (function + | BToken tok -> f tok; + | Braceised (xxs, tok1, tok2opt) -> + f tok1; do_option f tok2opt; + xxs +> List.iter (fun xs -> iter_token_brace f xs) + ) + +let rec iter_token_ifdef f xs = + xs +> List.iter (function + | NotIfdefLine xs -> xs +> List.iter f; + | Ifdefbool (_, xxs, info_ifdef) + | Ifdef (xxs, info_ifdef) -> + info_ifdef +> List.iter f; + xxs +> List.iter (iter_token_ifdef f) + ) + + + + +let tokens_of_paren xs = + let g = ref [] in + xs +> iter_token_paren (fun tok -> push2 tok g); + List.rev !g + + +let tokens_of_paren_ordered xs = + let g = ref [] in + + let rec aux_tokens_ordered = function + | PToken tok -> push2 tok g; + | Parenthised (xxs, info_parens) -> + let (opar, cpar, commas) = + match info_parens with + | opar::xs -> + (match List.rev xs with + | cpar::xs -> + opar, cpar, List.rev xs + | _ -> raise Impossible + ) + | _ -> raise Impossible + in + push2 opar g; + aux_args (xxs,commas); + push2 cpar g; + + and aux_args (xxs, commas) = + match xxs, commas with + | [], [] -> () + | [xs], [] -> xs +> List.iter aux_tokens_ordered + | xs::ys::xxs, comma::commas -> + xs +> List.iter aux_tokens_ordered; + push2 comma g; + aux_args (ys::xxs, commas) + | _ -> raise Impossible + + in + + xs +> List.iter aux_tokens_ordered; + List.rev !g + + + + +(* ------------------------------------------------------------------------- *) +(* set the context info in token *) +(* ------------------------------------------------------------------------- *) + + +let rec set_in_function_tag xs = + (* could try: ) { } but it can be the ) of a if or while, so + * better to base the heuristic on the position in column zero. + * Note that some struct or enum or init put also their { in first column + * but set_in_other will overwrite the previous InFunction tag. + *) + match xs with + | [] -> () + (* ) { and the closing } is in column zero, then certainly a function *) + | BToken ({tok = TCPar _ })::(Braceised (body, tok1, Some tok2))::xs + when tok1.col <> 0 && tok2.col = 0 -> + body +> List.iter (iter_token_brace (fun tok -> + tok.where <- InFunction + )); + set_in_function_tag xs + + | (BToken x)::xs -> set_in_function_tag xs + + | (Braceised (body, tok1, Some tok2))::xs + when tok1.col = 0 && tok2.col = 0 -> + body +> List.iter (iter_token_brace (fun tok -> + tok.where <- InFunction + )); + set_in_function_tag xs + | Braceised (body, tok1, tok2)::xs -> + set_in_function_tag xs + + +let rec set_in_other xs = + match xs with + | [] -> () + (* enum x { } *) + | BToken ({tok = Tenum _})::BToken ({tok = TIdent _}) + ::Braceised(body, tok1, tok2)::xs + | BToken ({tok = Tenum _}) + ::Braceised(body, tok1, tok2)::xs + -> + body +> List.iter (iter_token_brace (fun tok -> + tok.where <- InEnum; + )); + set_in_other xs + + (* struct x { } *) + | BToken ({tok = Tstruct _})::BToken ({tok = TIdent _}) + ::Braceised(body, tok1, tok2)::xs -> + body +> List.iter (iter_token_brace (fun tok -> + tok.where <- InStruct; + )); + set_in_other xs + (* = { } *) + | BToken ({tok = TEq _}) + ::Braceised(body, tok1, tok2)::xs -> + body +> List.iter (iter_token_brace (fun tok -> + tok.where <- InInitializer; + )); + set_in_other xs + + | BToken _::xs -> set_in_other xs + + | Braceised(body, tok1, tok2)::xs -> + body +> List.iter set_in_other; + set_in_other xs + + + + +let set_context_tag xs = + begin + set_in_function_tag xs; + set_in_other xs; + end + + +(* ------------------------------------------------------------------------- *) +(* ifdef keeping/passing *) +(* ------------------------------------------------------------------------- *) + +(* #if 0, #if 1, #if LINUX_VERSION handling *) +let rec find_ifdef_bool xs = + xs +> List.iter (function + | NotIfdefLine _ -> () + | Ifdefbool (is_ifdef_positif, xxs, info_ifdef_stmt) -> + + if is_ifdef_positif + then pr2_cpp "commenting parts of a #if 1 or #if LINUX_VERSION" + else pr2_cpp "commenting a #if 0 or #if LINUX_VERSION or __cplusplus"; + + (match xxs with + | [] -> raise Impossible + | firstclause::xxs -> + info_ifdef_stmt +> List.iter (set_as_comment Ast_c.CppDirective); + + if is_ifdef_positif + then xxs +> List.iter + (iter_token_ifdef (set_as_comment Ast_c.CppOther)) + else begin + firstclause +> iter_token_ifdef (set_as_comment Ast_c.CppOther); + (match List.rev xxs with + (* keep only last *) + | last::startxs -> + startxs +> List.iter + (iter_token_ifdef (set_as_comment Ast_c.CppOther)) + | [] -> (* not #else *) () + ); + end + ); + + | Ifdef (xxs, info_ifdef_stmt) -> xxs +> List.iter find_ifdef_bool + ) + + + +(* the pair is the status of '()' and '{}', ex: (-1,0) + * if too much ')' and good '{}' + * could do for [] too ? + * could do for ',' if encounter ',' at "toplevel", not inside () or {} + * then if have ifdef, then certainly can lead to a problem. + *) +let (count_open_close_stuff_ifdef_clause: ifdef_grouped list -> (int * int)) = + fun xs -> + let cnt_paren, cnt_brace = ref 0, ref 0 in + xs +> iter_token_ifdef (fun x -> + (match x.tok with + | x when TH.is_opar x -> incr cnt_paren + | TOBrace _ -> incr cnt_brace + | x when TH.is_cpar x -> decr cnt_paren + | TCBrace _ -> decr cnt_brace + | _ -> () + ) + ); + !cnt_paren, !cnt_brace + +let thresholdIfdefSizeMid = 6 + +(* infer ifdef involving not-closed expressions/statements *) +let rec find_ifdef_mid xs = + xs +> List.iter (function + | NotIfdefLine _ -> () + | Ifdef (xxs, info_ifdef_stmt) -> + (match xxs with + | [] -> raise Impossible + | [first] -> () + | first::second::rest -> + (* don't analyse big ifdef *) + if xxs +> List.for_all + (fun xs -> List.length xs <= thresholdIfdefSizeMid) && + (* don't want nested ifdef *) + xxs +> List.for_all (fun xs -> + xs +> List.for_all + (function NotIfdefLine _ -> true | _ -> false) + ) + + then + let counts = xxs +> List.map count_open_close_stuff_ifdef_clause in + let cnt1, cnt2 = List.hd counts in + if cnt1 <> 0 || cnt2 <> 0 && + counts +> List.for_all (fun x -> x = (cnt1, cnt2)) + (* + if counts +> List.exists (fun (cnt1, cnt2) -> + cnt1 <> 0 || cnt2 <> 0 + ) + *) + then begin + pr2_cpp "found ifdef-mid-something"; + (* keep only first, treat the rest as comment *) + info_ifdef_stmt +> List.iter (set_as_comment Ast_c.CppDirective); + (second::rest) +> List.iter + (iter_token_ifdef (set_as_comment Ast_c.CppOther)); + end + + ); + List.iter find_ifdef_mid xxs + + (* no need complex analysis for ifdefbool *) + | Ifdefbool (_, xxs, info_ifdef_stmt) -> + List.iter find_ifdef_mid xxs + + + ) + + +let thresholdFunheaderLimit = 4 + +(* ifdef defining alternate function header, type *) +let rec find_ifdef_funheaders = function + | [] -> () + | NotIfdefLine _::xs -> find_ifdef_funheaders xs + + (* ifdef-funheader if ifdef with 2 lines and a '{' in next line *) + | Ifdef + ([(NotIfdefLine (({col = 0} as _xline1)::line1))::ifdefblock1; + (NotIfdefLine (({col = 0} as xline2)::line2))::ifdefblock2 + ], info_ifdef_stmt + ) + ::NotIfdefLine (({tok = TOBrace i; col = 0})::line3) + ::xs + when List.length ifdefblock1 <= thresholdFunheaderLimit && + List.length ifdefblock2 <= thresholdFunheaderLimit + -> + find_ifdef_funheaders xs; + info_ifdef_stmt +> List.iter (set_as_comment Ast_c.CppDirective); + let all_toks = [xline2] @ line2 in + all_toks +> List.iter (set_as_comment Ast_c.CppOther) ; + ifdefblock2 +> iter_token_ifdef (set_as_comment Ast_c.CppOther); + + (* ifdef with nested ifdef *) + | Ifdef + ([[NotIfdefLine (({col = 0} as _xline1)::line1)]; + [Ifdef + ([[NotIfdefLine (({col = 0} as xline2)::line2)]; + [NotIfdefLine (({col = 0} as xline3)::line3)]; + ], info_ifdef_stmt2 + ) + ] + ], info_ifdef_stmt + ) + ::NotIfdefLine (({tok = TOBrace i; col = 0})::line4) + ::xs + -> + find_ifdef_funheaders xs; + info_ifdef_stmt +> List.iter (set_as_comment Ast_c.CppDirective); + info_ifdef_stmt2 +> List.iter (set_as_comment Ast_c.CppDirective); + let all_toks = [xline2;xline3] @ line2 @ line3 in + all_toks +> List.iter (set_as_comment Ast_c.CppOther); + + (* ifdef with elseif *) + | Ifdef + ([[NotIfdefLine (({col = 0} as _xline1)::line1)]; + [NotIfdefLine (({col = 0} as xline2)::line2)]; + [NotIfdefLine (({col = 0} as xline3)::line3)]; + ], info_ifdef_stmt + ) + ::NotIfdefLine (({tok = TOBrace i; col = 0})::line4) + ::xs + -> + find_ifdef_funheaders xs; + info_ifdef_stmt +> List.iter (set_as_comment Ast_c.CppDirective); + let all_toks = [xline2;xline3] @ line2 @ line3 in + all_toks +> List.iter (set_as_comment Ast_c.CppOther) + + + | Ifdef (xxs,info_ifdef_stmt)::xs + | Ifdefbool (_, xxs,info_ifdef_stmt)::xs -> + List.iter find_ifdef_funheaders xxs; + find_ifdef_funheaders xs + + + + +let rec adjust_inifdef_include xs = + xs +> List.iter (function + | NotIfdefLine _ -> () + | Ifdef (xxs, info_ifdef_stmt) | Ifdefbool (_, xxs, info_ifdef_stmt) -> + xxs +> List.iter (iter_token_ifdef (fun tokext -> + match tokext.tok with + | Parser_c.TInclude (s1, s2, inifdef_ref, ii) -> + inifdef_ref := true; + | _ -> () + )); + ) + + + +(* ------------------------------------------------------------------------- *) +(* cpp-builtin part1, macro, using standard.h or other defs *) +(* ------------------------------------------------------------------------- *) + +(* Thanks to this function many stuff are not anymore hardcoded in ocaml code + * (but they are now hardcoded in standard.h ...) + *) + +let rec (cpp_engine: (string , Parser_c.token list) assoc -> + Parser_c.token list -> Parser_c.token list) = fun env xs -> + xs +> List.map (fun tok -> + match tok with + | TIdent (s,i1) when List.mem_assoc s env -> Common.assoc s env + | x -> [x] + ) + +> List.flatten + +(* no need to take care to not substitute the macro name itself + * that occurs in the macro definition because the macro name is + * after fix_token_define a TDefineIdent, no more a TIdent. + *) + +let rec apply_macro_defs xs = + match xs with + | [] -> () + + (* recognized macro of standard.h (or other) *) + | PToken ({tok = TIdent (s,i1)} as id)::Parenthised (xxs,info_parens)::xs + when Hashtbl.mem !_defs s -> + pr2_cpp ("MACRO: found known macro = " ^ s); + (match Hashtbl.find !_defs s with + | Left (), bodymacro -> + pr2 ("macro without param used before parenthize, wierd: " ^ s); + (* ex: PRINTP("NCR53C400 card%s detected\n" ANDP(((struct ... *) + set_as_comment (Ast_c.CppMacro) id; + id.new_tokens_before <- bodymacro; + | Right params, bodymacro -> + if List.length params = List.length xxs + then + let xxs' = xxs +> List.map (fun x -> + (tokens_of_paren_ordered x) +> List.map (fun x -> + TH.visitor_info_of_tok Ast_c.make_expanded x.tok + ) + ) in + id.new_tokens_before <- + cpp_engine (Common.zip params xxs') bodymacro + + else begin + pr2 ("macro with wrong number of arguments, wierd: " ^ s); + id.new_tokens_before <- bodymacro; + end; + (* important to do that after have apply the macro, otherwise + * will pass as argument to the macro some tokens that + * are all TCommentCpp + *) + [Parenthised (xxs, info_parens)] +> + iter_token_paren (set_as_comment Ast_c.CppMacro); + set_as_comment Ast_c.CppMacro id; + + + + ); + apply_macro_defs xs + + | PToken ({tok = TIdent (s,i1)} as id)::xs + when Hashtbl.mem !_defs s -> + pr2_cpp ("MACRO: found known macro = " ^ s); + (match Hashtbl.find !_defs s with + | Right params, bodymacro -> + pr2 ("macro with params but no parens found, wierd: " ^ s); + (* dont apply the macro, perhaps a redefinition *) + () + | Left (), bodymacro -> + (* special case when 1-1 substitution, we reuse the token *) + (match bodymacro with + | [newtok] -> + id.tok <- (newtok +> TH.visitor_info_of_tok (fun _ -> + TH.info_of_tok id.tok)) + + | _ -> + set_as_comment Ast_c.CppMacro id; + id.new_tokens_before <- bodymacro; + ) + ); + apply_macro_defs xs + + + + + (* recurse *) + | (PToken x)::xs -> apply_macro_defs xs + | (Parenthised (xxs, info_parens))::xs -> + xxs +> List.iter apply_macro_defs; + apply_macro_defs xs + + + + + +(* ------------------------------------------------------------------------- *) +(* stringification *) +(* ------------------------------------------------------------------------- *) + +let rec find_string_macro_paren xs = + match xs with + | [] -> () + | Parenthised(xxs, info_parens)::xs -> + xxs +> List.iter (fun xs -> + if xs +> List.exists + (function PToken({tok = TString _}) -> true | _ -> false) && + xs +> List.for_all + (function PToken({tok = TString _}) | PToken({tok = TIdent _}) -> + true | _ -> false) + then + xs +> List.iter (fun tok -> + match tok with + | PToken({tok = TIdent (s,_)} as id) -> + msg_stringification s; + id.tok <- TMacroString (TH.info_of_tok id.tok); + | _ -> () + ) + else + find_string_macro_paren xs + ); + find_string_macro_paren xs + | PToken(tok)::xs -> + find_string_macro_paren xs + + +(* ------------------------------------------------------------------------- *) +(* macro2 *) +(* ------------------------------------------------------------------------- *) + +(* don't forget to recurse in each case *) +let rec find_macro_paren xs = + match xs with + | [] -> () + + (* attribute *) + | PToken ({tok = Tattribute _} as id) + ::Parenthised (xxs,info_parens) + ::xs + -> + pr2_cpp ("MACRO: __attribute detected "); + [Parenthised (xxs, info_parens)] +> + iter_token_paren (set_as_comment Ast_c.CppAttr); + set_as_comment Ast_c.CppAttr id; + find_macro_paren xs + + (* stringification + * + * the order of the matching clause is important + * + *) + + (* string macro with params, before case *) + | PToken ({tok = TString _})::PToken ({tok = TIdent (s,_)} as id) + ::Parenthised (xxs, info_parens) + ::xs -> + pr2_cpp ("MACRO: string-macro with params : " ^ s); + id.tok <- TMacroString (TH.info_of_tok id.tok); + [Parenthised (xxs, info_parens)] +> + iter_token_paren (set_as_comment Ast_c.CppMacro); + find_macro_paren xs + + (* after case *) + | PToken ({tok = TIdent (s,_)} as id) + ::Parenthised (xxs, info_parens) + ::PToken ({tok = TString _}) + ::xs -> + pr2_cpp ("MACRO: string-macro with params : " ^ s); + id.tok <- TMacroString (TH.info_of_tok id.tok); + [Parenthised (xxs, info_parens)] +> + iter_token_paren (set_as_comment Ast_c.CppMacro); + find_macro_paren xs + + + (* for the case where the string is not inside a funcall, but + * for instance in an initializer. + *) + + (* string macro variable, before case *) + | PToken ({tok = TString _})::PToken ({tok = TIdent (s,_)} as id) + ::xs -> + msg_stringification s; + id.tok <- TMacroString (TH.info_of_tok id.tok); + find_macro_paren xs + + (* after case *) + | PToken ({tok = TIdent (s,_)} as id)::PToken ({tok = TString _}) + ::xs -> + msg_stringification s; + id.tok <- TMacroString (TH.info_of_tok id.tok); + find_macro_paren xs + + + + (* cooperating with standard.h *) + | PToken ({tok = TIdent (s,i1)} as id)::xs + when s = "MACROSTATEMENT" -> + id.tok <- TMacroStmt(TH.info_of_tok id.tok); + find_macro_paren xs + + + + (* recurse *) + | (PToken x)::xs -> find_macro_paren xs + | (Parenthised (xxs, info_parens))::xs -> + xxs +> List.iter find_macro_paren; + find_macro_paren xs + + + + + +(* don't forget to recurse in each case *) +let rec find_macro_lineparen xs = + match xs with + | [] -> () + + (* linuxext: ex: static [const] DEVICE_ATTR(); *) + | (Line + ( + [PToken ({tok = Tstatic _}); + PToken ({tok = TIdent (s,_)} as macro); + Parenthised (xxs,info_parens); + PToken ({tok = TPtVirg _}); + ] + )) + ::xs + when (s ==~ regexp_macro) -> + msg_declare_macro s; + let info = TH.info_of_tok macro.tok in + macro.tok <- TMacroDecl (Ast_c.str_of_info info, info); + + find_macro_lineparen (xs) + + (* the static const case *) + | (Line + ( + [PToken ({tok = Tstatic _}); + PToken ({tok = Tconst _} as const); + PToken ({tok = TIdent (s,_)} as macro); + Parenthised (xxs,info_parens); + PToken ({tok = TPtVirg _}); + ] + (*as line1*) + + )) + ::xs + when (s ==~ regexp_macro) -> + msg_declare_macro s; + let info = TH.info_of_tok macro.tok in + macro.tok <- TMacroDecl (Ast_c.str_of_info info, info); + + (* need retag this const, otherwise ambiguity in grammar + 21: shift/reduce conflict (shift 121, reduce 137) on Tconst + decl2 : Tstatic . TMacroDecl TOPar argument_list TCPar ... + decl2 : Tstatic . Tconst TMacroDecl TOPar argument_list TCPar ... + storage_class_spec : Tstatic . (137) + *) + const.tok <- TMacroDeclConst (TH.info_of_tok const.tok); + + find_macro_lineparen (xs) + + + (* same but without trailing ';' + * + * I do not put the final ';' because it can be on a multiline and + * because of the way mk_line is coded, we will not have access to + * this ';' on the next line, even if next to the ')' *) + | (Line + ([PToken ({tok = Tstatic _}); + PToken ({tok = TIdent (s,_)} as macro); + Parenthised (xxs,info_parens); + ] + )) + ::xs + when s ==~ regexp_macro -> + + msg_declare_macro s; + let info = TH.info_of_tok macro.tok in + macro.tok <- TMacroDecl (Ast_c.str_of_info info, info); + + find_macro_lineparen (xs) + + + + + (* on multiple lines *) + | (Line + ( + (PToken ({tok = Tstatic _})::[] + ))) + ::(Line + ( + [PToken ({tok = TIdent (s,_)} as macro); + Parenthised (xxs,info_parens); + PToken ({tok = TPtVirg _}); + ] + ) + ) + ::xs + when (s ==~ regexp_macro) -> + msg_declare_macro s; + let info = TH.info_of_tok macro.tok in + macro.tok <- TMacroDecl (Ast_c.str_of_info info, info); + + find_macro_lineparen (xs) + + + (* linuxext: ex: DECLARE_BITMAP(); + * + * Here I use regexp_declare and not regexp_macro because + * Sometimes it can be a FunCallMacro such as DEBUG(foo()); + * Here we don't have the preceding 'static' so only way to + * not have positive is to restrict to .*DECLARE.* macros. + * + * but there is a grammar rule for that, so don't need this case anymore + * unless the parameter of the DECLARE_xxx are wierd and can not be mapped + * on a argument_list + *) + + | (Line + ([PToken ({tok = TIdent (s,_)} as macro); + Parenthised (xxs,info_parens); + PToken ({tok = TPtVirg _}); + ] + )) + ::xs + when (s ==~ regexp_declare) -> + + msg_declare_macro s; + let info = TH.info_of_tok macro.tok in + macro.tok <- TMacroDecl (Ast_c.str_of_info info, info); + + find_macro_lineparen (xs) + + + (* toplevel macros. + * module_init(xxx) + * + * Could also transform the TIdent in a TMacroTop but can have false + * positive, so easier to just change the TCPar and so just solve + * the end-of-stream pb of ocamlyacc + *) + | (Line + ([PToken ({tok = TIdent (s,ii); col = col1; where = ctx} as _macro); + Parenthised (xxs,info_parens); + ] as _line1 + )) + ::xs when col1 = 0 + -> + let condition = + (* to reduce number of false positive *) + (match xs with + | (Line (PToken ({col = col2 } as other)::restline2))::_ -> + TH.is_eof other.tok || (col2 = 0 && + (match other.tok with + | TOBrace _ -> false (* otherwise would match funcdecl *) + | TCBrace _ when ctx <> InFunction -> false + | TPtVirg _ + | TDotDot _ + -> false + | tok when TH.is_binary_operator tok -> false + + | _ -> true + ) + ) + | _ -> false + ) + in + if condition + then begin + msg_macro_toplevel_noptvirg s; + (* just to avoid the end-of-stream pb of ocamlyacc *) + let tcpar = Common.last info_parens in + tcpar.tok <- TCParEOL (TH.info_of_tok tcpar.tok); + + (*macro.tok <- TMacroTop (s, TH.info_of_tok macro.tok);*) + + end; + + find_macro_lineparen (xs) + + + + (* macro with parameters + * ex: DEBUG() + * return x; + *) + | (Line + ([PToken ({tok = TIdent (s,ii); col = col1; where = ctx} as macro); + Parenthised (xxs,info_parens); + ] as _line1 + )) + ::(Line + (PToken ({col = col2 } as other)::restline2 + ) as line2) + ::xs + (* when s ==~ regexp_macro *) + -> + let condition = + (col1 = col2 && + (match other.tok with + | TOBrace _ -> false (* otherwise would match funcdecl *) + | TCBrace _ when ctx <> InFunction -> false + | TPtVirg _ + | TDotDot _ + -> false + | tok when TH.is_binary_operator tok -> false + + | _ -> true + ) + ) + || + (col2 <= col1 && + (match other.tok with + | TCBrace _ when ctx = InFunction -> true + | Treturn _ -> true + | Tif _ -> true + | Telse _ -> true + + | _ -> false + ) + ) + + in + + if condition + then + if col1 = 0 then () + else begin + msg_macro_noptvirg s; + macro.tok <- TMacroStmt (TH.info_of_tok macro.tok); + [Parenthised (xxs, info_parens)] +> + iter_token_paren (set_as_comment Ast_c.CppMacro); + end; + + find_macro_lineparen (line2::xs) + + (* linuxext:? single macro + * ex: LOCK + * foo(); + * UNLOCK + *) + | (Line + ([PToken ({tok = TIdent (s,ii); col = col1; where = ctx} as macro); + ] as _line1 + )) + ::(Line + (PToken ({col = col2 } as other)::restline2 + ) as line2) + ::xs -> + (* when s ==~ regexp_macro *) + + let condition = + (col1 = col2 && + col1 <> 0 && (* otherwise can match typedef of fundecl*) + (match other.tok with + | TPtVirg _ -> false + | TOr _ -> false + | TCBrace _ when ctx <> InFunction -> false + | tok when TH.is_binary_operator tok -> false + + | _ -> true + )) || + (col2 <= col1 && + (match other.tok with + | TCBrace _ when ctx = InFunction -> true + | Treturn _ -> true + | Tif _ -> true + | Telse _ -> true + | _ -> false + )) + in + + if condition + then begin + msg_macro_noptvirg_single s; + macro.tok <- TMacroStmt (TH.info_of_tok macro.tok); + end; + find_macro_lineparen (line2::xs) + + | x::xs -> + find_macro_lineparen xs + + +(* ------------------------------------------------------------------------- *) +(* action *) +(* ------------------------------------------------------------------------- *) + +let rec find_actions = function + | [] -> () + + | PToken ({tok = TIdent (s,ii)}) + ::Parenthised (xxs,info_parens) + ::xs -> + find_actions xs; + xxs +> List.iter find_actions; + let modified = find_actions_params xxs in + if modified + then msg_macro_higher_order s + + | x::xs -> + find_actions xs + +and find_actions_params xxs = + xxs +> List.fold_left (fun acc xs -> + let toks = tokens_of_paren xs in + if toks +> List.exists (fun x -> TH.is_statement x.tok) + then begin + xs +> iter_token_paren (fun x -> + if TH.is_eof x.tok + then + (* certainly because paren detection had a pb because of + * some ifdef-exp + *) + pr2 "PB: wierd, I try to tag an EOF token as action" + else + x.tok <- TAction (TH.info_of_tok x.tok); + ); + true (* modified *) + end + else acc + ) false + + + +(* ------------------------------------------------------------------------- *) +(* main fix cpp function *) +(* ------------------------------------------------------------------------- *) + +let rebuild_tokens_extented toks_ext = + let _tokens = ref [] in + toks_ext +> List.iter (fun tok -> + tok.new_tokens_before +> List.iter (fun x -> push2 x _tokens); + push2 tok.tok _tokens + ); + let tokens = List.rev !_tokens in + (tokens +> acc_map mk_token_extended) + +let filter_cpp_stuff xs = + let rec aux xs = + match xs with + | [] -> [] + | x::xs -> + (match x.tok with + | tok when TH.is_comment tok -> aux xs + (* don't want drop the define, or if drop, have to drop + * also its body otherwise the line heuristics may be lost + * by not finding the TDefine in column 0 but by finding + * a TDefineIdent in a column > 0 + *) + | Parser_c.TDefine _ -> + x::aux xs + | tok when TH.is_cpp_instruction tok -> aux xs + | _ -> x::aux xs + ) + in + aux xs + +let insert_virtual_positions l = + let strlen x = String.length (Ast_c.str_of_info x) in + let rec loop prev offset = function + [] -> [] + | x::xs -> + let ii = TH.info_of_tok x in + let inject pi = + TH.visitor_info_of_tok (function ii -> Ast_c.rewrap_pinfo pi ii) x in + match Ast_c.pinfo_of_info ii with + Ast_c.OriginTok pi -> + let prev = Ast_c.parse_info_of_info ii in + x::(loop prev (strlen ii) xs) + | Ast_c.ExpandedTok (pi,_) -> + inject (Ast_c.ExpandedTok (pi,(prev,offset))) :: + (loop prev (offset + (strlen ii)) xs) + | Ast_c.FakeTok (s,_) -> + inject (Ast_c.FakeTok (s,(prev,offset))) :: + (loop prev (offset + (strlen ii)) xs) + | Ast_c.AbstractLineTok _ -> failwith "abstract not expected" in + let rec skip_fake = function + [] -> [] + | x::xs -> + let ii = TH.info_of_tok x in + match Ast_c.pinfo_of_info ii with + Ast_c.OriginTok pi -> + let prev = Ast_c.parse_info_of_info ii in + x::(loop prev (strlen ii) xs) + | _ -> x::skip_fake xs in + skip_fake l + +let fix_tokens_cpp2 tokens = + let tokens2 = ref (tokens +> acc_map mk_token_extended) in + + begin + (* the order is important, if you put the action heuristic first, + * then because of ifdef, can have not closed paren + * and so may believe that higher order macro + * and it will eat too much tokens. So important to do + * first the ifdef. + * + * I recompute multiple times cleaner cos the mutable + * can have be changed and so may have more comments + * in the token original list. + * + *) + + (* ifdef *) + let cleaner = !tokens2 +> List.filter (fun x -> + not (TH.is_comment x.tok) (* could filter also #define/#include *) + ) in + let ifdef_grouped = mk_ifdef cleaner in + find_ifdef_funheaders ifdef_grouped; + find_ifdef_bool ifdef_grouped; + find_ifdef_mid ifdef_grouped; + adjust_inifdef_include ifdef_grouped; + + + (* macro 1 *) + let cleaner = !tokens2 +> filter_cpp_stuff in + + let paren_grouped = mk_parenthised cleaner in + apply_macro_defs paren_grouped; + (* because the before field is used by apply_macro_defs *) + tokens2 := rebuild_tokens_extented !tokens2; + + (* tagging contextual info (InFunc, InStruct, etc). Better to do + * that after the "ifdef-simplification" phase. + *) + let cleaner = !tokens2 +> List.filter (fun x -> + not (TH.is_comment x.tok) (* could filter also #define/#include *) + ) in + + let brace_grouped = mk_braceised cleaner in + set_context_tag brace_grouped; + + + + (* macro *) + let cleaner = !tokens2 +> filter_cpp_stuff in + + let paren_grouped = mk_parenthised cleaner in + let line_paren_grouped = mk_line_parenthised paren_grouped in + find_string_macro_paren paren_grouped; + find_macro_lineparen line_paren_grouped; + find_macro_paren paren_grouped; + + + (* actions *) + let cleaner = !tokens2 +> filter_cpp_stuff in + let paren_grouped = mk_parenthised cleaner in + find_actions paren_grouped; + + + insert_virtual_positions (!tokens2 +> acc_map (fun x -> x.tok)) + end + +let fix_tokens_cpp a = + Common.profile_code "C parsing.fix_cpp" (fun () -> fix_tokens_cpp2 a) + + + + +(*****************************************************************************) +(* The #define tricks *) +(*****************************************************************************) + +(* ugly hack, a better solution perhaps would be to erase TDefEOL + * from the Ast and list of tokens in parse_c. + * + * note: I do a +1 somewhere, it's for the unparsing to correctly sync. + * + * note: can't replace mark_end_define by simply a fakeInfo(). The reason + * is where is the \n TCommentSpace. Normally there is always a last token + * to synchronize on, either EOF or the token of the next toplevel. + * In the case of the #define we got in list of token + * [TCommentSpace "\n"; TDefEOL] but if TDefEOL is a fakeinfo then we will + * not synchronize on it and so we will not print the "\n". + * A solution would be to put the TDefEOL before the "\n". + * + * todo?: could put a ExpandedTok for that ? + *) +let mark_end_define ii = + let ii' = + { Ast_c.pinfo = Ast_c.OriginTok { (Ast_c.parse_info_of_info ii) with + Common.str = ""; + Common.charpos = Ast_c.pos_of_info ii + 1 + }; + cocci_tag = ref Ast_c.emptyAnnot; + comments_tag = ref Ast_c.emptyComments; + } + in + TDefEOL (ii') + +(* put the TDefEOL at the good place *) +let rec define_line_1 acc xs = + match xs with + | [] -> List.rev acc + | TDefine ii::xs -> + let line = Ast_c.line_of_info ii in + let acc = (TDefine ii) :: acc in + define_line_2 acc line ii xs + | TCppEscapedNewline ii::xs -> + pr2 "WIERD: a \\ outside a #define"; + let acc = (TCommentSpace ii) :: acc in + define_line_1 acc xs + | x::xs -> define_line_1 (x::acc) xs + +and define_line_2 acc line lastinfo xs = + match xs with + | [] -> + (* should not happened, should meet EOF before *) + pr2 "PB: WIERD"; + List.rev (mark_end_define lastinfo::acc) + | x::xs -> + let line' = TH.line_of_tok x in + let info = TH.info_of_tok x in + + (match x with + | EOF ii -> + let acc = (mark_end_define lastinfo) :: acc in + let acc = (EOF ii) :: acc in + define_line_1 acc xs + | TCppEscapedNewline ii -> + if (line' <> line) then pr2 "PB: WIERD: not same line number"; + let acc = (TCommentSpace ii) :: acc in + define_line_2 acc (line+1) info xs + | x -> + if line' = line + then define_line_2 (x::acc) line info xs + else define_line_1 (mark_end_define lastinfo::acc) (x::xs) + ) + +let rec define_ident acc xs = + match xs with + | [] -> List.rev acc + | TDefine ii::xs -> + let acc = TDefine ii :: acc in + (match xs with + | TCommentSpace i1::TIdent (s,i2)::TOPar (i3)::xs -> + (* Change also the kind of TIdent to avoid bad interaction + * with other parsing_hack tricks. For instant if keep TIdent then + * the stringication algo can believe the TIdent is a string-macro. + * So simpler to change the kind of the ident too. + *) + (* if TOParDefine sticked to the ident, then + * it's a macro-function. Change token to avoid ambiguity + * between #define foo(x) and #define foo (x) + *) + let acc = (TCommentSpace i1) :: acc in + let acc = (TIdentDefine (s,i2)) :: acc in + let acc = (TOParDefine i3) :: acc in + define_ident acc xs + | TCommentSpace i1::TIdent (s,i2)::xs -> + let acc = (TCommentSpace i1) :: acc in + let acc = (TIdentDefine (s,i2)) :: acc in + define_ident acc xs + | _ -> + pr2 "wierd #define body"; + define_ident acc xs + ) + | x::xs -> + let acc = x :: acc in + define_ident acc xs + + + +let fix_tokens_define2 xs = + define_ident [] (define_line_1 [] xs) + +let fix_tokens_define a = + Common.profile_code "C parsing.fix_define" (fun () -> fix_tokens_define2 a) + + +(*****************************************************************************) +(* for the cpp-builtin *) +(*****************************************************************************) + +let rec define_parse xs = + match xs with + | [] -> [] + | TDefine i1::TIdentDefine (s,i2)::TOParDefine i3::xs -> + let (tokparams, _, xs) = + xs +> Common.split_when (function TCPar _ -> true | _ -> false) in + let (body, _, xs) = + xs +> Common.split_when (function TDefEOL _ -> true | _ -> false) in + let params = + tokparams +> Common.map_filter (function + | TComma _ -> None + | TIdent (s, _) -> Some s + | x -> error_cant_have x + ) in + let body = body +> List.map + (TH.visitor_info_of_tok Ast_c.make_expanded) in + let def = (s, (Right params, body)) in + def::define_parse xs + + | TDefine i1::TIdentDefine (s,i2)::xs -> + let (body, _, xs) = + xs +> Common.split_when (function TDefEOL _ -> true | _ -> false) in + let body = body +> List.map + (TH.visitor_info_of_tok Ast_c.make_expanded) in + let def = (s, (Left (), body)) in + def::define_parse xs + + | TDefine i1::_ -> + raise Impossible + | x::xs -> define_parse xs + + +let extract_cpp_define xs = + let cleaner = xs +> List.filter (fun x -> + not (TH.is_comment x) + ) in + define_parse cleaner + + + + +(*****************************************************************************) +(* Lexing with lookahead *) +(*****************************************************************************) + +(* Why using yet another parsing_hack technique ? The fix_xxx where do + * some pre-processing on the full list of tokens is not enough ? + * No cos sometimes we need more contextual info, and even if + * set_context() tries to give some contextual info, it's not completely + * accurate so the following code give yet another alternative, yet another + * chance to transform some tokens. + * + * todo?: maybe could try to get rid of this technique. Maybe a better + * set_context() would make possible to move this code using a fix_xx + * technique. + *) + +open Lexer_parser (* for the fields of lexer_hint type *) + +let not_struct_enum = function + | (Parser_c.Tstruct _ | Parser_c.Tunion _ | Parser_c.Tenum _)::_ -> false + | _ -> true + + +let not_annot s = + not (s ==~ regexp_annot) + + +let forLOOKAHEAD = 30 + + +(* look if there is a '{' just after the closing ')', and handling the + * possibility to have nested expressions inside nested parenthesis + *) +let rec is_really_foreach xs = + let rec is_foreach_aux = function + | [] -> false, [] + | TCPar _::TOBrace _::xs -> true, xs + (* the following attempts to handle the cases where there is a + single statement in the body of the loop. undoubtedly more + cases are needed. + todo: premier(statement) - suivant(funcall) + *) + | TCPar _::TIdent _::xs -> true, xs + | TCPar _::Tif _::xs -> true, xs + | TCPar _::Twhile _::xs -> true, xs + | TCPar _::Tfor _::xs -> true, xs + | TCPar _::Tswitch _::xs -> true, xs + + | TCPar _::xs -> false, xs + | TOPar _::xs -> + let (_, xs') = is_foreach_aux xs in + is_foreach_aux xs' + | x::xs -> is_foreach_aux xs + in + is_foreach_aux xs +> fst + + +let ok_typedef s = not (List.mem s false_typedef) + + + +(* LALR(k) trick. We can do stuff by adding cases in lexer_c.mll, but + * it is more general to do it via my LALR(k) tech. Because here we can + * transform some token give some context information. So sometimes it + * makes sense to transform a token in one context, sometimes not, and + * lex can not provide us this context information. Note that the order + * in the pattern matching in lookahead is important. Do not cut/paste. + * + * Note that in next there is only "clean" tokens, there is no comment + * or space tokens. This is done by the caller. + * + *) + + +let lookahead2 next before = + + match (next, before) with + + (*-------------------------------------------------------------*) + (* typedef inference, parse_typedef_fix3 *) + (*-------------------------------------------------------------*) + (* xx xx *) + | (TIdent(s,i1)::TIdent(s2,i2)::_ , _) when not_struct_enum before && s = s2 + && ok_typedef s + (* (take_safe 1 !passed_tok <> [TOPar]) -> *) + -> + (* parse_typedef_fix3: + * acpi_object acpi_object; + * etait mal parsé, car pas le temps d'appeler dt() dans le type_spec. + * Le parser en interne a deja appelé le prochain token pour pouvoir + * decider des choses. + * => special case in lexer_heuristic, again + *) + if !Flag_parsing_c.debug_typedef + then pr2 ("TYPEDEF: disable typedef cos special case: " ^ s); + + LP.disable_typedef(); + + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (* xx yy *) + | (TIdent (s, i1)::TIdent (s2, i2)::_ , _) when not_struct_enum before + && ok_typedef s + -> + (* && not_annot s2 BUT lead to false positive*) + + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + (* xx inline *) + | (TIdent (s, i1)::Tinline i2::_ , _) when not_struct_enum before + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + (* [,(] xx [,)] AND param decl *) + | (TIdent (s, i1)::(TComma _|TCPar _)::_ , (TComma _ |TOPar _)::_ ) + when not_struct_enum before && !LP._lexer_hint.parameterDeclaration + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (* xx* [,)] *) + (* specialcase: [,(] xx* [,)] *) + | (TIdent (s, i1)::TMul _::(TComma _|TCPar _)::_ , (*(TComma _|TOPar _)::*)_ ) + when not_struct_enum before + (* && !LP._lexer_hint = Some LP.ParameterDeclaration *) + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + (* xx** [,)] *) + (* specialcase: [,(] xx** [,)] *) + | (TIdent (s, i1)::TMul _::TMul _::(TComma _|TCPar _)::_ , (*(TComma _|TOPar _)::*)_ ) + when not_struct_enum before + (* && !LP._lexer_hint = Some LP.ParameterDeclaration *) + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + + (* xx const * USELESS because of next rule ? *) + | (TIdent (s, i1)::(Tconst _|Tvolatile _)::TMul _::_ , _ ) + when not_struct_enum before + (* && !LP._lexer_hint = Some LP.ParameterDeclaration *) + && ok_typedef s + -> + + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (* xx const *) + | (TIdent (s, i1)::(Tconst _|Tvolatile _)::_ , _ ) + when not_struct_enum before + && ok_typedef s + (* && !LP._lexer_hint = Some LP.ParameterDeclaration *) + -> + + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + (* xx * const *) + | (TIdent (s, i1)::TMul _::(Tconst _ | Tvolatile _)::_ , _ ) + when not_struct_enum before + && ok_typedef s + -> + (* && !LP._lexer_hint = Some LP.ParameterDeclaration *) + + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + (* ( const xx) *) + | (TIdent (s, i1)::TCPar _::_, (Tconst _ | Tvolatile _)::TOPar _::_) when + ok_typedef s -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + + (* ( xx ) [sizeof, ~] *) + | (TIdent (s, i1)::TCPar _::(Tsizeof _|TTilde _)::_ , TOPar _::_ ) + when not_struct_enum before + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (* [(,] xx [ AND parameterdeclaration *) + | (TIdent (s, i1)::TOCro _::_, (TComma _ |TOPar _)::_) + when !LP._lexer_hint.parameterDeclaration + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (*------------------------------------------------------------*) + (* if 'x*y' maybe an expr, maybe just a classic multiplication *) + (* but if have a '=', or ',' I think not *) + (*------------------------------------------------------------*) + + (* static xx * yy *) + | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::_ , + (Tregister _|Tstatic _ |Tvolatile _|Tconst _)::_) when + ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (* TODO xx * yy ; AND in start of compound element *) + + + (* xx * yy, AND in paramdecl *) + | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TComma _::_ , _) + when not_struct_enum before && !LP._lexer_hint.parameterDeclaration + && ok_typedef s + -> + + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + (* xx * yy ; AND in Toplevel, except when have = before *) + | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TPtVirg _::_ , TEq _::_) -> + TIdent (s, i1) + | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TPtVirg _::_ , _) + when not_struct_enum before && !LP._lexer_hint.toplevel -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (* xx * yy , AND in Toplevel *) + | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TComma _::_ , _) + when not_struct_enum before && !LP._lexer_hint.toplevel + && ok_typedef s + -> + + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (* xx * yy ( AND in Toplevel *) + | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TOPar _::_ , _) + when not_struct_enum before && !LP._lexer_hint.toplevel + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (* xx * yy [ *) + (* todo? enough ? cos in struct def we can have some expression ! *) + | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TOCro _::_ , _) + when not_struct_enum before && + (!LP._lexer_hint.structDefinition > 0 || !LP._lexer_hint.toplevel) + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (* u16: 10; in struct *) + | (TIdent (s, i1)::TDotDot _::_ , (TOBrace _ | TPtVirg _)::_) + when (!LP._lexer_hint.structDefinition > 0 || !LP._lexer_hint.toplevel) + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + (* why need TOPar condition as stated in preceding rule ? really needed ? *) + (* YES cos at toplevel can have some expression !! for instance when *) + (* enter in the dimension of an array *) + (* + | (TIdent s::TMul::TIdent s2::_ , _) + when (take_safe 1 !passed_tok <> [Tstruct] && + (take_safe 1 !passed_tok <> [Tenum])) + && + !LP._lexer_hint = Some LP.Toplevel -> + msg_typedef s; + LP.add_typedef_root s; + TypedefIdent s + *) + + (* xx * yy = *) + | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TEq _::_ , _) + when not_struct_enum before + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + (* xx * yy) AND in paramdecl *) + | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TCPar _::_ , _) + when not_struct_enum before && !LP._lexer_hint.parameterDeclaration + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + (* xx * yy; *) (* wrong ? *) + | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TPtVirg _::_ , + (TOBrace _| TPtVirg _)::_) when not_struct_enum before + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + pr2 ("PB MAYBE: dangerous typedef inference, maybe not a typedef: " ^ s); + TypedefIdent (s, i1) + + + (* xx * yy, and ';' before xx *) (* wrong ? *) + | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TComma _::_ , + (TOBrace _| TPtVirg _)::_) when + ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + (* xx_t * yy *) + | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::_ , _) + when s ==~ regexp_typedef && not_struct_enum before + (* struct user_info_t sometimes *) + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (* xx ** yy *) (* wrong ? *) + | (TIdent (s, i1)::TMul _::TMul _::TIdent (s2, i2)::_ , _) + when not_struct_enum before + (* && !LP._lexer_hint = Some LP.ParameterDeclaration *) + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (* xx *** yy *) + | (TIdent (s, i1)::TMul _::TMul _::TMul _::TIdent (s2, i2)::_ , _) + when not_struct_enum before + && ok_typedef s + (* && !LP._lexer_hint = Some LP.ParameterDeclaration *) + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + (* xx ** ) *) + | (TIdent (s, i1)::TMul _::TMul _::TCPar _::_ , _) + when not_struct_enum before + (* && !LP._lexer_hint = Some LP.ParameterDeclaration *) + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + + (* ----------------------------------- *) + + (* (xx) yy *) + | (TOPar info::TIdent (s, i1)::TCPar i2::(TIdent (_,i3)|TInt (_,i3))::_ , + x::_) + when not (TH.is_stuff_taking_parenthized x) && + Ast_c.line_of_info i2 = Ast_c.line_of_info i3 + && ok_typedef s + -> + + msg_typedef s; LP.add_typedef_root s; + TOPar info + + + (* (xx) ( yy) *) + | (TOPar info::TIdent (s, i1)::TCPar _::TOPar _::_ , x::_) + when not (TH.is_stuff_taking_parenthized x) + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TOPar info + + (* (xx * ) yy *) + | (TOPar info::TIdent (s, i1)::TMul _::TCPar _::TIdent (s2, i2)::_ , _) when + ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TOPar info + + (* (xx){ ... } constructor *) + | (TIdent (s, i1)::TCPar _::TOBrace _::_ , TOPar _::x::_) + when (*s ==~ regexp_typedef && *) not (TH.is_stuff_taking_parenthized x) + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + (* can have sizeof on expression + | (Tsizeof::TOPar::TIdent s::TCPar::_, _) -> + msg_typedef s; + LP.add_typedef_root s; + Tsizeof + *) + (* x ( *y )(params), function pointer *) + | (TIdent (s, i1)::TOPar _::TMul _::TIdent _::TCPar _::TOPar _::_, _) + when not_struct_enum before + && ok_typedef s + -> + msg_typedef s; LP.add_typedef_root s; + TypedefIdent (s, i1) + + + (*-------------------------------------------------------------*) + (* CPP *) + (*-------------------------------------------------------------*) + | ((TIfdef ii |TIfdefelse ii |TIfdefelif ii |TEndif ii | + TIfdefBool (_,ii)|TIfdefMisc(_,ii)|TIfdefVersion(_,ii)) + as x) + ::_, _ + -> + if not !Flag_parsing_c.ifdef_to_if + then TCommentCpp (Ast_c.CppDirective, ii) + else + if not !LP._lexer_hint.toplevel + then x + else begin + pr2_cpp("IFDEF: or related outside function. I treat it as comment"); + TCommentCpp (Ast_c.CppDirective, ii) + end + + + (* If ident contain a for_each, then certainly a macro. But to be + * sure should look if there is a '{' after the ')', but it requires + * to count the '('. Because this can be expensive, we do that only + * when the token contains "for_each". + *) + | (TIdent (s, i1)::TOPar _::rest, _) when not !LP._lexer_hint.toplevel + (* otherwise a function such as static void loopback_enable(int i) { + * will be considered as a loop + *) + -> + + + if s ==~ regexp_foreach && + is_really_foreach (Common.take_safe forLOOKAHEAD rest) + + then begin + msg_foreach s; + TMacroIterator (s, i1) + end + else TIdent (s, i1) + + + + (*-------------------------------------------------------------*) + | v::xs, _ -> v + | _ -> raise Impossible + +let lookahead a b = + Common.profile_code "C parsing.lookahead" (fun () -> lookahead2 a b) + + diff --git a/parsing_c/parsing_hacks.mli b/parsing_c/parsing_hacks.mli new file mode 100644 index 0000000..3897a47 --- /dev/null +++ b/parsing_c/parsing_hacks.mli @@ -0,0 +1,49 @@ +open Common + +(* Try detect some cpp idioms so can parse as is files by adjusting or + * commenting some tokens. Parsing hack style. Sometime use indentation info, + * Sometimes do some kind of lalr(k) by finding patterns. Often try to + * work on better token representation, like ifdef-paren-ized, brace-ized, + * paren-ized, so can do easier pattern matching to more easily match + * complex cpp idiom pattern. Also try to get context info such as + * whether the token is in a initializer as some common patterns have different + * use depending on context. + * + * + * Example of cpp idioms: + * - if 0 for commenting stuff (not always code, sometimes just real comments) + * - ifdef old version + * - ifdef funheader + * - ifdef statements, ifdef expression, ifdef-mid + * - macro toplevel (with or without ptvirg) + * - macro foreach + * - macro higher order + * - macro declare + * - macro debug + * - macro no ptvirg + * - macro string, and macro function string taking param and ## + * - macro attribute + * Cf the TMacroXxx in parser_c.mly and MacroXxx in ast_c.ml + * + * Also try infer typedef. + * + * Also do other stuff involving cpp like expanding some macros, + * or try parse well define body by finding the end of define virtual + * end-of-line token. + *) + +(* the either is to differentialte macro-variables from macro-functions *) +type define_body = (unit,string list) either * Parser_c.token list + +val _defs : (string, define_body) Hashtbl.t ref + + +val fix_tokens_define : Parser_c.token list -> Parser_c.token list +val extract_cpp_define : Parser_c.token list -> (string, define_body) assoc + + +val fix_tokens_cpp : Parser_c.token list -> Parser_c.token list + +(* next stream tokens -> passed stream tokens -> final next token *) +val lookahead : Parser_c.token list -> Parser_c.token list -> Parser_c.token + diff --git a/parsing_c/pretty_print_c.ml b/parsing_c/pretty_print_c.ml new file mode 100644 index 0000000..be1931b --- /dev/null +++ b/parsing_c/pretty_print_c.ml @@ -0,0 +1,937 @@ +(* Copyright (C) 2002-2008 Yoann Padioleau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License (GPL) + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * file license.txt for more details. + *) +open Common + +open Ast_c + +type pr_elem_func = Ast_c.info -> unit +type pr_space_func = unit -> unit + +(*****************************************************************************) + +(* This module is used by unparse_c, but because unparse_c have also + * the list of tokens, pretty_print_c could be useless in the futur + * (except that the ast_c have some fake tokens not present in the list + * of tokens so it's still useful). But this module is also useful to + * unparse C when you don't have the ordered list of tokens separately, + * or tokens without position information, for instance when you want + * to pretty print some piece of C that was generated, or some + * abstract-lined piece of code, etc. *) + +let rec pp_expression_gen pr_elem pr_space = + (* subtil: dont try to shorten the def of pp_statement by omitting e, + otherwise get infinite funcall and huge memory consumption *) + let pp_statement e = pp_statement_gen pr_elem pr_space e in + let rec pp_expression = fun ((exp, typ), ii) -> + (match exp, ii with + | Ident (c), [i] -> pr_elem i + (* only a MultiString can have multiple ii *) + | Constant (MultiString), is -> is +> List.iter pr_elem + | Constant (c), [i] -> pr_elem i + | FunCall (e, es), [i1;i2] -> + pp_expression e; pr_elem i1; + es +> List.iter (fun (e, opt) -> + assert (List.length opt <= 1); (* opt must be a comma? *) + opt +> List.iter (function x -> pr_elem x; pr_space()); + pp_argument_gen pr_elem pr_space e; + ); + pr_elem i2; + + | CondExpr (e1, e2, e3), [i1;i2] -> + pp_expression e1; pr_space(); pr_elem i1; pr_space(); + do_option (function x -> pp_expression x; pr_space()) e2; pr_elem i2; + pp_expression e3 + | Sequence (e1, e2), [i] -> + pp_expression e1; pr_elem i; pr_space(); pp_expression e2 + | Assignment (e1, op, e2), [i] -> + pp_expression e1; pr_space(); pr_elem i; pr_space(); pp_expression e2 + + | Postfix (e, op), [i] -> pp_expression e; pr_elem i; + | Infix (e, op), [i] -> pr_elem i; pp_expression e; + | Unary (e, op), [i] -> pr_elem i; pp_expression e + | Binary (e1, op, e2), [i] -> + pp_expression e1; pr_space(); pr_elem i; pr_space(); pp_expression e2 + + | ArrayAccess (e1, e2), [i1;i2] -> + pp_expression e1; pr_elem i1; pp_expression e2; pr_elem i2 + | RecordAccess (e, s), [i1;i2] -> + pp_expression e; pr_elem i1; pr_elem i2 + | RecordPtAccess (e, s), [i1;i2] -> + pp_expression e; pr_elem i1; pr_elem i2 + + | SizeOfExpr (e), [i] -> pr_elem i; pp_expression e + | SizeOfType (t), [i1;i2;i3] -> + pr_elem i1; pr_elem i2; pp_type_gen pr_elem pr_space t; + pr_elem i3 + | Cast (t, e), [i1;i2] -> + pr_elem i1; pp_type_gen pr_elem pr_space t; pr_elem i2; + pp_expression e + + | StatementExpr (statxs, [ii1;ii2]), [i1;i2] -> + pr_elem i1; + pr_elem ii1; + statxs +> List.iter pp_statement; + pr_elem ii2; + pr_elem i2; + | Constructor (t, xs), lp::rp::i1::i2::iicommaopt -> + pr_elem lp; + pp_type_gen pr_elem pr_space t; + pr_elem rp; + pr_elem i1; + xs +> List.iter (fun (x, ii) -> + assert (List.length ii <= 1); + ii +> List.iter (function x -> pr_elem x; pr_space()); + pp_init_gen pr_elem pr_space x + ); + iicommaopt +> List.iter pr_elem; + pr_elem i2; + + + + | ParenExpr (e), [i1;i2] -> pr_elem i1; pp_expression e; pr_elem i2; + + | (Ident (_) | Constant _ | FunCall (_,_) | CondExpr (_,_,_) + | Sequence (_,_) + | Assignment (_,_,_) + | Postfix (_,_) | Infix (_,_) | Unary (_,_) | Binary (_,_,_) + | ArrayAccess (_,_) | RecordAccess (_,_) | RecordPtAccess (_,_) + | SizeOfExpr (_) | SizeOfType (_) | Cast (_,_) + | StatementExpr (_) | Constructor _ + | ParenExpr (_) + ),_ -> raise Impossible + ); + if !Flag_parsing_c.pretty_print_type_info + then begin + pr_elem (Ast_c.fakeInfo() +> Ast_c.rewrap_str "/*"); + !typ +> + (fun (ty,_test) -> ty +> + Common.do_option + (fun (x,l) -> pp_type_gen pr_elem pr_space x; + let s = match l with + Ast_c.LocalVar _ -> ", local" + | _ -> "" in + pr_elem (Ast_c.fakeInfo() +> Ast_c.rewrap_str s))); + pr_elem (Ast_c.fakeInfo() +> Ast_c.rewrap_str "*/"); + end + + in + pp_expression + + +and pp_argument_gen pr_elem pr_space argument = + let rec pp_action = function + | (ActMisc ii) -> ii +> List.iter pr_elem + in + match argument with + | Left e -> pp_expression_gen pr_elem pr_space e + | Right wierd -> + (match wierd with + | ArgType param -> pp_param_gen pr_elem pr_space param + | ArgAction action -> pp_action action + ) + + + + + +(* ---------------------- *) +and pp_statement_gen pr_elem pr_space = + let pp_expression e = pp_expression_gen pr_elem pr_space e in + let rec pp_statement = function + | Labeled (Label (s, st)), [i1;i2] -> + pr_elem i1; pr_elem i2; pp_statement st + | Labeled (Case (e, st)), [i1;i2] -> + pr_elem i1; pp_expression e; pr_elem i2; pp_statement st + | Labeled (CaseRange (e, e2, st)), [i1;i2;i3] -> + pr_elem i1; pp_expression e; pr_elem i2; pp_expression e2; pr_elem i3; + pp_statement st + | Labeled (Default st), [i1;i2] -> pr_elem i1; pr_elem i2; pp_statement st + | Compound statxs, [i1;i2] -> + pr_elem i1; statxs +> List.iter pp_statement; pr_elem i2; + + | ExprStatement (None), [i] -> pr_elem i; + | ExprStatement (None), [] -> () + | ExprStatement (Some e), [i] -> pp_expression e; pr_elem i + (* the last ExprStatement of a for does not have a trailing + ';' hence the [] for ii *) + | ExprStatement (Some e), [] -> pp_expression e; + | Selection (If (e, st1, st2)), i1::i2::i3::is -> + pr_elem i1; pr_elem i2; pp_expression e; pr_elem i3; pp_statement st1; + (match (st2, is) with + | ((ExprStatement None, []), []) -> () + | ((ExprStatement None, []), [iifakend]) -> pr_elem iifakend + | st2, [i4;iifakend] -> pr_elem i4; pp_statement st2; pr_elem iifakend + | x -> raise Impossible + ) + | Selection (Switch (e, st)), [i1;i2;i3;iifakend] -> + pr_elem i1; pr_elem i2; pp_expression e; pr_elem i3; pp_statement st; + pr_elem iifakend + | Iteration (While (e, st)), [i1;i2;i3;iifakend] -> + pr_elem i1; pr_elem i2; pp_expression e; pr_elem i3; pp_statement st; + pr_elem iifakend + | Iteration (DoWhile (st, e)), [i1;i2;i3;i4;i5;iifakend] -> + pr_elem i1; pp_statement st; pr_elem i2; pr_elem i3; pp_expression e; + pr_elem i4; pr_elem i5; + pr_elem iifakend + + + | Iteration (For ((e1opt,il1),(e2opt,il2),(e3opt, il3),st)), + [i1;i2;i3;iifakend] -> + + pr_elem i1; + pr_elem i2; + pp_statement (ExprStatement e1opt, il1); + pp_statement (ExprStatement e2opt, il2); + assert (null il3); + pp_statement (ExprStatement e3opt, il3); + pr_elem i3; + pp_statement st; + pr_elem iifakend + + | Iteration (MacroIteration (s,es,st)), [i1;i2;i3;iifakend] -> + pr_elem i1; + pr_elem i2; + + es +> List.iter (fun (e, opt) -> + assert (List.length opt <= 1); + opt +> List.iter pr_elem; + pp_argument_gen pr_elem pr_space e; + ); + + pr_elem i3; + pp_statement st; + pr_elem iifakend + + | Jump (Goto s), [i1;i2;i3] -> + pr_elem i1; pr_space(); pr_elem i2; pr_elem i3; + | Jump ((Continue|Break|Return)), [i1;i2] -> pr_elem i1; pr_elem i2; + | Jump (ReturnExpr e), [i1;i2] -> + pr_elem i1; pr_space(); pp_expression e; pr_elem i2 + | Jump (GotoComputed e), [i1;i2;i3] -> + pr_elem i1; pr_elem i2; pp_expression e; pr_elem i3 + + | Decl decl, [] -> pp_decl_gen pr_elem pr_space decl + | Asm asmbody, ii -> + (match ii with + | [iasm;iopar;icpar;iptvirg] -> + pr_elem iasm; pr_elem iopar; + pp_asmbody_gen pr_elem pr_space asmbody; + pr_elem icpar; pr_elem iptvirg + | [iasm;ivolatile;iopar;icpar;iptvirg] -> + pr_elem iasm; pr_elem ivolatile; pr_elem iopar; + pp_asmbody_gen pr_elem pr_space asmbody; + pr_elem icpar; pr_elem iptvirg + | _ -> raise Impossible + ) + + | NestedFunc def, ii -> + assert (null ii); + pp_def_gen pr_elem pr_space def + | MacroStmt, ii -> + ii +> List.iter pr_elem ; + + | Selection (Ifdef (st1s, st2s)), i1::i2::is -> + pr_elem i1; + st1s +> List.iter pp_statement; + (match (st2s, is) with + | [], [iifakend] -> pr_elem i2; pr_elem iifakend + | x::xs, [i3;iifakend] -> + pr_elem i2; + st2s +> List.iter pp_statement; + pr_elem i3; + pr_elem iifakend + + | _ -> raise Impossible + ) + | ( Labeled (Label (_,_)) | Labeled (Case (_,_)) + | Labeled (CaseRange (_,_,_)) | Labeled (Default _) + | Compound _ | ExprStatement _ + | Selection (If (_, _, _)) | Selection (Switch (_, _)) + | Iteration (While (_, _)) | Iteration (DoWhile (_, _)) + | Iteration (For ((_,_), (_,_), (_, _), _)) + | Iteration (MacroIteration (_,_,_)) + | Jump (Goto _) | Jump ((Continue|Break|Return)) | Jump (ReturnExpr _) + | Jump (GotoComputed _) + | Decl _ | Selection (Ifdef (_,_)) + ), _ -> raise Impossible + + in + pp_statement + + +and pp_asmbody_gen pr_elem pr_space (string_list, colon_list) = + string_list +> List.iter pr_elem ; + colon_list +> List.iter (fun (Colon xs, ii) -> + ii +> List.iter pr_elem; + xs +> List.iter (fun (x,iicomma) -> + assert ((List.length iicomma) <= 1); + iicomma +> List.iter (function x -> pr_elem x; pr_space()); + (match x with + | ColonMisc, ii -> ii +> List.iter pr_elem; + | ColonExpr e, [istring;iopar;icpar] -> + pr_elem istring; + pr_elem iopar; + pp_expression_gen pr_elem pr_space e; + pr_elem icpar + | _ -> raise Impossible + ) + )) + + +(* ---------------------- *) +and (pp_type_with_ident_gen: + pr_elem_func -> pr_space_func -> + (string * info) option -> (storage * il) option -> fullType -> unit) = + fun pr_elem pr_space -> + fun ident sto ((qu, iiqu), (ty, iity)) -> + pp_base_type_gen pr_elem pr_space ((qu, iiqu), (ty, iity)) sto; + pp_type_with_ident_rest_gen pr_elem pr_space ident + ((qu, iiqu), (ty, iity)) + + +and (pp_base_type_gen: + pr_elem_func -> pr_space_func -> fullType -> + (storage * il) option -> unit) = + fun pr_elem pr_space -> + let pp_expression e = pp_expression_gen pr_elem pr_space e in + + let rec pp_base_type = + fun (qu, (ty, iity)) sto -> + let get_sto sto = + match sto with + | None -> [] | Some (s, iis) -> (*assert (List.length iis = 1);*) iis + in + let print_sto_qu (sto, (qu, iiqu)) = + let all_ii = get_sto sto ++ iiqu in + all_ii + +> List.sort Ast_c.compare_pos + +> List.iter pr_elem; + + in + let print_sto_qu_ty (sto, (qu, iiqu), iity) = + let all_ii = get_sto sto ++ iiqu ++ iity in + let all_ii2 = all_ii +> List.sort Ast_c.compare_pos in + + if all_ii <> all_ii2 + then begin + (* TODO in fact for pointer, the qualifier is after the type + * cf -test strangeorder + *) + pr2 "STRANGEORDER"; + all_ii2 +> List.iter pr_elem + end + else all_ii2 +> List.iter pr_elem + in + + match ty, iity with + | (Pointer t, [i]) -> pp_base_type t sto + | (ParenType t, _) -> pp_base_type t sto + | (Array (eopt, t), [i1;i2]) -> pp_base_type t sto + | (FunctionType (returnt, paramst), [i1;i2]) -> + pp_base_type returnt sto + + + | (StructUnion (su, sopt, fields),iis) -> + print_sto_qu (sto, qu); + + (match sopt,iis with + | Some s , [i1;i2;i3;i4] -> + pr_elem i1; pr_elem i2; pr_elem i3; + | None, [i1;i2;i3] -> + pr_elem i1; pr_elem i2; + | x -> raise Impossible + ); + + fields +> List.iter + (fun (xfield, iipttvirg) -> + + match xfield with + | FieldDeclList onefield_multivars -> + (match onefield_multivars with + | x::xs -> + (* handling the first var. Special case, with the + first var, we print the whole type *) + + (match x with + | (Simple (sopt, typ), iis), iivirg -> + (* first var cant have a preceding ',' *) + assert (List.length iivirg = 0); + let identinfo = + (match sopt, iis with + None,_ -> None + | (Some s, [iis]) -> Some (s, iis) + | x -> raise Impossible) + in + pp_type_with_ident_gen pr_elem pr_space + identinfo None typ; + + | (BitField (sopt, typ, expr), ii), iivirg -> + (* first var cant have a preceding ',' *) + assert (List.length iivirg = 0); + (match sopt, ii with + | (None , [idot]) -> + pp_type_gen pr_elem pr_space typ; + pr_elem idot; + pp_expression expr + | (Some s, [is;idot]) -> + pp_type_with_ident_gen + pr_elem pr_space (Some (s, is)) None typ; + pr_elem idot; + pp_expression expr + | x -> raise Impossible + ) + + ); + + (* for other vars *) + xs +> List.iter (function + | (Simple (sopt, typ), iis), iivirg -> + iivirg +> List.iter pr_elem; + let identinfo = + (match sopt, iis with + | None,_ -> None + | (Some s, [iis]) -> Some (s, iis) + | x -> raise Impossible) + in + pp_type_with_ident_rest_gen pr_elem pr_space + identinfo typ; + + | (BitField (sopt, typ, expr), ii), iivirg -> + iivirg +> List.iter pr_elem; + (match sopt, ii with + | (Some s, [is;idot]) -> + pp_type_with_ident_rest_gen + pr_elem pr_space (Some (s, is)) typ; + pr_elem idot; + pp_expression expr + | x -> raise Impossible + ); + + ); + + assert (List.length iipttvirg = 1); + iipttvirg +> List.iter pr_elem; + | x -> raise Impossible + ) + | EmptyField -> () + ); + + (match sopt,iis with + | Some s , [i1;i2;i3;i4] -> pr_elem i4 + | None, [i1;i2;i3] -> pr_elem i3; + | x -> raise Impossible + ); + + + + | (Enum (sopt, enumt), iis) -> + print_sto_qu (sto, qu); + + (match sopt, iis with + | (Some s, ([i1;i2;i3;i4]|[i1;i2;i3;i4;_])) -> + pr_elem i1; pr_elem i2; pr_elem i3; + | (None, ([i1;i2;i3]|[i1;i2;i3;_])) -> + pr_elem i1; pr_elem i2 + | x -> raise Impossible + ); + + enumt +> List.iter (fun (((s, eopt),ii_s_eq), iicomma) -> + assert (List.length iicomma <= 1); + iicomma +> List.iter (function x -> pr_elem x; pr_space()); + (match eopt, ii_s_eq with + | None, [is] -> pr_elem is; + | Some e, [is;ieq] -> pr_elem is; pr_elem ieq; pp_expression e + | _ -> raise Impossible + ) + + ); + + (match sopt, iis with + | (Some s, [i1;i2;i3;i4]) -> pr_elem i4 + | (Some s, [i1;i2;i3;i4;i5]) -> + pr_elem i5; pr_elem i4 (* trailing comma *) + | (None, [i1;i2;i3]) -> pr_elem i3 + | (None, [i1;i2;i3;i4]) -> + pr_elem i4; pr_elem i3 (* trailing comma *) + + + | x -> raise Impossible + ); + + + | (BaseType _, iis) -> + print_sto_qu_ty (sto, qu, iis); + + | (StructUnionName (s, structunion), iis) -> + assert (List.length iis = 2); + print_sto_qu_ty (sto, qu, iis); + + | (EnumName s, iis) -> + assert (List.length iis = 2); + print_sto_qu_ty (sto, qu, iis); + + | (TypeName (s,_typ), iis) -> + assert (List.length iis = 1); + print_sto_qu_ty (sto, qu, iis); + + | (TypeOfExpr (e), iis) -> + print_sto_qu (sto, qu); + (match iis with + | [itypeof;iopar;icpar] -> + pr_elem itypeof; pr_elem iopar; + pp_expression_gen pr_elem pr_space e; + pr_elem icpar; + | _ -> raise Impossible + ) + + | (TypeOfType (t), iis) -> + print_sto_qu (sto, qu); + (match iis with + | [itypeof;iopar;icpar] -> + pr_elem itypeof; pr_elem iopar; + pp_type_gen pr_elem pr_space t; + pr_elem icpar; + | _ -> raise Impossible + ) + + + | x -> raise Impossible + in + pp_base_type + + +(* used because of DeclList, in int i,*j[23]; we dont print anymore the + int before *j *) +and (pp_type_with_ident_rest_gen: + pr_elem_func -> pr_space_func -> + (string * info) option -> fullType -> unit) = + fun pr_elem pr_space -> + fun ident (((qu, iiqu), (ty, iity)) as fullt) -> + let print_ident ident = do_option (fun (s, iis) -> pr_elem iis) ident + in + + match ty, iity with + (* the work is to do in base_type !! *) + | (BaseType _, iis) -> print_ident ident + | (Enum (sopt, enumt), iis) -> print_ident ident + | (StructUnion (_, sopt, fields),iis) -> print_ident ident + | (StructUnionName (s, structunion), iis) -> print_ident ident + | (EnumName s, iis) -> print_ident ident + | (TypeName (s,_typ), iis) -> print_ident ident + | (TypeOfExpr (e), iis) -> print_ident ident + | (TypeOfType (e), iis) -> print_ident ident + + + + | (Pointer t, [i]) -> + (* subtil: void ( *done)(int i) is a Pointer + (FunctionType (return=void, params=int i) *) + (*WRONG I THINK, use left & right function *) + (* bug: pp_type_with_ident_rest None t; print_ident ident *) + pr_elem i; + iiqu +> List.iter pr_elem; (* le const est forcement apres le '*' *) + pp_type_with_ident_rest_gen pr_elem pr_space ident t; + + (* ugly special case ... todo? maybe sufficient in practice *) + | (ParenType (q1, (Pointer (q2, (FunctionType t, ii3)) , + [ipointer]) ), [i1;i2]) -> + pp_type_left_gen pr_elem pr_space (q2, (FunctionType t, ii3)); + pr_elem i1; + pr_elem ipointer; + print_ident ident; + pr_elem i2; + pp_type_right_gen pr_elem pr_space (q2, (FunctionType t, ii3)); + + (* another ugly special case *) + | (ParenType + (q1, (Array (eopt, + (q2, (Pointer + (q3, (FunctionType t, iifunc)), + [ipointer]))), + [iarray1;iarray2])), [i1;i2]) -> + pp_type_left_gen pr_elem pr_space (q3, (FunctionType t, iifunc)); + pr_elem i1; + pr_elem ipointer; + print_ident ident; + pr_elem iarray1; + do_option (pp_expression_gen pr_elem pr_space) eopt; + pr_elem iarray2; + pr_elem i2; + pp_type_right_gen pr_elem pr_space (q3, (FunctionType t, iifunc)) + + + + | (ParenType t, [i1;i2]) -> + pr2 "PB PARENTYPE ZARB, I forget about the ()"; + pp_type_with_ident_rest_gen pr_elem pr_space ident t; + + + | (Array (eopt, t), [i1;i2]) -> + pp_type_left_gen pr_elem pr_space fullt; + + iiqu +> List.iter pr_elem; + print_ident ident; + + pp_type_right_gen pr_elem pr_space fullt; + + + | (FunctionType (returnt, paramst), [i1;i2]) -> + pp_type_left_gen pr_elem pr_space fullt; + + iiqu +> List.iter pr_elem; + print_ident ident; + + pp_type_right_gen pr_elem pr_space fullt; + + | x -> raise Impossible + + +and (pp_type_left_gen: pr_elem_func -> pr_space_func -> fullType -> unit) = + fun pr_elem pr_space -> + let rec pp_type_left = fun ((qu, iiqu), (ty, iity)) -> + match ty, iity with + | (Pointer t, [i]) -> + pr_elem i; + iiqu +> List.iter pr_elem; (* le const est forcement apres le '*' *) + pp_type_left t + + | (Array (eopt, t), [i1;i2]) -> pp_type_left t + | (FunctionType (returnt, paramst), [i1;i2]) -> pp_type_left returnt + + | (ParenType t, _) -> failwith "parenType" + + + | (BaseType _, iis) -> () + | (Enum (sopt, enumt), iis) -> () + | (StructUnion (_, sopt, fields),iis) -> () + | (StructUnionName (s, structunion), iis) -> () + | (EnumName s, iis) -> () + | (TypeName (s,_typ), iis) -> () + | x -> raise Impossible + in + pp_type_left + + +and pp_param_gen pr_elem pr_space = fun ((b, sopt, t), ii_b_s) -> + match b, sopt, ii_b_s with + | false, None, [] -> + pp_type_gen pr_elem pr_space t + | true, None, [i1] -> + pr_elem i1; + pp_type_gen pr_elem pr_space t + + | false, Some s, [i1] -> + pp_type_with_ident_gen pr_elem pr_space (Some (s, i1)) None t; + | true, Some s, [i1;i2] -> + pr_elem i1; + pp_type_with_ident_gen pr_elem pr_space (Some (s, i2)) None t; + | _ -> raise Impossible + + +and (pp_type_right_gen: pr_elem_func -> pr_space_func -> fullType -> unit) = + fun pr_elem pr_space -> + let rec pp_type_right = fun ((qu, iiqu), (ty, iity)) -> + match ty, iity with + | (Pointer t, [i]) -> pp_type_right t + + | (Array (eopt, t), [i1;i2]) -> + pr_elem i1; + eopt +> do_option (fun e -> pp_expression_gen pr_elem pr_space e); + pr_elem i2; + pp_type_right t + + | (ParenType t, _) -> failwith "parenType" + | (FunctionType (returnt, paramst), [i1;i2]) -> + pr_elem i1; + (match paramst with + | (ts, (b, iib)) -> + ts +> List.iter (fun (param,iicomma) -> + assert ((List.length iicomma) <= 1); + iicomma +> List.iter (function x -> pr_elem x; pr_space()); + + pp_param_gen pr_elem pr_space param; + ); + iib +> List.iter pr_elem; + ); + pr_elem i2; + + + + + | (BaseType _, iis) -> () + | (Enum (sopt, enumt), iis) -> () + | (StructUnion (_, sopt, fields),iis)-> () + | (StructUnionName (s, structunion), iis) -> () + | (EnumName s, iis) -> () + | (TypeName (s,_typ), iis) -> () + | x -> raise Impossible + in + pp_type_right + +and pp_type_gen pr_elem pr_space t = + pp_type_with_ident_gen pr_elem pr_space None None t + +(* ---------------------- *) +and pp_decl_gen pr_elem pr_space = function + | DeclList ((((var, returnType, storage, _local),[])::xs), + iivirg::ifakestart::iisto) -> + + pr_elem ifakestart; + + (* old: iisto +> List.iter pr_elem; *) + + + (* handling the first var. Special case, we print the whole type *) + (match var with + | Some ((s, ini), iis::iini) -> + pp_type_with_ident_gen pr_elem pr_space + (Some (s, iis)) (Some (storage, iisto)) + returnType; + ini +> do_option (fun init -> + List.iter pr_elem iini; pp_init_gen pr_elem pr_space init); + | None -> pp_type_gen pr_elem pr_space returnType + | _ -> raise Impossible + ); + + (* for other vars, we just call pp_type_with_ident_rest. *) + xs +> List.iter (function + | ((Some ((s, ini), iis::iini), returnType, storage2, _local), iivirg) -> + assert (storage2 = storage); + iivirg +> List.iter pr_elem; + pp_type_with_ident_rest_gen pr_elem pr_space + (Some (s, iis)) returnType; + ini +> do_option (fun (init) -> + List.iter pr_elem iini; pp_init_gen pr_elem pr_space init); + + + | x -> raise Impossible + ); + + pr_elem iivirg; + + | MacroDecl ((s, es), iis::lp::rp::iiend::ifakestart::iisto) -> + pr_elem ifakestart; + iisto +> List.iter pr_elem; (* static and const *) + pr_elem iis; + pr_elem lp; + es +> List.iter (fun (e, opt) -> + assert (List.length opt <= 1); + opt +> List.iter pr_elem; + pp_argument_gen pr_elem pr_space e; + ); + + pr_elem rp; + pr_elem iiend; + + | x -> raise Impossible + + +(* ---------------------- *) +and pp_init_gen = fun pr_elem pr_space -> + let pp_expression e = pp_expression_gen pr_elem pr_space e in + let rec pp_init = fun (init, iinit) -> + match init, iinit with + | InitExpr e, [] -> pp_expression e; + | InitList xs, i1::i2::iicommaopt -> + pr_elem i1; + xs +> List.iter (fun (x, ii) -> + assert (List.length ii <= 1); + ii +> List.iter pr_elem; + pp_init x + ); + iicommaopt +> List.iter pr_elem; + pr_elem i2; + + | InitDesignators (xs, initialiser), [i1] -> (* : *) + xs +> List.iter (pp_designator pr_elem pr_space); + pr_elem i1; + pp_init initialiser + + (* no use of '=' in the "Old" style *) + | InitFieldOld (string, initialiser), [i1;i2] -> (* label: in oldgcc *) + pr_elem i1; pr_elem i2; pp_init initialiser + | InitIndexOld (expression, initialiser), [i1;i2] -> (* [1] in oldgcc *) + pr_elem i1; pp_expression expression; pr_elem i2; + pp_init initialiser + | x -> raise Impossible + in + pp_init + + + +and pp_designator pr_elem pr_space design = + let pp_expression e = pp_expression_gen pr_elem pr_space e in + match design with + | DesignatorField (s), [i1; i2] -> + pr_elem i1; pr_elem i2; + | DesignatorIndex (expression), [i1;i2] -> + pr_elem i1; pp_expression expression; pr_elem i2; + + | DesignatorRange (e1, e2), [iocro;iellipsis;iccro] -> + pr_elem iocro; pp_expression e1; pr_elem iellipsis; + pp_expression e2; pr_elem iccro; + | x -> raise Impossible + + + + +(* ---------------------- *) +and pp_def_gen pr_elem pr_space def = + match def with + | ((s, (returnt, (paramst, (b, iib))), sto, statxs), + is::iifunc1::iifunc2::i1::i2::ifakestart::isto) -> + + pr_elem ifakestart; + + pp_type_with_ident_gen pr_elem pr_space None (Some (sto, isto)) + returnt; + pr_elem is; + pr_elem iifunc1; + + (* not anymore, cf tests/optional_name_parameter and + macro_parameter_shortcut.c + (match paramst with + | [(((bool, None, t), ii_b_s), iicomma)] -> + assert + (match t with + | qu, (BaseType Void, ii) -> true + | _ -> true + ); + assert (null iicomma); + assert (null ii_b_s); + pp_type_with_ident_gen pr_elem pr_space None None t + + | paramst -> + paramst +> List.iter (fun (((bool, s, t), ii_b_s), iicomma) -> + iicomma +> List.iter pr_elem; + + (match b, s, ii_b_s with + | false, Some s, [i1] -> + pp_type_with_ident_gen + pr_elem pr_space (Some (s, i1)) None t; + | true, Some s, [i1;i2] -> + pr_elem i1; + pp_type_with_ident_gen + pr_elem pr_space (Some (s, i2)) None t; + + (* in definition we have name for params, except when f(void) *) + | _, None, _ -> raise Impossible + | false, None, [] -> + + | _ -> raise Impossible + ) + ); + ); + + (* normally ii represent the ",..." but it is also abused + with the f(void) case *) + (* assert (List.length iib <= 2);*) + iib +> List.iter pr_elem; + + *) + paramst +> List.iter (fun (param,iicomma) -> + assert ((List.length iicomma) <= 1); + iicomma +> List.iter (function x -> pr_elem x; pr_space()); + + pp_param_gen pr_elem pr_space param; + ); + iib +> List.iter pr_elem; + + + pr_elem iifunc2; + pr_elem i1; + statxs +> List.iter (pp_statement_gen pr_elem pr_space); + pr_elem i2; + | _ -> raise Impossible + + + + +let pp_program_gen pr_elem pr_space progelem = + match progelem with + | Declaration decl -> pp_decl_gen pr_elem pr_space decl + | Definition def -> pp_def_gen pr_elem pr_space def + + | Include ((s, [i1;i2]),h_rel_pos) -> + pr_elem i1; pr_elem i2 + | Define ((s,[idefine;iident;ieol]), (defkind, defval)) -> + pr_elem idefine; + pr_elem iident; + + let define_val = function + | DefineExpr e -> pp_expression_gen pr_elem pr_space e + | DefineStmt st -> pp_statement_gen pr_elem pr_space st + | DefineDoWhileZero (st, ii) -> + (match ii with + | [ido;iwhile;iopar;iint;icpar] -> + pr_elem ido; + pp_statement_gen pr_elem pr_space st; + pr_elem iwhile; pr_elem iopar; pr_elem iint; pr_elem icpar + | _ -> raise Impossible + ) + | DefineFunction def -> pp_def_gen pr_elem pr_space def + + | DefineType ty -> pp_type_gen pr_elem pr_space ty + | DefineText (s, ii) -> List.iter pr_elem ii + | DefineEmpty -> () + in + (match defkind with + | DefineVar -> () + | DefineFunc (params, ii) -> + let (i1,i2) = tuple_of_list2 ii in + pr_elem i1; + params +> List.iter (fun ((s,iis), iicomma) -> + assert (List.length iicomma <= 1); + iicomma +> List.iter pr_elem; + iis +> List.iter pr_elem; + ); + pr_elem i2; + ); + define_val defval; + pr_elem ieol + + + | MacroTop (s, es, [i1;i2;i3;i4]) -> + pr_elem i1; + pr_elem i2; + es +> List.iter (fun (e, opt) -> + assert (List.length opt <= 1); + opt +> List.iter pr_elem; + pp_argument_gen pr_elem pr_space e; + ); + pr_elem i3; + pr_elem i4; + + + | EmptyDef ii -> ii +> List.iter pr_elem + | NotParsedCorrectly ii -> + assert (List.length ii >= 1); + ii +> List.iter pr_elem + | FinalDef info -> pr_elem (Ast_c.rewrap_str "" info) + + | _ -> raise Impossible + + + + +(*****************************************************************************) + +(* Here we do not use (mcode, env). It is a simple C pretty printer. *) +let pr_elem info = + let s = Ast_c.str_of_info info in + pp s + +let pr_space _ = Format.print_space() + +let pp_expression_simple = pp_expression_gen pr_elem pr_space +let pp_statement_simple = pp_statement_gen pr_elem pr_space +let pp_type_simple = pp_type_gen pr_elem pr_space diff --git a/parsing_c/pretty_print_c.mli b/parsing_c/pretty_print_c.mli new file mode 100644 index 0000000..70091fa --- /dev/null +++ b/parsing_c/pretty_print_c.mli @@ -0,0 +1,23 @@ + +type pr_elem_func = Ast_c.info -> unit +type pr_space_func = unit -> unit + +val pp_expression_gen : + pr_elem_func -> pr_space_func -> Ast_c.expression -> unit +val pp_statement_gen : pr_elem_func -> pr_space_func -> Ast_c.statement -> unit +val pp_decl_gen : pr_elem_func -> pr_space_func -> Ast_c.declaration -> unit +val pp_init_gen : pr_elem_func -> pr_space_func -> Ast_c.initialiser -> unit +val pp_param_gen : pr_elem_func -> pr_space_func -> Ast_c.parameterType -> unit + +val pp_type_gen : pr_elem_func -> pr_space_func -> Ast_c.fullType -> unit +val pp_type_with_ident_gen : + pr_elem_func -> pr_space_func -> + (string * Ast_c.info) option -> + (Ast_c.storage * Ast_c.il) option -> Ast_c.fullType -> unit + + +val pp_program_gen : pr_elem_func -> pr_space_func -> Ast_c.toplevel -> unit + +val pp_expression_simple : Ast_c.expression -> unit +val pp_statement_simple : Ast_c.statement -> unit +val pp_type_simple : Ast_c.fullType -> unit diff --git a/parsing_c/semantic_c.ml b/parsing_c/semantic_c.ml new file mode 100644 index 0000000..96785b4 --- /dev/null +++ b/parsing_c/semantic_c.ml @@ -0,0 +1 @@ +exception Semantic of string * Common.parse_info diff --git a/parsing_c/test_parsing_c.ml b/parsing_c/test_parsing_c.ml new file mode 100644 index 0000000..d49f7b0 --- /dev/null +++ b/parsing_c/test_parsing_c.ml @@ -0,0 +1,277 @@ +open Common + +let score_path = "/home/pad/c-yacfe/tmp" + +let tmpfile = "/tmp/output.c" + +(*****************************************************************************) +(* Subsystem testing *) +(*****************************************************************************) + +let test_tokens_c file = + if not (file =~ ".*\\.c") + then pr2 "warning: seems not a .c file"; + + Flag_parsing_c.debug_lexer := true; + Flag_parsing_c.verbose_lexing := true; + Flag_parsing_c.verbose_parsing := true; + + Parse_c.tokens file +> List.iter (fun x -> pr2_gen x); + () + + + +(* ---------------------------------------------------------------------- *) +let test_parse_gen xs ext = + + Flag_parsing_c.debug_typedef := true; + Flag_parsing_c.debug_cpp := true; + Flag_parsing_c.debug_etdt := false; + Flag_parsing_c.filter_msg := true; + + let dirname_opt = + match xs with + | [x] when is_directory x -> Some x + | _ -> None + in + + (* old: + let xs = if !Flag.dir then + process_output_to_list ("find " ^ x ^" -name \"*.c\"") else x::xs in + *) + let fullxs = Common.files_of_dir_or_files ext xs in + + let stat_list = ref [] in + let newscore = Common.empty_score () in + + (*cocci: Common.check_stack_nbfiles (List.length fullxs); *) + + fullxs +> List.iter (fun file -> + if not (file =~ (".*\\."^ext)) + then pr2 ("warning: seems not a ."^ext^" file"); + + + pr2 ""; + pr2 ("PARSING: " ^ file); + + let (xs, stat) = Parse_c.parse_print_error_heuristic file in + xs +> List.iter (fun (ast, (s, toks)) -> + Parse_c.print_commentized toks + ); + + Common.push2 stat stat_list; + let s = + sprintf "bad = %d, timeout = %B" + stat.Parse_c.bad stat.Parse_c.have_timeout + in + if stat.Parse_c.bad = 0 && not stat.Parse_c.have_timeout + then Hashtbl.add newscore file (Common.Ok) + else Hashtbl.add newscore file (Common.Pb s) + ); + + if not (null !stat_list) + then Parse_c.print_parsing_stat_list !stat_list; + + dirname_opt +> Common.do_option (fun dirname -> + pr2 "--------------------------------"; + pr2 "regression testing information"; + pr2 "--------------------------------"; + let str = Str.global_replace (Str.regexp "/") "__" dirname in + let def = if !Flag_parsing_c.filter_define_error then "_def_" else "" in + let ext = if ext = "c" then "" else ext in + Common.regression_testing newscore + (Filename.concat score_path + ("score_parsing__" ^str ^ def ^ ext ^ ".marshalled")) + ) + + +let test_parse_c xs = + test_parse_gen xs "c" +let test_parse_h xs = + test_parse_gen xs "h" +let test_parse_ch xs = + test_parse_gen xs "[ch]" + + + + + + + + + + + + +(* ---------------------------------------------------------------------- *) +(* file can be "foo.c" or "foo.c:main" *) +let test_cfg file = + + let (file, specific_func) = + if file =~ "\\(.*\\.c\\):\\(.*\\)" + then + let (a,b) = matched2 file in + a, Some b + else + file, None + in + + if not (file =~ ".*\\.c") + then pr2 "warning: seems not a .c file"; + + let (program, _stat) = Parse_c.parse_print_error_heuristic file in + + program +> List.iter (fun (e,_) -> + let toprocess = + match specific_func, e with + | None, _ -> true + | Some s, Ast_c.Definition (((funcs, _, _, c),_)) -> + s = funcs + | _, _ -> false + in + + if toprocess + then + (* old: Flow_to_ast.test !Flag.show_flow def *) + (try + let flow = Ast_to_flow.ast_to_control_flow e in + flow +> do_option (fun flow -> + Ast_to_flow.deadcode_detection flow; + let flow = Ast_to_flow.annotate_loop_nodes flow in + + let flow' = +(* + if !Flag_cocci.show_before_fixed_flow + then flow + else Ctlcocci_integration.fix_flow_ctl flow +*) + flow + in + Ograph_extended.print_ograph_mutable flow' ("/tmp/output.dot") true + ) + with Ast_to_flow.Error (x) -> Ast_to_flow.report_error x + ) + ) + + + + +(* ---------------------------------------------------------------------- *) +let test_parse_unparse infile = + if not (infile =~ ".*\\.c") + then pr2 "warning: seems not a .c file"; + +(* for cocci: to remove one day + let (program2, _stat) = Parse_c.parse_print_error_heuristic infile in + let program2_with_ppmethod = + program2 +> List.map (fun x -> x, Unparse_c2.PPnormal) + in + Unparse_c2.pp_program program2_with_ppmethod tmpfile; + Common.command2 ("cat " ^ tmpfile); + (* if want see diff of space => no -b -B *) + Common.command2 (spf "diff -u -p %s %s" infile tmpfile); + (* +> Transformation.test_simple_trans1;*) +*) + () + + + + +let test_type_c infile = + if not (infile =~ ".*\\.c") + then pr2 "warning: seems not a .c file"; + + Flag_parsing_c.pretty_print_type_info := true; + + let (program2, _stat) = Parse_c.parse_print_error_heuristic infile in + let _program2 = + program2 + +> Common.unzip + +> (fun (program, infos) -> + Type_annoter_c.annotate_program Type_annoter_c.initial_env true + program +> List.map fst, + infos + ) + +> Common.uncurry Common.zip + in +(* for cocci: to remove one day *) + let program2_with_ppmethod = + program2 +> List.map (fun x -> x, Unparse_c2.PPnormal) + in + Unparse_c2.pp_program program2_with_ppmethod tmpfile; + Common.command2 ("cat " ^ tmpfile); + ();; + + +(* ---------------------------------------------------------------------- *) +(* used by generic_makefile now *) +let test_compare_c file1 file2 = + let (correct, diffxs) = Compare_c.compare_default file1 file2 in + let res = Compare_c.compare_result_to_bool correct in + if res + then raise (Common.UnixExit 0) + else raise (Common.UnixExit (-1)) + + +let test_compare_c_hardcoded () = + Compare_c.compare_default + "tests/compare1.c" + "tests/compare2.c" + (* + "tests/equal_modulo1.c" + "tests/equal_modulo2.c" + *) + +> Compare_c.compare_result_to_string + +> pr2 + + + +(* ---------------------------------------------------------------------- *) +let test_xxx a = + () + +(* + ignore(Parse_c.parse_cpp_define_file "standard.h") + pr2 "pr2"; + pr "pr" + + Format.print_newline(); + Format.printf "@[--@,--@,@[--@,--@,@]--@,--@,@]"; + Format.print_newline(); + Format.printf "@[(---@[(---@[(---@,)@]@,)@]@,)@]" +*) + + + +(*****************************************************************************) +(* Main entry for Arg *) +(*****************************************************************************) + +let actions () = [ + "-tokens_c", " ", + Common.mk_action_1_arg test_tokens_c; + "-parse_c", " ", + Common.mk_action_n_arg test_parse_c; + "-parse_h", " ", + Common.mk_action_n_arg test_parse_h; + "-parse_ch", " ", + Common.mk_action_n_arg test_parse_ch; + + "-show_flow", " ", + Common.mk_action_1_arg test_cfg; + "-control_flow", " ", + Common.mk_action_1_arg test_cfg; + "-parse_unparse", " ", + Common.mk_action_1_arg test_parse_unparse; + "-type_c", " ", + Common.mk_action_1_arg test_type_c; + "-compare_c", " ", + Common.mk_action_2_arg test_compare_c (* result is in unix code *); + + "-compare_c_hardcoded", " ", + Common.mk_action_0_arg test_compare_c_hardcoded; + + "-xxx", " <>", + Common.mk_action_n_arg test_xxx; +] + diff --git a/parsing_c/test_parsing_c.mli b/parsing_c/test_parsing_c.mli new file mode 100644 index 0000000..082c9cc --- /dev/null +++ b/parsing_c/test_parsing_c.mli @@ -0,0 +1,21 @@ +open Common.BasicType + +val test_tokens_c : filename -> unit +(* parse and handle some regression information when called with dirmode *) +val test_parse_c : filename list -> unit +val test_parse_h : filename list -> unit +val test_parse_ch : filename list -> unit + +val test_parse_unparse : filename -> unit + +val test_cfg : filename (* foo.c or foo.c:main *) -> unit +val test_type_c : filename -> unit + +val test_compare_c : filename -> filename -> unit (* result is in unix code *) +val test_compare_c_hardcoded : unit -> unit + + +val test_xxx : string list -> unit + + +val actions: unit -> Common.cmdline_actions diff --git a/parsing_c/token_helpers.ml b/parsing_c/token_helpers.ml new file mode 100644 index 0000000..14aed16 --- /dev/null +++ b/parsing_c/token_helpers.ml @@ -0,0 +1,411 @@ +open Common + +open Parser_c + +(*****************************************************************************) +(* Is_xxx, categories *) +(*****************************************************************************) + +let is_space = function + | TCommentSpace _ -> true + | _ -> false + +let is_comment_or_space = function + | TComment _ -> true + | TCommentSpace _ -> true + + | _ -> false + +let is_just_comment = function + | TComment _ -> true + | _ -> false + + + + + +let is_comment = function + | TComment _ | TCommentSpace _ | TCommentNewline _ + | TCommentCpp _ + | TCommentMisc _ -> true + | _ -> false + + +let is_real_comment = function + | TComment _ | TCommentSpace _ | TCommentNewline _ + -> true + | _ -> false + +let is_fake_comment = function + | TCommentCpp _ | TCommentMisc _ + -> true + | _ -> false + +let is_not_comment x = + not (is_comment x) + + +let is_cpp_instruction = function + | TInclude _ | TDefine _ + | TIfdef _ | TIfdefelse _ | TIfdefelif _ + | TEndif _ + | TIfdefBool _ | TIfdefMisc _ | TIfdefVersion _ + -> true + | _ -> false + + + + +let is_opar = function + | TOPar _ | TOParDefine _ -> true + | _ -> false + +let is_cpar = function + | TCPar _ | TCParEOL _ -> true + | _ -> false + +let is_eof = function + | EOF x -> true + | _ -> false + +let is_statement = function + | Tfor _ | Tdo _ | Tif _ | Twhile _ | Treturn _ + | Tbreak _ | Telse _ | Tswitch _ | Tcase _ | Tcontinue _ + | Tgoto _ + | TPtVirg _ + | TMacroIterator _ + -> true + | _ -> false + +(* is_start_of_something is used in parse_c for error recovery, to find + * a synchronisation token. + * + * Would like to put TIdent or TDefine, TIfdef but they can be in the + * middle of a function, for instance with label:. + * + * Could put Typedefident but fired ? it would work in error recovery + * on the already_passed tokens, which has been already gone in the + * Parsing_hacks.lookahead machinery, but it will not work on the + * "next" tokens. But because the namespace for labels is different + * from namespace for ident/typedef, we can use the name for a typedef + * for a label and so dangerous to put Typedefident at true here. + * + * Can look in parser_c.output to know what can be at toplevel + * at the very beginning. + *) + +let is_start_of_something = function + | Tchar _ | Tshort _ | Tint _ | Tdouble _ | Tfloat _ | Tlong _ + | Tunsigned _ | Tsigned _ | Tvoid _ + | Tauto _ | Tregister _ | Textern _ | Tstatic _ + | Tconst _ | Tvolatile _ + | Ttypedef _ + | Tstruct _ | Tunion _ | Tenum _ + -> true + | _ -> false + + + +let is_binary_operator = function + | TOrLog _ | TAndLog _ | TOr _ | TXor _ | TAnd _ + | TEqEq _ | TNotEq _ | TInf _ | TSup _ | TInfEq _ | TSupEq _ + | TShl _ | TShr _ + | TPlus _ | TMinus _ | TMul _ | TDiv _ | TMod _ + -> true + | _ -> false + +let is_stuff_taking_parenthized = function + | Tif _ + | Twhile _ + | Tswitch _ + | Ttypeof _ + | TMacroIterator _ + -> true + | _ -> false + +(*****************************************************************************) +(* Visitors *) +(*****************************************************************************) + +(* Because ocamlyacc force us to do it that way. The ocamlyacc token + * cant be a pair of a sum type, it must be directly a sum type. + *) +let info_of_tok = function + | TString ((string, isWchar), i) -> i + | TChar ((string, isWchar), i) -> i + | TFloat ((string, floatType), i) -> i + + | TAssign (assignOp, i) -> i + + | TIdent (s, i) -> i + | TypedefIdent (s, i) -> i + + | TInt (s, i) -> i + + | TDefine (ii) -> ii + | TInclude (includes, filename, inifdef, i1) -> i1 + + | TIncludeStart (i1, inifdef) -> i1 + | TIncludeFilename (s, i1) -> i1 + + | TDefEOL (i1) -> i1 + | TOParDefine (i1) -> i1 + | TIdentDefine (s, i) -> i + | TCppEscapedNewline (ii) -> ii + | TDefParamVariadic (s, i1) -> i1 + + | TUnknown (i) -> i + + | TMacroStmt (i) -> i + | TMacroString (i) -> i + | TMacroDecl (s, i) -> i + | TMacroDeclConst (i) -> i + | TMacroIterator (s,i) -> i +(* | TMacroTop (s,i) -> i *) + | TCParEOL (i1) -> i1 + + | TAction (i) -> i + + | TComment (i) -> i + | TCommentSpace (i) -> i + | TCommentNewline (i) -> i + | TCommentCpp (cppkind, i) -> i + | TCommentMisc (i) -> i + + | TIfdef (i) -> i + | TIfdefelse (i) -> i + | TIfdefelif (i) -> i + | TEndif (i) -> i + | TIfdefBool (b, i) -> i + | TIfdefMisc (b, i) -> i + | TIfdefVersion (b, i) -> i + + | TOPar (i) -> i + | TCPar (i) -> i + | TOBrace (i) -> i + | TCBrace (i) -> i + | TOCro (i) -> i + | TCCro (i) -> i + | TDot (i) -> i + | TComma (i) -> i + | TPtrOp (i) -> i + | TInc (i) -> i + | TDec (i) -> i + | TEq (i) -> i + | TWhy (i) -> i + | TTilde (i) -> i + | TBang (i) -> i + | TEllipsis (i) -> i + | TDotDot (i) -> i + | TPtVirg (i) -> i + | TOrLog (i) -> i + | TAndLog (i) -> i + | TOr (i) -> i + | TXor (i) -> i + | TAnd (i) -> i + | TEqEq (i) -> i + | TNotEq (i) -> i + | TInf (i) -> i + | TSup (i) -> i + | TInfEq (i) -> i + | TSupEq (i) -> i + | TShl (i) -> i + | TShr (i) -> i + | TPlus (i) -> i + | TMinus (i) -> i + | TMul (i) -> i + | TDiv (i) -> i + | TMod (i) -> i + + | Tchar (i) -> i + | Tshort (i) -> i + | Tint (i) -> i + | Tdouble (i) -> i + | Tfloat (i) -> i + | Tlong (i) -> i + | Tunsigned (i) -> i + | Tsigned (i) -> i + | Tvoid (i) -> i + | Tauto (i) -> i + | Tregister (i) -> i + | Textern (i) -> i + | Tstatic (i) -> i + | Tconst (i) -> i + | Tvolatile (i) -> i + | Tstruct (i) -> i + | Tenum (i) -> i + | Ttypedef (i) -> i + | Tunion (i) -> i + | Tbreak (i) -> i + | Telse (i) -> i + | Tswitch (i) -> i + | Tcase (i) -> i + | Tcontinue (i) -> i + | Tfor (i) -> i + | Tdo (i) -> i + | Tif (i) -> i + | Twhile (i) -> i + | Treturn (i) -> i + | Tgoto (i) -> i + | Tdefault (i) -> i + | Tsizeof (i) -> i + | Tasm (i) -> i + | Tattribute (i) -> i + | Tinline (i) -> i + | Ttypeof (i) -> i + + | EOF (i) -> i + + + +(* used by tokens to complete the parse_info with filename, line, col infos *) +let visitor_info_of_tok f = function + | TString ((s, isWchar), i) -> TString ((s, isWchar), f i) + | TChar ((s, isWchar), i) -> TChar ((s, isWchar), f i) + | TFloat ((s, floatType), i) -> TFloat ((s, floatType), f i) + | TAssign (assignOp, i) -> TAssign (assignOp, f i) + + | TIdent (s, i) -> TIdent (s, f i) + | TypedefIdent (s, i) -> TypedefIdent (s, f i) + | TInt (s, i) -> TInt (s, f i) + + | TDefine (i1) -> TDefine(f i1) + + | TInclude (includes, filename, inifdef, i1) -> + TInclude (includes, filename, inifdef, f i1) + + | TIncludeStart (i1, inifdef) -> TIncludeStart (f i1, inifdef) + | TIncludeFilename (s, i1) -> TIncludeFilename (s, f i1) + + | TCppEscapedNewline (i1) -> TCppEscapedNewline (f i1) + | TDefEOL (i1) -> TDefEOL (f i1) + | TOParDefine (i1) -> TOParDefine (f i1) + | TIdentDefine (s, i) -> TIdentDefine (s, f i) + + | TDefParamVariadic (s, i1) -> TDefParamVariadic (s, f i1) + + + | TUnknown (i) -> TUnknown (f i) + + | TMacroStmt (i) -> TMacroStmt (f i) + | TMacroString (i) -> TMacroString (f i) + | TMacroDecl (s,i) -> TMacroDecl (s, f i) + | TMacroDeclConst (i) -> TMacroDeclConst (f i) + | TMacroIterator (s,i) -> TMacroIterator (s,f i) +(* | TMacroTop (s,i) -> TMacroTop (s,f i) *) + | TCParEOL (i) -> TCParEOL (f i) + + + | TAction (i) -> TAction (f i) + + | TComment (i) -> TComment (f i) + | TCommentSpace (i) -> TCommentSpace (f i) + | TCommentNewline (i) -> TCommentNewline (f i) + | TCommentCpp (cppkind, i) -> TCommentCpp (cppkind, f i) + | TCommentMisc (i) -> TCommentMisc (f i) + | TIfdef (i) -> TIfdef (f i) + | TIfdefelse (i) -> TIfdefelse (f i) + | TIfdefelif (i) -> TIfdefelif (f i) + | TEndif (i) -> TEndif (f i) + | TIfdefBool (b, i) -> TIfdefBool (b, f i) + | TIfdefMisc (b, i) -> TIfdefMisc (b, f i) + | TIfdefVersion (b, i) -> TIfdefVersion (b, f i) + + | TOPar (i) -> TOPar (f i) + | TCPar (i) -> TCPar (f i) + | TOBrace (i) -> TOBrace (f i) + | TCBrace (i) -> TCBrace (f i) + | TOCro (i) -> TOCro (f i) + | TCCro (i) -> TCCro (f i) + | TDot (i) -> TDot (f i) + | TComma (i) -> TComma (f i) + | TPtrOp (i) -> TPtrOp (f i) + | TInc (i) -> TInc (f i) + | TDec (i) -> TDec (f i) + | TEq (i) -> TEq (f i) + | TWhy (i) -> TWhy (f i) + | TTilde (i) -> TTilde (f i) + | TBang (i) -> TBang (f i) + | TEllipsis (i) -> TEllipsis (f i) + | TDotDot (i) -> TDotDot (f i) + | TPtVirg (i) -> TPtVirg (f i) + | TOrLog (i) -> TOrLog (f i) + | TAndLog (i) -> TAndLog (f i) + | TOr (i) -> TOr (f i) + | TXor (i) -> TXor (f i) + | TAnd (i) -> TAnd (f i) + | TEqEq (i) -> TEqEq (f i) + | TNotEq (i) -> TNotEq (f i) + | TInf (i) -> TInf (f i) + | TSup (i) -> TSup (f i) + | TInfEq (i) -> TInfEq (f i) + | TSupEq (i) -> TSupEq (f i) + | TShl (i) -> TShl (f i) + | TShr (i) -> TShr (f i) + | TPlus (i) -> TPlus (f i) + | TMinus (i) -> TMinus (f i) + | TMul (i) -> TMul (f i) + | TDiv (i) -> TDiv (f i) + | TMod (i) -> TMod (f i) + | Tchar (i) -> Tchar (f i) + | Tshort (i) -> Tshort (f i) + | Tint (i) -> Tint (f i) + | Tdouble (i) -> Tdouble (f i) + | Tfloat (i) -> Tfloat (f i) + | Tlong (i) -> Tlong (f i) + | Tunsigned (i) -> Tunsigned (f i) + | Tsigned (i) -> Tsigned (f i) + | Tvoid (i) -> Tvoid (f i) + | Tauto (i) -> Tauto (f i) + | Tregister (i) -> Tregister (f i) + | Textern (i) -> Textern (f i) + | Tstatic (i) -> Tstatic (f i) + | Tconst (i) -> Tconst (f i) + | Tvolatile (i) -> Tvolatile (f i) + | Tstruct (i) -> Tstruct (f i) + | Tenum (i) -> Tenum (f i) + | Ttypedef (i) -> Ttypedef (f i) + | Tunion (i) -> Tunion (f i) + | Tbreak (i) -> Tbreak (f i) + | Telse (i) -> Telse (f i) + | Tswitch (i) -> Tswitch (f i) + | Tcase (i) -> Tcase (f i) + | Tcontinue (i) -> Tcontinue (f i) + | Tfor (i) -> Tfor (f i) + | Tdo (i) -> Tdo (f i) + | Tif (i) -> Tif (f i) + | Twhile (i) -> Twhile (f i) + | Treturn (i) -> Treturn (f i) + | Tgoto (i) -> Tgoto (f i) + | Tdefault (i) -> Tdefault (f i) + | Tsizeof (i) -> Tsizeof (f i) + | Tasm (i) -> Tasm (f i) + | Tattribute (i) -> Tattribute (f i) + | Tinline (i) -> Tinline (f i) + | Ttypeof (i) -> Ttypeof (f i) + | EOF (i) -> EOF (f i) + + +(*****************************************************************************) +(* Accessors *) +(*****************************************************************************) + +let linecol_of_tok tok = + let info = info_of_tok tok in + Ast_c.line_of_info info, Ast_c.col_of_info info + +let col_of_tok x = snd (linecol_of_tok x) +let line_of_tok x = fst (linecol_of_tok x) +let pos_of_tok x = Ast_c.opos_of_info (info_of_tok x) +let str_of_tok x = Ast_c.str_of_info (info_of_tok x) +let file_of_tok x = Ast_c.file_of_info (info_of_tok x) +let pinfo_of_tok x = Ast_c.pinfo_of_info (info_of_tok x) + +let is_origin x = + match pinfo_of_tok x with Ast_c.OriginTok _ -> true | _ -> false +let is_expanded x = + match pinfo_of_tok x with Ast_c.ExpandedTok _ -> true | _ -> false +let is_fake x = + match pinfo_of_tok x with Ast_c.FakeTok _ -> true | _ -> false +let is_abstract x = + match pinfo_of_tok x with Ast_c.AbstractLineTok _ -> true | _ -> false diff --git a/parsing_c/token_helpers.mli b/parsing_c/token_helpers.mli new file mode 100644 index 0000000..8c48683 --- /dev/null +++ b/parsing_c/token_helpers.mli @@ -0,0 +1,37 @@ + +val is_space : Parser_c.token -> bool +val is_comment_or_space : Parser_c.token -> bool +val is_just_comment : Parser_c.token -> bool +val is_comment : Parser_c.token -> bool +val is_real_comment : Parser_c.token -> bool +val is_fake_comment : Parser_c.token -> bool +val is_not_comment : Parser_c.token -> bool + +val is_cpp_instruction : Parser_c.token -> bool +val is_eof : Parser_c.token -> bool +val is_statement : Parser_c.token -> bool +val is_start_of_something : Parser_c.token -> bool +val is_binary_operator : Parser_c.token -> bool +val is_stuff_taking_parenthized : Parser_c.token -> bool + +val is_opar : Parser_c.token -> bool +val is_cpar : Parser_c.token -> bool + +val info_of_tok : Parser_c.token -> Ast_c.info + +val visitor_info_of_tok : + (Ast_c.info -> Ast_c.info) -> Parser_c.token -> Parser_c.token + +val linecol_of_tok : Parser_c.token -> int * int +val col_of_tok : Parser_c.token -> int +val line_of_tok : Parser_c.token -> int +val pos_of_tok : Parser_c.token -> int +val str_of_tok : Parser_c.token -> string +val file_of_tok : Parser_c.token -> Common.filename +val pinfo_of_tok : Parser_c.token -> Ast_c.parse_info + +(* val mark_of_tok : Parser_c.token -> Ast_c.mark_token *) +val is_origin : Parser_c.token -> bool +val is_expanded : Parser_c.token -> bool +val is_fake : Parser_c.token -> bool +val is_abstract : Parser_c.token -> bool diff --git a/parsing_c/type_annoter_c.ml b/parsing_c/type_annoter_c.ml new file mode 100644 index 0000000..d35aeba --- /dev/null +++ b/parsing_c/type_annoter_c.ml @@ -0,0 +1,652 @@ +(* Copyright (C) 2002-2008 Yoann Padioleau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License (GPL) + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * file license.txt for more details. + *) +open Common + +open Ast_c + +module Lib = Lib_parsing_c + +(*****************************************************************************) +(* can either: + * + * - do a kind of inferer + * * can first do a simple inferer, that just pass context + * * then a real inferer, managing partial info. + * type context = fullType option + * + * - extract the information from the .h files + * (so no inference at all needed) + * + * todo: expression contain types, and statements, which in turn can contain + * expression, so need recurse. Need define an annote_statement and + * annotate_type. + + * todo: how deal with typedef isomorphisms ? How store them in Ast_c ? + * store all posible variations in ast_c ? a list of type instead of just + * the type ? + * + * todo: define a new type ? like type_cocci ? where have a bool ? + * + * How handle scope ? When search for type of field, we return + * a type, but this type makes sense only in a certain scope. + * We could add a tag to each typedef, structUnionName to differentiate + * them and also associate in ast_c to the type the scope + * of this type, the env that were used to define this type. + *) + +(*****************************************************************************) +(* Wrappers *) +(*****************************************************************************) +let pr2 s = + if !Flag_parsing_c.verbose_type + then Common.pr2 s + +(*****************************************************************************) +(* Environment *) +(*****************************************************************************) + +(* the different namespaces from stdC manual: + * + * You introduce two new name spaces with every block that you write. + * One name space includes all functions, objects, type definitions, + * and enumeration constants that you declare or define within the + * block. The other name space includes all enumeration, structure, and + * union tags that you define within the block. + * + * You introduce a new member name space with every structure or union + * whose content you define. You identify a member name space by the + * type of left operand that you write for a member selection + * operator, as in x.y or p->y. A member name space ends with the end + * of the block in which you declare it. + * + * You introduce a new goto label name space with every function + * definition you write. Each goto label name space ends with its + * function definition. + *) + +(* But I don't try to do a type-checker, I try to "resolve" type of var + * so don't need make difference between namespaces here. + * + * But, why not make simply a (string, kindstring) assoc ? + * Because we dont want that a variable shadow a struct definition, because + * they are still in 2 different namespace. But could for typedef, + * because VarOrFunc and Typedef are in the same namespace. + * But could do a record as in c_info.ml + *) + + +(* the wrap for StructUnionNameDef contain the whole ii, the i for + * the string, the structUnion and the structType + *) +type namedef = + | VarOrFunc of string * Ast_c.exp_type + | TypeDef of string * fullType + | StructUnionNameDef of string * (structUnion * structType) wrap + (* todo: EnumConstant *) + (* todo: EnumDef *) + +(* because have nested scope, have nested list, hence the list list *) +type environment = namedef list list + +let initial_env = [ + [VarOrFunc("NULL",(Lib.al_type (Parse_c.type_of_string "void *"), + Ast_c.NotLocalVar))] +] + + +let rec lookup_env f env = + match env with + | [] -> raise Not_found + | []::zs -> lookup_env f zs + | (x::xs)::zs -> + match f x with + | None -> lookup_env f (xs::zs) + | Some y -> y, xs::zs + + + +let lookup_var s env = + let f = function + | VarOrFunc (s2, typ) -> if s2 = s then Some typ else None + | _ -> None + in + lookup_env f env + +let lookup_typedef s env = + let f = function + | TypeDef (s2, typ) -> if s2 = s then Some typ else None + | _ -> None + in + lookup_env f env + +let lookup_structunion (_su, s) env = + let f = function + | StructUnionNameDef (s2, typ) -> if s2 = s then Some typ else None + | _ -> None + in + lookup_env f env + +let member_env lookupf env = + try + let _ = lookupf env in + true + with Not_found -> false + +(*****************************************************************************) +(* "type-lookup" *) +(*****************************************************************************) + +(* find_final_type is used to know to what type a field correspond in + * x.foo. Sometimes the type of x is a typedef or a structName in which + * case we must look in environment to find the complete type, here + * structUnion that contains the information. + * + * Because in C one can redefine in nested blocks some typedefs, + * struct, or variables, we have a static scoping resolving process. + * So, when we look for the type of a var, if this var is in an + * enclosing block, then maybe its type refer to a typdef of this + * enclosing block, so must restart the "type-resolving" of this + * typedef from this enclosing block, not from the bottom. So our + * "resolving-type functions" take an env and also return an env from + * where the next search must be performed. *) + +(* +let rec find_final_type ty env = + + match Ast_c.unwrap_typeC ty with + | BaseType x -> (BaseType x) +> Ast_c.rewrap_typeC ty + + | Pointer t -> (Pointer (find_final_type t env)) +> Ast_c.rewrap_typeC ty + | Array (e, t) -> Array (e, find_final_type t env) +> Ast_c.rewrap_typeC ty + + | StructUnion (sopt, su) -> StructUnion (sopt, su) +> Ast_c.rewrap_typeC ty + + | FunctionType t -> (FunctionType t) (* todo ? *) +> Ast_c.rewrap_typeC ty + | Enum (s, enumt) -> (Enum (s, enumt)) (* todo? *) +> Ast_c.rewrap_typeC ty + | EnumName s -> (EnumName s) (* todo? *) +> Ast_c.rewrap_typeC ty + + | StructUnionName (su, s) -> + (try + let ((structtyp,ii), env') = lookup_structunion (su, s) env in + Ast_c.nQ, (StructUnion (Some s, structtyp), ii) + (* old: +> Ast_c.rewrap_typeC ty + * but must wrap with good ii, otherwise pretty_print_c + * will be lost and raise some Impossible + *) + with Not_found -> + ty + ) + + | TypeName s -> + (try + let (t', env') = lookup_typedef s env in + find_final_type t' env' + with Not_found -> + ty + ) + + | ParenType t -> find_final_type t env + | Typeof e -> failwith "typeof" +*) + + + + +let rec type_unfold_one_step ty env = + + match Ast_c.unwrap_typeC ty with + | BaseType x -> ty + | Pointer t -> ty + | Array (e, t) -> ty + | StructUnion (sopt, su, fields) -> ty + + | FunctionType t -> ty + | Enum (s, enumt) -> ty + | EnumName s -> ty + + | StructUnionName (su, s) -> + (try + let (((su,fields),ii), env') = lookup_structunion (su, s) env in + Ast_c.nQ, (StructUnion (su, Some s, fields), ii) + (* old: +> Ast_c.rewrap_typeC ty + * but must wrap with good ii, otherwise pretty_print_c + * will be lost and raise some Impossible + *) + with Not_found -> + ty + ) + + | TypeName (s,_typ) -> + (try + let (t', env') = lookup_typedef s env in + type_unfold_one_step t' env' + with Not_found -> + ty + ) + + | ParenType t -> type_unfold_one_step t env + | TypeOfExpr e -> + pr2_once ("Type_annoter: not handling typeof"); + ty + | TypeOfType t -> type_unfold_one_step t env + + + +let (type_field: + string -> (Ast_c.structUnion * Ast_c.structType) -> Ast_c.fullType) = + fun fld (su, fields) -> + fields +> Common.find_some (fun x -> + match Ast_c.unwrap x with + | FieldDeclList onefield_multivars -> + Common.optionise (fun () -> + onefield_multivars +> Common.find_some (fun fieldkind -> + + match Ast_c.unwrap (Ast_c.unwrap fieldkind) with + | Simple (Some s, t) | BitField (Some s, t, _) -> + if s = fld then Some t else None + | _ -> None + ) + ) + | EmptyField -> None + ) + + + + +let structdef_to_struct_name ty = + match ty with + | qu, (StructUnion (su, sopt, fields), iis) -> + (match sopt,iis with + | Some s , [i1;i2;i3;i4] -> + qu, (StructUnionName (su, s), [i1;i2]) + | None, _ -> + ty + + | x -> raise Impossible + ) + | _ -> raise Impossible + + + +let rec typedef_fix ty env = + + match Ast_c.unwrap_typeC ty with + | BaseType x -> ty + | Pointer t -> Pointer (typedef_fix t env) +> Ast_c.rewrap_typeC ty + | Array (e, t) -> Array (e, typedef_fix t env) +> Ast_c.rewrap_typeC ty + | StructUnion (su, sopt, fields) -> structdef_to_struct_name ty + | FunctionType ft -> + (FunctionType ft) (* todo ? *) +> Ast_c.rewrap_typeC ty + | Enum (s, enumt) -> + (Enum (s, enumt)) (* todo? *) +> Ast_c.rewrap_typeC ty + | EnumName s -> + (EnumName s) (* todo? *) +> Ast_c.rewrap_typeC ty + + (* we prefer StructUnionName to StructUnion when it comes to typed metavar *) + | StructUnionName (su, s) -> ty + + | TypeName (s, _typ) -> + (try + let (t', env') = lookup_typedef s env in + TypeName (s, Some (typedef_fix t' env)) +> Ast_c.rewrap_typeC ty + with Not_found -> + ty + ) + + | ParenType t -> typedef_fix t env + | TypeOfExpr e -> + pr2_once ("Type_annoter: not handling typeof"); + ty + + | TypeOfType t -> typedef_fix t env + +(*****************************************************************************) +(* (Semi) Globals, Julia's style *) +(*****************************************************************************) + +(* opti: cache ? use hash ? *) +let _scoped_env = ref initial_env + +(* memoise unnanoted var, to avoid too much warning messages *) +let _notyped_var = ref (Hashtbl.create 100) + +let new_scope() = _scoped_env := []::!_scoped_env +let del_scope() = _scoped_env := List.tl !_scoped_env + +let do_in_new_scope f = + begin + new_scope(); + let res = f() in + del_scope(); + res + end + +let add_in_scope namedef = + let (current, older) = Common.uncons !_scoped_env in + _scoped_env := (namedef::current)::older + +(* sort of hackish... *) +let islocal info = + if List.length (!_scoped_env) = List.length initial_env + then Ast_c.NotLocalVar + else Ast_c.LocalVar info + +(* the warning argument is here to allow some binding to overwrite an + * existing one. With function, we first have the protype and then the def + * and the def binding the same string is not an error. + * todo?: but if we define two times the same function, then we will not + * detect it :( would require to make a diff between adding a binding + * from a prototype and from a definition. + *) +let add_binding namedef warning = + let (current_scope, _older_scope) = Common.uncons !_scoped_env in + + (match namedef with + | VarOrFunc (s, typ) -> + if Hashtbl.mem !_notyped_var s + then pr2 ("warning: found typing information for a variable that was" ^ + "previously unknown:" ^ s); + | _ -> () + ); + + let (memberf, s) = + (match namedef with + | VarOrFunc (s, typ) -> member_env (lookup_var s), s + | TypeDef (s, typ) -> member_env (lookup_typedef s), s + | StructUnionNameDef (s, (su, typ)) -> + member_env (lookup_structunion (su, s)), s + ) in + + if memberf [current_scope] && warning + then pr2 ("Type_annoter: warning, " ^ s ^ + " is already in current binding" ^ "\n" ^ + " so there is a wierd shadowing"); + add_in_scope namedef + + +(*****************************************************************************) +(* Helpers *) +(*****************************************************************************) + +let make_info t = (Some t,Ast_c.NotTest) + +let type_of_s s = + (Lib.al_type (Parse_c.type_of_string s), Ast_c.NotLocalVar) + +let noTypeHere = (None,Ast_c.NotTest) + +let do_with_type f (t,_test) = + match t with + | None -> noTypeHere + | Some (t,_local) -> f t + + +(*****************************************************************************) +(* Entry point *) +(*****************************************************************************) +(* catch all the decl to grow the environment *) + +let rec (annotate_program2 : + environment -> toplevel list -> (toplevel * environment Common.pair) list + ) = fun env prog -> + + (* globals (re)initialialisation *) + _scoped_env := env; + _notyped_var := (Hashtbl.create 100); + + + let bigf = { Visitor_c.default_visitor_c with + + Visitor_c.kexpr = (fun (k,bigf) expr -> + k expr; (* recurse to set the types-ref of sub expressions *) + let ty = + match Ast_c.unwrap_expr expr with + (* todo: should analyse the 's' for int to know if unsigned or not *) + | Constant (String (s,kind)) -> make_info (type_of_s "char *") + | Constant (Char (s,kind)) -> make_info (type_of_s "char") + | Constant (Int (s)) -> make_info (type_of_s "int") + | Constant (Float (s,kind)) -> + let iinull = [] in + make_info + ((Ast_c.nQ, (BaseType (FloatType kind), iinull)), + Ast_c.NotLocalVar) + + (* don't want a warning on the Ident that are a FunCall *) + | FunCall (((Ident f, typ), ii), args) -> + args +> List.iter (fun (e,ii) -> + Visitor_c.vk_argument bigf e + ); + noTypeHere + + | Ident (s) -> + (match (Common.optionise (fun () -> lookup_var s !_scoped_env)) with + | Some ((typ,local),_nextenv) -> + make_info ((typedef_fix typ !_scoped_env),local) + | None -> + if not (s =~ "[A-Z_]+") (* if macro then no warning *) + then + if not (Hashtbl.mem !_notyped_var s) + then begin + pr2 ("Type_annoter: not finding type for " ^ s); + Hashtbl.add !_notyped_var s true; + end; + noTypeHere + ) + | Unary (e, UnMinus) | Unary (e, UnPlus) -> make_info (type_of_s "int") + | Unary (e, DeRef) + | ArrayAccess (e, _) -> + (Ast_c.get_type_expr e) +> do_with_type (fun t -> + (* todo: maybe not good env !! *) + match Ast_c.unwrap_typeC (type_unfold_one_step t !_scoped_env) with + | Pointer x + | Array (_, x) -> + make_info ((typedef_fix x !_scoped_env),Ast_c.NotLocalVar) + | _ -> noTypeHere + ) + + | RecordAccess (e, fld) -> + (Ast_c.get_type_expr e) +> do_with_type (fun t -> + match Ast_c.unwrap_typeC (type_unfold_one_step t !_scoped_env) with + | StructUnion (su, sopt, fields) -> + (try + (* todo: which env ? *) + make_info + ((typedef_fix (type_field fld (su, fields)) !_scoped_env), + Ast_c.NotLocalVar) + with Not_found -> + pr2 + ("TYPE-ERROR: field '" ^ fld ^ "' does not belong in" ^ + " struct '"^(match sopt with Some s -> s |_ -> "")^ + "'"); + noTypeHere + ) + | _ -> noTypeHere + ) + + | RecordPtAccess (e, fld) -> + (Ast_c.get_type_expr e) +> do_with_type (fun t -> + match Ast_c.unwrap_typeC (type_unfold_one_step t !_scoped_env) with + | Pointer (t) -> + (match Ast_c.unwrap_typeC (type_unfold_one_step t !_scoped_env) + with + | StructUnion (su, sopt, fields) -> + (try + (* todo: which env ? *) + make_info + ((typedef_fix (type_field fld (su, fields)) !_scoped_env), + Ast_c.NotLocalVar) + with Not_found -> + pr2 + ("TYPE-ERROR: field '" ^ fld ^ "' does not belong in" ^ + " struct '"^(match sopt with Some s -> s |_ -> "")^ + "'"); + noTypeHere + ) + + | _ -> noTypeHere + ) + | _ -> noTypeHere + ) + | Cast (t, e) -> + (* todo: add_types_expr [t] e ? *) + make_info + ((typedef_fix (Lib.al_type t) !_scoped_env),Ast_c.NotLocalVar) + + (* todo: check e2 ? *) + | Assignment (e1, op, e2) -> + Ast_c.get_type_expr e1 + | ParenExpr e -> + Ast_c.get_type_expr e + + | _ -> noTypeHere + in + Ast_c.set_type_expr expr ty + + ); + + Visitor_c.kstatement = (fun (k, bigf) st -> + match st with + | Compound statxs, ii -> do_in_new_scope (fun () -> k st); + | _ -> k st + + ); + Visitor_c.kdecl = (fun (k, bigf) d -> + (match d with + | (DeclList (xs, ii)) -> + xs +> List.iter (fun ((var, t, sto, local), iicomma) -> + let local = + match local with + Ast_c.NotLocalDecl -> Ast_c.NotLocalVar + | Ast_c.LocalDecl -> Ast_c.LocalVar (offset t) in + + (* to add possible definition in type found in Decl *) + Visitor_c.vk_type bigf t; + + var +> do_option (fun ((s, ini), ii_s_ini) -> + match sto with + | StoTypedef, _inline -> + add_binding (TypeDef (s,Lib.al_type t)) true; + | _ -> + add_binding (VarOrFunc (s, (Lib.al_type t, local))) true; + (* int x = sizeof(x) is legal so need process ini *) + ini +> Common.do_option (fun ini -> + Visitor_c.vk_ini bigf ini); + ); + ); + | _ -> k d + ); + + ); + + Visitor_c.ktype = (fun (k, bigf) typ -> + let (q, t) = Lib.al_type typ in + match t with + | StructUnion (su, Some s, structType),ii -> + add_binding (StructUnionNameDef (s, ((su, structType),ii))) true; + k typ (* todo: restrict ? new scope so use do_in_scope ? *) + + + (* TODO: if have a TypeName, then maybe can fill the option + * information. + *) + | _ -> k typ + + ); + + Visitor_c.ktoplevel = (fun (k, bigf) elem -> + _notyped_var := Hashtbl.create 100; + match elem with + | Definition def -> + let (funcs, ((returnt, (paramst, b)) as ftyp), sto, statxs),ii = def + in + let (i1, i2) = + match ii with + | is::iifunc1::iifunc2::ibrace1::ibrace2::ifakestart::isto -> + iifunc1, iifunc2 + | _ -> raise Impossible + in + let typ' = Lib.al_type (Ast_c.nQ, (FunctionType ftyp, [i1;i2])) in + + add_binding (VarOrFunc (funcs, (typ',islocal i1.Ast_c.pinfo))) false; + do_in_new_scope (fun () -> + paramst +> List.iter (fun (((b, s, t), _),_) -> + match s with + | Some s -> + let local = Ast_c.LocalVar (offset t) in + add_binding (VarOrFunc (s,(Lib.al_type t,local))) true + | None -> pr2 "no type, certainly because Void type ?" + ); + k elem + ); + | _ -> k elem + ); + } + in + + prog +> List.map (fun elem -> + let beforeenv = !_scoped_env in + Visitor_c.vk_toplevel bigf elem; + let afterenv = !_scoped_env in + (elem, (beforeenv, afterenv)) + ) + +and offset (_,(ty,iis)) = + match iis with + ii::_ -> ii.Ast_c.pinfo + | _ -> failwith "type has no text; need to think again" + + +let annotate_test_expressions prog = + let rec propagate_test e = + let ((e_term,info),_) = e in + let (ty,_) = !info in + info := (ty,Test); + match e_term with + Binary(e1,Logical(AndLog),e2) + | Binary(e1,Logical(OrLog),e2) -> propagate_test e1; propagate_test e2 + | Unary(e1,Not) -> propagate_test e1 + | ParenExpr(e) -> propagate_test e + | _ -> () in + + let bigf = { Visitor_c.default_visitor_c with + Visitor_c.kexpr = (fun (k,bigf) expr -> + (match unwrap expr with + (CondExpr(e,_,_),_) -> propagate_test e + | _ -> ()); + k expr); + Visitor_c.kstatement = (fun (k, bigf) st -> + match unwrap st with + Selection(s) -> + (match s with If(e1,s1,s2) -> propagate_test e1 | _ -> ()); + k st; + | Iteration(i) -> + (match i with + While(e,s) -> propagate_test e + | DoWhile(s,e) -> propagate_test e + | For(_,es,_,_) -> + (match unwrap es with Some e -> propagate_test e | None -> ()) + | _ -> ()); + k st + | _ -> k st) } in + (prog +> List.iter (fun elem -> + Visitor_c.vk_toplevel bigf elem + )) + +let annotate_program a types_needed = + Common.profile_code "annotate_type" + (fun () prog -> + let res = + if true (*types_needed*) + then annotate_program2 a prog + else prog +> List.map (fun c -> c, (initial_env, initial_env)) in + annotate_test_expressions prog; + res) diff --git a/parsing_c/type_annoter_c.mli b/parsing_c/type_annoter_c.mli new file mode 100644 index 0000000..9a98877 --- /dev/null +++ b/parsing_c/type_annoter_c.mli @@ -0,0 +1,17 @@ + +type namedef = + | VarOrFunc of string * Ast_c.exp_type + | TypeDef of string * Ast_c.fullType + | StructUnionNameDef of + string * (Ast_c.structUnion * Ast_c.structType) Ast_c.wrap + +type environment = namedef list list (* cos have nested scope, so nested list*) + +val initial_env : environment + +(* In fact do via side effects. Fill in the type information that was put + * to None during parsing + *) +val annotate_program : + environment -> bool (*true if types needed*) -> Ast_c.toplevel list -> + (Ast_c.toplevel * environment Common.pair) list diff --git a/parsing_c/unparse_c2.ml b/parsing_c/unparse_c2.ml new file mode 100644 index 0000000..7fb532e --- /dev/null +++ b/parsing_c/unparse_c2.ml @@ -0,0 +1,760 @@ +(* Copyright (C) 2002-2008 Yoann Padioleau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License (GPL) + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * file license.txt for more details. + *) +open Common + +open Ast_c + +module TH = Token_helpers + + + + +(*****************************************************************************) +(* Types used during the intermediate phases of the unparsing *) +(*****************************************************************************) + +type token1 = + | Fake1 of info + | T1 of Parser_c.token + +(* The cocci_tag of the token should always be a NOTHING. The mark of + * the token can only be OriginTok or ExpandedTok. Why not get rid of + * token and get something simpler ? because we need to know if the + * info is a TCommentCpp or TCommentSpace, etc for some of the further + * analysis so easier to keep with the token. + * + * This type contains the whole information. Have all the tokens with this + * type. + *) +type token2 = + | T2 of Parser_c.token * bool (* minus *) * + int option (* orig index, abstracting away comments and space *) + | Fake2 + | Cocci2 of string + | C2 of string + | Indent_cocci2 + | Unindent_cocci2 + +(* not used yet *) +type token3 = + | T3 of Parser_c.token + | Cocci3 of string + | C3 of string + + +(* similar to the tech in parsing_hack *) +type token_extended = { + tok2 : token2; + str : string; + idx: int option; (* to know if 2 tokens were consecutive in orig file *) + mutable new_tokens_before : token2 list; + mutable remove : bool; +} + + +(*****************************************************************************) +(* Helpers *) +(*****************************************************************************) + +let info_of_token1 t = + match t with + | Fake1 info -> info + | T1 tok -> TH.info_of_tok tok + +let str_of_token2 = function + | T2 (t,_,_) -> TH.str_of_tok t + | Fake2 -> "" + | Cocci2 s -> s + | C2 s -> s + | Indent_cocci2 -> "" + | Unindent_cocci2 -> "" + +let print_token2 = function + | T2 (t,b,_) -> "T2:"^(if b then "-" else "")^TH.str_of_tok t + | Fake2 -> "" + | Cocci2 s -> "Cocci2:"^s + | C2 s -> "C2:"^s + | Indent_cocci2 -> "Indent" + | Unindent_cocci2 -> "Unindent" + +let print_all_tokens2 l = + List.iter (function x -> Printf.printf "%s " (print_token2 x)) l; + Printf.printf "\n" + +let str_of_token3 = function + | T3 t -> TH.str_of_tok t + | Cocci3 s | C3 s -> s + + + +let mk_token_extended x = + let origidx = + match x with + | T2 (_,_, idx) -> idx + | _ -> None + in + { tok2 = x; + str = str_of_token2 x; + idx = origidx; + new_tokens_before = []; + remove = false; + } + +let rebuild_tokens_extented toks_ext = + let _tokens = ref [] in + toks_ext +> List.iter (fun tok -> + tok.new_tokens_before +> List.iter (fun x -> push2 x _tokens); + if not tok.remove then push2 tok.tok2 _tokens; + ); + let tokens = List.rev !_tokens in + (tokens +> List.map mk_token_extended) + + +let mcode_contain_plus = function + | Ast_cocci.CONTEXT (_,Ast_cocci.NOTHING) -> false + | Ast_cocci.CONTEXT _ -> true + | Ast_cocci.MINUS (_,[]) -> false + | Ast_cocci.MINUS (_,x::xs) -> true + | Ast_cocci.PLUS -> raise Impossible + +let contain_plus info = + let mck = Ast_c.mcode_of_info info in + mcode_contain_plus mck + +(*****************************************************************************) +(* Last fix on the ast *) +(*****************************************************************************) + +(* Because of the ugly trick to handle initialiser, I generate fake ',' + * for the last initializer element, but if there is nothing around it, + * I don't want in the end to print it. + *) + +let remove_useless_fakeInfo_struct program = + let bigf = { Visitor_c.default_visitor_c_s with + Visitor_c.kini_s = (fun (k,bigf) ini -> + match k ini with + | InitList args, ii -> + (match ii with + | [_i1;_i2] -> ini + | [i1;i2;iicommaopt] -> + if (not (contain_plus iicommaopt)) && (not (contain_plus i2)) + && (Ast_c.is_fake iicommaopt) + (* sometimes the guy put a normal iicommaopt *) + + then InitList args, [i1;i2] + else InitList args, [i1;i2;iicommaopt] + | _ -> raise Impossible + ) + | x -> x + ) + } in + Visitor_c.vk_toplevel_s bigf program + + +(*****************************************************************************) +(* Tokens1 generation *) +(*****************************************************************************) + +let get_fakeInfo_and_tokens celem toks = + let toks_in = ref toks in + let toks_out = ref [] in + + (* todo? verify good order of position ? *) + let pr_elem info = + match Ast_c.pinfo_of_info info with + | FakeTok _ -> + Common.push2 (Fake1 info) toks_out + | OriginTok _ | ExpandedTok _ -> + (* get the associated comments/space/cppcomment tokens *) + let (before, x, after) = !toks_in +> Common.split_when (fun tok -> + info =*= TH.info_of_tok tok) + in + assert(info = TH.info_of_tok x); + (*old: assert(before +> List.for_all (TH.is_comment)); *) + before +> List.iter (fun x -> + if not (TH.is_comment x) + then pr2 ("WIERD: not a comment:" ^ TH.str_of_tok x) + (* case such as int asm d3("x"); not yet in ast *) + ); + before +> List.iter (fun x -> Common.push2 (T1 x) toks_out); + push2 (T1 x) toks_out; + toks_in := after; + | AbstractLineTok _ -> + (* can be called on type info when for instance use -type_c *) + if !Flag_parsing_c.pretty_print_type_info + then Common.push2 (Fake1 info) toks_out + else raise Impossible (* at this stage *) + in + + let pr_space _ = () in (* use the spacing that is there already *) + + Pretty_print_c.pp_program_gen pr_elem pr_space celem; + + if not (null !toks_in) + then failwith "WIERD: unparsing not finished"; + + List.rev !toks_out + +(* Fake nodes that have BEFORE code should be moved over any subsequent +whitespace and newlines, but not any comments, to get as close to the affected +code as possible. Similarly, face nodes that have AFTER code should be moved +backwards. No fake nodes should have both before and after code. *) + +let displace_fake_nodes toks = + let is_fake = function Fake1 _ -> true | _ -> false in + let is_whitespace = function + T1(Parser_c.TCommentSpace _) + | T1(Parser_c.TCommentNewline _) -> true + | _ -> false in + let rec loop toks = + let fake_info = + try Some (Common.split_when is_fake toks) + with Not_found -> None in + match fake_info with + Some(bef,((Fake1 info) as fake),aft) -> + (match !(info.cocci_tag) with + (Ast_cocci.CONTEXT(_,Ast_cocci.BEFORE _),_) -> + (* move the fake node forwards *) + let (whitespace,rest) = Common.span is_whitespace aft in + bef @ whitespace @ fake :: (loop rest) + | (Ast_cocci.CONTEXT(_,Ast_cocci.AFTER _),_) -> + (* move the fake node backwards *) + let revbef = List.rev bef in + let (revwhitespace,revprev) = Common.span is_whitespace revbef in + let whitespace = List.rev revwhitespace in + let prev = List.rev revprev in + prev @ fake :: (loop (whitespace @ aft)) + | (Ast_cocci.CONTEXT(_,Ast_cocci.NOTHING),_) -> + bef @ fake :: (loop aft) + | (Ast_cocci.CONTEXT(_,Ast_cocci.BEFOREAFTER _),_) -> + failwith "fake node should not be before-after" + | _ -> bef @ fake :: (loop aft)) + | None -> toks + | _ -> raise Impossible in + loop toks + +(*****************************************************************************) +(* Tokens2 generation *) +(*****************************************************************************) + +let expand_mcode toks = + let toks_out = ref [] in + + let index = ref 0 in + + let add_elem t minus = + match t with + | Fake1 info -> + let str = Ast_c.str_of_info info in + if str = "" + then push2 (Fake2) toks_out + (* perhaps the fake ',' *) + else push2 (C2 str) toks_out + + + | T1 tok -> + (* no tag on expandedTok ! *) + assert(not (TH.is_expanded tok && + !((TH.info_of_tok tok).cocci_tag) <> Ast_c.emptyAnnot)); + + let tok' = tok +> TH.visitor_info_of_tok (fun i -> + { i with cocci_tag = ref Ast_c.emptyAnnot; } + ) in + + let optindex = + if TH.is_origin tok && not (TH.is_real_comment tok) + then begin + incr index; + Some !index + end + else None + in + + push2 (T2 (tok', minus, optindex)) toks_out + in + + let expand_info t = + let (mcode,env) = !((info_of_token1 t).cocci_tag) in + + let pr_cocci s = + push2 (Cocci2 s) toks_out + in + let pr_c info = + match Ast_c.pinfo_of_info info with + Ast_c.AbstractLineTok _ -> push2 (C2 (Ast_c.str_of_info info)) toks_out + | Ast_c.FakeTok (s,_) -> push2 (C2 s) toks_out + | _ -> + Printf.printf "line: %s\n" (Common.dump info); + failwith "not an abstract line" in + + let pr_space _ = push2 (C2 " ") toks_out in + + let indent _ = push2 Indent_cocci2 toks_out in + let unindent _ = push2 Unindent_cocci2 toks_out in + + let args_pp = (env, pr_cocci, pr_c, pr_space, indent, unindent) in + + + match mcode with + | Ast_cocci.MINUS (_,any_xxs) -> + (* Why adding ? because I want to have all the information, the whole + * set of tokens, so I can then process and remove the + * is_between_two_minus for instance *) + add_elem t true; + Unparse_cocci2.pp_list_list_any args_pp any_xxs Unparse_cocci2.InPlace + | Ast_cocci.CONTEXT (_,any_befaft) -> + (match any_befaft with + | Ast_cocci.NOTHING -> + add_elem t false + | Ast_cocci.BEFORE xxs -> + Unparse_cocci2.pp_list_list_any args_pp xxs Unparse_cocci2.Before; + add_elem t false + | Ast_cocci.AFTER xxs -> + add_elem t false; + Unparse_cocci2.pp_list_list_any args_pp xxs Unparse_cocci2.After; + | Ast_cocci.BEFOREAFTER (xxs, yys) -> + Unparse_cocci2.pp_list_list_any args_pp xxs Unparse_cocci2.Before; + add_elem t false; + Unparse_cocci2.pp_list_list_any args_pp yys Unparse_cocci2.After; + ) + | Ast_cocci.PLUS -> raise Impossible + + in + + toks +> List.iter expand_info; + List.rev !toks_out + + +(*****************************************************************************) +(* Tokens2 processing, filtering, adjusting *) +(*****************************************************************************) + +let is_minusable_comment = function + | T2 (t,_b,_i) -> + (match t with + | Parser_c.TCommentSpace _ (* only whitespace *) + | Parser_c.TCommentNewline _ (* newline plus whitespace *) + | Parser_c.TComment _ + | Parser_c.TCommentCpp (Ast_c.CppAttr, _) + | Parser_c.TCommentCpp (Ast_c.CppMacro, _) + -> true + + | Parser_c.TCommentMisc _ + | Parser_c.TCommentCpp (Ast_c.CppDirective, _) + | Parser_c.TCommentCpp (Ast_c.CppOther, _) + -> false + + | _ -> false + ) + | _ -> false + +let all_coccis = function + Cocci2 _ | C2 _ | Indent_cocci2 | Unindent_cocci2 -> true + | _ -> false + +let is_minusable_comment_or_plus = function + T2(Parser_c.TCommentNewline _,_b,_i) -> false + | x -> is_minusable_comment x or all_coccis x + +let set_minus_comment = function + | T2 (t,false,idx) -> + let str = TH.str_of_tok t in + (match t with + | Parser_c.TCommentSpace _ + | Parser_c.TCommentNewline _ -> () + + | Parser_c.TComment _ + | Parser_c.TCommentCpp (Ast_c.CppAttr, _) + | Parser_c.TCommentCpp (Ast_c.CppMacro, _) + -> + pr2 ("ERASING_COMMENTS: " ^ str) + | _ -> raise Impossible + ); + T2 (t, true, idx) + | T2 (Parser_c.TCommentNewline _,true,idx) as x -> x + | _ -> raise Impossible + +let set_minus_comment_or_plus = function + Cocci2 _ | C2 _ | Indent_cocci2 | Unindent_cocci2 as x -> x + | x -> set_minus_comment x + + +let remove_minus_and_between_and_expanded_and_fake xs = + + (* get rid of exampled and fake tok *) + let xs = xs +> Common.exclude (function + | T2 (t,_,_) when TH.is_expanded t -> true + | Fake2 -> true + + | _ -> false + ) + in + + (*This drops the space before each completely minused block (no plus code).*) + let rec adjust_before_minus = function + [] -> [] + | (T2(Parser_c.TCommentNewline c,_b,_i) as x)::((T2(_,true,_)::_) as xs) -> + let minus_or_comment = function + T2(_,true,_) -> true + | T2(Parser_c.TCommentNewline _,_b,_i) -> false + | x -> is_minusable_comment x in + let (between_minus,rest) = Common.span minus_or_comment xs in + (match rest with + [] -> (set_minus_comment x) :: between_minus + | T2(Parser_c.TCommentNewline _,_b,_i)::_ -> + (set_minus_comment x) :: between_minus @ + (adjust_before_minus rest) + | _ -> x :: between_minus @ (adjust_before_minus rest)) + | x::xs -> x::adjust_before_minus xs in + + let xs = adjust_before_minus xs in + + (* this deals with any stuff that is between the minused code, eg + spaces, comments, attributes, etc. *) + (* The use of is_minusable_comment_or_plus and set_minus_comment_or_plus + is because the + code can end up anywhere in the middle of the - code; + it is not necessarily to the far left *) + let rec adjust_between_minus xs = + match xs with + | [] -> [] + | (T2 (t1,true,idx1))::xs -> + + let (between_comments, rest) = + Common.span is_minusable_comment_or_plus xs in + (match rest with + | [] -> [(T2 (t1, true,idx1))] + + | (T2 (t2, true,idx2))::rest -> + (T2 (t1, true,idx1)):: + (List.map set_minus_comment_or_plus between_comments @ + adjust_between_minus ((T2 (t2, true, idx2))::rest)) + | x::xs -> + (T2 (t1, true, idx1)):: + (between_comments @ adjust_between_minus (x::xs)) + ) + + | x::xs -> x::adjust_between_minus xs in + + let xs = adjust_between_minus xs in + + let xs = xs +> Common.exclude (function + | T2 (t,true,_) -> true + | _ -> false + ) in + xs + + +let is_ident_like s = s ==~ Common.regexp_alpha + +let rec add_space xs = + match xs with + | [] -> [] + | [x] -> [x] + | x::y::xs -> + let sx = str_of_token2 x in + let sy = str_of_token2 y in + if is_ident_like sx && is_ident_like sy + then x::C2 " "::(add_space (y::xs)) + else x::(add_space (y::xs)) + + + +(* When insert some new code, because of a + in a SP, we must add this + * code at the right place, with the good indentation. So each time we + * encounter some spacing info, with some newline, we maintain the + * current indentation level used. + * + * TODO problems: not accurate. ex: TODO + * + * TODO: if in #define region, should add a \ \n + *) +let new_tabbing2 space = + (list_of_string space) + +> List.rev + +> Common.take_until (fun c -> c = '\n') + +> List.rev + +> List.map string_of_char + +> String.concat "" + +let new_tabbing a = + Common.profile_code "C unparsing.new_tabbing" (fun () -> new_tabbing2 a) + + +let rec adjust_indentation xs = + let _current_tabbing = ref "" in + let tabbing_unit = ref None in + + let string_of_list l = String.concat "" (List.map string_of_char l) in + + (* try to pick a tabbing unit for the plus code *) + let adjust_tabbing_unit old_tab new_tab = + if !tabbing_unit = None && String.length new_tab > String.length old_tab + then + let old_tab = list_of_string old_tab in + let new_tab = list_of_string new_tab in + let rec loop = function + ([],new_tab) -> + tabbing_unit := Some(string_of_list new_tab,List.rev new_tab) + | (_,[]) -> failwith "not possible" + | (o::os,n::ns) -> loop (os,ns) in (* could check for equality *) + loop (old_tab,new_tab) in + + let remtab tu current_tab = + let current_tab = List.rev(list_of_string current_tab) in + let rec loop = function + ([],new_tab) -> string_of_list (List.rev new_tab) + | (_,[]) -> "" (*wierd; tabbing unit used up more than the current tab*) + | (t::ts,n::ns) when t = n -> loop (ts,ns) + | (_,ns) -> (* mismatch; remove what we can *) + string_of_list (List.rev ns) in + loop (tu,current_tab) in + + let rec find_first_tab started = function + [] -> () + | ((T2 (tok,_,_)) as x)::xs when str_of_token2 x = "{" -> + find_first_tab true xs + | ((T2 (Parser_c.TCommentNewline s, _, _)) as x)::_ + when started -> + let s = str_of_token2 x +> new_tabbing in + tabbing_unit := Some (s,List.rev (list_of_string s)) + | x::xs -> find_first_tab started xs in + find_first_tab false xs; + + let rec aux started xs = + match xs with + | [] -> [] + | ((T2 (tok,_,_)) as x)::(T2 (Parser_c.TCommentNewline s, _, _)):: + (Cocci2 "{")::xs when started && str_of_token2 x = ")" -> + (* to be done for if, etc, but not for a function header *) + x::(Cocci2 " {")::(aux started xs) + | ((T2 (Parser_c.TCommentNewline s, _, _)) as x)::xs -> + let old_tabbing = !_current_tabbing in + str_of_token2 x +> new_tabbing +> (fun s -> _current_tabbing := s); + (* only trust the indentation after the first { *) + (if started then adjust_tabbing_unit old_tabbing !_current_tabbing); + let coccis_rest = Common.span all_coccis xs in + (match coccis_rest with + (_::_,((T2 (tok,_,_)) as y)::_) when str_of_token2 y = "}" -> + (* the case where cocci code has been added before a close } *) + x::aux started (Indent_cocci2::xs) + | _ -> x::aux started xs) + | Indent_cocci2::xs -> + (match !tabbing_unit with + None -> aux started xs + | Some (tu,_) -> + _current_tabbing := (!_current_tabbing)^tu; + Cocci2 (tu)::aux started xs) + | Unindent_cocci2::xs -> + (match !tabbing_unit with + None -> aux started xs + | Some (_,tu) -> + _current_tabbing := remtab tu (!_current_tabbing); + aux started xs) + (* border between existing code and cocci code *) + | ((T2 (tok,_,_)) as x)::((Cocci2 "\n") as y)::xs + when str_of_token2 x = "{" -> + x::aux true (y::Indent_cocci2::xs) + | ((Cocci2 _) as x)::((T2 (tok,_,_)) as y)::xs + when str_of_token2 y = "}" -> + x::aux started (y::Unindent_cocci2::xs) + (* starting the body of the function *) + | ((T2 (tok,_,_)) as x)::xs when str_of_token2 x = "{" -> x::aux true xs + | (Cocci2 "{")::xs -> (Cocci2 "{")::aux true xs + | ((Cocci2 "\n") as x)::xs -> + (* dont inline in expr because of wierd eval order of ocaml *) + let s = !_current_tabbing in + x::Cocci2 (s)::aux started xs + | x::xs -> x::aux started xs in + aux false xs + + +let rec find_paren_comma = function + | [] -> () + + (* do nothing if was like this in original file *) + | ({ str = "("; idx = Some p1 } as _x1)::({ str = ","; idx = Some p2} as x2) + ::xs when p2 = p1 + 1 -> + find_paren_comma (x2::xs) + + | ({ str = ","; idx = Some p1 } as _x1)::({ str = ","; idx = Some p2} as x2) + ::xs when p2 = p1 + 1 -> + find_paren_comma (x2::xs) + + | ({ str = ","; idx = Some p1 } as _x1)::({ str = ")"; idx = Some p2} as x2) + ::xs when p2 = p1 + 1 -> + find_paren_comma (x2::xs) + + (* otherwise yes can adjust *) + | ({ str = "(" } as _x1)::({ str = ","} as x2)::xs -> + x2.remove <- true; + find_paren_comma (x2::xs) + | ({ str = "," } as x1)::({ str = ","} as x2)::xs -> + x1.remove <- true; + find_paren_comma (x2::xs) + + | ({ str = "," } as x1)::({ str = ")"} as x2)::xs -> + x1.remove <- true; + find_paren_comma (x2::xs) + + | x::xs -> + find_paren_comma xs + + +let fix_tokens toks = + let toks = toks +> List.map mk_token_extended in + + let cleaner = toks +> Common.exclude (function + | {tok2 = T2 (t,_,_)} -> TH.is_real_comment t (* I want the ifdef *) + | _ -> false + ) in + find_paren_comma cleaner; + + let toks = rebuild_tokens_extented toks in + toks +> List.map (fun x -> x.tok2) + + + +(*****************************************************************************) +(* Final unparsing (and debugging support) *) +(*****************************************************************************) + +(* for debugging *) +type kind_token2 = KFake | KCocci | KC | KExpanded | KOrigin + +let kind_of_token2 = function + | Fake2 -> KFake + | Cocci2 _ -> KCocci + | C2 _ -> KC + | T2 (t,_,_) -> + (match TH.pinfo_of_tok t with + | ExpandedTok _ -> KExpanded + | OriginTok _ -> KOrigin + | FakeTok _ -> raise Impossible (* now a Fake2 *) + | AbstractLineTok _ -> raise Impossible (* now a KC *) + ) + | Unindent_cocci2 | Indent_cocci2 -> raise Impossible + +let end_mark = "!" + +let start_mark = function + | KFake -> "!F!" + | KCocci -> "!S!" + | KC -> "!A!" + | KExpanded -> "!E!" + | KOrigin -> "" + +let print_all_tokens2 pr xs = + if !Flag_parsing_c.debug_unparsing + then + let current_kind = ref KOrigin in + xs +> List.iter (fun t -> + let newkind = kind_of_token2 t in + if newkind = !current_kind + then pr (str_of_token2 t) + else begin + pr (end_mark); + pr (start_mark newkind); + pr (str_of_token2 t); + current_kind := newkind + end + ); + else + xs +> List.iter (fun x -> pr (str_of_token2 x)) + + + + +(*****************************************************************************) +(* Entry points *) +(*****************************************************************************) + +(* old: PPviatok was made in the beginning to allow to pretty print a + * complete C file, including a modified C file by transformation.ml, + * even if we don't handle yet in pretty_print_c.ml, ast_to_flow (and + * maybe flow_to_ast) all the cases. Indeed we don't need to do some + * fancy stuff when a function was not modified at all. Just need to + * print the list of token as-is. But now pretty_print_c.ml handles + * almost everything so maybe less useful. Maybe PPviatok allows to + * optimize a little the pretty printing. + * + * update: now have PPviastr which goes even faster than PPviatok, so + * PPviatok has disappeared. + *) + +type ppmethod = PPnormal | PPviastr + + + + +(* The pp_program function will call pretty_print_c.ml with a special + * function to print the leaf components, the tokens. When we want to + * print a token, we need to print also maybe the space and comments that + * were close to it in the original file (and that was omitted during the + * parsing phase), and honor what the cocci-info attached to the token says. + * Maybe we will not print the token if it's a MINUS-token, and maybe we will + * print it and also print some cocci-code attached in a PLUS to it. + * So we will also maybe call unparse_cocci. Because the cocci-code may + * contain metavariables, unparse_cocci will in fact sometimes call back + * pretty_print_c (which will this time don't call back again unparse_cocci) + *) + +let pp_program2 xs outfile = + Common.with_open_outfile outfile (fun (pr,chan) -> + let pr s = + if !Flag_parsing_c.debug_unparsing + then begin pr2_no_nl s; flush stderr end + else pr s + (* flush chan; *) + (* Common.pr2 ("UNPARSING: >" ^ s ^ "<"); *) + in + + xs +> List.iter (fun ((e,(str, toks_e)), ppmethod) -> + + (* here can still work on ast *) + let e = remove_useless_fakeInfo_struct e in + + match ppmethod with + | PPnormal -> + (* now work on tokens *) + + (* phase1: just get all the tokens, all the information *) + assert(toks_e +> List.for_all (fun t -> + TH.is_origin t or TH.is_expanded t + )); + let toks = get_fakeInfo_and_tokens e toks_e in + let toks = displace_fake_nodes toks in + (* assert Origin;ExpandedTok;Faketok *) + let toks = expand_mcode toks in + (* assert Origin;ExpandedTok; + Cocci + C (was AbstractLineTok) + * and no tag information, just NOTHING. *) + + (* phase2: can now start to filter and adjust *) + let toks = adjust_indentation toks in + let toks = remove_minus_and_between_and_expanded_and_fake toks in + (* assert Origin + Cocci + C and no minus *) + let toks = add_space toks in + let toks = fix_tokens toks in + + (* in theory here could reparse and rework the ast! or + * apply some SP. Not before cos julia may have generated + * not parsable file. Need do unparsing_tricks call before being + * ready to reparse. *) + print_all_tokens2 pr toks; + + | PPviastr -> pr str + ) + ) + +let pp_program a b = + Common.profile_code "C unparsing" (fun () -> pp_program2 a b) + diff --git a/parsing_c/unparse_c2.mli b/parsing_c/unparse_c2.mli new file mode 100644 index 0000000..b0bcd36 --- /dev/null +++ b/parsing_c/unparse_c2.mli @@ -0,0 +1,7 @@ +open Common + +type ppmethod = PPnormal | PPviastr + +(* program -> output filename (often "/tmp/output.c") -> unit *) +val pp_program : + (Parse_c.toplevel2 * ppmethod) list -> filename -> unit diff --git a/parsing_c/unparse_cocci2.ml b/parsing_c/unparse_cocci2.ml new file mode 100644 index 0000000..77e6a7f --- /dev/null +++ b/parsing_c/unparse_cocci2.ml @@ -0,0 +1,757 @@ +open Common + +(*****************************************************************************) +(* mostly a copy paste of parsing_cocci/pretty_print_cocci.ml + * todo?: try to factorize ? + *) +(*****************************************************************************) + +module Ast = Ast_cocci + +let term s = Ast.unwrap_mcode s + +(* or perhaps can have in plus, for instance a Disj, but those Disj must be + * handled by interactive tool (by proposing alternatives) + *) +exception CantBeInPlus + +(*****************************************************************************) + +type pos = Before | After | InPlace + +let rec pp_list_list_any (env, pr, pr_elem, pr_space, indent, unindent) + xxs before = + +(* Just to be able to copy paste the code from pretty_print_cocci.ml. *) +let print_string = pr in +let close_box _ = () in +let print_space() = pr " " in +let force_newline () = pr "\n" in + +let start_block () = force_newline(); indent() in +let end_block () = unindent(); force_newline () in +let print_string_box s = print_string s in + +let print_option = Common.do_option in +let print_between = Common.print_between in + +(* --------------------------------------------------------------------- *) + +let handle_metavar name fn = + match (Common.optionise (fun () -> List.assoc (term name) env)) with + | None -> + let name_string (_,s) = s in + failwith (Printf.sprintf "SP line %d: Not found a value in env for: %s" + (Ast_cocci.get_mcode_line name) (name_string (term name))) + | Some e -> fn e +in + +(* --------------------------------------------------------------------- *) +(* Here we don't care about the annotation on s. *) +let mcode fn (s,info,_,_) = + List.iter (function str -> print_string str; print_string "\n") + info.Ast.strbef; + if info.Ast.column > 0 && not(info.Ast.strbef = []) + then print_string (String.make info.Ast.column ' '); + fn s; + match info.Ast.straft with + [] -> () + | aft -> + List.iter (function str -> print_string "\n"; print_string str) aft; + print_string "\n"; (*XXX pr current_tabbing *) +in + +(* --------------------------------------------------------------------- *) +let dots between fn d = + match Ast.unwrap d with + Ast.DOTS(l) -> print_between between fn l + | Ast.CIRCLES(l) -> print_between between fn l + | Ast.STARS(l) -> print_between between fn l +in + + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +let rec ident i = + match Ast.unwrap i with + Ast.Id(name) -> mcode print_string name + | Ast.MetaId(name,_,_,_) -> + handle_metavar name (function + | (Ast_c.MetaIdVal id) -> pr id + | _ -> raise Impossible + ) + | Ast.MetaFunc(name,_,_,_) -> + handle_metavar name (function + | (Ast_c.MetaFuncVal id) -> pr id + | _ -> raise Impossible + ) + | Ast.MetaLocalFunc(name,_,_,_) -> + handle_metavar name (function + | (Ast_c.MetaLocalFuncVal id) -> pr id + | _ -> raise Impossible + ) + + | Ast.OptIdent(_) | Ast.UniqueIdent(_) -> + raise CantBeInPlus + +in + +(* --------------------------------------------------------------------- *) +(* Expression *) + +let rec expression e = + match Ast.unwrap e with + Ast.Ident(id) -> ident id + + | Ast.Constant(const) -> mcode constant const + | Ast.FunCall(fn,lp,args,rp) -> + expression fn; mcode print_string_box lp; + dots (function _ -> ()) expression args; + close_box(); mcode print_string rp + | Ast.Assignment(left,op,right,_) -> + expression left; print_string " "; mcode assignOp op; + print_string " "; expression right + | Ast.CondExpr(exp1,why,exp2,colon,exp3) -> + expression exp1; print_string " "; mcode print_string why; + print_option (function e -> print_string " "; expression e) exp2; + print_string " "; mcode print_string colon; expression exp3 + | Ast.Postfix(exp,op) -> expression exp; mcode fixOp op + | Ast.Infix(exp,op) -> mcode fixOp op; expression exp + | Ast.Unary(exp,op) -> mcode unaryOp op; expression exp + | Ast.Binary(left,op,right) -> + expression left; print_string " "; mcode binaryOp op; print_string " "; + expression right + | Ast.Nested(left,op,right) -> failwith "nested only in minus code" + | Ast.Paren(lp,exp,rp) -> + mcode print_string_box lp; expression exp; close_box(); + mcode print_string rp + | Ast.ArrayAccess(exp1,lb,exp2,rb) -> + expression exp1; mcode print_string_box lb; expression exp2; close_box(); + mcode print_string rb + | Ast.RecordAccess(exp,pt,field) -> + expression exp; mcode print_string pt; ident field + | Ast.RecordPtAccess(exp,ar,field) -> + expression exp; mcode print_string ar; ident field + | Ast.Cast(lp,ty,rp,exp) -> + mcode print_string_box lp; fullType ty; close_box(); + mcode print_string rp; expression exp + | Ast.SizeOfExpr(sizeof,exp) -> + mcode print_string sizeof; expression exp + | Ast.SizeOfType(sizeof,lp,ty,rp) -> + mcode print_string sizeof; + mcode print_string_box lp; fullType ty; close_box(); + mcode print_string rp + | Ast.TypeExp(ty) -> fullType ty + + | Ast.MetaErr(name,_,_,_) -> + failwith "metaErr not handled" + + | Ast.MetaExpr (name,_,_,_typedontcare,_formdontcare,_) -> + handle_metavar name (function + | Ast_c.MetaExprVal exp -> + Pretty_print_c.pp_expression_gen pr_elem pr_space exp + | _ -> raise Impossible + ) + + | Ast.MetaExprList (name,_,_,_) -> + failwith "not handling MetaExprList" + + | Ast.EComma(cm) -> mcode print_string cm; print_space() + + | Ast.DisjExpr _ + | Ast.NestExpr(_) + | Ast.Edots(_) + | Ast.Ecircles(_) + | Ast.Estars(_) + -> raise CantBeInPlus + + | Ast.OptExp(exp) | Ast.UniqueExp(exp) -> + raise CantBeInPlus + +and unaryOp = function + Ast.GetRef -> print_string "&" + | Ast.DeRef -> print_string "*" + | Ast.UnPlus -> print_string "+" + | Ast.UnMinus -> print_string "-" + | Ast.Tilde -> print_string "~" + | Ast.Not -> print_string "!" + +and assignOp = function + Ast.SimpleAssign -> print_string "=" + | Ast.OpAssign(aop) -> arithOp aop; print_string "=" + +and fixOp = function + Ast.Dec -> print_string "--" + | Ast.Inc -> print_string "++" + +and binaryOp = function + Ast.Arith(aop) -> arithOp aop + | Ast.Logical(lop) -> logicalOp lop + +and arithOp = function + Ast.Plus -> print_string "+" + | Ast.Minus -> print_string "-" + | Ast.Mul -> print_string "*" + | Ast.Div -> print_string "/" + | Ast.Mod -> print_string "%" + | Ast.DecLeft -> print_string "<<" + | Ast.DecRight -> print_string ">>" + | Ast.And -> print_string "&" + | Ast.Or -> print_string "|" + | Ast.Xor -> print_string "^" + +and logicalOp = function + Ast.Inf -> print_string "<" + | Ast.Sup -> print_string ">" + | Ast.InfEq -> print_string "<=" + | Ast.SupEq -> print_string ">=" + | Ast.Eq -> print_string "==" + | Ast.NotEq -> print_string "!=" + | Ast.AndLog -> print_string "&&" + | Ast.OrLog -> print_string "||" + +and constant = function + Ast.String(s) -> print_string "\""; print_string s; print_string "\"" + | Ast.Char(s) -> print_string s + | Ast.Int(s) -> print_string s + | Ast.Float(s) -> print_string s + +(* --------------------------------------------------------------------- *) +(* Types *) + + +and fullType ft = + match Ast.unwrap ft with + Ast.Type(cv,ty) -> + print_option (function x -> mcode const_vol x; print_string " ") cv; + typeC ty + | Ast.DisjType _ -> failwith "can't be in plus" + | Ast.OptType(_) | Ast.UniqueType(_) -> + raise CantBeInPlus + +and print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2) fn = + fullType ty; mcode print_string lp1; mcode print_string star; fn(); + mcode print_string rp1; mcode print_string lp1; + parameter_list params; mcode print_string rp2 + +and print_function_type (ty,lp1,params,rp1) fn = + print_option fullType ty; fn(); mcode print_string lp1; + parameter_list params; mcode print_string rp1 + +and typeC ty = + match Ast.unwrap ty with + Ast.BaseType(ty,sgn) -> print_option (mcode sign) sgn; mcode baseType ty + | Ast.ImplicitInt(sgn) -> mcode signns sgn + | Ast.Pointer(ty,star) -> fullType ty; ft_space ty; mcode print_string star + | Ast.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2) + (function _ -> ()) + | Ast.FunctionType (am,ty,lp1,params,rp1) -> + print_function_type (ty,lp1,params,rp1) (function _ -> ()) + | Ast.Array(ty,lb,size,rb) -> + fullType ty; mcode print_string lb; print_option expression size; + mcode print_string rb + | Ast.StructUnionName(kind,name) -> + mcode structUnion kind; + print_option ident name + | Ast.StructUnionDef(ty,lb,decls,rb) -> + fullType ty; + mcode print_string lb; + dots force_newline declaration decls; + mcode print_string rb + | Ast.TypeName(name)-> mcode print_string name + | Ast.MetaType(name,_,_) -> + handle_metavar name (function + Ast_c.MetaTypeVal exp -> + Pretty_print_c.pp_type_gen pr_elem pr_space exp + | _ -> raise Impossible) + +and baseType = function + Ast.VoidType -> print_string "void" + | Ast.CharType -> print_string "char" + | Ast.ShortType -> print_string "short" + | Ast.IntType -> print_string "int" + | Ast.DoubleType -> print_string "double" + | Ast.FloatType -> print_string "float" + | Ast.LongType -> print_string "long" + +and structUnion = function + Ast.Struct -> print_string "struct " + | Ast.Union -> print_string "union " + +and sign = function + Ast.Signed -> print_string "signed " + | Ast.Unsigned -> print_string "unsigned " + +and signns = function (* no space, like a normal type *) + Ast.Signed -> print_string "signed" + | Ast.Unsigned -> print_string "unsigned" + + +and const_vol = function + Ast.Const -> print_string "const " + | Ast.Volatile -> print_string "volatile " + +(* --------------------------------------------------------------------- *) +(* Function declaration *) + +and storage = function + Ast.Static -> print_string "static " + | Ast.Auto -> print_string "auto " + | Ast.Register -> print_string "register " + | Ast.Extern -> print_string "extern " + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) + +and print_named_type ty id = + match Ast.unwrap ty with + Ast.Type(None,ty1) -> + (match Ast.unwrap ty1 with + Ast.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2) + (function _ -> print_string " "; ident id) + | Ast.FunctionType(am,ty,lp1,params,rp1) -> + print_function_type (ty,lp1,params,rp1) + (function _ -> print_string " "; ident id) + | Ast.Array(_,_,_,_) -> + let rec loop ty k = + match Ast.unwrap ty with + Ast.Array(ty,lb,size,rb) -> + (match Ast.unwrap ty with + Ast.Type(None,ty) -> + loop ty + (function _ -> + k (); + mcode print_string lb; + print_option expression size; + mcode print_string rb) + | _ -> failwith "complex array types not supported") + | _ -> typeC ty; ty_space ty; ident id; k () in + loop ty1 (function _ -> ()) + (*| should have a case here for pointer to array or function type + that would put ( * ) around the variable. This makes one wonder + why we really need a special case for function pointer *) + | _ -> fullType ty; ft_space ty; ident id) + | _ -> fullType ty; ft_space ty; ident id + +and ty_space ty = + match Ast.unwrap ty with + Ast.Pointer(_,_) -> () + | _ -> print_space() + +and ft_space ty = + match Ast.unwrap ty with + Ast.Type(cv,ty) -> + (match Ast.unwrap ty with + Ast.Pointer(_,_) -> () + | _ -> print_space()) + | _ -> print_space() + +and declaration d = + match Ast.unwrap d with + Ast.Init(stg,ty,id,eq,ini,sem) -> + print_option (mcode storage) stg; + print_named_type ty id; + print_string " "; mcode print_string eq; + print_string " "; initialiser true ini; mcode print_string sem + | Ast.UnInit(stg,ty,id,sem) -> + print_option (mcode storage) stg; + print_named_type ty id; + mcode print_string sem + | Ast.MacroDecl(name,lp,args,rp,sem) -> + ident name; mcode print_string_box lp; + dots (function _ -> ()) expression args; + close_box(); mcode print_string rp; mcode print_string sem + | Ast.TyDecl(ty,sem) -> fullType ty; mcode print_string sem + | Ast.Typedef(stg,ty,id,sem) -> + mcode print_string stg; + fullType ty; typeC id; + mcode print_string sem + | Ast.DisjDecl(_) | Ast.MetaDecl(_,_,_) -> raise CantBeInPlus + | Ast.Ddots(_,_) -> raise CantBeInPlus + | Ast.OptDecl(decl) | Ast.UniqueDecl(decl) -> + raise CantBeInPlus + +(* --------------------------------------------------------------------- *) +(* Initialiser *) + +and initialiser nlcomma i = + match Ast.unwrap i with + Ast.InitExpr(exp) -> expression exp + | Ast.InitList(lb,initlist,rb,[]) -> + mcode print_string lb; start_block(); + (* awkward, because the comma is separate from the initialiser *) + let rec loop = function + [] -> () + | [x] -> initialiser false x + | x::xs -> initialiser nlcomma x; loop xs in + loop initlist; + end_block(); mcode print_string rb + | Ast.InitList(lb,initlist,rb,_) -> failwith "unexpected whencode in plus" + | Ast.InitGccDotName(dot,name,eq,ini) -> + mcode print_string dot; ident name; print_string " "; + mcode print_string eq; print_string " "; initialiser nlcomma ini + | Ast.InitGccName(name,eq,ini) -> + ident name; mcode print_string eq; initialiser nlcomma ini + | Ast.InitGccIndex(lb,exp,rb,eq,ini) -> + mcode print_string lb; expression exp; mcode print_string rb; + print_string " "; mcode print_string eq; print_string " "; + initialiser nlcomma ini + | Ast.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> + mcode print_string lb; expression exp1; mcode print_string dots; + expression exp2; mcode print_string rb; + print_string " "; mcode print_string eq; print_string " "; + initialiser nlcomma ini + | Ast.IComma(comma) -> + mcode print_string comma; + if nlcomma then force_newline() + | Ast.OptIni(ini) | Ast.UniqueIni(ini) -> + raise CantBeInPlus + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +and parameterTypeDef p = + match Ast.unwrap p with + Ast.VoidParam(ty) -> fullType ty + | Ast.Param(ty,Some id) -> print_named_type ty id + | Ast.Param(ty,None) -> fullType ty + + | Ast.MetaParam(name,_,_) -> + failwith "not handling MetaParam" + | Ast.MetaParamList(name,_,_,_) -> + failwith "not handling MetaParamList" + + | Ast.PComma(cm) -> mcode print_string cm; print_space() + | Ast.Pdots(dots) + | Ast.Pcircles(dots) + -> raise CantBeInPlus + | Ast.OptParam(param) | Ast.UniqueParam(param) -> raise CantBeInPlus + +and parameter_list l = dots (function _ -> ()) parameterTypeDef l +in + + +(* --------------------------------------------------------------------- *) +(* CPP code *) + +let rec inc_file = function + Ast.Local(elems) -> + print_string "\""; + print_between (function _ -> print_string "/") inc_elem elems; + print_string "\"" + | Ast.NonLocal(elems) -> + print_string "<"; + print_between (function _ -> print_string "/") inc_elem elems; + print_string ">" + +and inc_elem = function + Ast.IncPath s -> print_string s + | Ast.IncDots -> print_string "..." + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +and rule_elem arity re = + match Ast.unwrap re with + Ast.FunHeader(_,_,fninfo,name,lp,params,rp) -> + print_string arity; List.iter print_fninfo fninfo; + ident name; mcode print_string_box lp; + parameter_list params; close_box(); mcode print_string rp; + print_string " " + | Ast.Decl(_,_,decl) -> print_string arity; declaration decl + + | Ast.SeqStart(brace) -> + print_string arity; mcode print_string brace; start_block() + | Ast.SeqEnd(brace) -> + end_block(); print_string arity; mcode print_string brace + + | Ast.ExprStatement(exp,sem) -> + print_string arity; expression exp; mcode print_string sem + + | Ast.IfHeader(iff,lp,exp,rp) -> + print_string arity; + mcode print_string iff; print_string " "; mcode print_string_box lp; + expression exp; close_box(); mcode print_string rp; print_string " " + | Ast.Else(els) -> + print_string arity; mcode print_string els; print_string " " + + | Ast.WhileHeader(whl,lp,exp,rp) -> + print_string arity; + mcode print_string whl; print_string " "; mcode print_string_box lp; + expression exp; close_box(); mcode print_string rp; print_string " " + | Ast.DoHeader(d) -> + print_string arity; mcode print_string d; print_string " " + | Ast.WhileTail(whl,lp,exp,rp,sem) -> + print_string arity; + mcode print_string whl; print_string " "; mcode print_string_box lp; + expression exp; close_box(); mcode print_string rp; + mcode print_string sem + | Ast.ForHeader(fr,lp,e1,sem1,e2,sem2,e3,rp) -> + print_string arity; + mcode print_string fr; mcode print_string_box lp; + print_option expression e1; mcode print_string sem1; + print_option expression e2; mcode print_string sem2; + print_option expression e3; close_box(); + mcode print_string rp; print_string " " + | Ast.IteratorHeader(nm,lp,args,rp) -> + print_string arity; + ident nm; print_string " "; mcode print_string_box lp; + dots (function _ -> ()) expression args; close_box(); + mcode print_string rp; print_string " " + + | Ast.SwitchHeader(switch,lp,exp,rp) -> + print_string arity; + mcode print_string switch; print_string " "; mcode print_string_box lp; + expression exp; close_box(); mcode print_string rp; print_string " " + + | Ast.Break(br,sem) -> + print_string arity; mcode print_string br; mcode print_string sem + | Ast.Continue(cont,sem) -> + print_string arity; mcode print_string cont; mcode print_string sem + | Ast.Label(l,dd) -> ident l; mcode print_string dd + | Ast.Goto(goto,l,sem) -> + mcode print_string goto; ident l; mcode print_string sem + | Ast.Return(ret,sem) -> + print_string arity; mcode print_string ret; + mcode print_string sem + | Ast.ReturnExpr(ret,exp,sem) -> + print_string arity; mcode print_string ret; print_string " "; + expression exp; mcode print_string sem + + | Ast.Exp(exp) -> print_string arity; expression exp + | Ast.TopExp(exp) -> print_string arity; expression exp + | Ast.Ty(ty) -> print_string arity; fullType ty + | Ast.Include(inc,s) -> + mcode print_string inc; print_string " "; mcode inc_file s + | Ast.DefineHeader(def,id,params) -> + mcode print_string def; print_string " "; ident id; + print_define_parameters params + | Ast.Default(def,colon) -> + mcode print_string def; mcode print_string colon; print_string " " + | Ast.Case(case,exp,colon) -> + mcode print_string case; print_string " "; expression exp; + mcode print_string colon; print_string " " + | Ast.DisjRuleElem(res) -> raise CantBeInPlus + + | Ast.MetaRuleElem(name,_,_) -> + raise Impossible + + | Ast.MetaStmt(name,_,_,_) -> + handle_metavar name (function + | Ast_c.MetaStmtVal exp -> + Pretty_print_c.pp_statement_gen pr_elem pr_space exp + | _ -> raise Impossible + ) + | Ast.MetaStmtList(name,_,_) -> + failwith + "MetaStmtList not supported (not even in ast_c metavars binding)" + +and print_define_parameters params = + match Ast.unwrap params with + Ast.NoParams -> () + | Ast.DParams(lp,params,rp) -> + mcode print_string lp; + dots (function _ -> ()) print_define_param params; mcode print_string rp + +and print_define_param param = + match Ast.unwrap param with + Ast.DParam(id) -> ident id + | Ast.DPComma(comma) -> mcode print_string comma + | Ast.DPdots(dots) -> mcode print_string dots + | Ast.DPcircles(circles) -> mcode print_string circles + | Ast.OptDParam(dp) -> print_string "?"; print_define_param dp + | Ast.UniqueDParam(dp) -> print_string "!"; print_define_param dp + +and print_fninfo = function + Ast.FStorage(stg) -> mcode storage stg + | Ast.FType(ty) -> fullType ty + | Ast.FInline(inline) -> mcode print_string inline; print_string " " + | Ast.FAttr(attr) -> mcode print_string attr; print_string " " in + +let rec statement arity s = + match Ast.unwrap s with + Ast.Seq(lbrace,decls,body,rbrace) -> + rule_elem arity lbrace; + dots force_newline (statement arity) decls; + dots force_newline (statement arity) body; + rule_elem arity rbrace + + | Ast.IfThen(header,branch,_) -> + rule_elem arity header; statement arity branch + | Ast.IfThenElse(header,branch1,els,branch2,_) -> + rule_elem arity header; statement arity branch1; print_string " "; + rule_elem arity els; statement arity branch2 + + | Ast.While(header,body,_) -> + rule_elem arity header; statement arity body + | Ast.Do(header,body,tail) -> + rule_elem arity header; statement arity body; + rule_elem arity tail + | Ast.For(header,body,_) -> + rule_elem arity header; statement arity body + | Ast.Iterator(header,body,(_,_,_,aft)) -> + rule_elem arity header; statement arity body; + mcode (function _ -> ()) ((),Ast.no_info,aft,Ast.NoMetaPos) + + | Ast.Switch(header,lb,cases,rb) -> + rule_elem arity header; rule_elem arity lb; + List.iter (function x -> case_line arity x; force_newline()) cases; + rule_elem arity rb + + | Ast.Atomic(re) -> rule_elem arity re + + | Ast.FunDecl(header,lbrace,decls,body,rbrace) -> + rule_elem arity header; rule_elem arity lbrace; + dots force_newline (statement arity) decls; + dots force_newline (statement arity) body; rule_elem arity rbrace + + | Ast.Define(header,body) -> + rule_elem arity header; print_string " "; + dots force_newline (statement arity) body + + | Ast.Disj(_)| Ast.Nest(_) + | Ast.Dots(_) | Ast.Circles(_) | Ast.Stars(_) -> + raise CantBeInPlus + + | Ast.OptStm(s) | Ast.UniqueStm(s) -> + raise CantBeInPlus + +and case_line arity c = + match Ast.unwrap c with + Ast.CaseLine(header,code) -> + rule_elem arity header; print_string " "; + dots force_newline (statement arity) code + | Ast.OptCase(case) -> raise CantBeInPlus in + +let top_level t = + match Ast.unwrap t with + Ast.FILEINFO(old_file,new_file) -> raise CantBeInPlus + | Ast.DECL(stmt) -> statement "" stmt + | Ast.CODE(stmt_dots) -> dots force_newline (statement "") stmt_dots + | Ast.ERRORWORDS(exps) -> raise CantBeInPlus +in + +(* +let rule = + print_between (function _ -> force_newline(); force_newline()) top_level +in +*) + +let if_open_brace = function "{" -> true | _ -> false in + +let rec pp_any = function + (* assert: normally there is only CONTEXT NOTHING tokens in any *) + Ast.FullTypeTag(x) -> fullType x; false + | Ast.BaseTypeTag(x) -> baseType x; false + | Ast.StructUnionTag(x) -> structUnion x; false + | Ast.SignTag(x) -> sign x; false + + | Ast.IdentTag(x) -> ident x; false + + | Ast.ExpressionTag(x) -> expression x; false + + | Ast.ConstantTag(x) -> constant x; false + | Ast.UnaryOpTag(x) -> unaryOp x; false + | Ast.AssignOpTag(x) -> assignOp x; false + | Ast.FixOpTag(x) -> fixOp x; false + | Ast.BinaryOpTag(x) -> binaryOp x; false + | Ast.ArithOpTag(x) -> arithOp x; false + | Ast.LogicalOpTag(x) -> logicalOp x; false + + | Ast.InitTag(x) -> initialiser false x; false + | Ast.DeclarationTag(x) -> declaration x; false + + | Ast.StorageTag(x) -> storage x; false + | Ast.IncFileTag(x) -> inc_file x; false + + | Ast.Rule_elemTag(x) -> rule_elem "" x; false + | Ast.StatementTag(x) -> statement "" x; false + | Ast.CaseLineTag(x) -> case_line "" x; false + + | Ast.ConstVolTag(x) -> const_vol x; false + | Ast.Token(x,None) -> print_string x; if_open_brace x + | Ast.Token(x,Some info) -> + mcode + (function x -> + (match x with + "else" -> pr "\n" + | _ -> ()); + print_string x; + (* if x ==~ Common.regexp_alpha then print_string " "; *) + (match x with + (*"return" |*) "else" -> print_string " " + | _ -> ())) + (x,info,(),Ast.NoMetaPos); + if_open_brace x + + | Ast.Code(x) -> let _ = top_level x in false + + (* this is not '...', but a list of expr/statement/params, and + normally there should be no '...' inside them *) + | Ast.ExprDotsTag(x) -> dots (function _ -> ()) expression x; false + | Ast.ParamDotsTag(x) -> parameter_list x; false + | Ast.StmtDotsTag(x) -> dots (function _ -> pr "\n") (statement "") x; false + | Ast.DeclDotsTag(x) -> dots (function _ -> pr "\n") declaration x; false + + | Ast.TypeCTag(x) -> typeC x; false + | Ast.ParamTag(x) -> parameterTypeDef x; false + | Ast.SgrepStartTag(x) -> failwith "unexpected start tag" + | Ast.SgrepEndTag(x) -> failwith "unexpected end tag" +in + + (* todo? imitate what is in pretty_print_cocci ? *) + match xxs with + [] -> () + | x::xs -> + (* for many tags, we must not do a newline before the first '+' *) + let isfn s = + match Ast.unwrap s with Ast.FunDecl _ -> true | _ -> false in + let unindent_before = function + (* need to get unindent before newline for } *) + (Ast.Token ("}",_)::_) -> true + | _ -> false in + let prnl x = + (if unindent_before x then unindent()); + pr "\n" in + let newline_before _ = + if before = After + then + let hd = List.hd xxs in + match hd with + (Ast.StatementTag s::_) when isfn s -> pr "\n\n" + | (Ast.Rule_elemTag _::_) | (Ast.StatementTag _::_) + | (Ast.InitTag _::_) + | (Ast.DeclarationTag _::_) | (Ast.Token ("}",_)::_) -> prnl hd + | _ -> () in + let newline_after _ = + if before = Before + then + match List.rev(List.hd(List.rev xxs)) with + (Ast.StatementTag s::_) when isfn s -> pr "\n\n" + | (Ast.Rule_elemTag _::_) | (Ast.StatementTag _::_) + | (Ast.InitTag _::_) + | (Ast.DeclarationTag _::_) | (Ast.Token ("{",_)::_) -> pr "\n" + | _ -> () in + (* print a newline at the beginning, if needed *) + newline_before(); + (* print a newline before each of the rest *) + let rec loop leading_newline indent_needed = function + [] -> () + | x::xs -> + (if leading_newline + then + match (indent_needed,unindent_before x) with + (true,true) -> pr "\n" + | (true,false) -> pr "\n"; indent() + | (false,true) -> unindent(); pr "\n" + | (false,false) -> pr "\n"); + let indent_needed = + List.fold_left (function indent_needed -> pp_any) false x in + loop true indent_needed xs in + loop false false (x::xs); + (* print a newline at the end, if needed *) + newline_after() + diff --git a/parsing_c/unparse_cocci2.mli b/parsing_c/unparse_cocci2.mli new file mode 100644 index 0000000..3db061d --- /dev/null +++ b/parsing_c/unparse_cocci2.mli @@ -0,0 +1,11 @@ +exception CantBeInPlus + +type pos = Before | After | InPlace + +val pp_list_list_any : + Ast_c.metavars_binding * + (string -> unit) (* pr cocci *) * Pretty_print_c.pr_elem_func (* pr c *) * + (unit -> unit) (* pr space *) * + (unit -> unit) (* indent *) * (unit -> unit) (* unindent *) -> + Ast_cocci.anything list list -> pos -> + unit diff --git a/parsing_c/unparse_hrule.ml b/parsing_c/unparse_hrule.ml new file mode 100644 index 0000000..a2fcfb6 --- /dev/null +++ b/parsing_c/unparse_hrule.ml @@ -0,0 +1,156 @@ +module TH = Token_helpers + +let names = ref ([] : (string * int ref) list) + +(* ----------------------------------------------------------------------- *) +(* drop tokens representing the function header and the final close brace *) + +let drop_header_toks toks_e = + let remove t = + if not (TH.is_comment_or_space t) + then + (TH.info_of_tok t).Ast_c.cocci_tag := + (Ast_cocci.MINUS(Ast_cocci.DontCarePos,[]),[]) in + let rec drop_up_to_brace = function + [] -> () + | ((Parser_c.TOBrace _) as t) :: _ -> remove t + | x :: rest -> remove x; drop_up_to_brace rest in + let drop_final_brace toks = + match List.rev toks with + ((Parser_c.TCBrace _) as t) :: _ -> remove t + | _ -> failwith "unexpected end of function" in + drop_up_to_brace toks_e; + drop_final_brace toks_e + +(* ----------------------------------------------------------------------- *) +(* remove coments from tokens *) + +let strip_comments toks = + let toks = List.filter (function x -> not (TH.is_just_comment x)) toks in + List.iter + (function t -> + (TH.info_of_tok t).Ast_c.comments_tag := + {Ast_c.mbefore = []; Ast_c.mafter = [];}) + toks; + toks + +(* ----------------------------------------------------------------------- *) +(* Create rule to check for header include *) + +let print_header_rule pr srcfile = + match Str.split (Str.regexp "/") srcfile with + [x] -> + pr "@header@\n@@\n\n#include \""; pr x; pr "\"\n\n"; true + | l -> + let rec loop = function + [] -> false + | [x] -> + pr "@header@\n@@\n\n#include \""; pr x; pr "\"\n\n"; true + | "include"::(x::xs) -> + pr "@header@\n@@\n\n#include <"; + let x = + if Str.string_match (Str.regexp "asm-") x 0 then "asm" else x in + pr (String.concat "/" (x::xs)); + pr ">\n\n"; true + | x::xs -> loop xs in + loop l + +(* ----------------------------------------------------------------------- *) +(* Print metavariable declarations *) + +let rec print_typedef typedefs pr = function + (Ast_c.TypeName(s,_),_) -> + if not (List.mem s !typedefs) + then (typedefs := s::!typedefs; pr "typedef "; pr s; pr ";\n") + | (Ast_c.Pointer(_,ty),_) -> print_typedef typedefs pr ty + | _ -> () + +let print_metavar pr typedefs = function + ((_,Some param,(_,(Ast_c.Pointer(_,(Ast_c.BaseType(Ast_c.Void),_)),_))),_) + -> + pr "expression "; pr param + | (((_,Some param,(_,ty)),il) : Ast_c.parameterType) -> + print_typedef typedefs pr ty; + Pretty_print_c.pp_param_gen + (function x -> + let str = Ast_c.str_of_info x in + if not (List.mem str ["const";"volatile"]) + then (pr str; pr " ")) + (function _ -> pr " ") + ((false,Some param, + (({Ast_c.const = false; Ast_c.volatile = false},[]),ty)), + il) + | _ -> failwith "function must have named parameters" + +let print_metavariables pr (s, (_, (paramst, (b, iib))), _, _) header_req = + (if header_req + then pr "@depends on header@\n" + else pr "@@\n"); + (if b then failwith "not handling variable argument functions"); + let typedefs = ref ([] : string list) in + (match paramst with + [] | [(((_,_,(_,(Ast_c.BaseType(Ast_c.Void),_))),_),_)] -> () + | (first,_)::rest -> + print_metavar pr typedefs first; pr ";\n"; + List.iter (function (x,_) -> print_metavar pr typedefs x; pr ";\n") + rest); + pr "@@\n\n" + +(* ----------------------------------------------------------------------- *) +(* copy a file, adding - at the beginning of every line *) + +let minus_file pr file = + Common.with_open_infile file (function chan -> + let rec loop _ = + let l = input_line chan in + pr "- "; pr l; pr "\n"; + loop() in + try loop() with End_of_file -> ()) + +(* ----------------------------------------------------------------------- *) +(* Print call to the defined function *) + +let print_param_name pr = function + ((_,Some param,_),_) -> pr param + | _ -> failwith "function must have named parameters" + +let pp_def_gen pr (s, (_, (paramst, (b, iib))), _, _) isexp = + pr s; pr "("; + (if b then failwith "not handling variable argument functions"); + (match paramst with + [] | [(((_,_,(_,(Ast_c.BaseType(Ast_c.Void),_))),_),_)] -> () + | (first,_)::rest -> + print_param_name pr first; + List.iter (function (x,_) -> pr ", "; print_param_name pr x) rest); + pr ")"; if not isexp then pr ";" + +(* ----------------------------------------------------------------------- *) +(* Entry point *) + +let pp_program (e,(str, toks_e)) outdir srcfile isexp = + match e with + Ast_c.Definition(((name,_,_,_) as defn),_) -> + (* generate the - code *) + drop_header_toks toks_e; + let toks_e = strip_comments toks_e in + let tmp_file = Common.new_temp_file "cocci_small_output" ".c" in + Unparse_c2.pp_program [((e,(str, toks_e)), Unparse_c2.PPnormal)] + tmp_file; + let outfile = outdir ^ "/" ^ name in + let outfile = + try + let cell = List.assoc outfile !names in + let ct = !cell in + cell := ct + 1; + outfile ^ (string_of_int ct) + with Not_found -> + let cell = ref 1 in names := (outfile,cell) :: !names; outfile in + let outfile = outfile ^ ".cocci" in + Common.with_open_outfile outfile (fun (pr,chan) -> + let header_req = print_header_rule pr srcfile in + print_metavariables pr defn header_req; + minus_file pr tmp_file; + pr "+ "; + pp_def_gen pr defn isexp; + pr "\n") + | _ -> Common.pr2_once "warning: function expected"; () diff --git a/parsing_c/unparse_hrule.mli b/parsing_c/unparse_hrule.mli new file mode 100644 index 0000000..8c49cfd --- /dev/null +++ b/parsing_c/unparse_hrule.mli @@ -0,0 +1,7 @@ +open Common + +(* program -> output filename (often "/tmp/output.c") -> unit *) +val pp_program : + Parse_c.toplevel2 -> filename -> filename -> + bool (* true if res is an exp *) -> unit + diff --git a/parsing_c/visitor_c.ml b/parsing_c/visitor_c.ml new file mode 100644 index 0000000..32f85bc --- /dev/null +++ b/parsing_c/visitor_c.ml @@ -0,0 +1,1196 @@ +(* Copyright (C) 2002-2008 Yoann Padioleau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License (GPL) + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * file license.txt for more details. + *) +open Common + + +open Ast_c +module F = Control_flow_c + +(*****************************************************************************) +(* Functions to visit the Ast, and now also the CFG nodes *) +(*****************************************************************************) + + +(* Visitor based on continuation. Cleaner than the one based on mutable + * pointer functions. src: based on a (vague) idea from Remy Douence. + * + * + * + * Diff with Julia's visitor ? She does: + * + * let ident r k i = + * ... + * let expression r k e = + * ... + * ... (List.map r.V0.combiner_expression expr_list) ... + * ... + * let res = V0.combiner bind option_default + * mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + * donothing donothing donothing donothing + * ident expression typeC donothing parameter declaration statement + * donothing in + * ... + * collect_unitary_nonunitary + * (List.concat (List.map res.V0.combiner_top_level t)) + * + * + * + * So she has to remember at which position you must put the 'expression' + * function. I use record which is easier. + * + * When she calls recursively, her res.V0.combiner_xxx does not take bigf + * in param whereas I do + * | F.Decl decl -> Visitor_c.vk_decl bigf decl + * And with the record she gets, she does not have to do my + * multiple defs of function such as 'let al_type = V0.vk_type_s bigf' + * + * The code of visitor.ml is cleaner with julia because mutual recursive calls + * are clean such as ... 'expression e' ... and not 'f (k, bigf) e' + * or 'vk_expr bigf e'. + * + * So it is very dual: + * - I give a record but then I must handle bigf. + * - She gets a record, and gives a list of function + * + *) + + +(* old: first version (only visiting expr) + +let (iter_expr:((expression -> unit) -> expression -> unit) -> expression -> unit) + = fun f expr -> + let rec k e = + match e with + | Constant c -> () + | FunCall (e, es) -> f k e; List.iter (f k) es + | CondExpr (e1, e2, e3) -> f k e1; f k e2; f k e3 + | Sequence (e1, e2) -> f k e1; f k e2; + | Assignment (e1, op, e2) -> f k e1; f k e2; + + | Postfix (e, op) -> f k e + | Infix (e, op) -> f k e + | Unary (e, op) -> f k e + | Binary (e1, op, e2) -> f k e1; f k e2; + + | ArrayAccess (e1, e2) -> f k e1; f k e2; + | RecordAccess (e, s) -> f k e + | RecordPtAccess (e, s) -> f k e + + | SizeOfExpr e -> f k e + | SizeOfType t -> () + | _ -> failwith "to complete" + + in f k expr + +let ex1 = Sequence (Sequence (Constant (Ident "1"), Constant (Ident "2")), + Constant (Ident "4")) +let test = + iter_expr (fun k e -> match e with + | Constant (Ident x) -> Common.pr2 x + | rest -> k rest + ) ex1 +==> +1 +2 +4 + +*) + +(*****************************************************************************) +(* Side effect style visitor *) +(*****************************************************************************) + +(* Visitors for all langage concept, not just for expression. + * + * Note that I don't visit necesserally in the order of the token + * found in the original file. So don't assume such hypothesis! + *) +type visitor_c = + { + kexpr: (expression -> unit) * visitor_c -> expression -> unit; + kstatement: (statement -> unit) * visitor_c -> statement -> unit; + ktype: (fullType -> unit) * visitor_c -> fullType -> unit; + + kdecl: (declaration -> unit) * visitor_c -> declaration -> unit; + kdef: (definition -> unit) * visitor_c -> definition -> unit; + kini: (initialiser -> unit) * visitor_c -> initialiser -> unit; + + kinfo: (info -> unit) * visitor_c -> info -> unit; + + (* CFG *) + knode: (F.node -> unit) * visitor_c -> F.node -> unit; + (* AST *) + ktoplevel: (toplevel -> unit) * visitor_c -> toplevel -> unit; + } + +let default_visitor_c = + { kexpr = (fun (k,_) e -> k e); + kstatement = (fun (k,_) st -> k st); + ktype = (fun (k,_) t -> k t); + kdecl = (fun (k,_) d -> k d); + kdef = (fun (k,_) d -> k d); + kini = (fun (k,_) ie -> k ie); + kinfo = (fun (k,_) ii -> k ii); + knode = (fun (k,_) n -> k n); + ktoplevel = (fun (k,_) p -> k p); + } + +let rec vk_expr = fun bigf expr -> + let iif ii = vk_ii bigf ii in + + let rec exprf e = bigf.kexpr (k,bigf) e + (* dont go in _typ *) + and k ((e,_typ), ii) = + iif ii; + match e with + | Ident (s) -> () + | Constant (c) -> () + | FunCall (e, es) -> + exprf e; + es +> List.iter (fun (e, ii) -> + iif ii; + vk_argument bigf e + ); + | CondExpr (e1, e2, e3) -> + exprf e1; do_option (exprf) e2; exprf e3 + | Sequence (e1, e2) -> exprf e1; exprf e2; + | Assignment (e1, op, e2) -> exprf e1; exprf e2; + + | Postfix (e, op) -> exprf e + | Infix (e, op) -> exprf e + | Unary (e, op) -> exprf e + | Binary (e1, op, e2) -> exprf e1; exprf e2; + + | ArrayAccess (e1, e2) -> exprf e1; exprf e2; + | RecordAccess (e, s) -> exprf e + | RecordPtAccess (e, s) -> exprf e + + | SizeOfExpr (e) -> exprf e + | SizeOfType (t) -> vk_type bigf t + | Cast (t, e) -> vk_type bigf t; exprf e + + (* old: | StatementExpr (((declxs, statxs), is)), is2 -> + * List.iter (vk_decl bigf) declxs; + * List.iter (vk_statement bigf) statxs + *) + | StatementExpr ((statxs, is)) -> + iif is; + statxs +> List.iter (vk_statement bigf); + + (* TODO, we will certainly have to then do a special visitor for + * initializer + *) + | Constructor (t, initxs) -> + vk_type bigf t; + initxs +> List.iter (fun (ini, ii) -> + vk_ini bigf ini; + vk_ii bigf ii; + ) + + | ParenExpr (e) -> exprf e + + + in exprf expr + +and vk_argument = fun bigf arg -> + let rec do_action = function + | (ActMisc ii) -> vk_ii bigf ii + in + match arg with + | Left e -> (vk_expr bigf) e + | Right (ArgType param) -> vk_param bigf param + | Right (ArgAction action) -> do_action action + + + + +and vk_statement = fun bigf st -> + let iif ii = vk_ii bigf ii in + + let rec statf x = bigf.kstatement (k,bigf) x + and k st = + let (unwrap_st, ii) = st in + iif ii; + match unwrap_st with + | Labeled (Label (s, st)) -> statf st; + | Labeled (Case (e, st)) -> vk_expr bigf e; statf st; + | Labeled (CaseRange (e, e2, st)) -> + vk_expr bigf e; vk_expr bigf e2; statf st; + | Labeled (Default st) -> statf st; + + | Compound statxs -> statxs +> List.iter (vk_statement bigf) + | ExprStatement (eopt) -> do_option (vk_expr bigf) eopt; + + | Selection (If (e, st1, st2)) -> + vk_expr bigf e; statf st1; statf st2; + | Selection (Ifdef (st1s, st2s)) -> + st1s +> List.iter (vk_statement bigf); + st2s +> List.iter (vk_statement bigf) + | Selection (Switch (e, st)) -> + vk_expr bigf e; statf st; + | Iteration (While (e, st)) -> + vk_expr bigf e; statf st; + | Iteration (DoWhile (st, e)) -> statf st; vk_expr bigf e; + | Iteration (For ((e1opt,i1), (e2opt,i2), (e3opt,i3), st)) -> + statf (ExprStatement (e1opt),i1); + statf (ExprStatement (e2opt),i2); + statf (ExprStatement (e3opt),i3); + statf st; + + | Iteration (MacroIteration (s, es, st)) -> + es +> List.iter (fun (e, ii) -> + iif ii; + vk_argument bigf e + ); + statf st; + + | Jump (Goto s) -> () + | Jump ((Continue|Break|Return)) -> () + | Jump (ReturnExpr e) -> vk_expr bigf e; + | Jump (GotoComputed e) -> vk_expr bigf e; + + | Decl decl -> vk_decl bigf decl + | Asm asmbody -> vk_asmbody bigf asmbody + | NestedFunc def -> vk_def bigf def + | MacroStmt -> () + + in statf st + +and vk_asmbody = fun bigf (string_list, colon_list) -> + let iif ii = vk_ii bigf ii in + + iif string_list; + colon_list +> List.iter (fun (Colon xs, ii) -> + iif ii; + xs +> List.iter (fun (x,iicomma) -> + iif iicomma; + (match x with + | ColonMisc, ii -> iif ii + | ColonExpr e, ii -> + vk_expr bigf e; + iif ii + ) + )) + +and vk_type = fun bigf t -> + let iif ii = vk_ii bigf ii in + + let rec typef x = bigf.ktype (k, bigf) x + and k t = + let (q, t) = t in + let (unwrap_q, iiq) = q in + let (unwrap_t, iit) = t in + iif iiq; + iif iit; + match unwrap_t with + | BaseType _ -> () + | Pointer t -> typef t + | Array (eopt, t) -> + do_option (vk_expr bigf) eopt; + typef t + | FunctionType (returnt, paramst) -> + typef returnt; + (match paramst with + | (ts, (b,iihas3dots)) -> + iif iihas3dots; + ts +> List.iter (fun (param,iicomma) -> + vk_param bigf param; + iif iicomma; + + ) + ) + + | Enum (sopt, enumt) -> + enumt +> List.iter (fun (((s, eopt),ii_s_eq), iicomma) -> + iif ii_s_eq; iif iicomma; + eopt +> do_option (vk_expr bigf) + ); + + | StructUnion (sopt, _su, fields) -> + vk_struct_fields bigf fields + + | StructUnionName (s, structunion) -> () + | EnumName s -> () + + (* dont go in _typ *) + | TypeName (s, _typ) -> () + + | ParenType t -> typef t + | TypeOfExpr e -> vk_expr bigf e + | TypeOfType t -> typef t + + in typef t + +and vk_decl = fun bigf d -> + let iif ii = vk_ii bigf ii in + + let f = bigf.kdecl in + let rec k decl = + match decl with + | DeclList (xs,ii) -> iif ii; List.iter aux xs + | MacroDecl ((s, args),ii) -> + iif ii; + args +> List.iter (fun (e, ii) -> + iif ii; + vk_argument bigf e + ); + + + and aux ((var, t, _sto, _local), iicomma) = + iif iicomma; + vk_type bigf t; + var +> do_option (fun ((s, ini), ii_s_ini) -> + iif ii_s_ini; + ini +> do_option (vk_ini bigf) + ); + in f (k, bigf) d + +and vk_ini = fun bigf ini -> + let iif ii = vk_ii bigf ii in + + let rec inif x = bigf.kini (k, bigf) x + and k (ini, iini) = + iif iini; + match ini with + | InitExpr e -> vk_expr bigf e + | InitList initxs -> + initxs +> List.iter (fun (ini, ii) -> + inif ini; + iif ii; + ) + | InitDesignators (xs, e) -> + xs +> List.iter (vk_designator bigf); + inif e + + | InitFieldOld (s, e) -> inif e + | InitIndexOld (e1, e) -> + vk_expr bigf e1; inif e + + in inif ini + + +and vk_designator = fun bigf design -> + let iif ii = vk_ii bigf ii in + let (designator, ii) = design in + iif ii; + match designator with + | DesignatorField s -> () + | DesignatorIndex e -> vk_expr bigf e + | DesignatorRange (e1, e2) -> vk_expr bigf e1; vk_expr bigf e2 + +and vk_struct_fields = fun bigf fields -> + let iif ii = vk_ii bigf ii in + + fields +> List.iter (fun (xfield, ii) -> + iif ii; + match xfield with + | FieldDeclList onefield_multivars -> + vk_struct_field bigf onefield_multivars + | EmptyField -> () + ) + +and vk_struct_field = fun bigf onefield_multivars -> + let iif ii = vk_ii bigf ii in + onefield_multivars +> List.iter (fun (field, iicomma) -> + iif iicomma; + match field with + | Simple (s, t), ii -> iif ii; vk_type bigf t; + | BitField (sopt, t, expr), ii -> + iif ii; + vk_expr bigf expr; + vk_type bigf t + ) + + + +and vk_def = fun bigf d -> + let iif ii = vk_ii bigf ii in + + let f = bigf.kdef in + let rec k d = + match d with + | (s, (returnt, (paramst, (b, iib))), sto, statxs), ii -> + iif ii; + iif iib; + vk_type bigf returnt; + paramst +> List.iter (fun (param,iicomma) -> + vk_param bigf param; + iif iicomma; + ); + statxs +> List.iter (vk_statement bigf) + in f (k, bigf) d + + + + +and vk_toplevel = fun bigf p -> + let f = bigf.ktoplevel in + let iif ii = vk_ii bigf ii in + let rec k p = + match p with + | Declaration decl -> (vk_decl bigf decl) + | Definition def -> (vk_def bigf def) + | EmptyDef ii -> iif ii + | MacroTop (s, xs, ii) -> + xs +> List.iter (fun (elem, iicomma) -> + vk_argument bigf elem; iif iicomma + ); + iif ii + + | Include ((s, ii), h_rel_pos) -> iif ii; + | Define ((s,ii), (defkind, defval)) -> + iif ii; + vk_define_kind bigf defkind; + vk_define_val bigf defval + + | NotParsedCorrectly ii -> iif ii + | FinalDef info -> vk_info bigf info + in f (k, bigf) p + +and vk_define_kind bigf defkind = + match defkind with + | DefineVar -> () + | DefineFunc (params, ii) -> + vk_ii bigf ii; + params +> List.iter (fun ((s,iis), iicomma) -> + vk_ii bigf iis; + vk_ii bigf iicomma; + ) + +and vk_define_val bigf defval = + match defval with + | DefineExpr e -> + vk_expr bigf e + | DefineStmt stmt -> vk_statement bigf stmt + | DefineDoWhileZero (stmt, ii) -> + vk_statement bigf stmt; + vk_ii bigf ii + | DefineFunction def -> vk_def bigf def + | DefineType ty -> vk_type bigf ty + | DefineText (s, ii) -> vk_ii bigf ii + | DefineEmpty -> () + + + +(* ------------------------------------------------------------------------ *) +(* Now keep fullstatement inside the control flow node, + * so that can then get in a MetaStmtVar the fullstatement to later + * pp back when the S is in a +. But that means that + * Exp will match an Ifnode even if there is no such exp + * inside the condition of the Ifnode (because the exp may + * be deeper, in the then branch). So have to not visit + * all inside a node anymore. + * + * update: j'ai choisi d'accrocher au noeud du CFG à la + * fois le fullstatement et le partialstatement et appeler le + * visiteur que sur le partialstatement. + *) + +and vk_node = fun bigf node -> + let iif ii = vk_ii bigf ii in + let infof info = vk_info bigf info in + + let f = bigf.knode in + let rec k n = + match F.unwrap n with + + | F.FunHeader ((idb, (rett, (paramst,(isvaargs,iidotsb))), stob),ii) -> + vk_type bigf rett; + paramst +> List.iter (fun (param, iicomma) -> + vk_param bigf param; + iif iicomma; + ); + + + | F.Decl decl -> vk_decl bigf decl + | F.ExprStatement (st, (eopt, ii)) -> + iif ii; + eopt +> do_option (vk_expr bigf) + + | F.IfHeader (_, (e,ii)) + | F.SwitchHeader (_, (e,ii)) + | F.WhileHeader (_, (e,ii)) + | F.DoWhileTail (e,ii) -> + iif ii; + vk_expr bigf e + + | F.ForHeader (_st, (((e1opt,i1), (e2opt,i2), (e3opt,i3)), ii)) -> + iif i1; iif i2; iif i3; + iif ii; + e1opt +> do_option (vk_expr bigf); + e2opt +> do_option (vk_expr bigf); + e3opt +> do_option (vk_expr bigf); + | F.MacroIterHeader (_s, ((s,es), ii)) -> + iif ii; + es +> List.iter (fun (e, ii) -> + iif ii; + vk_argument bigf e + ); + + | F.ReturnExpr (_st, (e,ii)) -> iif ii; vk_expr bigf e + + | F.Case (_st, (e,ii)) -> iif ii; vk_expr bigf e + | F.CaseRange (_st, ((e1, e2),ii)) -> + iif ii; vk_expr bigf e1; vk_expr bigf e2 + + + | F.CaseNode i -> () + + | F.DefineExpr e -> vk_expr bigf e + | F.DefineType ft -> vk_type bigf ft + | F.DefineHeader ((s,ii), (defkind)) -> + iif ii; + vk_define_kind bigf defkind; + + | F.DefineDoWhileZeroHeader (((),ii)) -> iif ii + + | F.Include ((s, ii),h_rel_pos) -> iif ii + + | F.MacroTop (s, args, ii) -> + iif ii; + args +> List.iter (fun (e, ii) -> vk_argument bigf e; iif ii) + + | F.Ifdef (st, ((),ii)) -> iif ii + + | F.Break (st,((),ii)) -> iif ii + | F.Continue (st,((),ii)) -> iif ii + | F.Default (st,((),ii)) -> iif ii + | F.Return (st,((),ii)) -> iif ii + | F.Goto (st, (s,ii)) -> iif ii + | F.Label (st, (s,ii)) -> iif ii + | F.EndStatement iopt -> do_option infof iopt + | F.DoHeader (st, info) -> infof info + | F.Else info -> infof info + | F.SeqEnd (i, info) -> infof info + | F.SeqStart (st, i, info) -> infof info + + | F.MacroStmt (st, ((),ii)) -> iif ii + | F.Asm (st, (asmbody,ii)) -> + iif ii; + vk_asmbody bigf asmbody + + | ( + F.TopNode|F.EndNode| + F.ErrorExit|F.Exit|F.Enter| + F.FallThroughNode|F.AfterNode|F.FalseNode|F.TrueNode|F.InLoopNode| + F.Fake + ) -> () + + + + in + f (k, bigf) node + +(* ------------------------------------------------------------------------ *) +and vk_info = fun bigf info -> + let rec infof ii = bigf.kinfo (k, bigf) ii + and k i = () + in + infof info + +and vk_ii = fun bigf ii -> + List.iter (vk_info bigf) ii + + +and vk_param = fun bigf (((b, s, t), ii_b_s)) -> + let iif ii = vk_ii bigf ii in + iif ii_b_s; + vk_type bigf t + + +let vk_args_splitted = fun bigf args_splitted -> + let iif ii = vk_ii bigf ii in + args_splitted +> List.iter (function + | Left arg -> vk_argument bigf arg + | Right ii -> iif ii + ) + + +let vk_define_params_splitted = fun bigf args_splitted -> + let iif ii = vk_ii bigf ii in + args_splitted +> List.iter (function + | Left (s, iis) -> vk_ii bigf iis + | Right ii -> iif ii + ) + + + +let vk_params_splitted = fun bigf args_splitted -> + let iif ii = vk_ii bigf ii in + args_splitted +> List.iter (function + | Left arg -> vk_param bigf arg + | Right ii -> iif ii + ) + + +let vk_cst = fun bigf (cst, ii) -> + let iif ii = vk_ii bigf ii in + iif ii; + (match cst with + | Left cst -> () + | Right s -> () + ) + + + + +(*****************************************************************************) +(* "syntetisized attributes" style *) +(*****************************************************************************) +type 'a inout = 'a -> 'a + +(* _s for synthetizized attributes + * + * Note that I don't visit necesserally in the order of the token + * found in the original file. So don't assume such hypothesis! + *) +type visitor_c_s = { + kexpr_s: (expression inout * visitor_c_s) -> expression inout; + kstatement_s: (statement inout * visitor_c_s) -> statement inout; + ktype_s: (fullType inout * visitor_c_s) -> fullType inout; + kini_s: (initialiser inout * visitor_c_s) -> initialiser inout; + + kdecl_s: (declaration inout * visitor_c_s) -> declaration inout; + kdef_s: (definition inout * visitor_c_s) -> definition inout; + + ktoplevel_s: (toplevel inout * visitor_c_s) -> toplevel inout; + knode_s: (F.node inout * visitor_c_s) -> F.node inout; + + kdefineval_s: (define_val inout * visitor_c_s) -> define_val inout; + + kinfo_s: (info inout * visitor_c_s) -> info inout; + } + +let default_visitor_c_s = + { kexpr_s = (fun (k,_) e -> k e); + kstatement_s = (fun (k,_) st -> k st); + ktype_s = (fun (k,_) t -> k t); + kdecl_s = (fun (k,_) d -> k d); + kdef_s = (fun (k,_) d -> k d); + kini_s = (fun (k,_) d -> k d); + ktoplevel_s = (fun (k,_) p -> k p); + knode_s = (fun (k,_) n -> k n); + kinfo_s = (fun (k,_) i -> k i); + kdefineval_s = (fun (k,_) x -> k x); + } + +let rec vk_expr_s = fun bigf expr -> + let iif ii = vk_ii_s bigf ii in + let rec exprf e = bigf.kexpr_s (k, bigf) e + and k e = + let ((unwrap_e, typ), ii) = e in + (* don't analyse optional type + * old: typ +> map_option (vk_type_s bigf) in + *) + let typ' = typ in + let e' = + match unwrap_e with + | Ident (s) -> Ident (s) + | Constant (c) -> Constant (c) + | FunCall (e, es) -> + FunCall (exprf e, + es +> List.map (fun (e,ii) -> + vk_argument_s bigf e, iif ii + )) + + | CondExpr (e1, e2, e3) -> CondExpr (exprf e1, fmap exprf e2, exprf e3) + | Sequence (e1, e2) -> Sequence (exprf e1, exprf e2) + | Assignment (e1, op, e2) -> Assignment (exprf e1, op, exprf e2) + + | Postfix (e, op) -> Postfix (exprf e, op) + | Infix (e, op) -> Infix (exprf e, op) + | Unary (e, op) -> Unary (exprf e, op) + | Binary (e1, op, e2) -> Binary (exprf e1, op, exprf e2) + + | ArrayAccess (e1, e2) -> ArrayAccess (exprf e1, exprf e2) + | RecordAccess (e, s) -> RecordAccess (exprf e, s) + | RecordPtAccess (e, s) -> RecordPtAccess (exprf e, s) + + | SizeOfExpr (e) -> SizeOfExpr (exprf e) + | SizeOfType (t) -> SizeOfType (vk_type_s bigf t) + | Cast (t, e) -> Cast (vk_type_s bigf t, exprf e) + + | StatementExpr (statxs, is) -> + StatementExpr ( + statxs +> List.map (vk_statement_s bigf), + iif is) + | Constructor (t, initxs) -> + Constructor + (vk_type_s bigf t, + (initxs +> List.map (fun (ini, ii) -> + vk_ini_s bigf ini, vk_ii_s bigf ii) + )) + + | ParenExpr (e) -> ParenExpr (exprf e) + + in + (e', typ'), (iif ii) + in exprf expr + +and vk_argument_s bigf argument = + let iif ii = vk_ii_s bigf ii in + let rec do_action = function + | (ActMisc ii) -> ActMisc (iif ii) + in + (match argument with + | Left e -> Left (vk_expr_s bigf e) + | Right (ArgType param) -> Right (ArgType (vk_param_s bigf param)) + | Right (ArgAction action) -> Right (ArgAction (do_action action)) + ) + + + + + + +and vk_statement_s = fun bigf st -> + let rec statf st = bigf.kstatement_s (k, bigf) st + and k st = + let (unwrap_st, ii) = st in + let st' = + match unwrap_st with + | Labeled (Label (s, st)) -> + Labeled (Label (s, statf st)) + | Labeled (Case (e, st)) -> + Labeled (Case ((vk_expr_s bigf) e , statf st)) + | Labeled (CaseRange (e, e2, st)) -> + Labeled (CaseRange ((vk_expr_s bigf) e, + (vk_expr_s bigf) e2, + statf st)) + | Labeled (Default st) -> Labeled (Default (statf st)) + | Compound statxs -> + Compound (statxs +> List.map (vk_statement_s bigf)) + | ExprStatement (None) -> ExprStatement (None) + | ExprStatement (Some e) -> ExprStatement (Some ((vk_expr_s bigf) e)) + | Selection (If (e, st1, st2)) -> + Selection (If ((vk_expr_s bigf) e, statf st1, statf st2)) + | Selection (Ifdef (st1s, st2s)) -> + Selection (Ifdef + (st1s +> List.map (vk_statement_s bigf), + st2s +> List.map (vk_statement_s bigf))) + | Selection (Switch (e, st)) -> + Selection (Switch ((vk_expr_s bigf) e, statf st)) + | Iteration (While (e, st)) -> + Iteration (While ((vk_expr_s bigf) e, statf st)) + | Iteration (DoWhile (st, e)) -> + Iteration (DoWhile (statf st, (vk_expr_s bigf) e)) + | Iteration (For ((e1opt,i1), (e2opt,i2), (e3opt,i3), st)) -> + let e1opt' = statf (ExprStatement (e1opt),i1) in + let e2opt' = statf (ExprStatement (e2opt),i2) in + let e3opt' = statf (ExprStatement (e3opt),i3) in + (match (e1opt', e2opt', e3opt') with + | ((ExprStatement x1,i1), (ExprStatement x2,i2), ((ExprStatement x3,i3))) -> + Iteration (For ((x1,i1), (x2,i2), (x3,i3), statf st)) + | x -> failwith "cant be here if iterator keep ExprStatement as is" + ) + + | Iteration (MacroIteration (s, es, st)) -> + Iteration + (MacroIteration + (s, + es +> List.map (fun (e, ii) -> + vk_argument_s bigf e, vk_ii_s bigf ii + ), + statf st + )) + + + | Jump (Goto s) -> Jump (Goto s) + | Jump (((Continue|Break|Return) as x)) -> Jump (x) + | Jump (ReturnExpr e) -> Jump (ReturnExpr ((vk_expr_s bigf) e)) + | Jump (GotoComputed e) -> Jump (GotoComputed (vk_expr_s bigf e)); + + | Decl decl -> Decl (vk_decl_s bigf decl) + | Asm asmbody -> Asm (vk_asmbody_s bigf asmbody) + | NestedFunc def -> NestedFunc (vk_def_s bigf def) + | MacroStmt -> MacroStmt + in + st', vk_ii_s bigf ii + in statf st + +and vk_asmbody_s = fun bigf (string_list, colon_list) -> + let iif ii = vk_ii_s bigf ii in + + iif string_list, + colon_list +> List.map (fun (Colon xs, ii) -> + Colon + (xs +> List.map (fun (x, iicomma) -> + (match x with + | ColonMisc, ii -> ColonMisc, iif ii + | ColonExpr e, ii -> ColonExpr (vk_expr_s bigf e), iif ii + ), iif iicomma + )), + iif ii + ) + + + + +and vk_type_s = fun bigf t -> + let rec typef t = bigf.ktype_s (k,bigf) t + and iif ii = vk_ii_s bigf ii + and k t = + let (q, t) = t in + let (unwrap_q, iiq) = q in + let q' = unwrap_q in (* todo? a visitor for qualifier *) + let (unwrap_t, iit) = t in + let t' = + match unwrap_t with + | BaseType x -> BaseType x + | Pointer t -> Pointer (typef t) + | Array (eopt, t) -> Array (fmap (vk_expr_s bigf) eopt, typef t) + | FunctionType (returnt, paramst) -> + FunctionType + (typef returnt, + (match paramst with + | (ts, (b, iihas3dots)) -> + (ts +> List.map (fun (param,iicomma) -> + (vk_param_s bigf param, iif iicomma)), + (b, iif iihas3dots)) + )) + + | Enum (sopt, enumt) -> + Enum (sopt, + enumt +> List.map (fun (((s, eopt),ii_s_eq), iicomma) -> + ((s, fmap (vk_expr_s bigf) eopt), iif ii_s_eq), + iif iicomma + ) + ) + | StructUnion (sopt, su, fields) -> + StructUnion (sopt, su, vk_struct_fields_s bigf fields) + + + | StructUnionName (s, structunion) -> StructUnionName (s, structunion) + | EnumName s -> EnumName s + | TypeName (s, typ) -> TypeName (s, typ) + + | ParenType t -> ParenType (typef t) + | TypeOfExpr e -> TypeOfExpr (vk_expr_s bigf e) + | TypeOfType t -> TypeOfType (typef t) + in + (q', iif iiq), + (t', iif iit) + + + in typef t + +and vk_decl_s = fun bigf d -> + let f = bigf.kdecl_s in + let iif ii = vk_ii_s bigf ii in + let rec k decl = + match decl with + | DeclList (xs, ii) -> + DeclList (List.map aux xs, iif ii) + | MacroDecl ((s, args),ii) -> + MacroDecl + ((s, + args +> List.map (fun (e,ii) -> vk_argument_s bigf e, iif ii) + ), + iif ii) + + + and aux ((var, t, sto, local), iicomma) = + ((var +> map_option (fun ((s, ini), ii_s_ini) -> + (s, ini +> map_option (fun init -> vk_ini_s bigf init)), + iif ii_s_ini + ) + ), + vk_type_s bigf t, + sto, local), + iif iicomma + + in f (k, bigf) d + +and vk_ini_s = fun bigf ini -> + let rec inif ini = bigf.kini_s (k,bigf) ini + and k ini = + let (unwrap_ini, ii) = ini in + let ini' = + match unwrap_ini with + | InitExpr e -> InitExpr (vk_expr_s bigf e) + | InitList initxs -> + InitList (initxs +> List.map (fun (ini, ii) -> + inif ini, vk_ii_s bigf ii) + ) + + + | InitDesignators (xs, e) -> + InitDesignators + (xs +> List.map (vk_designator_s bigf), + inif e + ) + + | InitFieldOld (s, e) -> InitFieldOld (s, inif e) + | InitIndexOld (e1, e) -> InitIndexOld (vk_expr_s bigf e1, inif e) + + in ini', vk_ii_s bigf ii + in inif ini + + +and vk_designator_s = fun bigf design -> + let iif ii = vk_ii_s bigf ii in + let (designator, ii) = design in + (match designator with + | DesignatorField s -> DesignatorField s + | DesignatorIndex e -> DesignatorIndex (vk_expr_s bigf e) + | DesignatorRange (e1, e2) -> + DesignatorRange (vk_expr_s bigf e1, vk_expr_s bigf e2) + ), iif ii + + + + +and vk_struct_fields_s = fun bigf fields -> + + let iif ii = vk_ii_s bigf ii in + + fields +> List.map (fun (xfield, iiptvirg) -> + + (match xfield with + | FieldDeclList onefield_multivars -> + FieldDeclList ( + onefield_multivars +> List.map (fun (field, iicomma) -> + (match field with + | Simple (s, t), iis -> Simple (s, vk_type_s bigf t), iif iis + | BitField (sopt, t, expr), iis -> + BitField (sopt, vk_type_s bigf t, vk_expr_s bigf expr), + iif iis + ), iif iicomma + ) + ) + | EmptyField -> EmptyField + ), iif iiptvirg + ) + + +and vk_def_s = fun bigf d -> + let f = bigf.kdef_s in + let iif ii = vk_ii_s bigf ii in + let rec k d = + match d with + | (s, (returnt, (paramst, (b, iib))), sto, statxs), ii -> + (s, + (vk_type_s bigf returnt, + (paramst +> List.map (fun (param, iicomma) -> + (vk_param_s bigf param, iif iicomma) + ), + (b, iif iib))), + sto, + statxs +> List.map (vk_statement_s bigf) + ), + iif ii + + in f (k, bigf) d + +and vk_toplevel_s = fun bigf p -> + let f = bigf.ktoplevel_s in + let iif ii = vk_ii_s bigf ii in + let rec k p = + match p with + | Declaration decl -> Declaration (vk_decl_s bigf decl) + | Definition def -> Definition (vk_def_s bigf def) + | EmptyDef ii -> EmptyDef (iif ii) + | MacroTop (s, xs, ii) -> + MacroTop + (s, + xs +> List.map (fun (elem, iicomma) -> + vk_argument_s bigf elem, iif iicomma + ), + iif ii + ) + | Include ((s, ii), h_rel_pos) -> Include ((s, iif ii), h_rel_pos) + | Define ((s,ii), (defkind, defval)) -> + Define ((s, iif ii), + (vk_define_kind_s bigf defkind, vk_define_val_s bigf defval)) + + | NotParsedCorrectly ii -> NotParsedCorrectly (iif ii) + | FinalDef info -> FinalDef (vk_info_s bigf info) + in f (k, bigf) p + +and vk_define_kind_s = fun bigf defkind -> + match defkind with + | DefineVar -> DefineVar + | DefineFunc (params, ii) -> + DefineFunc + (params +> List.map (fun ((s,iis),iicomma) -> + ((s, vk_ii_s bigf iis), vk_ii_s bigf iicomma) + ), + vk_ii_s bigf ii + ) + + +and vk_define_val_s = fun bigf x -> + let f = bigf.kdefineval_s in + let iif ii = vk_ii_s bigf ii in + let rec k x = + match x with + | DefineExpr e -> DefineExpr (vk_expr_s bigf e) + | DefineStmt st -> DefineStmt (vk_statement_s bigf st) + | DefineDoWhileZero (st,ii) -> + DefineDoWhileZero (vk_statement_s bigf st, iif ii) + | DefineFunction def -> DefineFunction (vk_def_s bigf def) + | DefineType ty -> DefineType (vk_type_s bigf ty) + | DefineText (s, ii) -> DefineText (s, iif ii) + | DefineEmpty -> DefineEmpty + in + f (k, bigf) x + + +and vk_info_s = fun bigf info -> + let rec infof ii = bigf.kinfo_s (k, bigf) ii + and k i = i + in + infof info + +and vk_ii_s = fun bigf ii -> + List.map (vk_info_s bigf) ii + +(* ------------------------------------------------------------------------ *) +and vk_node_s = fun bigf node -> + let iif ii = vk_ii_s bigf ii in + let infof info = vk_info_s bigf info in + + let rec nodef n = bigf.knode_s (k, bigf) n + and k node = + F.rewrap node ( + match F.unwrap node with + | F.FunHeader ((idb, (rett, (paramst,(isvaargs,iidotsb))), stob),ii) -> + F.FunHeader + ((idb, + (vk_type_s bigf rett, + (paramst +> List.map (fun (param, iicomma) -> + (vk_param_s bigf param, iif iicomma) + ), (isvaargs,iif iidotsb))), stob),iif ii) + + + | F.Decl declb -> F.Decl (vk_decl_s bigf declb) + | F.ExprStatement (st, (eopt, ii)) -> + F.ExprStatement (st, (eopt +> map_option (vk_expr_s bigf), iif ii)) + + | F.IfHeader (st, (e,ii)) -> + F.IfHeader (st, (vk_expr_s bigf e, iif ii)) + | F.SwitchHeader (st, (e,ii)) -> + F.SwitchHeader(st, (vk_expr_s bigf e, iif ii)) + | F.WhileHeader (st, (e,ii)) -> + F.WhileHeader (st, (vk_expr_s bigf e, iif ii)) + | F.DoWhileTail (e,ii) -> + F.DoWhileTail (vk_expr_s bigf e, iif ii) + + | F.ForHeader (st, (((e1opt,i1), (e2opt,i2), (e3opt,i3)), ii)) -> + F.ForHeader (st, + (((e1opt +> Common.map_option (vk_expr_s bigf), iif i1), + (e2opt +> Common.map_option (vk_expr_s bigf), iif i2), + (e3opt +> Common.map_option (vk_expr_s bigf), iif i3)), + iif ii)) + + | F.MacroIterHeader (st, ((s,es), ii)) -> + F.MacroIterHeader + (st, + ((s, es +> List.map (fun (e, ii) -> vk_argument_s bigf e, iif ii)), + iif ii)) + + + | F.ReturnExpr (st, (e,ii)) -> + F.ReturnExpr (st, (vk_expr_s bigf e, iif ii)) + + | F.Case (st, (e,ii)) -> F.Case (st, (vk_expr_s bigf e, iif ii)) + | F.CaseRange (st, ((e1, e2),ii)) -> + F.CaseRange (st, ((vk_expr_s bigf e1, vk_expr_s bigf e2), iif ii)) + + | F.CaseNode i -> F.CaseNode i + + | F.DefineHeader((s,ii), (defkind)) -> + F.DefineHeader ((s, iif ii), (vk_define_kind_s bigf defkind)) + + | F.DefineExpr e -> F.DefineExpr (vk_expr_s bigf e) + | F.DefineType ft -> F.DefineType (vk_type_s bigf ft) + | F.DefineDoWhileZeroHeader ((),ii) -> + F.DefineDoWhileZeroHeader ((),iif ii) + + | F.Include ((s, ii), h_rel_pos) -> F.Include ((s, iif ii), h_rel_pos) + | F.Ifdef (st, ((),ii)) -> F.Ifdef (st, ((),iif ii)) + | F.MacroTop (s, args, ii) -> + F.MacroTop + (s, + args +> List.map (fun (e, ii) -> vk_argument_s bigf e, iif ii), + iif ii) + + + | F.MacroStmt (st, ((),ii)) -> F.MacroStmt (st, ((),iif ii)) + | F.Asm (st, (body,ii)) -> F.Asm (st, (vk_asmbody_s bigf body,iif ii)) + + | F.Break (st,((),ii)) -> F.Break (st,((),iif ii)) + | F.Continue (st,((),ii)) -> F.Continue (st,((),iif ii)) + | F.Default (st,((),ii)) -> F.Default (st,((),iif ii)) + | F.Return (st,((),ii)) -> F.Return (st,((),iif ii)) + | F.Goto (st, (s,ii)) -> F.Goto (st, (s,iif ii)) + | F.Label (st, (s,ii)) -> F.Label (st, (s,iif ii)) + | F.EndStatement iopt -> F.EndStatement (map_option infof iopt) + | F.DoHeader (st, info) -> F.DoHeader (st, infof info) + | F.Else info -> F.Else (infof info) + | F.SeqEnd (i, info) -> F.SeqEnd (i, infof info) + | F.SeqStart (st, i, info) -> F.SeqStart (st, i, infof info) + + | ( + ( + F.TopNode|F.EndNode| + F.ErrorExit|F.Exit|F.Enter| + F.FallThroughNode|F.AfterNode|F.FalseNode|F.TrueNode|F.InLoopNode| + F.Fake + ) as x) -> x + + + ) + in + nodef node + +(* ------------------------------------------------------------------------ *) +and vk_param_s = fun bigf ((b, s, t), ii_b_s) -> + let iif ii = vk_ii_s bigf ii in + ((b, s, vk_type_s bigf t), iif ii_b_s) + +let vk_args_splitted_s = fun bigf args_splitted -> + let iif ii = vk_ii_s bigf ii in + args_splitted +> List.map (function + | Left arg -> Left (vk_argument_s bigf arg) + | Right ii -> Right (iif ii) + ) + +let vk_arguments_s = fun bigf args -> + let iif ii = vk_ii_s bigf ii in + args +> List.map (fun (e, ii) -> vk_argument_s bigf e, iif ii) + + +let vk_params_splitted_s = fun bigf args_splitted -> + let iif ii = vk_ii_s bigf ii in + args_splitted +> List.map (function + | Left arg -> Left (vk_param_s bigf arg) + | Right ii -> Right (iif ii) + ) + +let vk_params_s = fun bigf args -> + let iif ii = vk_ii_s bigf ii in + args +> List.map (fun (p,ii) -> vk_param_s bigf p, iif ii) + +let vk_define_params_splitted_s = fun bigf args_splitted -> + let iif ii = vk_ii_s bigf ii in + args_splitted +> List.map (function + | Left (s, iis) -> Left (s, vk_ii_s bigf iis) + | Right ii -> Right (iif ii) + ) + +let vk_cst_s = fun bigf (cst, ii) -> + let iif ii = vk_ii_s bigf ii in + (match cst with + | Left cst -> Left cst + | Right s -> Right s + ), iif ii diff --git a/parsing_c/visitor_c.mli b/parsing_c/visitor_c.mli new file mode 100644 index 0000000..58f0523 --- /dev/null +++ b/parsing_c/visitor_c.mli @@ -0,0 +1,104 @@ +open Ast_c + +type visitor_c = { + kexpr : (expression -> unit) * visitor_c -> expression -> unit; + kstatement : (statement -> unit) * visitor_c -> statement -> unit; + ktype : (fullType -> unit) * visitor_c -> fullType -> unit; + kdecl : (declaration -> unit) * visitor_c -> declaration -> unit; + kdef : (definition -> unit) * visitor_c -> definition -> unit; + kini : (initialiser -> unit) * visitor_c -> initialiser -> unit; + kinfo : (info -> unit) * visitor_c -> info -> unit; + knode : + (Control_flow_c.node -> unit) * visitor_c -> Control_flow_c.node -> unit; + ktoplevel: (toplevel -> unit) * visitor_c -> toplevel -> unit; +} + +val default_visitor_c : visitor_c + +val vk_expr : visitor_c -> expression -> unit +val vk_statement : visitor_c -> statement -> unit +val vk_type : visitor_c -> fullType -> unit +val vk_decl : visitor_c -> declaration -> unit +val vk_ini : visitor_c -> initialiser -> unit +val vk_def : visitor_c -> definition -> unit +val vk_node : visitor_c -> Control_flow_c.node -> unit +val vk_info : visitor_c -> info -> unit +val vk_toplevel : visitor_c -> toplevel -> unit + +val vk_argument : visitor_c -> argument -> unit + +val vk_args_splitted : visitor_c -> (argument, il) Common.either list -> unit +val vk_param : visitor_c -> parameterType -> unit +val vk_params_splitted : + visitor_c -> (parameterType, il) Common.either list -> unit + +val vk_struct_fields : visitor_c -> field wrap list -> unit +val vk_struct_field : visitor_c -> fieldkind wrap list -> unit + +val vk_cst : visitor_c -> ((constant, string) Common.either wrap) -> unit + +val vk_define_params_splitted : + visitor_c -> (string Ast_c.wrap, il) Common.either list -> unit + + + + +type 'a inout = 'a -> 'a +type visitor_c_s = { + kexpr_s : expression inout * visitor_c_s -> expression inout; + kstatement_s : statement inout * visitor_c_s -> statement inout; + ktype_s : fullType inout * visitor_c_s -> fullType inout; + kini_s : initialiser inout * visitor_c_s -> initialiser inout; + kdecl_s : declaration inout * visitor_c_s -> declaration inout; + kdef_s : definition inout * visitor_c_s -> definition inout; + ktoplevel_s : toplevel inout * visitor_c_s -> toplevel inout; + knode_s : + Control_flow_c.node inout * visitor_c_s -> Control_flow_c.node inout; + kdefineval_s : (define_val inout * visitor_c_s) -> define_val inout; + kinfo_s : info inout * visitor_c_s -> info inout; + } + +val default_visitor_c_s : visitor_c_s + +val vk_expr_s : visitor_c_s -> expression -> expression +val vk_argument_s : visitor_c_s -> argument -> argument +val vk_statement_s : visitor_c_s -> statement -> statement +val vk_type_s : visitor_c_s -> fullType -> fullType +val vk_decl_s : visitor_c_s -> declaration -> declaration +val vk_ini_s : visitor_c_s -> initialiser -> initialiser +val vk_def_s : visitor_c_s -> definition -> definition +val vk_toplevel_s : visitor_c_s -> toplevel -> toplevel +val vk_info_s : visitor_c_s -> info -> info +val vk_node_s : visitor_c_s -> Control_flow_c.node -> Control_flow_c.node + +val vk_arguments_s : + visitor_c_s -> + argument wrap2 list -> argument wrap2 list + +val vk_args_splitted_s : + visitor_c_s -> + (argument, il) Common.either list -> + (argument, il) Common.either list + +val vk_params_s : + visitor_c_s -> + parameterType wrap2 list -> parameterType wrap2 list + +val vk_params_splitted_s : + visitor_c_s -> + (parameterType, il) Common.either list -> + (parameterType, il) Common.either list + + + +val vk_param_s : visitor_c_s -> parameterType -> parameterType + +val vk_define_params_splitted_s : + visitor_c_s -> + (string Ast_c.wrap, il) Common.either list -> + (string Ast_c.wrap, il) Common.either list + +val vk_struct_fields_s : visitor_c_s -> + field wrap list -> field wrap list + +val vk_cst_s : visitor_c_s -> ((constant, string) Common.either wrap) inout diff --git a/parsing_cocci/.depend b/parsing_cocci/.depend new file mode 100644 index 0000000..68b202b --- /dev/null +++ b/parsing_cocci/.depend @@ -0,0 +1,180 @@ +arity.cmi: ast0_cocci.cmi +ast0_cocci.cmi: type_cocci.cmi ast_cocci.cmi +ast0toast.cmi: ast_cocci.cmi ast0_cocci.cmi +ast_cocci.cmi: type_cocci.cmi +check_meta.cmi: ast_cocci.cmi ast0_cocci.cmi +comm_assoc.cmi: ast0_cocci.cmi +compute_lines.cmi: ast0_cocci.cmi +context_neg.cmi: ../commons/common.cmi ast0_cocci.cmi +data.cmi: type_cocci.cmi ast_cocci.cmi ast0_cocci.cmi +disjdistr.cmi: ast_cocci.cmi +free_vars.cmi: ast_cocci.cmi +function_prototypes.cmi: ast_cocci.cmi ast0_cocci.cmi +get_constants.cmi: ast_cocci.cmi +get_constants2.cmi: ast_cocci.cmi +index.cmi: ast0_cocci.cmi +insert_plus.cmi: ast0_cocci.cmi +iso_compile.cmi: iso_pattern.cmi +iso_pattern.cmi: visitor_ast0.cmi ast_cocci.cmi ast0_cocci.cmi +merge.cmi: ast_cocci.cmi ast0_cocci.cmi +parse_cocci.cmi: ast_cocci.cmi +parser_cocci_menhir.cmi: parse_aux.cmo data.cmi ../commons/common.cmi \ + ast_cocci.cmi ast0_cocci.cmi +plus.cmi: ast_cocci.cmi +pretty_print_cocci.cmi: ast_cocci.cmi +simple_assignments.cmi: ast0_cocci.cmi +single_statement.cmi: ast0_cocci.cmi +test_exps.cmi: ast0_cocci.cmi +top_level.cmi: ast0_cocci.cmi +type_infer.cmi: ast0_cocci.cmi +unify_ast.cmi: ast_cocci.cmi +unitary_ast0.cmi: ast0_cocci.cmi +unparse_ast0.cmi: ast0_cocci.cmi +visitor_ast.cmi: ast_cocci.cmi +visitor_ast0.cmi: ast_cocci.cmi ast0_cocci.cmi +arity.cmo: ast_cocci.cmi ast0_cocci.cmi arity.cmi +arity.cmx: ast_cocci.cmx ast0_cocci.cmx arity.cmi +ast0_cocci.cmo: type_cocci.cmi ../globals/flag.cmo ast_cocci.cmi \ + ast0_cocci.cmi +ast0_cocci.cmx: type_cocci.cmx ../globals/flag.cmx ast_cocci.cmx \ + ast0_cocci.cmi +ast0toast.cmo: visitor_ast0.cmi visitor_ast.cmi type_cocci.cmi \ + ../globals/flag.cmo ast_cocci.cmi ast0_cocci.cmi ast0toast.cmi +ast0toast.cmx: visitor_ast0.cmx visitor_ast.cmx type_cocci.cmx \ + ../globals/flag.cmx ast_cocci.cmx ast0_cocci.cmx ast0toast.cmi +ast_cocci.cmo: type_cocci.cmi ../commons/common.cmi ast_cocci.cmi +ast_cocci.cmx: type_cocci.cmx ../commons/common.cmx ast_cocci.cmi +check_meta.cmo: visitor_ast0.cmi type_cocci.cmi ../commons/common.cmi \ + ast_cocci.cmi ast0_cocci.cmi check_meta.cmi +check_meta.cmx: visitor_ast0.cmx type_cocci.cmx ../commons/common.cmx \ + ast_cocci.cmx ast0_cocci.cmx check_meta.cmi +comm_assoc.cmo: visitor_ast0.cmi unparse_ast0.cmi ../globals/flag.cmo \ + ast_cocci.cmi ast0_cocci.cmi comm_assoc.cmi +comm_assoc.cmx: visitor_ast0.cmx unparse_ast0.cmx ../globals/flag.cmx \ + ast_cocci.cmx ast0_cocci.cmx comm_assoc.cmi +compute_lines.cmo: ast_cocci.cmi ast0_cocci.cmi compute_lines.cmi +compute_lines.cmx: ast_cocci.cmx ast0_cocci.cmx compute_lines.cmi +context_neg.cmo: visitor_ast0.cmi unparse_ast0.cmi index.cmi \ + ../globals/flag.cmo compute_lines.cmi ../commons/common.cmi ast_cocci.cmi \ + ast0_cocci.cmi context_neg.cmi +context_neg.cmx: visitor_ast0.cmx unparse_ast0.cmx index.cmx \ + ../globals/flag.cmx compute_lines.cmx ../commons/common.cmx ast_cocci.cmx \ + ast0_cocci.cmx context_neg.cmi +data.cmo: type_cocci.cmi ast_cocci.cmi ast0_cocci.cmi data.cmi +data.cmx: type_cocci.cmx ast_cocci.cmx ast0_cocci.cmx data.cmi +disjdistr.cmo: visitor_ast.cmi ../globals/flag.cmo ../commons/common.cmi \ + ast_cocci.cmi disjdistr.cmi +disjdistr.cmx: visitor_ast.cmx ../globals/flag.cmx ../commons/common.cmx \ + ast_cocci.cmx disjdistr.cmi +free_vars.cmo: visitor_ast.cmi type_cocci.cmi ../commons/common.cmi \ + ast_cocci.cmi free_vars.cmi +free_vars.cmx: visitor_ast.cmx type_cocci.cmx ../commons/common.cmx \ + ast_cocci.cmx free_vars.cmi +function_prototypes.cmo: visitor_ast0.cmi iso_pattern.cmi insert_plus.cmi \ + context_neg.cmi compute_lines.cmi ast_cocci.cmi ast0toast.cmi \ + ast0_cocci.cmi function_prototypes.cmi +function_prototypes.cmx: visitor_ast0.cmx iso_pattern.cmx insert_plus.cmx \ + context_neg.cmx compute_lines.cmx ast_cocci.cmx ast0toast.cmx \ + ast0_cocci.cmx function_prototypes.cmi +get_constants.cmo: visitor_ast.cmi type_cocci.cmi ../globals/flag.cmo \ + ../commons/common.cmi ast_cocci.cmi get_constants.cmi +get_constants.cmx: visitor_ast.cmx type_cocci.cmx ../globals/flag.cmx \ + ../commons/common.cmx ast_cocci.cmx get_constants.cmi +get_constants2.cmo: visitor_ast.cmi type_cocci.cmi ../globals/flag.cmo \ + ../commons/common.cmi ast_cocci.cmi get_constants2.cmi +get_constants2.cmx: visitor_ast.cmx type_cocci.cmx ../globals/flag.cmx \ + ../commons/common.cmx ast_cocci.cmx get_constants2.cmi +index.cmo: ast_cocci.cmi ast0_cocci.cmi index.cmi +index.cmx: ast_cocci.cmx ast0_cocci.cmx index.cmi +insert_plus.cmo: visitor_ast0.cmi pretty_print_cocci.cmi context_neg.cmi \ + ast_cocci.cmi ast0toast.cmi ast0_cocci.cmi insert_plus.cmi +insert_plus.cmx: visitor_ast0.cmx pretty_print_cocci.cmx context_neg.cmx \ + ast_cocci.cmx ast0toast.cmx ast0_cocci.cmx insert_plus.cmi +iso_compile.cmo: visitor_ast0.cmi ../commons/common.cmi ast_cocci.cmi \ + ast0_cocci.cmi iso_compile.cmi +iso_compile.cmx: visitor_ast0.cmx ../commons/common.cmx ast_cocci.cmx \ + ast0_cocci.cmx iso_compile.cmi +iso_pattern.cmo: visitor_ast0.cmi unparse_ast0.cmi type_cocci.cmi \ + flag_parsing_cocci.cmo ../globals/flag.cmo compute_lines.cmi \ + ../commons/common.cmi ast_cocci.cmi ast0_cocci.cmi iso_pattern.cmi +iso_pattern.cmx: visitor_ast0.cmx unparse_ast0.cmx type_cocci.cmx \ + flag_parsing_cocci.cmx ../globals/flag.cmx compute_lines.cmx \ + ../commons/common.cmx ast_cocci.cmx ast0_cocci.cmx iso_pattern.cmi +lexer_cocci.cmo: parser_cocci_menhir.cmi parse_aux.cmo ../globals/flag.cmo \ + data.cmi ../commons/common.cmi ast_cocci.cmi ast0_cocci.cmi +lexer_cocci.cmx: parser_cocci_menhir.cmx parse_aux.cmx ../globals/flag.cmx \ + data.cmx ../commons/common.cmx ast_cocci.cmx ast0_cocci.cmx +lexer_script.cmo: parser_cocci_menhir.cmi data.cmi ast_cocci.cmi +lexer_script.cmx: parser_cocci_menhir.cmx data.cmx ast_cocci.cmx +main.cmo: parse_cocci.cmi +main.cmx: parse_cocci.cmx +merge.cmo: visitor_ast0.cmi ast_cocci.cmi ast0_cocci.cmi merge.cmi +merge.cmx: visitor_ast0.cmx ast_cocci.cmx ast0_cocci.cmx merge.cmi +parse_aux.cmo: type_cocci.cmi semantic_cocci.cmo data.cmi \ + ../commons/common.cmi ast_cocci.cmi ast0_cocci.cmi +parse_aux.cmx: type_cocci.cmx semantic_cocci.cmx data.cmx \ + ../commons/common.cmx ast_cocci.cmx ast0_cocci.cmx +parse_cocci.cmo: visitor_ast0.cmi unitary_ast0.cmi type_infer.cmi \ + test_exps.cmi single_statement.cmi simple_assignments.cmi \ + semantic_cocci.cmo pretty_print_cocci.cmi parser_cocci_menhir.cmi \ + parse_aux.cmo lexer_script.cmo lexer_cocci.cmo iso_pattern.cmi \ + iso_compile.cmi insert_plus.cmi get_constants2.cmi get_constants.cmi \ + function_prototypes.cmi free_vars.cmi flag_parsing_cocci.cmo \ + ../globals/flag.cmo disjdistr.cmi data.cmi context_neg.cmi \ + ../globals/config.cmo compute_lines.cmi ../commons/common.cmi \ + comm_assoc.cmi check_meta.cmi ast_cocci.cmi ast0toast.cmi ast0_cocci.cmi \ + arity.cmi parse_cocci.cmi +parse_cocci.cmx: visitor_ast0.cmx unitary_ast0.cmx type_infer.cmx \ + test_exps.cmx single_statement.cmx simple_assignments.cmx \ + semantic_cocci.cmx pretty_print_cocci.cmx parser_cocci_menhir.cmx \ + parse_aux.cmx lexer_script.cmx lexer_cocci.cmx iso_pattern.cmx \ + iso_compile.cmx insert_plus.cmx get_constants2.cmx get_constants.cmx \ + function_prototypes.cmx free_vars.cmx flag_parsing_cocci.cmx \ + ../globals/flag.cmx disjdistr.cmx data.cmx context_neg.cmx \ + ../globals/config.cmx compute_lines.cmx ../commons/common.cmx \ + comm_assoc.cmx check_meta.cmx ast_cocci.cmx ast0toast.cmx ast0_cocci.cmx \ + arity.cmx parse_cocci.cmi +parser_cocci_menhir.cmo: type_cocci.cmi top_level.cmi semantic_cocci.cmo \ + parse_aux.cmo data.cmi ../commons/common.cmi ast_cocci.cmi ast0_cocci.cmi \ + parser_cocci_menhir.cmi +parser_cocci_menhir.cmx: type_cocci.cmx top_level.cmx semantic_cocci.cmx \ + parse_aux.cmx data.cmx ../commons/common.cmx ast_cocci.cmx ast0_cocci.cmx \ + parser_cocci_menhir.cmi +plus.cmo: visitor_ast.cmi ast_cocci.cmi plus.cmi +plus.cmx: visitor_ast.cmx ast_cocci.cmx plus.cmi +pretty_print_cocci.cmo: type_cocci.cmi ../globals/flag.cmo \ + ../commons/common.cmi ast_cocci.cmi pretty_print_cocci.cmi +pretty_print_cocci.cmx: type_cocci.cmx ../globals/flag.cmx \ + ../commons/common.cmx ast_cocci.cmx pretty_print_cocci.cmi +simple_assignments.cmo: visitor_ast0.cmi ../globals/flag.cmo \ + ../commons/common.cmi ast_cocci.cmi ast0_cocci.cmi simple_assignments.cmi +simple_assignments.cmx: visitor_ast0.cmx ../globals/flag.cmx \ + ../commons/common.cmx ast_cocci.cmx ast0_cocci.cmx simple_assignments.cmi +single_statement.cmo: visitor_ast0.cmi iso_pattern.cmi flag_parsing_cocci.cmo \ + compute_lines.cmi ast_cocci.cmi ast0_cocci.cmi single_statement.cmi +single_statement.cmx: visitor_ast0.cmx iso_pattern.cmx flag_parsing_cocci.cmx \ + compute_lines.cmx ast_cocci.cmx ast0_cocci.cmx single_statement.cmi +test_exps.cmo: visitor_ast0.cmi ast_cocci.cmi ast0_cocci.cmi test_exps.cmi +test_exps.cmx: visitor_ast0.cmx ast_cocci.cmx ast0_cocci.cmx test_exps.cmi +top_level.cmo: ast0_cocci.cmi top_level.cmi +top_level.cmx: ast0_cocci.cmx top_level.cmi +type_cocci.cmo: type_cocci.cmi +type_cocci.cmx: type_cocci.cmi +type_infer.cmo: visitor_ast0.cmi type_cocci.cmi ast_cocci.cmi ast0_cocci.cmi \ + type_infer.cmi +type_infer.cmx: visitor_ast0.cmx type_cocci.cmx ast_cocci.cmx ast0_cocci.cmx \ + type_infer.cmi +unify_ast.cmo: visitor_ast.cmi ast_cocci.cmi unify_ast.cmi +unify_ast.cmx: visitor_ast.cmx ast_cocci.cmx unify_ast.cmi +unitary_ast0.cmo: visitor_ast0.cmi ../globals/flag.cmo ast_cocci.cmi \ + ast0_cocci.cmi unitary_ast0.cmi +unitary_ast0.cmx: visitor_ast0.cmx ../globals/flag.cmx ast_cocci.cmx \ + ast0_cocci.cmx unitary_ast0.cmi +unparse_ast0.cmo: type_cocci.cmi pretty_print_cocci.cmi ../commons/common.cmi \ + ast0_cocci.cmi unparse_ast0.cmi +unparse_ast0.cmx: type_cocci.cmx pretty_print_cocci.cmx ../commons/common.cmx \ + ast0_cocci.cmx unparse_ast0.cmi +visitor_ast.cmo: ast_cocci.cmi visitor_ast.cmi +visitor_ast.cmx: ast_cocci.cmx visitor_ast.cmi +visitor_ast0.cmo: ast_cocci.cmi ast0_cocci.cmi visitor_ast0.cmi +visitor_ast0.cmx: ast_cocci.cmx ast0_cocci.cmx visitor_ast0.cmi diff --git a/parsing_cocci/Makefile b/parsing_cocci/Makefile new file mode 100644 index 0000000..027e433 --- /dev/null +++ b/parsing_cocci/Makefile @@ -0,0 +1,137 @@ +# Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +# Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +# This file is part of Coccinelle. +# +# Coccinelle is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, according to version 2 of the License. +# +# Coccinelle is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Coccinelle. If not, see . +# +# The authors reserve the right to distribute this or future versions of +# Coccinelle under other licenses. + + +TARGET=cocci_parser + +LEXER_SOURCES = lexer_cocci.mll +SCRIPT_LEXER_SOURCES = lexer_script.mll +PARSER_SOURCES = parser_cocci_menhir.mly +SOURCES = flag_parsing_cocci.ml type_cocci.ml ast_cocci.ml ast0_cocci.ml \ +pretty_print_cocci.ml unparse_ast0.ml \ +visitor_ast.ml visitor_ast0.ml compute_lines.ml comm_assoc.ml \ +iso_pattern.ml iso_compile.ml single_statement.ml simple_assignments.ml \ +ast0toast.ml check_meta.ml top_level.ml type_infer.ml test_exps.ml \ +unitary_ast0.ml arity.ml index.ml context_neg.ml \ +insert_plus.ml function_prototypes.ml \ +unify_ast.ml semantic_cocci.ml data.ml free_vars.ml parse_aux.ml disjdistr.ml \ +$(LEXER_SOURCES:.mll=.ml) $(PARSER_SOURCES:.mly=.ml) \ +$(SCRIPT_LEXER_SOURCES:.mll=.ml) \ +get_constants.ml get_constants2.ml parse_cocci.ml + +LIBS=../commons/commons.cma ../globals/globals.cma +SYSLIBS = str.cma unix.cma + +#MENHIR_PATH=$(shell ocamlfind query menhirLib) +MENHIR_PATH=../menhirlib + +INCLUDES = -I ../commons -I ../commons/ocamlextra -I ../globals \ +-I $(MENHIR_PATH) + +MENHIR=$(MENHIR_PATH)/menhirLib.cmo +MENHIRO=$(MENHIR_PATH)/menhirLib.cmx + + +# The Caml compilers. +OCAMLCFLAGS ?= -g -dtypes +OCAMLC =ocamlc$(OPTBIN) $(OCAMLCFLAGS) $(INCLUDES) +OCAMLOPT = ocamlopt$(OPTBIN) $(OPTFLAGS) $(INCLUDES) +OCAMLLEX = ocamllex$(OPTBIN) +OCAMLYACC= menhir --table +OCAMLDEP = ocamldep$(OPTBIN) $(INCLUDES) +EXEC=$(TARGET).byte +EXEC=$(TARGET) +LIB=$(TARGET).cma +OPTLIB=$(LIB:.cma=.cmxa) + +GENERATED= $(LEXER_SOURCES:.mll=.ml) $(SCRIPT_LEXER_SOURCES:.mll=.ml) \ + $(PARSER_SOURCES:.mly=.ml) $(PARSER_SOURCES:.mly=.mli) +OBJS = $(SOURCES:.ml=.cmo) +OPTOBJS = $(OBJS:.cmo=.cmx) + + +all: $(LIB) +local: $(EXEC) + +all.opt: $(OPTLIB) + + +$(LIB): $(GENERATED) $(OBJS) + $(OCAMLC) -I $(MENHIR_PATH) -a -o $(LIB) $(MENHIR) $(OBJS) + + +$(OPTLIB): $(GENERATED) $(OPTOBJS) + $(OCAMLOPT) -I $(MENHIR_PATH) -a -o $(OPTLIB) $(MENHIRO) $(OPTOBJS) + + +$(EXEC): $(OBJS) main.cmo $(LIBS) + $(OCAMLC) -o $(EXEC) $(SYSLIBS) $(LIBS) $(OBJS) main.cmo + + + + +clean:: + rm -f $(LIB) + rm -f $(OPTLIB) $(LIB:.cma=.a) + rm -f $(TARGET) + + + + +.SUFFIXES: +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) -c $< + +.mli.cmi: + $(OCAMLC) -c $< + +.ml.cmx: + $(OCAMLOPT) -c $< + +$(LEXER_SOURCES:.mll=.ml) : $(LEXER_SOURCES) + $(OCAMLLEX) $(LEXER_SOURCES) + +$(PARSER_SOURCES:.mly=.ml) $(PARSER_SOURCES:.mly=.mli) : $(PARSER_SOURCES) + $(OCAMLYACC) $(PARSER_SOURCES) + +$(SCRIPT_LEXER_SOURCES:.mll=.ml): $(SCRIPT_LEXER_SOURCES) + $(OCAMLLEX) $(SCRIPT_LEXER_SOURCES) + +clean:: + rm -f $(GENERATED) + +# clean rule for others files +clean:: + rm -f *.cm[iox] *.o *.annot + rm -f *~ .*~ #*# + +depend: $(GENERATED) + $(OCAMLDEP) *.mli *.ml > .depend + +.depend: + $(OCAMLDEP) *.mli *.ml > .depend + +-include .depend + +lexer_cocci.ml: lexer_cocci.mll +parser_cocci_menhir.ml: parser_cocci_menhir.mly lexer_cocci.mll +parser_cocci_menhir.mli: parser_cocci_menhir.mly lexer_cocci.mll +lexer_script.ml: lexer_script.mll diff --git a/parsing_cocci/README b/parsing_cocci/README new file mode 100644 index 0000000..7697270 --- /dev/null +++ b/parsing_cocci/README @@ -0,0 +1,32 @@ +Workflow: + +main.ml: an entry point to be used in place of the cocci top level, to +check only the parsing of SmPL files. + +parse_cocci.ml: Initiates the parsing process and subsequent processing +phases. There are two entry points: + + process: called by main, returns metavariables and merged ast code + + process_for_ctl: called by engine/main, returns no metavariables, but + instead ast and ast0 code. ast code is used by ast0toctl for printing + and ast0 code is transformed to CTL. + + + +arity.ml +ast0_cocci.ml +ast0toast.ml +ast_cocci.ml +check_meta.ml +data.ml +lexer_cocci.ml +main.ml +merge.ml +parse_cocci.ml +parser_cocci_menhir.ml +parser_cocci.ml +plus.ml +semantic_cocci.ml +top_level.ml +unparse_cocci.ml diff --git a/parsing_cocci/arity.ml b/parsing_cocci/arity.ml new file mode 100644 index 0000000..2248a97 --- /dev/null +++ b/parsing_cocci/arity.ml @@ -0,0 +1,1054 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* Arities matter for the minus slice, but not for the plus slice. *) + +(* ? only allowed on rule_elems, and on subterms if the context is ? also. *) + +module Ast0 = Ast0_cocci +module Ast = Ast_cocci + +(* --------------------------------------------------------------------- *) + +let warning s = Printf.printf "warning: %s\n" s + +let fail w str = + failwith + (Printf.sprintf "cocci line %d: %s" ((Ast0.get_info w).Ast0.line_start) + str) + +let make_opt_unique optfn uniquefn info tgt arity term = + let term = Ast0.rewrap info term in + if tgt = arity + then term + else (* tgt must be NONE *) + match arity with + Ast0.OPT -> Ast0.copywrap info (optfn term) + | Ast0.UNIQUE -> Ast0.copywrap info (uniquefn term) + | Ast0.NONE -> failwith "tgt must be NONE" + +let all_same opt_allowed tgt line arities = + let tgt = + match tgt with + Ast0.NONE -> + (match List.hd arities with + Ast0.OPT when not opt_allowed -> + failwith "opt only allowed for the elements of a statement list" + | x -> x) + | _ -> tgt in + if not(List.for_all (function x -> x = tgt) arities) + then warning (Printf.sprintf "incompatible arity found on line %d" line); + tgt + +let get_option fn = function + None -> None + | Some x -> Some (fn x) + +let anyopt l fn = List.exists (function w -> fn(Ast0.unwrap w)) l + +let allopt l fn = + let rec loop = function + [] -> [] + | x::xs -> + match fn (Ast0.unwrap x) with + Some x -> x :: (loop xs) + | None -> [] in + let res = loop l in + if List.length res = List.length l then Some res else None + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Mcode *) + +let mcode2line (_,_,info,_,_) = info.Ast0.line_start +let mcode2arity (_,arity,_,_,_) = arity + +let mcode x = x (* nothing to do ... *) + +(* --------------------------------------------------------------------- *) +(* Dots *) + +let dots fn d = + Ast0.rewrap d + (match Ast0.unwrap d with + Ast0.DOTS(x) -> Ast0.DOTS(List.map fn x) + | Ast0.CIRCLES(x) -> Ast0.CIRCLES(List.map fn x) + | Ast0.STARS(x) -> Ast0.STARS(List.map fn x)) + +let only_dots l = + not + (List.exists + (function x -> + match Ast0.unwrap x with + Ast0.Circles(_,_) | Ast0.Stars(_,_) -> true + | _ -> false) + l) + +let only_circles l = + not (List.exists + (function x -> + match Ast0.unwrap x with + Ast0.Dots(_,_) | Ast0.Stars(_,_) -> true + | _ -> false) + l) + +let only_stars l = + not (List.exists + (function x -> + match Ast0.unwrap x with + Ast0.Dots(_,_) | Ast0.Circles(_,_) -> true + | _ -> false) + l) + +let concat_dots fn d = + Ast0.rewrap d + (match Ast0.unwrap d with + Ast0.DOTS(x) -> + let l = List.map fn x in + if only_dots l + then Ast0.DOTS(l) + else fail d "inconsistent dots usage" + | Ast0.CIRCLES(x) -> + let l = List.map fn x in + if only_circles l + then Ast0.CIRCLES(l) + else fail d "inconsistent dots usage" + | Ast0.STARS(x) -> + let l = List.map fn x in + if only_stars l + then Ast0.STARS(l) + else fail d "inconsistent dots usage") + +let flat_concat_dots fn d = + match Ast0.unwrap d with + Ast0.DOTS(x) -> List.map fn x + | Ast0.CIRCLES(x) -> List.map fn x + | Ast0.STARS(x) -> List.map fn x + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +let make_id = + make_opt_unique + (function x -> Ast0.OptIdent x) + (function x -> Ast0.UniqueIdent x) + +let ident opt_allowed tgt i = + match Ast0.unwrap i with + Ast0.Id(name) -> + let arity = + all_same opt_allowed tgt (mcode2line name) + [mcode2arity name] in + let name = mcode name in + make_id i tgt arity (Ast0.Id(name)) + | Ast0.MetaId(name,constraints,pure) -> + let arity = + all_same opt_allowed tgt (mcode2line name) + [mcode2arity name] in + let name = mcode name in + make_id i tgt arity (Ast0.MetaId(name,constraints,pure)) + | Ast0.MetaFunc(name,constraints,pure) -> + let arity = + all_same opt_allowed tgt (mcode2line name) + [mcode2arity name] in + let name = mcode name in + make_id i tgt arity (Ast0.MetaFunc(name,constraints,pure)) + | Ast0.MetaLocalFunc(name,constraints,pure) -> + let arity = + all_same opt_allowed tgt (mcode2line name) + [mcode2arity name] in + let name = mcode name in + make_id i tgt arity (Ast0.MetaLocalFunc(name,constraints,pure)) + | Ast0.OptIdent(_) | Ast0.UniqueIdent(_) -> + failwith "unexpected code" + +(* --------------------------------------------------------------------- *) +(* Expression *) + +let make_exp = + make_opt_unique + (function x -> Ast0.OptExp x) + (function x -> Ast0.UniqueExp x) + +let rec top_expression opt_allowed tgt expr = + let exp_same = all_same opt_allowed tgt in + match Ast0.unwrap expr with + Ast0.Ident(id) -> + let new_id = ident opt_allowed tgt id in + Ast0.rewrap expr + (match Ast0.unwrap new_id with + Ast0.OptIdent(id) -> + Ast0.OptExp(Ast0.rewrap expr (Ast0.Ident(id))) + | Ast0.UniqueIdent(id) -> + Ast0.UniqueExp(Ast0.rewrap expr (Ast0.Ident(id))) + | _ -> Ast0.Ident(new_id)) + | Ast0.Constant(const) -> + let arity = exp_same (mcode2line const) [mcode2arity const] in + let const = mcode const in + make_exp expr tgt arity (Ast0.Constant(const)) + | Ast0.FunCall(fn,lp,args,rp) -> + let arity = exp_same (mcode2line lp) [mcode2arity lp;mcode2arity rp] in + let fn = expression arity fn in + let lp = mcode lp in + let args = dots (expression arity) args in + let rp = mcode rp in + make_exp expr tgt arity (Ast0.FunCall(fn,lp,args,rp)) + | Ast0.Assignment(left,op,right,simple) -> + let arity = exp_same (mcode2line op) [mcode2arity op] in + let left = expression arity left in + let op = mcode op in + let right = expression arity right in + make_exp expr tgt arity (Ast0.Assignment(left,op,right,simple)) + | Ast0.CondExpr(exp1,why,exp2,colon,exp3) -> + let arity = + exp_same (mcode2line why) [mcode2arity why; mcode2arity colon] in + let exp1 = expression arity exp1 in + let why = mcode why in + let exp2 = get_option (expression arity) exp2 in + let colon = mcode colon in + let exp3 = expression arity exp3 in + make_exp expr tgt arity (Ast0.CondExpr(exp1,why,exp2,colon,exp3)) + | Ast0.Postfix(exp,op) -> + let arity = exp_same (mcode2line op) [mcode2arity op] in + let exp = expression arity exp in + let op = mcode op in + make_exp expr tgt arity (Ast0.Postfix(exp,op)) + | Ast0.Infix(exp,op) -> + let arity = exp_same (mcode2line op) [mcode2arity op] in + let exp = expression arity exp in + let op = mcode op in + make_exp expr tgt arity (Ast0.Infix(exp,op)) + | Ast0.Unary(exp,op) -> + let arity = exp_same (mcode2line op) [mcode2arity op] in + let exp = expression arity exp in + let op = mcode op in + make_exp expr tgt arity (Ast0.Unary(exp,op)) + | Ast0.Binary(left,op,right) -> + let arity = exp_same (mcode2line op) [mcode2arity op] in + let left = expression arity left in + let op = mcode op in + let right = expression arity right in + make_exp expr tgt arity (Ast0.Binary(left,op,right)) + | Ast0.Nested(left,op,right) -> failwith "nested in arity not possible" + | Ast0.Paren(lp,exp,rp) -> + let arity = exp_same (mcode2line lp) [mcode2arity lp;mcode2arity rp] in + let lp = mcode lp in + let exp = expression arity exp in + let rp = mcode rp in + make_exp expr tgt arity (Ast0.Paren(lp,exp,rp)) + | Ast0.ArrayAccess(exp1,lb,exp2,rb) -> + let arity = exp_same (mcode2line lb) [mcode2arity lb; mcode2arity rb] in + let exp1 = expression arity exp1 in + let lb = mcode lb in + let exp2 = expression arity exp2 in + let rb = mcode rb in + make_exp expr tgt arity (Ast0.ArrayAccess(exp1,lb,exp2,rb)) + | Ast0.RecordAccess(exp,pt,field) -> + let arity = exp_same (mcode2line pt) [mcode2arity pt] in + let exp = expression arity exp in + let pt = mcode pt in + let field = ident false arity field in + make_exp expr tgt arity (Ast0.RecordAccess(exp,pt,field)) + | Ast0.RecordPtAccess(exp,ar,field) -> + let arity = exp_same (mcode2line ar) [mcode2arity ar] in + let exp = expression arity exp in + let ar = mcode ar in + let field = ident false arity field in + make_exp expr tgt arity (Ast0.RecordPtAccess(exp,ar,field)) + | Ast0.Cast(lp,ty,rp,exp) -> + let arity = exp_same (mcode2line lp) [mcode2arity lp;mcode2arity rp] in + let lp = mcode lp in + let ty = typeC arity ty in + let rp = mcode rp in + let exp = expression arity exp in + make_exp expr tgt arity (Ast0.Cast(lp,ty,rp,exp)) + | Ast0.SizeOfExpr(szf,exp) -> + let arity = exp_same (mcode2line szf) [mcode2arity szf] in + let szf = mcode szf in + let exp = expression arity exp in + make_exp expr tgt arity (Ast0.SizeOfExpr(szf,exp)) + | Ast0.SizeOfType(szf,lp,ty,rp) -> + let arity = + exp_same (mcode2line szf) (List.map mcode2arity [szf;lp;rp]) in + let szf = mcode szf in + let lp = mcode lp in + let ty = typeC arity ty in + let rp = mcode rp in + make_exp expr tgt arity (Ast0.SizeOfType(szf,lp,ty,rp)) + | Ast0.TypeExp(ty) -> Ast0.rewrap expr (Ast0.TypeExp(typeC tgt ty)) + | Ast0.MetaErr(name,constraints,pure) -> + let arity = exp_same (mcode2line name) [mcode2arity name] in + let name = mcode name in + make_exp expr tgt arity (Ast0.MetaErr(name,constraints,pure)) + | Ast0.MetaExpr(name,constraints,ty,form,pure) -> + let arity = exp_same (mcode2line name) [mcode2arity name] in + let name = mcode name in + make_exp expr tgt arity (Ast0.MetaExpr(name,constraints,ty,form,pure)) + | Ast0.MetaExprList(name,lenname,pure) -> + let arity = exp_same (mcode2line name) [mcode2arity name] in + let name = mcode name in + make_exp expr tgt arity (Ast0.MetaExprList(name,lenname,pure)) + | Ast0.EComma(cm) -> + let arity = exp_same (mcode2line cm) [mcode2arity cm] in + let cm = mcode cm in + make_exp expr tgt arity (Ast0.EComma(cm)) + | Ast0.DisjExpr(starter,exps,mids,ender) -> + let exps = List.map (top_expression opt_allowed tgt) exps in + (match List.rev exps with + _::xs -> + if anyopt xs (function Ast0.OptExp(_) -> true | _ -> false) + then fail expr "opt only allowed in the last disjunct" + | _ -> ()); + Ast0.rewrap expr (Ast0.DisjExpr(starter,exps,mids,ender)) + | Ast0.NestExpr(starter,exp_dots,ender,whencode,multi) -> + let res = + Ast0.NestExpr(starter, + dots (top_expression true Ast0.NONE) exp_dots, + ender,whencode,multi) in + Ast0.rewrap expr res + | Ast0.Edots(dots,whencode) -> + let arity = exp_same (mcode2line dots) [mcode2arity dots] in + let dots = mcode dots in + let whencode = get_option (expression Ast0.NONE) whencode in + make_exp expr tgt arity (Ast0.Edots(dots,whencode)) + | Ast0.Ecircles(dots,whencode) -> + let arity = exp_same (mcode2line dots) [mcode2arity dots] in + let dots = mcode dots in + let whencode = get_option (expression Ast0.NONE) whencode in + make_exp expr tgt arity (Ast0.Ecircles(dots,whencode)) + | Ast0.Estars(dots,whencode) -> + let arity = exp_same (mcode2line dots) [mcode2arity dots] in + let dots = mcode dots in + let whencode = get_option (expression Ast0.NONE) whencode in + make_exp expr tgt arity (Ast0.Estars(dots,whencode)) + | Ast0.OptExp(_) | Ast0.UniqueExp(_) -> + failwith "unexpected code" + +and expression tgt exp = top_expression false tgt exp + +(* --------------------------------------------------------------------- *) +(* Types *) + +and make_typeC = + make_opt_unique + (function x -> Ast0.OptType x) + (function x -> Ast0.UniqueType x) + +and top_typeC tgt opt_allowed typ = + match Ast0.unwrap typ with + Ast0.ConstVol(cv,ty) -> + let arity = all_same opt_allowed tgt (mcode2line cv) + [mcode2arity cv] in + let cv = mcode cv in + let ty = typeC arity ty in + make_typeC typ tgt arity (Ast0.ConstVol(cv,ty)) + | Ast0.BaseType(ty,Some sign) -> + let arity = + all_same opt_allowed tgt (mcode2line ty) + [mcode2arity ty; mcode2arity sign] in + let ty = mcode ty in + let sign = mcode sign in + make_typeC typ tgt arity (Ast0.BaseType(ty,Some sign)) + | Ast0.BaseType(ty,None) -> + let arity = + all_same opt_allowed tgt (mcode2line ty) [mcode2arity ty] in + let ty = mcode ty in + make_typeC typ tgt arity (Ast0.BaseType(ty,None)) + | Ast0.ImplicitInt(sign) -> + let arity = + all_same opt_allowed tgt (mcode2line sign) [mcode2arity sign] in + let sign = mcode sign in + make_typeC typ tgt arity (Ast0.ImplicitInt(sign)) + | Ast0.Pointer(ty,star) -> + let arity = + all_same opt_allowed tgt (mcode2line star) [mcode2arity star] in + let ty = typeC arity ty in + let star = mcode star in + make_typeC typ tgt arity (Ast0.Pointer(ty,star)) + | Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + let arity = + all_same opt_allowed tgt (mcode2line lp1) + (List.map mcode2arity [lp1;star;rp1;lp2;rp2]) in + let ty = typeC arity ty in + let params = parameter_list tgt params in + make_typeC typ tgt arity + (Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2)) + | Ast0.FunctionType(ty,lp1,params,rp1) -> + let arity = + all_same opt_allowed tgt (mcode2line lp1) + (List.map mcode2arity [lp1;rp1]) in + let ty = get_option (typeC arity) ty in + let params = parameter_list tgt params in + make_typeC typ tgt arity (Ast0.FunctionType(ty,lp1,params,rp1)) + | Ast0.Array(ty,lb,size,rb) -> + let arity = + all_same opt_allowed tgt (mcode2line lb) + [mcode2arity lb;mcode2arity rb] in + let ty = typeC arity ty in + let lb = mcode lb in + let size = get_option (expression arity) size in + let rb = mcode rb in + make_typeC typ tgt arity (Ast0.Array(ty,lb,size,rb)) + | Ast0.StructUnionName(kind,name) -> + let arity = + all_same opt_allowed tgt (mcode2line kind) + [mcode2arity kind] in + let kind = mcode kind in + let name = get_option (ident false arity) name in + make_typeC typ tgt arity (Ast0.StructUnionName(kind,name)) + | Ast0.StructUnionDef(ty,lb,decls,rb) -> + let arity = + all_same opt_allowed tgt (mcode2line lb) + (List.map mcode2arity [lb;rb]) in + let ty = typeC arity ty in + let lb = mcode lb in + let decls = dots (declaration tgt) decls in + let rb = mcode rb in + make_typeC typ tgt arity (Ast0.StructUnionDef(ty,lb,decls,rb)) + | Ast0.TypeName(name) -> + let arity = + all_same opt_allowed tgt (mcode2line name) [mcode2arity name] in + let name = mcode name in + make_typeC typ tgt arity (Ast0.TypeName(name)) + | Ast0.MetaType(name,pure) -> + let arity = + all_same opt_allowed tgt (mcode2line name) [mcode2arity name] in + let name = mcode name in + make_typeC typ tgt arity (Ast0.MetaType(name,pure)) + | Ast0.DisjType(starter,types,mids,ender) -> + let types = List.map (typeC tgt) types in + (match List.rev types with + _::xs -> + if anyopt xs (function Ast0.OptType(_) -> true | _ -> false) + then fail typ "opt only allowed in the last disjunct" + | _ -> ()); + let res = Ast0.DisjType(starter,types,mids,ender) in + Ast0.rewrap typ res + | Ast0.OptType(_) | Ast0.UniqueType(_) -> + failwith "unexpected code" + +and typeC tgt ty = top_typeC tgt false ty + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +and make_decl = + make_opt_unique + (function x -> Ast0.OptDecl x) + (function x -> Ast0.UniqueDecl x) + +and declaration tgt decl = + match Ast0.unwrap decl with + Ast0.Init(stg,ty,id,eq,exp,sem) -> + let arity = + all_same true tgt (mcode2line eq) + ((match stg with None -> [] | Some x -> [mcode2arity x]) @ + (List.map mcode2arity [eq;sem])) in + let stg = get_option mcode stg in + let ty = typeC arity ty in + let id = ident false arity id in + let eq = mcode eq in + let exp = initialiser arity exp in + let sem = mcode sem in + make_decl decl tgt arity (Ast0.Init(stg,ty,id,eq,exp,sem)) + | Ast0.UnInit(stg,ty,id,sem) -> + let arity = + all_same true tgt (mcode2line sem) + ((match stg with None -> [] | Some x -> [mcode2arity x]) @ + [mcode2arity sem]) in + let stg = get_option mcode stg in + let ty = typeC arity ty in + let id = ident false arity id in + let sem = mcode sem in + make_decl decl tgt arity (Ast0.UnInit(stg,ty,id,sem)) + | Ast0.MacroDecl(name,lp,args,rp,sem) -> + let arity = + all_same true tgt (mcode2line lp) (List.map mcode2arity [lp;rp;sem]) in + let name = ident false arity name in + let lp = mcode lp in + let args = dots (expression arity) args in + let rp = mcode rp in + let sem = mcode sem in + make_decl decl tgt arity (Ast0.MacroDecl(name,lp,args,rp,sem)) + | Ast0.TyDecl(ty,sem) -> + let arity = + all_same true tgt (mcode2line sem) [mcode2arity sem] in + let ty = typeC arity ty in + let sem = mcode sem in + make_decl decl tgt arity (Ast0.TyDecl(ty,sem)) + | Ast0.Typedef(stg,ty,id,sem) -> + let arity = + all_same true tgt (mcode2line sem) + [mcode2arity stg;mcode2arity sem] in + let stg = mcode stg in + let ty = typeC arity ty in + let id = typeC arity id in + let sem = mcode sem in + make_decl decl tgt arity (Ast0.Typedef(stg,ty,id,sem)) + | Ast0.DisjDecl(starter,decls,mids,ender) -> + let decls = List.map (declaration tgt) decls in + (match List.rev decls with + _::xs -> + if anyopt xs (function Ast0.OptDecl(_) -> true | _ -> false) + then fail decl "opt only allowed in the last disjunct" + | _ -> ()); + let res = Ast0.DisjDecl(starter,decls,mids,ender) in + Ast0.rewrap decl res + | Ast0.Ddots(dots,whencode) -> + let arity = all_same true tgt (mcode2line dots) [mcode2arity dots] in + let dots = mcode dots in + let whencode = get_option (declaration Ast0.NONE) whencode in + make_decl decl tgt arity (Ast0.Ddots(dots,whencode)) + | Ast0.OptDecl(_) | Ast0.UniqueDecl(_) -> + failwith "unexpected code" + +(* --------------------------------------------------------------------- *) +(* Initializer *) + +and make_init = + make_opt_unique + (function x -> Ast0.OptIni x) + (function x -> Ast0.UniqueIni x) + +and initialiser tgt i = + let init_same = all_same true tgt in + match Ast0.unwrap i with + Ast0.InitExpr(exp) -> + Ast0.rewrap i (Ast0.InitExpr(expression tgt exp)) + | Ast0.InitList(lb,initlist,rb) -> + let arity = init_same (mcode2line lb) [mcode2arity lb; mcode2arity rb] in + let lb = mcode lb in + let initlist = dots (initialiser arity) initlist in + let rb = mcode rb in + make_init i tgt arity (Ast0.InitList(lb,initlist,rb)) + | Ast0.InitGccDotName(dot,name,eq,ini) -> + let arity = + init_same (mcode2line dot) [mcode2arity dot; mcode2arity eq] in + let dot = mcode dot in + let name = ident true arity name in + let eq = mcode eq in + let ini = initialiser arity ini in + make_init i tgt arity (Ast0.InitGccDotName(dot,name,eq,ini)) + | Ast0.InitGccName(name,eq,ini) -> + let arity = init_same (mcode2line eq) [mcode2arity eq] in + let name = ident true arity name in + let eq = mcode eq in + let ini = initialiser arity ini in + make_init i tgt arity (Ast0.InitGccName(name,eq,ini)) + | Ast0.InitGccIndex(lb,exp,rb,eq,ini) -> + let arity = + init_same (mcode2line lb) + [mcode2arity lb; mcode2arity rb; mcode2arity eq] in + let lb = mcode lb in + let exp = expression arity exp in + let rb = mcode rb in + let eq = mcode eq in + let ini = initialiser arity ini in + make_init i tgt arity (Ast0.InitGccIndex(lb,exp,rb,eq,ini)) + | Ast0.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> + let arity = + init_same (mcode2line lb) + [mcode2arity lb; mcode2arity dots; mcode2arity rb; mcode2arity eq] in + let lb = mcode lb in + let exp1 = expression arity exp1 in + let dots = mcode dots in + let exp2 = expression arity exp2 in + let rb = mcode rb in + let eq = mcode eq in + let ini = initialiser arity ini in + make_init i tgt arity + (Ast0.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini)) + | Ast0.IComma(cm) -> + let arity = init_same (mcode2line cm) [mcode2arity cm] in + let cm = mcode cm in + make_init i tgt arity (Ast0.IComma(cm)) + | Ast0.Idots(dots,whencode) -> + let arity = init_same (mcode2line dots) [mcode2arity dots] in + let dots = mcode dots in + let whencode = get_option (initialiser Ast0.NONE) whencode in + make_init i tgt arity (Ast0.Idots(dots,whencode)) + | Ast0.OptIni(_) | Ast0.UniqueIni(_) -> + failwith "unexpected code" + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +and make_param = + make_opt_unique + (function x -> Ast0.OptParam x) + (function x -> Ast0.UniqueParam x) + +and parameterTypeDef tgt param = + let param_same = all_same true tgt in + match Ast0.unwrap param with + Ast0.VoidParam(ty) -> Ast0.rewrap param (Ast0.VoidParam(typeC tgt ty)) + | Ast0.Param(ty,Some id) -> + let ty = top_typeC tgt true ty in + let id = ident true tgt id in + Ast0.rewrap param + (match (Ast0.unwrap ty,Ast0.unwrap id) with + (Ast0.OptType(ty),Ast0.OptIdent(id)) -> + Ast0.OptParam(Ast0.rewrap param (Ast0.Param(ty,Some id))) + | (Ast0.UniqueType(ty),Ast0.UniqueIdent(id)) -> + Ast0.UniqueParam(Ast0.rewrap param (Ast0.Param(ty,Some id))) + | (Ast0.OptType(ty),_) -> + fail param "arity mismatch in param declaration" + | (_,Ast0.OptIdent(id)) -> + fail param "arity mismatch in param declaration" + | _ -> Ast0.Param(ty,Some id)) + | Ast0.Param(ty,None) -> + let ty = top_typeC tgt true ty in + Ast0.rewrap param + (match Ast0.unwrap ty with + Ast0.OptType(ty) -> + Ast0.OptParam(Ast0.rewrap param (Ast0.Param(ty,None))) + | Ast0.UniqueType(ty) -> + Ast0.UniqueParam(Ast0.rewrap param (Ast0.Param(ty,None))) + | _ -> Ast0.Param(ty,None)) + | Ast0.MetaParam(name,pure) -> + let arity = param_same (mcode2line name) [mcode2arity name] in + let name = mcode name in + make_param param tgt arity (Ast0.MetaParam(name,pure)) + | Ast0.MetaParamList(name,lenname,pure) -> + let arity = param_same (mcode2line name) [mcode2arity name] in + let name = mcode name in + make_param param tgt arity (Ast0.MetaParamList(name,lenname,pure)) + | Ast0.PComma(cm) -> + let arity = param_same (mcode2line cm) [mcode2arity cm] in + let cm = mcode cm in + make_param param tgt arity (Ast0.PComma(cm)) + | Ast0.Pdots(dots) -> + let arity = param_same (mcode2line dots) [mcode2arity dots] in + let dots = mcode dots in + make_param param tgt arity (Ast0.Pdots(dots)) + | Ast0.Pcircles(dots) -> + let arity = param_same (mcode2line dots) [mcode2arity dots] in + let dots = mcode dots in + make_param param tgt arity (Ast0.Pcircles(dots)) + | Ast0.OptParam(_) | Ast0.UniqueParam(_) -> + failwith "unexpected code" + +and parameter_list tgt = dots (parameterTypeDef tgt) + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +and make_rule_elem x = + make_opt_unique + (function x -> Ast0.OptStm x) + (function x -> Ast0.UniqueStm x) + x + +and statement tgt stm = + let stm_same = all_same true tgt in + match Ast0.unwrap stm with + Ast0.Decl(bef,decl) -> + let new_decl = declaration tgt decl in + Ast0.rewrap stm + (match Ast0.unwrap new_decl with + Ast0.OptDecl(decl) -> + Ast0.OptStm(Ast0.rewrap stm (Ast0.Decl(bef,decl))) + | Ast0.UniqueDecl(decl) -> + Ast0.UniqueStm(Ast0.rewrap stm (Ast0.Decl(bef,decl))) + | _ -> Ast0.Decl(bef,new_decl)) + | Ast0.Seq(lbrace,body,rbrace) -> + let arity = + stm_same (mcode2line lbrace) + [mcode2arity lbrace; mcode2arity rbrace] in + let lbrace = mcode lbrace in + let body = dots (statement arity) body in + let rbrace = mcode rbrace in + make_rule_elem stm tgt arity (Ast0.Seq(lbrace,body,rbrace)) + | Ast0.ExprStatement(exp,sem) -> + let arity = stm_same (mcode2line sem) [mcode2arity sem] in + let exp = expression arity exp in + let sem = mcode sem in + make_rule_elem stm tgt arity (Ast0.ExprStatement(exp,sem)) + | Ast0.IfThen(iff,lp,exp,rp,branch,aft) -> + let arity = + stm_same (mcode2line iff) (List.map mcode2arity [iff;lp;rp]) in + let iff = mcode iff in + let lp = mcode lp in + let exp = expression arity exp in + let rp = mcode rp in + let branch = statement arity branch in + make_rule_elem stm tgt arity (Ast0.IfThen(iff,lp,exp,rp,branch,aft)) + | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,aft) -> + let arity = + stm_same (mcode2line iff) (List.map mcode2arity [iff;lp;rp;els]) in + let iff = mcode iff in + let lp = mcode lp in + let exp = expression arity exp in + let rp = mcode rp in + let branch1 = statement arity branch1 in + let els = mcode els in + let branch2 = statement arity branch2 in + make_rule_elem stm tgt arity + (Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,aft)) + | Ast0.While(wh,lp,exp,rp,body,aft) -> + let arity = + stm_same (mcode2line wh) + (List.map mcode2arity [wh;lp;rp]) in + let wh = mcode wh in + let lp = mcode lp in + let exp = expression arity exp in + let rp = mcode rp in + let body = statement arity body in + make_rule_elem stm tgt arity (Ast0.While(wh,lp,exp,rp,body,aft)) + | Ast0.Do(d,body,wh,lp,exp,rp,sem) -> + let arity = + stm_same (mcode2line wh) (List.map mcode2arity [d;wh;lp;rp;sem]) in + let d = mcode d in + let body = statement arity body in + let wh = mcode wh in + let lp = mcode lp in + let exp = expression arity exp in + let rp = mcode rp in + let sem = mcode sem in + make_rule_elem stm tgt arity (Ast0.Do(d,body,wh,lp,exp,rp,sem)) + | Ast0.For(fr,lp,exp1,sem1,exp2,sem2,exp3,rp,body,aft) -> + let arity = + stm_same (mcode2line fr) (List.map mcode2arity [fr;lp;sem1;sem2;rp]) in + let fr = mcode fr in + let lp = mcode lp in + let exp1 = get_option (expression arity) exp1 in + let sem1 = mcode sem1 in + let exp2 = get_option (expression arity) exp2 in + let sem2= mcode sem2 in + let exp3 = get_option (expression arity) exp3 in + let rp = mcode rp in + let body = statement arity body in + make_rule_elem stm tgt arity + (Ast0.For(fr,lp,exp1,sem1,exp2,sem2,exp3,rp,body,aft)) + | Ast0.Iterator(nm,lp,args,rp,body,aft) -> + let arity = stm_same (mcode2line lp) (List.map mcode2arity [lp;rp]) in + let nm = ident false arity nm in + let lp = mcode lp in + let args = dots (expression arity) args in + let rp = mcode rp in + let body = statement arity body in + make_rule_elem stm tgt arity (Ast0.Iterator(nm,lp,args,rp,body,aft)) + | Ast0.Switch(switch,lp,exp,rp,lb,cases,rb) -> + let arity = + stm_same (mcode2line switch) + (List.map mcode2arity [switch;lp;rp;lb;rb]) in + let switch = mcode switch in + let lp = mcode lp in + let exp = expression arity exp in + let rp = mcode rp in + let lb = mcode lb in + let cases = dots (case_line arity) cases in + let rb = mcode rb in + make_rule_elem stm tgt arity + (Ast0.Switch(switch,lp,exp,rp,lb,cases,rb)) + | Ast0.Break(br,sem) -> + let arity = stm_same (mcode2line br) (List.map mcode2arity [br;sem]) in + let br = mcode br in + let sem = mcode sem in + make_rule_elem stm tgt arity (Ast0.Break(br,sem)) + | Ast0.Continue(cont,sem) -> + let arity = + stm_same (mcode2line cont) (List.map mcode2arity [cont;sem]) in + let cont = mcode cont in + let sem = mcode sem in + make_rule_elem stm tgt arity (Ast0.Continue(cont,sem)) + | Ast0.Label(l,dd) -> + let arity = mcode2arity dd in + let l = ident false tgt l in + let dd = mcode dd in + make_rule_elem stm tgt arity (Ast0.Label(l,dd)) + | Ast0.Goto(goto,l,sem) -> + let arity = + stm_same (mcode2line goto) (List.map mcode2arity [goto;sem]) in + let goto = mcode goto in + let l = ident false tgt l in + let sem = mcode sem in + make_rule_elem stm tgt arity (Ast0.Goto(goto,l,sem)) + | Ast0.Return(ret,sem) -> + let arity = stm_same (mcode2line ret) (List.map mcode2arity [ret;sem]) in + let ret = mcode ret in + let sem = mcode sem in + make_rule_elem stm tgt arity (Ast0.Return(ret,sem)) + | Ast0.ReturnExpr(ret,exp,sem) -> + let arity = stm_same (mcode2line ret) (List.map mcode2arity [ret;sem]) in + let ret = mcode ret in + let exp = expression arity exp in + let sem = mcode sem in + make_rule_elem stm tgt arity (Ast0.ReturnExpr(ret,exp,sem)) + | Ast0.MetaStmt(name,pure) -> + let arity = stm_same (mcode2line name) [mcode2arity name] in + let name = mcode name in + make_rule_elem stm tgt arity (Ast0.MetaStmt(name,pure)) + | Ast0.MetaStmtList(name,pure) -> + let arity = stm_same (mcode2line name) [mcode2arity name] in + let name = mcode name in + make_rule_elem stm tgt arity (Ast0.MetaStmtList(name,pure)) + | Ast0.Exp(exp) -> + let new_exp = top_expression true tgt exp in + Ast0.rewrap stm + (match Ast0.unwrap new_exp with + Ast0.OptExp(exp) -> + Ast0.OptStm(Ast0.rewrap stm (Ast0.Exp(exp))) + | Ast0.UniqueExp(exp) -> + Ast0.UniqueStm(Ast0.rewrap stm (Ast0.Exp(exp))) + | _ -> Ast0.Exp(new_exp)) + | Ast0.TopExp(exp) -> + let new_exp = top_expression true tgt exp in + Ast0.rewrap stm + (match Ast0.unwrap new_exp with + Ast0.OptExp(exp) -> + Ast0.OptStm(Ast0.rewrap stm (Ast0.TopExp(exp))) + | Ast0.UniqueExp(exp) -> + Ast0.UniqueStm(Ast0.rewrap stm (Ast0.TopExp(exp))) + | _ -> Ast0.TopExp(new_exp)) + | Ast0.Ty(ty) -> + let new_ty = typeC tgt ty in (* opt makes no sense alone at top level *) + Ast0.rewrap stm + (match Ast0.unwrap new_ty with + Ast0.OptType(ty) -> + Ast0.OptStm(Ast0.rewrap stm (Ast0.Ty(ty))) + | Ast0.UniqueType(ty) -> + Ast0.UniqueStm(Ast0.rewrap stm (Ast0.Ty(ty))) + | _ -> Ast0.Ty(new_ty)) + | Ast0.Disj(starter,rule_elem_dots_list,mids,ender) -> + let stms = + List.map (function x -> concat_dots (statement tgt) x) + rule_elem_dots_list in + let (found_opt,unopt) = + List.fold_left + (function (found_opt,lines) -> + function x -> + let rebuild l = + (* previously just checked the last thing in the list, + but everything should be optional for the whole thing to + be optional *) + let is_opt x = + match Ast0.unwrap x with + Ast0.OptStm(x) -> true + | _ -> false in + let unopt x = + match Ast0.unwrap x with + Ast0.OptStm(x) -> x + | _ -> x in + if List.for_all is_opt l + then (true,List.map unopt l) + else (false, l) in + let (l,k) = + match Ast0.unwrap x with + Ast0.DOTS(l) -> + (l,function l -> Ast0.rewrap x (Ast0.DOTS l)) + | Ast0.CIRCLES(l) -> + (l,function l -> Ast0.rewrap x (Ast0.CIRCLES l)) + | Ast0.STARS(l) -> + (l,function l -> Ast0.rewrap x (Ast0.STARS l)) in + let (found_opt,l) = rebuild l in + (found_opt,(k l)::lines)) + (false,[]) stms in + let unopt = List.rev unopt in + if found_opt + then + make_rule_elem stm tgt Ast0.OPT (Ast0.Disj(starter,unopt,mids,ender)) + else Ast0.rewrap stm (Ast0.Disj(starter,stms,mids,ender)) + | Ast0.Nest(starter,rule_elem_dots,ender,whn,multi) -> + let new_rule_elem_dots = + concat_dots (statement Ast0.NONE) rule_elem_dots in + let whn = + List.map + (whencode (concat_dots (statement Ast0.NONE)) (statement Ast0.NONE)) + whn in + Ast0.rewrap stm + (Ast0.Nest(starter,new_rule_elem_dots,ender,whn,multi)) + | Ast0.Dots(dots,whn) -> + let arity = stm_same (mcode2line dots) [mcode2arity dots] in + let dots = mcode dots in + let whn = + List.map + (whencode (concat_dots (statement Ast0.NONE)) (statement Ast0.NONE)) + whn in + make_rule_elem stm tgt arity (Ast0.Dots(dots,whn)) + | Ast0.Circles(dots,whn) -> + let arity = stm_same (mcode2line dots) [mcode2arity dots] in + let dots = mcode dots in + let whn = + List.map + (whencode (concat_dots (statement Ast0.NONE)) (statement Ast0.NONE)) + whn in + make_rule_elem stm tgt arity (Ast0.Circles(dots,whn)) + | Ast0.Stars(dots,whn) -> + let arity = stm_same (mcode2line dots) [mcode2arity dots] in + let dots = mcode dots in + let whn = + List.map + (whencode (concat_dots (statement Ast0.NONE)) (statement Ast0.NONE)) + whn in + make_rule_elem stm tgt arity (Ast0.Stars(dots,whn)) + | Ast0.FunDecl(bef,fi,name,lp,params,rp,lbrace,body,rbrace) -> + let arity = + all_same true tgt (mcode2line lp) + ((List.map mcode2arity [lp;rp;lbrace;rbrace]) @ (fninfo2arity fi)) in + let fi = List.map (fninfo arity) fi in + let name = ident false arity name in + let lp = mcode lp in + let params = parameter_list arity params in + let rp = mcode rp in + let lbrace = mcode lbrace in + let body = dots (statement arity) body in + let rbrace = mcode rbrace in + make_rule_elem stm tgt arity + (Ast0.FunDecl(bef,fi,name,lp,params,rp,lbrace,body,rbrace)) + | Ast0.Include(inc,s) -> + let arity = + all_same true tgt (mcode2line inc) [mcode2arity inc; mcode2arity s] in + let inc = mcode inc in + let s = mcode s in + make_rule_elem stm tgt arity (Ast0.Include(inc,s)) + | Ast0.Define(def,id,params,body) -> + let arity = all_same true tgt (mcode2line def) [mcode2arity def] in + let def = mcode def in + let id = ident false arity id in + let params = define_parameters arity params in + let body = dots (statement arity) body in + make_rule_elem stm tgt arity (Ast0.Define(def,id,params,body)) + | Ast0.OptStm(_) | Ast0.UniqueStm(_) -> + failwith "unexpected code" + +and define_parameters tgt params = + match Ast0.unwrap params with + Ast0.NoParams -> params + | Ast0.DParams(lp,params,rp) -> + let arity = + all_same true tgt (mcode2line lp) [mcode2arity lp;mcode2arity rp] in + let lp = mcode lp in + let params = dots (define_param arity) params in + let rp = mcode rp in + Ast0.rewrap params (Ast0.DParams(lp,params,rp)) + +and make_define_param x = + make_opt_unique + (function x -> Ast0.OptDParam x) + (function x -> Ast0.UniqueDParam x) + x + +and define_param tgt param = + match Ast0.unwrap param with + Ast0.DParam(id) -> + let new_id = ident true tgt id in + Ast0.rewrap param + (match Ast0.unwrap new_id with + Ast0.OptIdent(id) -> + Ast0.OptDParam(Ast0.rewrap param (Ast0.DParam(id))) + | Ast0.UniqueIdent(decl) -> + Ast0.UniqueDParam(Ast0.rewrap param (Ast0.DParam(id))) + | _ -> Ast0.DParam(new_id)) + | Ast0.DPComma(cm) -> + let arity = + all_same true tgt (mcode2line cm) [mcode2arity cm] in + let cm = mcode cm in + make_define_param param tgt arity (Ast0.DPComma(cm)) + | Ast0.DPdots(dots) -> + let arity = + all_same true tgt (mcode2line dots) [mcode2arity dots] in + let dots = mcode dots in + make_define_param param tgt arity (Ast0.DPdots(dots)) + | Ast0.DPcircles(circles) -> + let arity = + all_same true tgt (mcode2line circles) [mcode2arity circles] in + let circles = mcode circles in + make_define_param param tgt arity (Ast0.DPcircles(circles)) + | Ast0.OptDParam(dp) | Ast0.UniqueDParam(dp) -> + failwith "unexpected code" + +and fninfo arity = function + Ast0.FStorage(stg) -> Ast0.FStorage(mcode stg) + | Ast0.FType(ty) -> Ast0.FType(typeC arity ty) + | Ast0.FInline(inline) -> Ast0.FInline(mcode inline) + | Ast0.FAttr(attr) -> Ast0.FAttr(mcode attr) + +and fninfo2arity fninfo = + List.concat + (List.map + (function + Ast0.FStorage(stg) -> [mcode2arity stg] + | Ast0.FType(ty) -> [] + | Ast0.FInline(inline) -> [mcode2arity inline] + | Ast0.FAttr(attr) -> [mcode2arity attr]) + fninfo) + +and whencode notfn alwaysfn = function + Ast0.WhenNot a -> Ast0.WhenNot (notfn a) + | Ast0.WhenAlways a -> Ast0.WhenAlways (alwaysfn a) + | Ast0.WhenModifier(x) -> Ast0.WhenModifier(x) + +and make_case_line = + make_opt_unique + (function x -> Ast0.OptCase x) + (function x -> failwith "unique not allowed for case_line") + +and case_line tgt c = + match Ast0.unwrap c with + Ast0.Default(def,colon,code) -> + let arity = + all_same true tgt (mcode2line def) + [mcode2arity def; mcode2arity colon] in + let def = mcode def in + let colon = mcode colon in + let code = dots (statement arity) code in + make_case_line c tgt arity (Ast0.Default(def,colon,code)) + | Ast0.Case(case,exp,colon,code) -> + let arity = + all_same true tgt (mcode2line case) + [mcode2arity case; mcode2arity colon] in + let case = mcode case in + let exp = expression arity exp in + let colon = mcode colon in + let code = dots (statement arity) code in + make_case_line c tgt arity (Ast0.Case(case,exp,colon,code)) + | Ast0.OptCase(_) -> failwith "unexpected OptCase" + +(* --------------------------------------------------------------------- *) +(* Function declaration *) +(* Haven't thought much about arity here... *) + +let top_level tgt t = + Ast0.rewrap t + (match Ast0.unwrap t with + Ast0.FILEINFO(old_file,new_file) -> + if mcode2arity old_file = Ast0.NONE && mcode2arity new_file = Ast0.NONE + then Ast0.FILEINFO(mcode old_file,mcode new_file) + else fail t "unexpected arity for file info" + | Ast0.DECL(stmt) -> + Ast0.DECL(statement tgt stmt) + | Ast0.CODE(rule_elem_dots) -> + Ast0.CODE(concat_dots (statement tgt) rule_elem_dots) + | Ast0.ERRORWORDS(exps) -> + Ast0.ERRORWORDS(List.map (top_expression false Ast0.NONE) exps) + | Ast0.OTHER(_) -> fail t "eliminated by top_level") + +let rule tgt = List.map (top_level tgt) + +(* --------------------------------------------------------------------- *) +(* Entry points *) + +let minus_arity code = + rule Ast0.NONE code diff --git a/parsing_cocci/arity.mli b/parsing_cocci/arity.mli new file mode 100644 index 0000000..cd64e1e --- /dev/null +++ b/parsing_cocci/arity.mli @@ -0,0 +1 @@ +val minus_arity : Ast0_cocci.rule -> Ast0_cocci.rule diff --git a/parsing_cocci/ast0_cocci.ml b/parsing_cocci/ast0_cocci.ml new file mode 100644 index 0000000..5175cf7 --- /dev/null +++ b/parsing_cocci/ast0_cocci.ml @@ -0,0 +1,641 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast = Ast_cocci + +(* --------------------------------------------------------------------- *) +(* Modified code *) + +type arity = OPT | UNIQUE | NONE + +type token_info = + { tline_start : int; tline_end : int; + left_offset : int; right_offset : int } +let default_token_info = + { tline_start = -1; tline_end = -1; left_offset = -1; right_offset = -1 } + +(* MIXED is like CONTEXT, since sometimes MIXED things have to revert to +CONTEXT - see insert_plus.ml *) +type mcodekind = + MINUS of (Ast.anything list list * token_info) ref + | PLUS + | CONTEXT of (Ast.anything Ast.befaft * token_info * token_info) ref + | MIXED of (Ast.anything Ast.befaft * token_info * token_info) ref + +type info = { line_start : int; line_end : int; + logical_start : int; logical_end : int; + attachable_start : bool; attachable_end : bool; + mcode_start : mcodekind list; mcode_end : mcodekind list; + column : int; offset : int; + (* the following are only for + code *) + strings_before : string list; strings_after : string list } + +type 'a mcode = 'a * arity * info * mcodekind * meta_pos ref (* pos, - only *) +(* int ref is an index *) +and 'a wrap = + { node : 'a; + info : info; + index : int ref; + mcodekind : mcodekind ref; + exp_ty : Type_cocci.typeC option ref; (* only for expressions *) + bef_aft : dots_bef_aft; (* only for statements *) + true_if_arg : bool; (* true if "arg_exp", only for exprs *) + true_if_test : bool; (* true if "test position", only for exprs *) + true_if_test_exp : bool;(* true if "test_exp from iso", only for exprs *) + (*nonempty if this represents the use of an iso*) + iso_info : (string*anything) list } + +and dots_bef_aft = + NoDots | AddingBetweenDots of statement | DroppingBetweenDots of statement + +(* for iso metavariables, true if they can only match nonmodified terms with + all metavariables unitary + for SP metavariables, true if the metavariable is unitary (valid up to + isomorphism phase only) + In SP, the only options are impure and context +*) +and pure = Impure | Pure | Context | PureContext (* pure and only context *) + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Dots *) + +and 'a base_dots = + DOTS of 'a list + | CIRCLES of 'a list + | STARS of 'a list + +and 'a dots = 'a base_dots wrap + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +and base_ident = + Id of string mcode + | MetaId of Ast.meta_name mcode * ident list * pure + | MetaFunc of Ast.meta_name mcode * ident list * pure + | MetaLocalFunc of Ast.meta_name mcode * ident list * pure + | OptIdent of ident + | UniqueIdent of ident + +and ident = base_ident wrap + +(* --------------------------------------------------------------------- *) +(* Expression *) + +and base_expression = + Ident of ident + | Constant of Ast.constant mcode + | FunCall of expression * string mcode (* ( *) * + expression dots * string mcode (* ) *) + | Assignment of expression * Ast.assignOp mcode * expression * + bool (* true if it can match an initialization *) + | CondExpr of expression * string mcode (* ? *) * expression option * + string mcode (* : *) * expression + | Postfix of expression * Ast.fixOp mcode + | Infix of expression * Ast.fixOp mcode + | Unary of expression * Ast.unaryOp mcode + | Binary of expression * Ast.binaryOp mcode * expression + | Nested of expression * Ast.binaryOp mcode * expression + | Paren of string mcode (* ( *) * expression * + string mcode (* ) *) + | ArrayAccess of expression * string mcode (* [ *) * expression * + string mcode (* ] *) + | RecordAccess of expression * string mcode (* . *) * ident + | RecordPtAccess of expression * string mcode (* -> *) * ident + | Cast of string mcode (* ( *) * typeC * string mcode (* ) *) * + expression + | SizeOfExpr of string mcode (* sizeof *) * expression + | SizeOfType of string mcode (* sizeof *) * string mcode (* ( *) * + typeC * string mcode (* ) *) + | TypeExp of typeC (* type name used as an expression, only in args *) + | MetaErr of Ast.meta_name mcode * expression list * pure + | MetaExpr of Ast.meta_name mcode * expression list * + Type_cocci.typeC list option * Ast.form * pure + | MetaExprList of Ast.meta_name mcode (* only in arg lists *) * + listlen * pure + | EComma of string mcode (* only in arg lists *) + | DisjExpr of string mcode * expression list * + string mcode list (* the |s *) * string mcode + | NestExpr of string mcode * expression dots * string mcode * + expression option * Ast.multi + | Edots of string mcode (* ... *) * expression option + | Ecircles of string mcode (* ooo *) * expression option + | Estars of string mcode (* *** *) * expression option + | OptExp of expression + | UniqueExp of expression + +and expression = base_expression wrap + +and listlen = Ast.meta_name mcode option + +(* --------------------------------------------------------------------- *) +(* Types *) + +and base_typeC = + ConstVol of Ast.const_vol mcode * typeC + | BaseType of Ast.baseType mcode * Ast.sign mcode option + | ImplicitInt of Ast.sign mcode + | Pointer of typeC * string mcode (* * *) + | FunctionPointer of typeC * + string mcode(* ( *)*string mcode(* * *)*string mcode(* ) *)* + string mcode (* ( *)*parameter_list*string mcode(* ) *) + | FunctionType of typeC option * + string mcode (* ( *) * parameter_list * + string mcode (* ) *) + | Array of typeC * string mcode (* [ *) * + expression option * string mcode (* ] *) + | StructUnionName of Ast.structUnion mcode * ident option (* name *) + | StructUnionDef of typeC (* either StructUnionName or metavar *) * + string mcode (* { *) * declaration dots * string mcode (* } *) + | TypeName of string mcode + | MetaType of Ast.meta_name mcode * pure + | DisjType of string mcode * typeC list * (* only after iso *) + string mcode list (* the |s *) * string mcode + | OptType of typeC + | UniqueType of typeC + +and typeC = base_typeC wrap + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +and base_declaration = + Init of Ast.storage mcode option * typeC * ident * string mcode (*=*) * + initialiser * string mcode (*;*) + | UnInit of Ast.storage mcode option * typeC * ident * string mcode (* ; *) + | TyDecl of typeC * string mcode (* ; *) + | MacroDecl of ident (* name *) * string mcode (* ( *) * + expression dots * string mcode (* ) *) * string mcode (* ; *) + | Typedef of string mcode (* typedef *) * typeC * typeC * string mcode (*;*) + | DisjDecl of string mcode * declaration list * + string mcode list (* the |s *) * string mcode + (* Ddots is for a structure declaration *) + | Ddots of string mcode (* ... *) * declaration option (* whencode *) + | OptDecl of declaration + | UniqueDecl of declaration + +and declaration = base_declaration wrap + +(* --------------------------------------------------------------------- *) +(* Initializers *) + +and base_initialiser = + InitExpr of expression + | InitList of string mcode (*{*) * initialiser_list * string mcode (*}*) + | InitGccDotName of + string mcode (*.*) * ident (* name *) * string mcode (*=*) * + initialiser (* gccext: *) + | InitGccName of ident (* name *) * string mcode (*:*) * + initialiser + | InitGccIndex of + string mcode (*[*) * expression * string mcode (*]*) * + string mcode (*=*) * initialiser + | InitGccRange of + string mcode (*[*) * expression * string mcode (*...*) * + expression * string mcode (*]*) * string mcode (*=*) * initialiser + | IComma of string mcode (* , *) + | Idots of string mcode (* ... *) * initialiser option (* whencode *) + | OptIni of initialiser + | UniqueIni of initialiser + +and initialiser = base_initialiser wrap + +and initialiser_list = initialiser dots + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +and base_parameterTypeDef = + VoidParam of typeC + | Param of typeC * ident option + | MetaParam of Ast.meta_name mcode * pure + | MetaParamList of Ast.meta_name mcode * listlen * pure + | PComma of string mcode + | Pdots of string mcode (* ... *) + | Pcircles of string mcode (* ooo *) + | OptParam of parameterTypeDef + | UniqueParam of parameterTypeDef + +and parameterTypeDef = base_parameterTypeDef wrap + +and parameter_list = parameterTypeDef dots + +(* --------------------------------------------------------------------- *) +(* #define Parameters *) + +and base_define_param = + DParam of ident + | DPComma of string mcode + | DPdots of string mcode (* ... *) + | DPcircles of string mcode (* ooo *) + | OptDParam of define_param + | UniqueDParam of define_param + +and define_param = base_define_param wrap + +and base_define_parameters = + NoParams + | DParams of string mcode(*( *) * define_param dots * string mcode(* )*) + +and define_parameters = base_define_parameters wrap + +(* --------------------------------------------------------------------- *) +(* Statement*) + +and base_statement = + Decl of (info * mcodekind) (* before the decl *) * declaration + | Seq of string mcode (* { *) * statement dots * + string mcode (* } *) + | ExprStatement of expression * string mcode (*;*) + | IfThen of string mcode (* if *) * string mcode (* ( *) * + expression * string mcode (* ) *) * + statement * (info * mcodekind) (* after info *) + | IfThenElse of string mcode (* if *) * string mcode (* ( *) * + expression * string mcode (* ) *) * + statement * string mcode (* else *) * statement * + (info * mcodekind) + | While of string mcode (* while *) * string mcode (* ( *) * + expression * string mcode (* ) *) * + statement * (info * mcodekind) (* after info *) + | Do of string mcode (* do *) * statement * + string mcode (* while *) * string mcode (* ( *) * + expression * string mcode (* ) *) * + string mcode (* ; *) + | For of string mcode (* for *) * string mcode (* ( *) * + expression option * string mcode (*;*) * + expression option * string mcode (*;*) * + expression option * string mcode (* ) *) * statement * + (info * mcodekind) (* after info *) + | Iterator of ident (* name *) * string mcode (* ( *) * + expression dots * string mcode (* ) *) * + statement * (info * mcodekind) (* after info *) + | Switch of string mcode (* switch *) * string mcode (* ( *) * + expression * string mcode (* ) *) * string mcode (* { *) * + case_line dots * string mcode (* } *) + | Break of string mcode (* break *) * string mcode (* ; *) + | Continue of string mcode (* continue *) * string mcode (* ; *) + | Label of ident * string mcode (* : *) + | Goto of string mcode (* goto *) * ident * string mcode (* ; *) + | Return of string mcode (* return *) * string mcode (* ; *) + | ReturnExpr of string mcode (* return *) * expression * + string mcode (* ; *) + | MetaStmt of Ast.meta_name mcode * pure + | MetaStmtList of Ast.meta_name mcode(*only in statement lists*) * pure + | Exp of expression (* only in dotted statement lists *) + | TopExp of expression (* for macros body *) + | Ty of typeC (* only at top level *) + | Disj of string mcode * statement dots list * + string mcode list (* the |s *) * string mcode + | Nest of string mcode * statement dots * string mcode * + (statement dots,statement) whencode list * Ast.multi + | Dots of string mcode (* ... *) * + (statement dots,statement) whencode list + | Circles of string mcode (* ooo *) * + (statement dots,statement) whencode list + | Stars of string mcode (* *** *) * + (statement dots,statement) whencode list + | FunDecl of (info * mcodekind) (* before the function decl *) * + fninfo list * ident (* name *) * + string mcode (* ( *) * parameter_list * string mcode (* ) *) * + string mcode (* { *) * statement dots * + string mcode (* } *) + | Include of string mcode (* #include *) * Ast.inc_file mcode (* file *) + | Define of string mcode (* #define *) * ident (* name *) * + define_parameters (*params*) * statement dots + | OptStm of statement + | UniqueStm of statement + +and fninfo = + FStorage of Ast.storage mcode + | FType of typeC + | FInline of string mcode + | FAttr of string mcode + +and ('a,'b) whencode = + WhenNot of 'a + | WhenAlways of 'b + | WhenModifier of Ast.when_modifier + +and statement = base_statement wrap + +and base_case_line = + Default of string mcode (* default *) * string mcode (*:*) * statement dots + | Case of string mcode (* case *) * expression * string mcode (*:*) * + statement dots + | OptCase of case_line + +and case_line = base_case_line wrap + +(* --------------------------------------------------------------------- *) +(* Positions *) + +and meta_pos = + MetaPos of Ast.meta_name mcode * Ast.meta_name list * Ast.meta_collect + | NoMetaPos + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +and base_top_level = + DECL of statement + | CODE of statement dots + | FILEINFO of string mcode (* old file *) * string mcode (* new file *) + | ERRORWORDS of expression list + | OTHER of statement (* temporary, disappears after top_level.ml *) + +and top_level = base_top_level wrap +and rule = top_level list + +and parsed_rule = + CocciRule of + (rule * Ast.metavar list * + (string list * string list * Ast.dependency * string * Ast.exists)) * + (rule * Ast.metavar list) + | ScriptRule of + string * Ast.dependency * (string * Ast.meta_name) list * string + +(* --------------------------------------------------------------------- *) + +and anything = + DotsExprTag of expression dots + | DotsInitTag of initialiser dots + | DotsParamTag of parameterTypeDef dots + | DotsStmtTag of statement dots + | DotsDeclTag of declaration dots + | DotsCaseTag of case_line dots + | IdentTag of ident + | ExprTag of expression + | ArgExprTag of expression (* for isos *) + | TestExprTag of expression (* for isos *) + | TypeCTag of typeC + | ParamTag of parameterTypeDef + | InitTag of initialiser + | DeclTag of declaration + | StmtTag of statement + | CaseLineTag of case_line + | TopTag of top_level + | IsoWhenTag of Ast.when_modifier + | MetaPosTag of meta_pos + +let dotsExpr x = DotsExprTag x +let dotsParam x = DotsParamTag x +let dotsInit x = DotsInitTag x +let dotsStmt x = DotsStmtTag x +let dotsDecl x = DotsDeclTag x +let dotsCase x = DotsCaseTag x +let ident x = IdentTag x +let expr x = ExprTag x +let typeC x = TypeCTag x +let param x = ParamTag x +let ini x = InitTag x +let decl x = DeclTag x +let stmt x = StmtTag x +let case_line x = CaseLineTag x +let top x = TopTag x + +(* --------------------------------------------------------------------- *) +(* Avoid cluttering the parser. Calculated in compute_lines.ml. *) + +let default_info _ = (* why is this a function? *) + { line_start = -1; line_end = -1; + logical_start = -1; logical_end = -1; + attachable_start = true; attachable_end = true; + mcode_start = []; mcode_end = []; + column = -1; offset = -1; strings_before = []; strings_after = [] } + +let default_befaft _ = + MIXED(ref (Ast.NOTHING,default_token_info,default_token_info)) +let context_befaft _ = + CONTEXT(ref (Ast.NOTHING,default_token_info,default_token_info)) + +let wrap x = + { node = x; + info = default_info(); + index = ref (-1); + mcodekind = ref (default_befaft()); + exp_ty = ref None; + bef_aft = NoDots; + true_if_arg = false; + true_if_test = false; + true_if_test_exp = false; + iso_info = [] } +let context_wrap x = + { node = x; + info = default_info(); + index = ref (-1); + mcodekind = ref (context_befaft()); + exp_ty = ref None; + bef_aft = NoDots; + true_if_arg = false; + true_if_test = false; + true_if_test_exp = false; + iso_info = [] } +let unwrap x = x.node +let unwrap_mcode (x,_,_,_,_) = x +let rewrap model x = { model with node = x } +let rewrap_mcode (_,arity,info,mcodekind,pos) x = (x,arity,info,mcodekind,pos) +let copywrap model x = + { model with node = x; index = ref !(model.index); + mcodekind = ref !(model.mcodekind); exp_ty = ref !(model.exp_ty)} +let get_pos (_,_,_,_,x) = !x +let get_pos_ref (_,_,_,_,x) = x +let set_pos pos (m,arity,info,mcodekind,_) = (m,arity,info,mcodekind,ref pos) +let get_info x = x.info +let set_info x info = {x with info = info} +let get_line x = x.info.line_start +let get_line_end x = x.info.line_end +let get_index x = !(x.index) +let set_index x i = x.index := i +let get_mcodekind x = !(x.mcodekind) +let get_mcode_mcodekind (_,_,_,mcodekind,_) = mcodekind +let get_mcodekind_ref x = x.mcodekind +let set_mcodekind x mk = x.mcodekind := mk +let set_type x t = x.exp_ty := t +let get_type x = !(x.exp_ty) +let get_dots_bef_aft x = x.bef_aft +let set_dots_bef_aft x dots_bef_aft = {x with bef_aft = dots_bef_aft} +let get_arg_exp x = x.true_if_arg +let set_arg_exp x = {x with true_if_arg = true} +let get_test_pos x = x.true_if_test +let set_test_pos x = {x with true_if_test = true} +let get_test_exp x = x.true_if_test_exp +let set_test_exp x = {x with true_if_test_exp = true} +let get_iso x = x.iso_info +let set_iso x i = if !Flag.track_iso_usage then {x with iso_info = i} else x +let set_mcode_data data (_,ar,info,mc,pos) = (data,ar,info,mc,pos) + +(* --------------------------------------------------------------------- *) + +(* unique indices, for mcode and tree nodes *) +let index_counter = ref 0 +let fresh_index _ = let cur = !index_counter in index_counter := cur + 1; cur + +(* --------------------------------------------------------------------- *) + +let undots d = + match unwrap d with + | DOTS e -> e + | CIRCLES e -> e + | STARS e -> e + +(* --------------------------------------------------------------------- *) + +let rec ast0_type_to_type ty = + match unwrap ty with + ConstVol(cv,ty) -> Type_cocci.ConstVol(const_vol cv,ast0_type_to_type ty) + | BaseType(bty,None) -> + Type_cocci.BaseType(baseType bty,None) + | BaseType(bty,Some sgn) -> + Type_cocci.BaseType(baseType bty,Some (sign sgn)) + | ImplicitInt(sgn) -> + let bty = Type_cocci.IntType in + Type_cocci.BaseType(bty,Some (sign sgn)) + | Pointer(ty,_) -> Type_cocci.Pointer(ast0_type_to_type ty) + | FunctionPointer(ty,_,_,_,_,params,_) -> + Type_cocci.FunctionPointer(ast0_type_to_type ty) + | FunctionType _ -> failwith "not supported" + | Array(ety,_,_,_) -> Type_cocci.Array(ast0_type_to_type ety) + | StructUnionName(su,Some tag) -> + (match unwrap tag with + Id(tag) -> + Type_cocci.StructUnionName(structUnion su,false,unwrap_mcode tag) + | MetaId(tag,_,_) -> + (Printf.printf + "warning: struct/union with a metavariable name detected.\n"; + Printf.printf + "For type checking assuming the name of the metavariable is the name of the type\n"; + let (rule,tag) = unwrap_mcode tag in + Type_cocci.StructUnionName(structUnion su,true,rule^tag)) + | _ -> failwith "unexpected struct/union type name") + | StructUnionName(su,None) -> failwith "nameless structure - what to do???" + | StructUnionDef(ty,_,_,_) -> ast0_type_to_type ty + | TypeName(name) -> Type_cocci.TypeName(unwrap_mcode name) + | MetaType(name,_) -> + Type_cocci.MetaType(unwrap_mcode name,Type_cocci.Unitary,false) + | DisjType(_,types,_,_) -> failwith "unexpected DisjType" + | OptType(ty) | UniqueType(ty) -> + ast0_type_to_type ty + +and baseType t = + match unwrap_mcode t with + Ast.VoidType -> Type_cocci.VoidType + | Ast.CharType -> Type_cocci.CharType + | Ast.ShortType -> Type_cocci.ShortType + | Ast.IntType -> Type_cocci.IntType + | Ast.DoubleType -> Type_cocci.DoubleType + | Ast.FloatType -> Type_cocci.FloatType + | Ast.LongType -> Type_cocci.LongType + +and structUnion t = + match unwrap_mcode t with + Ast.Struct -> Type_cocci.Struct + | Ast.Union -> Type_cocci.Union + +and sign t = + match unwrap_mcode t with + Ast.Signed -> Type_cocci.Signed + | Ast.Unsigned -> Type_cocci.Unsigned + +and const_vol t = + match unwrap_mcode t with + Ast.Const -> Type_cocci.Const + | Ast.Volatile -> Type_cocci.Volatile + +(* --------------------------------------------------------------------- *) +(* this function is a rather minimal attempt. the problem is that information +has been lost. but since it is only used for metavariable types in the isos, +perhaps it doesn't matter *) +let make_mcode x = (x,NONE,default_info(),context_befaft(),ref NoMetaPos) +let make_mcode_info x info = (x,NONE,info,context_befaft(),ref NoMetaPos) + +exception TyConv + +let rec reverse_type ty = + match ty with + Type_cocci.ConstVol(cv,ty) -> + ConstVol(reverse_const_vol cv,wrap(reverse_type ty)) + | Type_cocci.BaseType(bty,None) -> + BaseType(reverse_baseType bty,None) + | Type_cocci.BaseType(bty,Some sgn) -> + BaseType(reverse_baseType bty,Some (reverse_sign sgn)) + | Type_cocci.Pointer(ty) -> + Pointer(wrap(reverse_type ty),make_mcode "*") + | Type_cocci.StructUnionName(su,mv,tag) -> + if mv + then + (* not right... *) + StructUnionName(reverse_structUnion su, + Some(wrap(MetaId(make_mcode ("",tag),[],Impure)))) + else + StructUnionName(reverse_structUnion su, + Some (wrap(Id(make_mcode tag)))) + | Type_cocci.TypeName(name) -> TypeName(make_mcode name) + | Type_cocci.MetaType(name,_,_) -> + MetaType(make_mcode name,Impure(*not really right*)) + | _ -> raise TyConv + +and reverse_baseType t = + make_mcode + (match t with + Type_cocci.VoidType -> Ast.VoidType + | Type_cocci.CharType -> Ast.CharType + | Type_cocci.BoolType -> Ast.IntType + | Type_cocci.ShortType -> Ast.ShortType + | Type_cocci.IntType -> Ast.IntType + | Type_cocci.DoubleType -> Ast.DoubleType + | Type_cocci.FloatType -> Ast.FloatType + | Type_cocci.LongType -> Ast.LongType) + +and reverse_structUnion t = + make_mcode + (match t with + Type_cocci.Struct -> Ast.Struct + | Type_cocci.Union -> Ast.Union) + +and reverse_sign t = + make_mcode + (match t with + Type_cocci.Signed -> Ast.Signed + | Type_cocci.Unsigned -> Ast.Unsigned) + +and reverse_const_vol t = + make_mcode + (match t with + Type_cocci.Const -> Ast.Const + | Type_cocci.Volatile -> Ast.Volatile) + +(* --------------------------------------------------------------------- *) + +let lub_pure x y = + match (x,y) with + (Impure,_) | (_,Impure) -> Impure + | (Pure,Context) | (Context,Pure) -> Impure + | (Pure,_) | (_,Pure) -> Pure + | (_,Context) | (Context,_) -> Context + | _ -> PureContext + +(* --------------------------------------------------------------------- *) + +let rule_name = ref "" (* for the convenience of the parser *) diff --git a/parsing_cocci/ast0_cocci.mli b/parsing_cocci/ast0_cocci.mli new file mode 100644 index 0000000..1b448fa --- /dev/null +++ b/parsing_cocci/ast0_cocci.mli @@ -0,0 +1,449 @@ +(* --------------------------------------------------------------------- *) +(* Modified code *) + +type arity = OPT | UNIQUE | NONE + +type token_info = + { tline_start : int; tline_end : int; + left_offset : int; right_offset : int } +val default_token_info : token_info + +type mcodekind = + MINUS of (Ast_cocci.anything list list * token_info) ref + | PLUS + | CONTEXT of (Ast_cocci.anything Ast_cocci.befaft * + token_info * token_info) ref + | MIXED of (Ast_cocci.anything Ast_cocci.befaft * + token_info * token_info) ref + +type info = { line_start : int; line_end : int; + logical_start : int; logical_end : int; + attachable_start : bool; attachable_end : bool; + mcode_start : mcodekind list; mcode_end : mcodekind list; + column : int; offset : int; + (* the following are only for + code *) + strings_before : string list; strings_after : string list } + +type 'a mcode = 'a * arity * info * mcodekind * meta_pos ref (* pos, - only *) +and 'a wrap = + { node : 'a; + info : info; + index : int ref; + mcodekind : mcodekind ref; + exp_ty : Type_cocci.typeC option ref; (* only for expressions *) + bef_aft : dots_bef_aft; (* only for statements *) + true_if_arg : bool; (* true if "arg_exp", only for exprs *) + true_if_test : bool; (* true if "test position", only for exprs *) + true_if_test_exp : bool;(* true if "test_exp from iso", only for exprs *) + (*nonempty if this represents the use of an iso*) + iso_info : (string*anything) list } + +and dots_bef_aft = + NoDots | AddingBetweenDots of statement | DroppingBetweenDots of statement + +(* for iso metavariables, true if they can only match nonmodified, unitary + metavariables + for SP metavariables, true if the metavariable is unitary (valid up to + isomorphism phase only) *) +and pure = Impure | Pure | Context | PureContext (* pure and only context *) + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Dots *) + +and 'a base_dots = + DOTS of 'a list + | CIRCLES of 'a list + | STARS of 'a list + +and 'a dots = 'a base_dots wrap + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +and base_ident = + Id of string mcode + | MetaId of Ast_cocci.meta_name mcode * ident list * pure + | MetaFunc of Ast_cocci.meta_name mcode * ident list * pure + | MetaLocalFunc of Ast_cocci.meta_name mcode * ident list * pure + | OptIdent of ident + | UniqueIdent of ident + +and ident = base_ident wrap + +(* --------------------------------------------------------------------- *) +(* Expression *) + +and base_expression = + Ident of ident + | Constant of Ast_cocci.constant mcode + | FunCall of expression * string mcode (* ( *) * + expression dots * string mcode (* ) *) + | Assignment of expression * Ast_cocci.assignOp mcode * expression * + bool (* true if it can match an initialization *) + | CondExpr of expression * string mcode (* ? *) * expression option * + string mcode (* : *) * expression + | Postfix of expression * Ast_cocci.fixOp mcode + | Infix of expression * Ast_cocci.fixOp mcode + | Unary of expression * Ast_cocci.unaryOp mcode + | Binary of expression * Ast_cocci.binaryOp mcode * expression + | Nested of expression * Ast_cocci.binaryOp mcode * expression + | Paren of string mcode (* ( *) * expression * + string mcode (* ) *) + | ArrayAccess of expression * string mcode (* [ *) * expression * + string mcode (* ] *) + | RecordAccess of expression * string mcode (* . *) * ident + | RecordPtAccess of expression * string mcode (* -> *) * ident + | Cast of string mcode (* ( *) * typeC * string mcode (* ) *) * + expression + | SizeOfExpr of string mcode (* sizeof *) * expression + | SizeOfType of string mcode (* sizeof *) * string mcode (* ( *) * + typeC * string mcode (* ) *) + | TypeExp of typeC + | MetaErr of Ast_cocci.meta_name mcode * expression list * pure + | MetaExpr of Ast_cocci.meta_name mcode * expression list * + Type_cocci.typeC list option * Ast_cocci.form * pure + | MetaExprList of Ast_cocci.meta_name mcode (* only in arglists *) * + listlen * pure + | EComma of string mcode (* only in arglists *) + | DisjExpr of string mcode * expression list * string mcode list * + string mcode + | NestExpr of string mcode * expression dots * string mcode * + expression option * Ast_cocci.multi + | Edots of string mcode (* ... *) * expression option + | Ecircles of string mcode (* ooo *) * expression option + | Estars of string mcode (* *** *) * expression option + | OptExp of expression + | UniqueExp of expression + +and expression = base_expression wrap + +and listlen = Ast_cocci.meta_name mcode option + +(* --------------------------------------------------------------------- *) +(* Types *) + +and base_typeC = + ConstVol of Ast_cocci.const_vol mcode * typeC + | BaseType of Ast_cocci.baseType mcode * Ast_cocci.sign mcode option + | ImplicitInt of Ast_cocci.sign mcode + | Pointer of typeC * string mcode (* * *) + | FunctionPointer of typeC * + string mcode(* ( *)*string mcode(* * *)*string mcode(* ) *)* + string mcode (* ( *)*parameter_list*string mcode(* ) *) + | FunctionType of typeC option * + string mcode (* ( *) * parameter_list * + string mcode (* ) *) + | Array of typeC * string mcode (* [ *) * + expression option * string mcode (* ] *) + | StructUnionName of Ast_cocci.structUnion mcode * ident option (* name *) + | StructUnionDef of typeC (* either StructUnionName or metavar *) * + string mcode (* { *) * declaration dots * string mcode (* } *) + | TypeName of string mcode + | MetaType of Ast_cocci.meta_name mcode * pure + | DisjType of string mcode * typeC list * (* only after iso *) + string mcode list (* the |s *) * string mcode + | OptType of typeC + | UniqueType of typeC + +and typeC = base_typeC wrap + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +and base_declaration = + Init of Ast_cocci.storage mcode option * typeC * ident * + string mcode (*=*) * initialiser * string mcode (*;*) + | UnInit of Ast_cocci.storage mcode option * typeC * ident * + string mcode (* ; *) + | TyDecl of typeC * string mcode (* ; *) + | MacroDecl of ident (* name *) * string mcode (* ( *) * + expression dots * string mcode (* ) *) * string mcode (* ; *) + | Typedef of string mcode (* typedef *) * typeC * typeC * string mcode (*;*) + | DisjDecl of string mcode * declaration list * string mcode list * + string mcode + | Ddots of string mcode (* ... *) * declaration option (* whencode *) + | OptDecl of declaration + | UniqueDecl of declaration + +and declaration = base_declaration wrap + +(* --------------------------------------------------------------------- *) +(* Initializers *) + +and base_initialiser = + InitExpr of expression + | InitList of string mcode (*{*) * initialiser_list * string mcode (*}*) + | InitGccDotName of + string mcode (*.*) * ident (* name *) * string mcode (*=*) * + initialiser (* gccext: *) + | InitGccName of ident (* name *) * string mcode (*:*) * + initialiser + | InitGccIndex of + string mcode (*[*) * expression * string mcode (*]*) * + string mcode (*=*) * initialiser + | InitGccRange of + string mcode (*[*) * expression * string mcode (*...*) * + expression * string mcode (*]*) * string mcode (*=*) * initialiser + | IComma of string mcode + | Idots of string mcode (* ... *) * initialiser option (* whencode *) + | OptIni of initialiser + | UniqueIni of initialiser + +and initialiser = base_initialiser wrap + +and initialiser_list = initialiser dots + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +and base_parameterTypeDef = + VoidParam of typeC + | Param of typeC * ident option + | MetaParam of Ast_cocci.meta_name mcode * pure + | MetaParamList of Ast_cocci.meta_name mcode * listlen * pure + | PComma of string mcode + | Pdots of string mcode (* ... *) + | Pcircles of string mcode (* ooo *) + | OptParam of parameterTypeDef + | UniqueParam of parameterTypeDef + +and parameterTypeDef = base_parameterTypeDef wrap + +and parameter_list = parameterTypeDef dots + +(* --------------------------------------------------------------------- *) +(* #define Parameters *) + +and base_define_param = + DParam of ident + | DPComma of string mcode + | DPdots of string mcode (* ... *) + | DPcircles of string mcode (* ooo *) + | OptDParam of define_param + | UniqueDParam of define_param + +and define_param = base_define_param wrap + +and base_define_parameters = + NoParams + | DParams of string mcode(*( *) * define_param dots * string mcode(* )*) + +and define_parameters = base_define_parameters wrap + +(* --------------------------------------------------------------------- *) +(* Statement*) + +and base_statement = + Decl of (info * mcodekind) (* before the decl *) * declaration + | Seq of string mcode (* { *) * statement dots * + string mcode (* } *) + | ExprStatement of expression * string mcode (*;*) + | IfThen of string mcode (* if *) * string mcode (* ( *) * + expression * string mcode (* ) *) * + statement * (info * mcodekind) + | IfThenElse of string mcode (* if *) * string mcode (* ( *) * + expression * string mcode (* ) *) * + statement * string mcode (* else *) * statement * + (info * mcodekind) + | While of string mcode (* while *) * string mcode (* ( *) * + expression * string mcode (* ) *) * + statement * (info * mcodekind) (* after info *) + | Do of string mcode (* do *) * statement * + string mcode (* while *) * string mcode (* ( *) * + expression * string mcode (* ) *) * + string mcode (* ; *) + | For of string mcode (* for *) * string mcode (* ( *) * + expression option * string mcode (*;*) * + expression option * string mcode (*;*) * + expression option * string mcode (* ) *) * statement * + (info * mcodekind) (* after info *) + | Iterator of ident (* name *) * string mcode (* ( *) * + expression dots * string mcode (* ) *) * + statement * (info * mcodekind) (* after info *) + | Switch of string mcode (* switch *) * string mcode (* ( *) * + expression * string mcode (* ) *) * string mcode (* { *) * + case_line dots * string mcode (* } *) + | Break of string mcode (* break *) * string mcode (* ; *) + | Continue of string mcode (* continue *) * string mcode (* ; *) + | Label of ident * string mcode (* : *) + | Goto of string mcode (* goto *) * ident * string mcode (* ; *) + | Return of string mcode (* return *) * string mcode (* ; *) + | ReturnExpr of string mcode (* return *) * expression * + string mcode (* ; *) + | MetaStmt of Ast_cocci.meta_name mcode * pure + | MetaStmtList of Ast_cocci.meta_name mcode (*only in statement lists*) * + pure + | Exp of expression (* only in dotted statement lists *) + | TopExp of expression (* for macros body *) + | Ty of typeC (* only at top level *) + | Disj of string mcode * statement dots list * string mcode list * + string mcode + | Nest of string mcode * statement dots * string mcode * + (statement dots,statement) whencode list * Ast_cocci.multi + | Dots of string mcode (* ... *) * + (statement dots,statement) whencode list + | Circles of string mcode (* ooo *) * + (statement dots,statement) whencode list + | Stars of string mcode (* *** *) * + (statement dots,statement) whencode list + | FunDecl of (info * mcodekind) (* before the function decl *) * + fninfo list * ident (* name *) * + string mcode (* ( *) * parameter_list * string mcode (* ) *) * + string mcode (* { *) * statement dots * + string mcode (* } *) + | Include of string mcode (* #include *) * Ast_cocci.inc_file mcode(* file *) + | Define of string mcode (* #define *) * ident (* name *) * + define_parameters (*params*) * statement dots + | OptStm of statement + | UniqueStm of statement + +and fninfo = + FStorage of Ast_cocci.storage mcode + | FType of typeC + | FInline of string mcode + | FAttr of string mcode + +and ('a,'b) whencode = + WhenNot of 'a + | WhenAlways of 'b + | WhenModifier of Ast_cocci.when_modifier + +and statement = base_statement wrap + +and base_case_line = + Default of string mcode (* default *) * string mcode (*:*) * statement dots + | Case of string mcode (* case *) * expression * string mcode (*:*) * + statement dots + | OptCase of case_line + +and case_line = base_case_line wrap + +(* --------------------------------------------------------------------- *) +(* Positions *) + +and meta_pos = + MetaPos of Ast_cocci.meta_name mcode * Ast_cocci.meta_name list * + Ast_cocci.meta_collect + | NoMetaPos + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +and base_top_level = + DECL of statement + | CODE of statement dots + | FILEINFO of string mcode (* old file *) * string mcode (* new file *) + | ERRORWORDS of expression list + | OTHER of statement (* temporary, disappears after top_level.ml *) + +and top_level = base_top_level wrap +and rule = top_level list + +and parsed_rule = + CocciRule of + (rule * Ast_cocci.metavar list * + (string list * string list * Ast_cocci.dependency * string * + Ast_cocci.exists)) * + (rule * Ast_cocci.metavar list) + | ScriptRule of + string * Ast_cocci.dependency * (string * Ast_cocci.meta_name) list * + string + +(* --------------------------------------------------------------------- *) + +and anything = + DotsExprTag of expression dots + | DotsInitTag of initialiser dots + | DotsParamTag of parameterTypeDef dots + | DotsStmtTag of statement dots + | DotsDeclTag of declaration dots + | DotsCaseTag of case_line dots + | IdentTag of ident + | ExprTag of expression + | ArgExprTag of expression (* for isos *) + | TestExprTag of expression (* for isos *) + | TypeCTag of typeC + | ParamTag of parameterTypeDef + | InitTag of initialiser + | DeclTag of declaration + | StmtTag of statement + | CaseLineTag of case_line + | TopTag of top_level + | IsoWhenTag of Ast_cocci.when_modifier (*only for when code, in iso phase*) + | MetaPosTag of meta_pos (* only in iso phase *) + +val dotsExpr : expression dots -> anything +val dotsInit : initialiser dots -> anything +val dotsParam : parameterTypeDef dots -> anything +val dotsStmt : statement dots -> anything +val dotsDecl : declaration dots -> anything +val dotsCase : case_line dots -> anything +val ident : ident -> anything +val expr : expression -> anything +val typeC : typeC -> anything +val param : parameterTypeDef -> anything +val ini : initialiser -> anything +val decl : declaration -> anything +val stmt : statement -> anything +val case_line : case_line -> anything +val top : top_level -> anything + +(* --------------------------------------------------------------------- *) + +val undots : 'a dots -> 'a list + +(* --------------------------------------------------------------------- *) +(* Avoid cluttering the parser. Calculated in compute_lines.ml. *) + +val default_info : unit -> info +val default_befaft : unit -> mcodekind +val context_befaft : unit -> mcodekind +val wrap : 'a -> 'a wrap +val context_wrap : 'a -> 'a wrap +val unwrap : 'a wrap -> 'a +val unwrap_mcode : 'a mcode -> 'a +val rewrap : 'a wrap -> 'b -> 'b wrap +val rewrap_mcode : 'a mcode -> 'b -> 'b mcode +val copywrap : 'a wrap -> 'b -> 'b wrap +val get_pos : 'a mcode -> meta_pos +val get_pos_ref : 'a mcode -> meta_pos ref +val set_pos : meta_pos -> 'a mcode -> 'a mcode +val get_info : 'a wrap -> info +val set_info : 'a wrap -> info -> 'a wrap +val get_index : 'a wrap -> int +val set_index : 'a wrap -> int -> unit +val get_line : 'a wrap -> int +val get_line_end : 'a wrap -> int +val get_mcodekind : 'a wrap -> mcodekind +val get_mcode_mcodekind : 'a mcode -> mcodekind +val get_mcodekind_ref : 'a wrap -> mcodekind ref +val set_mcodekind : 'a wrap -> mcodekind -> unit +val set_type : 'a wrap -> Type_cocci.typeC option -> unit +val get_type : 'a wrap -> Type_cocci.typeC option +val set_dots_bef_aft : statement -> dots_bef_aft -> statement +val get_dots_bef_aft : 'a wrap -> dots_bef_aft +val set_arg_exp : expression -> expression +val get_arg_exp : expression -> bool +val set_test_pos : expression -> expression +val get_test_pos : 'a wrap -> bool +val set_test_exp : expression -> expression +val get_test_exp : 'a wrap -> bool +val set_iso : 'a wrap -> (string*anything) list -> 'a wrap +val get_iso : 'a wrap -> (string*anything) list +val fresh_index : unit -> int +val set_mcode_data : 'a -> 'a mcode -> 'a mcode +val make_mcode : 'a -> 'a mcode +val make_mcode_info : 'a -> info -> 'a mcode + +val ast0_type_to_type : typeC -> Type_cocci.typeC +val reverse_type : Type_cocci.typeC -> base_typeC +exception TyConv + +val lub_pure : pure -> pure -> pure + +(* --------------------------------------------------------------------- *) + +val rule_name : string ref (* for the convenience of the parser *) diff --git a/parsing_cocci/ast0toast.ml b/parsing_cocci/ast0toast.ml new file mode 100644 index 0000000..ccc23cc --- /dev/null +++ b/parsing_cocci/ast0toast.ml @@ -0,0 +1,916 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* Arities matter for the minus slice, but not for the plus slice. *) + +(* + only allowed on code in a nest (in_nest = true). ? only allowed on +rule_elems, and on subterms if the context is ? also. *) + +module Ast0 = Ast0_cocci +module Ast = Ast_cocci +module V0 = Visitor_ast0 +module V = Visitor_ast + +let unitary = Type_cocci.Unitary + +let ctr = ref 0 +let get_ctr _ = + let c = !ctr in + ctr := !ctr + 1; + c + +(* --------------------------------------------------------------------- *) +(* Move plus tokens from the MINUS and CONTEXT structured nodes to the +corresponding leftmost and rightmost mcodes *) + +let inline_mcodes = + let bind x y = () in + let option_default = () in + let mcode _ = () in + let do_nothing r k e = + k e; + let einfo = Ast0.get_info e in + match (Ast0.get_mcodekind e) with + Ast0.MINUS(replacements) -> + (match !replacements with + ([],_) -> () + | replacements -> + let minus_try = function + (true,mc) -> + if List.for_all + (function + Ast0.MINUS(mreplacements) -> true | _ -> false) + mc + then + (List.iter + (function + Ast0.MINUS(mreplacements) -> + mreplacements := replacements + | _ -> ()) + mc; + true) + else false + | _ -> false in + if not (minus_try(einfo.Ast0.attachable_start, + einfo.Ast0.mcode_start) + or + minus_try(einfo.Ast0.attachable_end, + einfo.Ast0.mcode_end)) + then + failwith "minus tree should not have bad code on both sides") + | Ast0.CONTEXT(befaft) + | Ast0.MIXED(befaft) -> + let concat starter startinfo ender endinfo = + let lst = + match (starter,ender) with + ([],_) -> ender + | (_,[]) -> starter + | _ -> + if startinfo.Ast0.tline_end = endinfo.Ast0.tline_start + then (* put them in the same inner list *) + let last = List.hd (List.rev starter) in + let butlast = List.rev(List.tl(List.rev starter)) in + butlast @ (last@(List.hd ender)) :: (List.tl ender) + else starter @ ender in + (lst, + {endinfo with Ast0.tline_start = startinfo.Ast0.tline_start}) in + let attach_bef bef beforeinfo = function + (true,mcl) -> + List.iter + (function + Ast0.MINUS(mreplacements) -> + let (mrepl,tokeninfo) = !mreplacements in + mreplacements := concat bef beforeinfo mrepl tokeninfo + | Ast0.CONTEXT(mbefaft) -> + (match !mbefaft with + (Ast.BEFORE(mbef),mbeforeinfo,a) -> + let (newbef,newinfo) = + concat bef beforeinfo mbef mbeforeinfo in + mbefaft := (Ast.BEFORE(newbef),newinfo,a) + | (Ast.AFTER(maft),_,a) -> + mbefaft := + (Ast.BEFOREAFTER(bef,maft),beforeinfo,a) + | (Ast.BEFOREAFTER(mbef,maft),mbeforeinfo,a) -> + let (newbef,newinfo) = + concat bef beforeinfo mbef mbeforeinfo in + mbefaft := + (Ast.BEFOREAFTER(newbef,maft),newinfo,a) + | (Ast.NOTHING,_,a) -> + mbefaft := (Ast.BEFORE(bef),beforeinfo,a)) + | _ -> failwith "unexpected annotation") + mcl + | _ -> + failwith + "context tree should not have bad code on both sides" in + let attach_aft aft afterinfo = function + (true,mcl) -> + List.iter + (function + Ast0.MINUS(mreplacements) -> + let (mrepl,tokeninfo) = !mreplacements in + mreplacements := concat mrepl tokeninfo aft afterinfo + | Ast0.CONTEXT(mbefaft) -> + (match !mbefaft with + (Ast.BEFORE(mbef),b,_) -> + mbefaft := + (Ast.BEFOREAFTER(mbef,aft),b,afterinfo) + | (Ast.AFTER(maft),b,mafterinfo) -> + let (newaft,newinfo) = + concat maft mafterinfo aft afterinfo in + mbefaft := (Ast.AFTER(newaft),b,newinfo) + | (Ast.BEFOREAFTER(mbef,maft),b,mafterinfo) -> + let (newaft,newinfo) = + concat maft mafterinfo aft afterinfo in + mbefaft := + (Ast.BEFOREAFTER(mbef,newaft),b,newinfo) + | (Ast.NOTHING,b,_) -> + mbefaft := (Ast.AFTER(aft),b,afterinfo)) + | _ -> failwith "unexpected annotation") + mcl + | _ -> + failwith + "context tree should not have bad code on both sides" in + (match !befaft with + (Ast.BEFORE(bef),beforeinfo,_) -> + attach_bef bef beforeinfo + (einfo.Ast0.attachable_start,einfo.Ast0.mcode_start) + | (Ast.AFTER(aft),_,afterinfo) -> + attach_aft aft afterinfo + (einfo.Ast0.attachable_end,einfo.Ast0.mcode_end) + | (Ast.BEFOREAFTER(bef,aft),beforeinfo,afterinfo) -> + attach_bef bef beforeinfo + (einfo.Ast0.attachable_start,einfo.Ast0.mcode_start); + attach_aft aft afterinfo + (einfo.Ast0.attachable_end,einfo.Ast0.mcode_end) + | (Ast.NOTHING,_,_) -> ()) + | Ast0.PLUS -> () in + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode mcode mcode + do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing + +(* --------------------------------------------------------------------- *) +(* For function declarations. Can't use the mcode at the root, because that +might be mixed when the function contains ()s, where agglomeration of -s is +not possible. *) + +let check_allminus = + let donothing r k e = k e in + let bind x y = x && y in + let option_default = true in + let mcode (_,_,_,mc,_) = + match mc with + Ast0.MINUS(r) -> let (plusses,_) = !r in plusses = [] + | _ -> false in + + (* special case for disj *) + let expression r k e = + match Ast0.unwrap e with + Ast0.DisjExpr(starter,expr_list,mids,ender) -> + List.for_all r.V0.combiner_expression expr_list + | _ -> k e in + + let declaration r k e = + match Ast0.unwrap e with + Ast0.DisjDecl(starter,decls,mids,ender) -> + List.for_all r.V0.combiner_declaration decls + | _ -> k e in + + let typeC r k e = + match Ast0.unwrap e with + Ast0.DisjType(starter,decls,mids,ender) -> + List.for_all r.V0.combiner_typeC decls + | _ -> k e in + + let statement r k e = + match Ast0.unwrap e with + Ast0.Disj(starter,statement_dots_list,mids,ender) -> + List.for_all r.V0.combiner_statement_dots statement_dots_list + | _ -> k e in + + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode mcode mcode + donothing donothing donothing donothing donothing donothing + donothing expression typeC donothing donothing declaration + statement donothing donothing + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) + +let get_option fn = function + None -> None + | Some x -> Some (fn x) + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Mcode *) + +let convert_info info = + { Ast.line = info.Ast0.line_start; Ast.column = info.Ast0.column; + Ast.strbef = info.Ast0.strings_before; + Ast.straft = info.Ast0.strings_after; } + +let convert_mcodekind = function + Ast0.MINUS(replacements) -> + let (replacements,_) = !replacements in + Ast.MINUS(Ast.NoPos,replacements) + | Ast0.PLUS -> Ast.PLUS + | Ast0.CONTEXT(befaft) -> + let (befaft,_,_) = !befaft in Ast.CONTEXT(Ast.NoPos,befaft) + | Ast0.MIXED(_) -> failwith "not possible for mcode" + +let pos_mcode(term,_,info,mcodekind,pos) = + (* avoids a recursion problem *) + (term,convert_info info,convert_mcodekind mcodekind,Ast.NoMetaPos) + +let mcode(term,_,info,mcodekind,pos) = + let pos = + match !pos with + Ast0.MetaPos(pos,constraints,per) -> + Ast.MetaPos(pos_mcode pos,constraints,per,unitary,false) + | _ -> Ast.NoMetaPos in + (term,convert_info info,convert_mcodekind mcodekind,pos) + +(* --------------------------------------------------------------------- *) +(* Dots *) +let wrap ast line isos = + {(Ast.make_term ast) with Ast.node_line = line; + Ast.iso_info = isos} + +let rewrap ast0 isos ast = + wrap ast ((Ast0.get_info ast0).Ast0.line_start) isos + +let no_isos = [] + +(* no isos on tokens *) +let tokenwrap (_,info,_,_) s ast = wrap ast info.Ast.line no_isos +let iso_tokenwrap (_,info,_,_) s ast iso = wrap ast info.Ast.line iso + +let dots fn d = + rewrap d no_isos + (match Ast0.unwrap d with + Ast0.DOTS(x) -> Ast.DOTS(List.map fn x) + | Ast0.CIRCLES(x) -> Ast.CIRCLES(List.map fn x) + | Ast0.STARS(x) -> Ast.STARS(List.map fn x)) + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +let rec do_isos l = List.map (function (nm,x) -> (nm,anything x)) l + +and ident i = + rewrap i (do_isos (Ast0.get_iso i)) + (match Ast0.unwrap i with + Ast0.Id(name) -> Ast.Id(mcode name) + | Ast0.MetaId(name,constraints,_) -> + let constraints = List.map ident constraints in + Ast.MetaId(mcode name,constraints,unitary,false) + | Ast0.MetaFunc(name,constraints,_) -> + let constraints = List.map ident constraints in + Ast.MetaFunc(mcode name,constraints,unitary,false) + | Ast0.MetaLocalFunc(name,constraints,_) -> + let constraints = List.map ident constraints in + Ast.MetaLocalFunc(mcode name,constraints,unitary,false) + | Ast0.OptIdent(id) -> Ast.OptIdent(ident id) + | Ast0.UniqueIdent(id) -> Ast.UniqueIdent(ident id)) + +(* --------------------------------------------------------------------- *) +(* Expression *) + +and expression e = + let e1 = + rewrap e (do_isos (Ast0.get_iso e)) + (match Ast0.unwrap e with + Ast0.Ident(id) -> Ast.Ident(ident id) + | Ast0.Constant(const) -> + Ast.Constant(mcode const) + | Ast0.FunCall(fn,lp,args,rp) -> + let fn = expression fn in + let lp = mcode lp in + let args = dots expression args in + let rp = mcode rp in + Ast.FunCall(fn,lp,args,rp) + | Ast0.Assignment(left,op,right,simple) -> + Ast.Assignment(expression left,mcode op,expression right,simple) + | Ast0.CondExpr(exp1,why,exp2,colon,exp3) -> + let exp1 = expression exp1 in + let why = mcode why in + let exp2 = get_option expression exp2 in + let colon = mcode colon in + let exp3 = expression exp3 in + Ast.CondExpr(exp1,why,exp2,colon,exp3) + | Ast0.Postfix(exp,op) -> + Ast.Postfix(expression exp,mcode op) + | Ast0.Infix(exp,op) -> + Ast.Infix(expression exp,mcode op) + | Ast0.Unary(exp,op) -> + Ast.Unary(expression exp,mcode op) + | Ast0.Binary(left,op,right) -> + Ast.Binary(expression left,mcode op,expression right) + | Ast0.Nested(left,op,right) -> + Ast.Nested(expression left,mcode op,expression right) + | Ast0.Paren(lp,exp,rp) -> + Ast.Paren(mcode lp,expression exp,mcode rp) + | Ast0.ArrayAccess(exp1,lb,exp2,rb) -> + Ast.ArrayAccess(expression exp1,mcode lb,expression exp2,mcode rb) + | Ast0.RecordAccess(exp,pt,field) -> + Ast.RecordAccess(expression exp,mcode pt,ident field) + | Ast0.RecordPtAccess(exp,ar,field) -> + Ast.RecordPtAccess(expression exp,mcode ar,ident field) + | Ast0.Cast(lp,ty,rp,exp) -> + Ast.Cast(mcode lp,typeC ty,mcode rp,expression exp) + | Ast0.SizeOfExpr(szf,exp) -> + Ast.SizeOfExpr(mcode szf,expression exp) + | Ast0.SizeOfType(szf,lp,ty,rp) -> + Ast.SizeOfType(mcode szf, mcode lp,typeC ty,mcode rp) + | Ast0.TypeExp(ty) -> Ast.TypeExp(typeC ty) + | Ast0.MetaErr(name,constraints,_) -> + let constraints = List.map expression constraints in + Ast.MetaErr(mcode name,constraints,unitary,false) + | Ast0.MetaExpr(name,constraints,ty,form,_) -> + let constraints = List.map expression constraints in + Ast.MetaExpr(mcode name,constraints,unitary,ty,form,false) + | Ast0.MetaExprList(name,Some lenname,_) -> + Ast.MetaExprList(mcode name,Some (mcode lenname,unitary,false), + unitary,false) + | Ast0.MetaExprList(name,None,_) -> + Ast.MetaExprList(mcode name,None,unitary,false) + | Ast0.EComma(cm) -> Ast.EComma(mcode cm) + | Ast0.DisjExpr(_,exps,_,_) -> Ast.DisjExpr(List.map expression exps) + | Ast0.NestExpr(_,exp_dots,_,whencode,multi) -> + let whencode = get_option expression whencode in + Ast.NestExpr(dots expression exp_dots,whencode,multi) + | Ast0.Edots(dots,whencode) -> + let dots = mcode dots in + let whencode = get_option expression whencode in + Ast.Edots(dots,whencode) + | Ast0.Ecircles(dots,whencode) -> + let dots = mcode dots in + let whencode = get_option expression whencode in + Ast.Ecircles(dots,whencode) + | Ast0.Estars(dots,whencode) -> + let dots = mcode dots in + let whencode = get_option expression whencode in + Ast.Estars(dots,whencode) + | Ast0.OptExp(exp) -> Ast.OptExp(expression exp) + | Ast0.UniqueExp(exp) -> Ast.UniqueExp(expression exp)) in + if Ast0.get_test_exp e then Ast.set_test_exp e1 else e1 + +and expression_dots ed = dots expression ed + +(* --------------------------------------------------------------------- *) +(* Types *) + +and typeC t = + rewrap t (do_isos (Ast0.get_iso t)) + (match Ast0.unwrap t with + Ast0.ConstVol(cv,ty) -> + let rec collect_disjs t = + match Ast0.unwrap t with + Ast0.DisjType(_,types,_,_) -> + if Ast0.get_iso t = [] + then List.concat (List.map collect_disjs types) + else failwith "unexpected iso on a disjtype" + | _ -> [t] in + let res = + List.map + (function ty -> + Ast.Type + (Some (mcode cv), + rewrap ty (do_isos (Ast0.get_iso ty)) (base_typeC ty))) + (collect_disjs ty) in + (* one could worry that isos are lost because we flatten the + disjunctions. but there should not be isos on the disjunctions + themselves. *) + (match res with + [ty] -> ty + | types -> Ast.DisjType(List.map (rewrap t no_isos) types)) + | Ast0.BaseType(_,_) | Ast0.ImplicitInt(_) | Ast0.Pointer(_,_) + | Ast0.FunctionPointer(_,_,_,_,_,_,_) | Ast0.FunctionType(_,_,_,_) + | Ast0.Array(_,_,_,_) | Ast0.StructUnionName(_,_) + | Ast0.StructUnionDef(_,_,_,_) | Ast0.TypeName(_) | Ast0.MetaType(_,_) -> + Ast.Type(None,rewrap t no_isos (base_typeC t)) + | Ast0.DisjType(_,types,_,_) -> Ast.DisjType(List.map typeC types) + | Ast0.OptType(ty) -> Ast.OptType(typeC ty) + | Ast0.UniqueType(ty) -> Ast.UniqueType(typeC ty)) + +and base_typeC t = + match Ast0.unwrap t with + Ast0.BaseType(ty,sign) -> + Ast.BaseType(mcode ty,get_option mcode sign) + | Ast0.ImplicitInt(sgn) -> Ast.ImplicitInt(mcode sgn) + | Ast0.Pointer(ty,star) -> Ast.Pointer(typeC ty,mcode star) + | Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + Ast.FunctionPointer + (typeC ty,mcode lp1,mcode star,mcode rp1, + mcode lp2,parameter_list params,mcode rp2) + | Ast0.FunctionType(ret,lp,params,rp) -> + let allminus = check_allminus.V0.combiner_typeC t in + Ast.FunctionType + (allminus,get_option typeC ret,mcode lp, + parameter_list params,mcode rp) + | Ast0.Array(ty,lb,size,rb) -> + Ast.Array(typeC ty,mcode lb,get_option expression size,mcode rb) + | Ast0.StructUnionName(kind,name) -> + Ast.StructUnionName(mcode kind,get_option ident name) + | Ast0.StructUnionDef(ty,lb,decls,rb) -> + Ast.StructUnionDef(typeC ty,mcode lb, + dots declaration decls, + mcode rb) + | Ast0.TypeName(name) -> Ast.TypeName(mcode name) + | Ast0.MetaType(name,_) -> + Ast.MetaType(mcode name,unitary,false) + | _ -> failwith "ast0toast: unexpected type" + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +and declaration d = + rewrap d (do_isos (Ast0.get_iso d)) + (match Ast0.unwrap d with + Ast0.Init(stg,ty,id,eq,ini,sem) -> + let stg = get_option mcode stg in + let ty = typeC ty in + let id = ident id in + let eq = mcode eq in + let ini = initialiser ini in + let sem = mcode sem in + Ast.Init(stg,ty,id,eq,ini,sem) + | Ast0.UnInit(stg,ty,id,sem) -> + (match Ast0.unwrap ty with + Ast0.FunctionType(tyx,lp1,params,rp1) -> + let allminus = check_allminus.V0.combiner_declaration d in + Ast.UnInit(get_option mcode stg, + rewrap ty (do_isos (Ast0.get_iso ty)) + (Ast.Type + (None, + rewrap ty no_isos + (Ast.FunctionType + (allminus,get_option typeC tyx,mcode lp1, + parameter_list params,mcode rp1)))), + ident id,mcode sem) + | _ -> Ast.UnInit(get_option mcode stg,typeC ty,ident id,mcode sem)) + | Ast0.MacroDecl(name,lp,args,rp,sem) -> + let name = ident name in + let lp = mcode lp in + let args = dots expression args in + let rp = mcode rp in + let sem = mcode sem in + Ast.MacroDecl(name,lp,args,rp,sem) + | Ast0.TyDecl(ty,sem) -> Ast.TyDecl(typeC ty,mcode sem) + | Ast0.Typedef(stg,ty,id,sem) -> + let id = typeC id in + (match Ast.unwrap id with + Ast.Type(None,id) -> (* only MetaType or Id *) + Ast.Typedef(mcode stg,typeC ty,id,mcode sem) + | _ -> failwith "bad typedef") + | Ast0.DisjDecl(_,decls,_,_) -> Ast.DisjDecl(List.map declaration decls) + | Ast0.Ddots(dots,whencode) -> + let dots = mcode dots in + let whencode = get_option declaration whencode in + Ast.Ddots(dots,whencode) + | Ast0.OptDecl(decl) -> Ast.OptDecl(declaration decl) + | Ast0.UniqueDecl(decl) -> Ast.UniqueDecl(declaration decl)) + +and declaration_dots l = dots declaration l + +(* --------------------------------------------------------------------- *) +(* Initialiser *) + +and strip_idots initlist = + match Ast0.unwrap initlist with + Ast0.DOTS(x) -> + let (whencode,init) = + List.fold_left + (function (prevwhen,previnit) -> + function cur -> + match Ast0.unwrap cur with + Ast0.Idots(dots,Some whencode) -> + (whencode :: prevwhen, previnit) + | Ast0.Idots(dots,None) -> (prevwhen,previnit) + | _ -> (prevwhen, cur :: previnit)) + ([],[]) x in + (List.rev whencode, List.rev init) + | Ast0.CIRCLES(x) | Ast0.STARS(x) -> failwith "not possible for an initlist" + +and initialiser i = + rewrap i no_isos + (match Ast0.unwrap i with + Ast0.InitExpr(exp) -> Ast.InitExpr(expression exp) + | Ast0.InitList(lb,initlist,rb) -> + let (whencode,initlist) = strip_idots initlist in + Ast.InitList(mcode lb,List.map initialiser initlist,mcode rb, + List.map initialiser whencode) + | Ast0.InitGccDotName(dot,name,eq,ini) -> + Ast.InitGccDotName(mcode dot,ident name,mcode eq,initialiser ini) + | Ast0.InitGccName(name,eq,ini) -> + Ast.InitGccName(ident name,mcode eq,initialiser ini) + | Ast0.InitGccIndex(lb,exp,rb,eq,ini) -> + Ast.InitGccIndex(mcode lb,expression exp,mcode rb,mcode eq, + initialiser ini) + | Ast0.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> + Ast.InitGccRange(mcode lb,expression exp1,mcode dots, + expression exp2,mcode rb,mcode eq,initialiser ini) + | Ast0.IComma(comma) -> Ast.IComma(mcode comma) + | Ast0.Idots(_,_) -> failwith "Idots should have been removed" + | Ast0.OptIni(ini) -> Ast.OptIni(initialiser ini) + | Ast0.UniqueIni(ini) -> Ast.UniqueIni(initialiser ini)) + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +and parameterTypeDef p = + rewrap p no_isos + (match Ast0.unwrap p with + Ast0.VoidParam(ty) -> Ast.VoidParam(typeC ty) + | Ast0.Param(ty,id) -> Ast.Param(typeC ty,get_option ident id) + | Ast0.MetaParam(name,_) -> + Ast.MetaParam(mcode name,unitary,false) + | Ast0.MetaParamList(name,Some lenname,_) -> + Ast.MetaParamList(mcode name,Some(mcode lenname,unitary,false), + unitary,false) + | Ast0.MetaParamList(name,None,_) -> + Ast.MetaParamList(mcode name,None,unitary,false) + | Ast0.PComma(cm) -> Ast.PComma(mcode cm) + | Ast0.Pdots(dots) -> Ast.Pdots(mcode dots) + | Ast0.Pcircles(dots) -> Ast.Pcircles(mcode dots) + | Ast0.OptParam(param) -> Ast.OptParam(parameterTypeDef param) + | Ast0.UniqueParam(param) -> Ast.UniqueParam(parameterTypeDef param)) + +and parameter_list l = dots parameterTypeDef l + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +and statement s = + let rec statement seqible s = + let rewrap_stmt ast0 ast = + let befaft = + match Ast0.get_dots_bef_aft s with + Ast0.NoDots -> Ast.NoDots + | Ast0.DroppingBetweenDots s -> + Ast.DroppingBetweenDots (statement seqible s,get_ctr()) + | Ast0.AddingBetweenDots s -> + Ast.AddingBetweenDots (statement seqible s,get_ctr()) in + Ast.set_dots_bef_aft befaft (rewrap ast0 no_isos ast) in + let rewrap_rule_elem ast0 ast = + rewrap ast0 (do_isos (Ast0.get_iso ast0)) ast in + rewrap_stmt s + (match Ast0.unwrap s with + Ast0.Decl((_,bef),decl) -> + Ast.Atomic(rewrap_rule_elem s + (Ast.Decl(convert_mcodekind bef, + check_allminus.V0.combiner_statement s, + declaration decl))) + | Ast0.Seq(lbrace,body,rbrace) -> + let lbrace = mcode lbrace in + let (decls,body) = separate_decls seqible body in + let rbrace = mcode rbrace in + Ast.Seq(iso_tokenwrap lbrace s (Ast.SeqStart(lbrace)) + (do_isos (Ast0.get_iso s)), + decls,body, + tokenwrap rbrace s (Ast.SeqEnd(rbrace))) + | Ast0.ExprStatement(exp,sem) -> + Ast.Atomic(rewrap_rule_elem s + (Ast.ExprStatement(expression exp,mcode sem))) + | Ast0.IfThen(iff,lp,exp,rp,branch,(_,aft)) -> + Ast.IfThen + (rewrap_rule_elem s + (Ast.IfHeader(mcode iff,mcode lp,expression exp,mcode rp)), + statement Ast.NotSequencible branch, + ([],[],[],convert_mcodekind aft)) + | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,(_,aft)) -> + let els = mcode els in + Ast.IfThenElse + (rewrap_rule_elem s + (Ast.IfHeader(mcode iff,mcode lp,expression exp,mcode rp)), + statement Ast.NotSequencible branch1, + tokenwrap els s (Ast.Else(els)), + statement Ast.NotSequencible branch2, + ([],[],[],convert_mcodekind aft)) + | Ast0.While(wh,lp,exp,rp,body,(_,aft)) -> + Ast.While(rewrap_rule_elem s + (Ast.WhileHeader + (mcode wh,mcode lp,expression exp,mcode rp)), + statement Ast.NotSequencible body, + ([],[],[],convert_mcodekind aft)) + | Ast0.Do(d,body,wh,lp,exp,rp,sem) -> + let wh = mcode wh in + Ast.Do(rewrap_rule_elem s (Ast.DoHeader(mcode d)), + statement Ast.NotSequencible body, + tokenwrap wh s + (Ast.WhileTail(wh,mcode lp,expression exp,mcode rp, + mcode sem))) + | Ast0.For(fr,lp,exp1,sem1,exp2,sem2,exp3,rp,body,(_,aft)) -> + let fr = mcode fr in + let lp = mcode lp in + let exp1 = get_option expression exp1 in + let sem1 = mcode sem1 in + let exp2 = get_option expression exp2 in + let sem2= mcode sem2 in + let exp3 = get_option expression exp3 in + let rp = mcode rp in + let body = statement Ast.NotSequencible body in + Ast.For(rewrap_rule_elem s + (Ast.ForHeader(fr,lp,exp1,sem1,exp2,sem2,exp3,rp)), + body,([],[],[],convert_mcodekind aft)) + | Ast0.Iterator(nm,lp,args,rp,body,(_,aft)) -> + Ast.Iterator(rewrap_rule_elem s + (Ast.IteratorHeader + (ident nm,mcode lp, + dots expression args, + mcode rp)), + statement Ast.NotSequencible body, + ([],[],[],convert_mcodekind aft)) + | Ast0.Switch(switch,lp,exp,rp,lb,cases,rb) -> + let switch = mcode switch in + let lp = mcode lp in + let exp = expression exp in + let rp = mcode rp in + let lb = mcode lb in + let cases = List.map case_line (Ast0.undots cases) in + let rb = mcode rb in + Ast.Switch(rewrap_rule_elem s (Ast.SwitchHeader(switch,lp,exp,rp)), + tokenwrap lb s (Ast.SeqStart(lb)), + cases, + tokenwrap rb s (Ast.SeqEnd(rb))) + | Ast0.Break(br,sem) -> + Ast.Atomic(rewrap_rule_elem s (Ast.Break(mcode br,mcode sem))) + | Ast0.Continue(cont,sem) -> + Ast.Atomic(rewrap_rule_elem s (Ast.Continue(mcode cont,mcode sem))) + | Ast0.Label(l,dd) -> + Ast.Atomic(rewrap_rule_elem s (Ast.Label(ident l,mcode dd))) + | Ast0.Goto(goto,l,sem) -> + Ast.Atomic + (rewrap_rule_elem s (Ast.Goto(mcode goto,ident l,mcode sem))) + | Ast0.Return(ret,sem) -> + Ast.Atomic(rewrap_rule_elem s (Ast.Return(mcode ret,mcode sem))) + | Ast0.ReturnExpr(ret,exp,sem) -> + Ast.Atomic + (rewrap_rule_elem s + (Ast.ReturnExpr(mcode ret,expression exp,mcode sem))) + | Ast0.MetaStmt(name,_) -> + Ast.Atomic(rewrap_rule_elem s + (Ast.MetaStmt(mcode name,unitary,seqible,false))) + | Ast0.MetaStmtList(name,_) -> + Ast.Atomic(rewrap_rule_elem s + (Ast.MetaStmtList(mcode name,unitary,false))) + | Ast0.TopExp(exp) -> + Ast.Atomic(rewrap_rule_elem s (Ast.TopExp(expression exp))) + | Ast0.Exp(exp) -> + Ast.Atomic(rewrap_rule_elem s (Ast.Exp(expression exp))) + | Ast0.Ty(ty) -> + Ast.Atomic(rewrap_rule_elem s (Ast.Ty(typeC ty))) + | Ast0.Disj(_,rule_elem_dots_list,_,_) -> + Ast.Disj(List.map (function x -> statement_dots seqible x) + rule_elem_dots_list) + | Ast0.Nest(_,rule_elem_dots,_,whn,multi) -> + Ast.Nest + (statement_dots Ast.Sequencible rule_elem_dots, + List.map + (whencode (statement_dots Ast.Sequencible) + (statement Ast.NotSequencible)) + whn, + multi,[],[]) + | Ast0.Dots(d,whn) -> + let d = mcode d in + let whn = + List.map + (whencode (statement_dots Ast.Sequencible) + (statement Ast.NotSequencible)) + whn in + Ast.Dots(d,whn,[],[]) + | Ast0.Circles(d,whn) -> + let d = mcode d in + let whn = + List.map + (whencode (statement_dots Ast.Sequencible) + (statement Ast.NotSequencible)) + whn in + Ast.Circles(d,whn,[],[]) + | Ast0.Stars(d,whn) -> + let d = mcode d in + let whn = + List.map + (whencode (statement_dots Ast.Sequencible) + (statement Ast.NotSequencible)) + whn in + Ast.Stars(d,whn,[],[]) + | Ast0.FunDecl((_,bef),fi,name,lp,params,rp,lbrace,body,rbrace) -> + let fi = List.map fninfo fi in + let name = ident name in + let lp = mcode lp in + let params = parameter_list params in + let rp = mcode rp in + let lbrace = mcode lbrace in + let (decls,body) = separate_decls seqible body in + let rbrace = mcode rbrace in + let allminus = check_allminus.V0.combiner_statement s in + Ast.FunDecl(rewrap_rule_elem s + (Ast.FunHeader(convert_mcodekind bef, + allminus,fi,name,lp,params,rp)), + tokenwrap lbrace s (Ast.SeqStart(lbrace)), + decls,body, + tokenwrap rbrace s (Ast.SeqEnd(rbrace))) + | Ast0.Include(inc,str) -> + Ast.Atomic(rewrap_rule_elem s (Ast.Include(mcode inc,mcode str))) + | Ast0.Define(def,id,params,body) -> + Ast.Define + (rewrap_rule_elem s + (Ast.DefineHeader + (mcode def,ident id, define_parameters params)), + statement_dots Ast.NotSequencible (*not sure*) body) + | Ast0.OptStm(stm) -> Ast.OptStm(statement seqible stm) + | Ast0.UniqueStm(stm) -> Ast.UniqueStm(statement seqible stm)) + + and define_parameters p = + rewrap p no_isos + (match Ast0.unwrap p with + Ast0.NoParams -> Ast.NoParams + | Ast0.DParams(lp,params,rp) -> + Ast.DParams(mcode lp, + dots define_param params, + mcode rp)) + + and define_param p = + rewrap p no_isos + (match Ast0.unwrap p with + Ast0.DParam(id) -> Ast.DParam(ident id) + | Ast0.DPComma(comma) -> Ast.DPComma(mcode comma) + | Ast0.DPdots(d) -> Ast.DPdots(mcode d) + | Ast0.DPcircles(c) -> Ast.DPcircles(mcode c) + | Ast0.OptDParam(dp) -> Ast.OptDParam(define_param dp) + | Ast0.UniqueDParam(dp) -> Ast.UniqueDParam(define_param dp)) + + and whencode notfn alwaysfn = function + Ast0.WhenNot a -> Ast.WhenNot (notfn a) + | Ast0.WhenAlways a -> Ast.WhenAlways (alwaysfn a) + | Ast0.WhenModifier(x) -> Ast.WhenModifier(x) + + and process_list seqible isos = function + [] -> [] + | x::rest -> + let first = statement seqible x in + let first = + if !Flag.track_iso_usage + then Ast.set_isos first (isos@(Ast.get_isos first)) + else first in + (match Ast0.unwrap x with + Ast0.Dots(_,_) | Ast0.Nest(_) -> + first::(process_list (Ast.SequencibleAfterDots []) no_isos rest) + | _ -> + first::(process_list Ast.Sequencible no_isos rest)) + + and statement_dots seqible d = + let isos = do_isos (Ast0.get_iso d) in + rewrap d no_isos + (match Ast0.unwrap d with + Ast0.DOTS(x) -> Ast.DOTS(process_list seqible isos x) + | Ast0.CIRCLES(x) -> Ast.CIRCLES(process_list seqible isos x) + | Ast0.STARS(x) -> Ast.STARS(process_list seqible isos x)) + + and separate_decls seqible d = + let rec collect_decls = function + [] -> ([],[]) + | (x::xs) as l -> + (match Ast0.unwrap x with + Ast0.Decl(_) -> + let (decls,other) = collect_decls xs in + (x :: decls,other) + | Ast0.Dots(_,_) | Ast0.Nest(_,_,_,_,_) -> + let (decls,other) = collect_decls xs in + (match decls with + [] -> ([],x::other) + | _ -> (x :: decls,other)) + | Ast0.Disj(starter,stmt_dots_list,mids,ender) -> + let disjs = List.map collect_dot_decls stmt_dots_list in + let all_decls = List.for_all (function (_,s) -> s=[]) disjs in + if all_decls + then + let (decls,other) = collect_decls xs in + (x :: decls,other) + else ([],l) + | _ -> ([],l)) + + and collect_dot_decls d = + match Ast0.unwrap d with + Ast0.DOTS(x) -> collect_decls x + | Ast0.CIRCLES(x) -> collect_decls x + | Ast0.STARS(x) -> collect_decls x in + + let process l d fn = + let (decls,other) = collect_decls l in + (rewrap d no_isos (fn (List.map (statement seqible) decls)), + rewrap d no_isos + (fn (process_list seqible (do_isos (Ast0.get_iso d)) other))) in + match Ast0.unwrap d with + Ast0.DOTS(x) -> process x d (function x -> Ast.DOTS x) + | Ast0.CIRCLES(x) -> process x d (function x -> Ast.CIRCLES x) + | Ast0.STARS(x) -> process x d (function x -> Ast.STARS x) in + + statement Ast.Sequencible s + +and fninfo = function + Ast0.FStorage(stg) -> Ast.FStorage(mcode stg) + | Ast0.FType(ty) -> Ast.FType(typeC ty) + | Ast0.FInline(inline) -> Ast.FInline(mcode inline) + | Ast0.FAttr(attr) -> Ast.FAttr(mcode attr) + +and option_to_list = function + Some x -> [x] + | None -> [] + +and case_line c = + rewrap c no_isos + (match Ast0.unwrap c with + Ast0.Default(def,colon,code) -> + let def = mcode def in + let colon = mcode colon in + let code = dots statement code in + Ast.CaseLine(rewrap c no_isos (Ast.Default(def,colon)),code) + | Ast0.Case(case,exp,colon,code) -> + let case = mcode case in + let exp = expression exp in + let colon = mcode colon in + let code = dots statement code in + Ast.CaseLine(rewrap c no_isos (Ast.Case(case,exp,colon)),code) + | Ast0.OptCase(case) -> Ast.OptCase(case_line case)) + +and statement_dots l = dots statement l + +(* --------------------------------------------------------------------- *) + +(* what is possible is only what is at the top level in an iso *) +and anything = function + Ast0.DotsExprTag(d) -> Ast.ExprDotsTag(expression_dots d) + | Ast0.DotsParamTag(d) -> Ast.ParamDotsTag(parameter_list d) + | Ast0.DotsInitTag(d) -> failwith "not possible" + | Ast0.DotsStmtTag(d) -> Ast.StmtDotsTag(statement_dots d) + | Ast0.DotsDeclTag(d) -> Ast.DeclDotsTag(declaration_dots d) + | Ast0.DotsCaseTag(d) -> failwith "not possible" + | Ast0.IdentTag(d) -> Ast.IdentTag(ident d) + | Ast0.ExprTag(d) -> Ast.ExpressionTag(expression d) + | Ast0.ArgExprTag(d) | Ast0.TestExprTag(d) -> + failwith "only in isos, not converted to ast" + | Ast0.TypeCTag(d) -> Ast.FullTypeTag(typeC d) + | Ast0.ParamTag(d) -> Ast.ParamTag(parameterTypeDef d) + | Ast0.InitTag(d) -> Ast.InitTag(initialiser d) + | Ast0.DeclTag(d) -> Ast.DeclarationTag(declaration d) + | Ast0.StmtTag(d) -> Ast.StatementTag(statement d) + | Ast0.CaseLineTag(d) -> Ast.CaseLineTag(case_line d) + | Ast0.TopTag(d) -> Ast.Code(top_level d) + | Ast0.IsoWhenTag(_) -> failwith "not possible" + | Ast0.MetaPosTag _ -> failwith "not possible" + +(* --------------------------------------------------------------------- *) +(* Function declaration *) +(* top level isos are probably lost to tracking *) + +and top_level t = + rewrap t no_isos + (match Ast0.unwrap t with + Ast0.FILEINFO(old_file,new_file) -> + Ast.FILEINFO(mcode old_file,mcode new_file) + | Ast0.DECL(stmt) -> Ast.DECL(statement stmt) + | Ast0.CODE(rule_elem_dots) -> + Ast.CODE(statement_dots rule_elem_dots) + | Ast0.ERRORWORDS(exps) -> Ast.ERRORWORDS(List.map expression exps) + | Ast0.OTHER(_) -> failwith "eliminated by top_level") + +(* --------------------------------------------------------------------- *) +(* Entry point for minus code *) + +(* Inline_mcodes is very important - sends + code attached to the - code +down to the mcodes. The functions above can only be used when there is no +attached + code, eg in + code itself. *) +let ast0toast_toplevel x = + inline_mcodes.V0.combiner_top_level x; + top_level x + +let ast0toast name deps dropped exists x is_exp = + List.iter inline_mcodes.V0.combiner_top_level x; + Ast.CocciRule (name,(deps,dropped,exists),List.map top_level x,is_exp) diff --git a/parsing_cocci/ast0toast.mli b/parsing_cocci/ast0toast.mli new file mode 100644 index 0000000..a2dc7c3 --- /dev/null +++ b/parsing_cocci/ast0toast.mli @@ -0,0 +1,26 @@ +val ast0toast : + string -> Ast_cocci.dependency -> string list (* dropped isos *) -> + Ast_cocci.exists -> Ast0_cocci.rule -> bool list -> Ast_cocci.rule +val ast0toast_toplevel : Ast0_cocci.top_level -> Ast_cocci.top_level + +val ident : Ast0_cocci.ident -> Ast_cocci.ident +val expression : Ast0_cocci.expression -> Ast_cocci.expression +val expression_dots : + Ast0_cocci.expression Ast0_cocci.dots -> + Ast_cocci.expression Ast_cocci.dots +val initialiser : Ast0_cocci.initialiser -> Ast_cocci.initialiser +val statement : Ast0_cocci.statement -> Ast_cocci.statement +val statement_dots : + Ast0_cocci.statement Ast0_cocci.dots -> Ast_cocci.statement Ast_cocci.dots +val declaration_dots : + Ast0_cocci.declaration Ast0_cocci.dots -> + Ast_cocci.declaration Ast_cocci.dots +val case_line : Ast0_cocci.case_line -> Ast_cocci.case_line +val typeC : Ast0_cocci.typeC -> Ast_cocci.fullType +val declaration : Ast0_cocci.declaration -> Ast_cocci.declaration +val parameterTypeDef : + Ast0_cocci.parameterTypeDef -> Ast_cocci.parameterTypeDef +val parameter_list : Ast0_cocci.parameter_list -> Ast_cocci.parameter_list +val top_level : Ast0_cocci.top_level -> Ast_cocci.top_level +val mcode : 'a Ast0_cocci.mcode -> 'a Ast_cocci.mcode +val convert_info : Ast0_cocci.info -> Ast_cocci.info diff --git a/parsing_cocci/ast_cocci.ml b/parsing_cocci/ast_cocci.ml new file mode 100644 index 0000000..a98a8dc --- /dev/null +++ b/parsing_cocci/ast_cocci.ml @@ -0,0 +1,668 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* --------------------------------------------------------------------- *) +(* Modified code *) + +type info = { line : int; column : int; + strbef : string list; straft : string list } +type line = int +type meta_name = string * string +(* need to be careful about rewrapping, to avoid duplicating pos info +currently, the pos info is always None until asttoctl2. *) +type 'a wrap = + {node : 'a; + node_line : line; + free_vars : meta_name list; (*free vars*) + minus_free_vars : meta_name list; (*minus free vars*) + fresh_vars : meta_name list; (*fresh vars*) + inherited : meta_name list; (*inherited vars*) + saved_witness : meta_name list; (*witness vars*) + bef_aft : dots_bef_aft; + (* the following is for or expressions *) + pos_info : meta_name mcode option; (* pos info, try not to duplicate *) + true_if_test_exp : bool;(* true if "test_exp from iso", only for exprs *) + (* isos relevant to the term; ultimately only used for rule_elems *) + iso_info : (string*anything) list } + +and 'a befaft = + BEFORE of 'a list list + | AFTER of 'a list list + | BEFOREAFTER of 'a list list * 'a list list + | NOTHING + +and 'a mcode = 'a * info * mcodekind * meta_pos (* pos variable *) + (* pos is an offset indicating where in the C code the mcodekind has an + effect *) + and mcodekind = + MINUS of pos * anything list list + | CONTEXT of pos * anything befaft + | PLUS + and fixpos = + Real of int (* charpos *) | Virt of int * int (* charpos + offset *) + and pos = NoPos | DontCarePos | FixPos of (fixpos * fixpos) + +and dots_bef_aft = + NoDots + | AddingBetweenDots of statement * int (*index of let var*) + | DroppingBetweenDots of statement * int (*index of let var*) + +and inherited = Type_cocci.inherited +and keep_binding = Type_cocci.keep_binding +and multi = bool (*true if a nest is one or more, false if it is zero or more*) + +and end_info = + meta_name list (*free vars*) * meta_name list (*inherited vars*) * + meta_name list (*witness vars*) * mcodekind + +(* --------------------------------------------------------------------- *) +(* Metavariables *) + +and arity = UNIQUE | OPT | MULTI | NONE + +and metavar = + MetaIdDecl of arity * meta_name (* name *) + | MetaFreshIdDecl of arity * meta_name (* name *) + | MetaTypeDecl of arity * meta_name (* name *) + | MetaListlenDecl of meta_name (* name *) + | MetaParamDecl of arity * meta_name (* name *) + | MetaParamListDecl of arity * meta_name (*name*) * meta_name option (*len*) + | MetaConstDecl of + arity * meta_name (* name *) * Type_cocci.typeC list option + | MetaErrDecl of arity * meta_name (* name *) + | MetaExpDecl of + arity * meta_name (* name *) * Type_cocci.typeC list option + | MetaIdExpDecl of + arity * meta_name (* name *) * Type_cocci.typeC list option + | MetaLocalIdExpDecl of + arity * meta_name (* name *) * Type_cocci.typeC list option + | MetaExpListDecl of arity * meta_name (*name*) * meta_name option (*len*) + | MetaStmDecl of arity * meta_name (* name *) + | MetaStmListDecl of arity * meta_name (* name *) + | MetaFuncDecl of arity * meta_name (* name *) + | MetaLocalFuncDecl of arity * meta_name (* name *) + | MetaPosDecl of arity * meta_name (* name *) + | MetaDeclarerDecl of arity * meta_name (* name *) + | MetaIteratorDecl of arity * meta_name (* name *) + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Dots *) + +and 'a base_dots = + DOTS of 'a list + | CIRCLES of 'a list + | STARS of 'a list + +and 'a dots = 'a base_dots wrap + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +and base_ident = + Id of string mcode + + | MetaId of meta_name mcode * ident list * keep_binding * inherited + | MetaFunc of meta_name mcode * ident list * keep_binding * inherited + | MetaLocalFunc of meta_name mcode * ident list * keep_binding * inherited + + | OptIdent of ident + | UniqueIdent of ident + +and ident = base_ident wrap + +(* --------------------------------------------------------------------- *) +(* Expression *) + +and base_expression = + Ident of ident + | Constant of constant mcode + | FunCall of expression * string mcode (* ( *) * + expression dots * string mcode (* ) *) + | Assignment of expression * assignOp mcode * expression * + bool (* true if it can match an initialization *) + | CondExpr of expression * string mcode (* ? *) * expression option * + string mcode (* : *) * expression + | Postfix of expression * fixOp mcode + | Infix of expression * fixOp mcode + | Unary of expression * unaryOp mcode + | Binary of expression * binaryOp mcode * expression + | Nested of expression * binaryOp mcode * expression + | ArrayAccess of expression * string mcode (* [ *) * expression * + string mcode (* ] *) + | RecordAccess of expression * string mcode (* . *) * ident + | RecordPtAccess of expression * string mcode (* -> *) * ident + | Cast of string mcode (* ( *) * fullType * string mcode (* ) *) * + expression + | SizeOfExpr of string mcode (* sizeof *) * expression + | SizeOfType of string mcode (* sizeof *) * string mcode (* ( *) * + fullType * string mcode (* ) *) + | TypeExp of fullType (*type name used as an expression, only in + arg or #define*) + + | Paren of string mcode (* ( *) * expression * + string mcode (* ) *) + + | MetaErr of meta_name mcode * expression list * keep_binding * + inherited + | MetaExpr of meta_name mcode * expression list * keep_binding * + Type_cocci.typeC list option * form * inherited + | MetaExprList of meta_name mcode * listlen option * keep_binding * + inherited (* only in arg lists *) + + | EComma of string mcode (* only in arg lists *) + + | DisjExpr of expression list + | NestExpr of expression dots * expression option * multi + + (* can appear in arg lists, and also inside Nest, as in: + if(< ... X ... Y ...>) + In the following, the expression option is the WHEN *) + | Edots of string mcode (* ... *) * expression option + | Ecircles of string mcode (* ooo *) * expression option + | Estars of string mcode (* *** *) * expression option + + | OptExp of expression + | UniqueExp of expression + +(* ANY = int E; ID = idexpression int X; CONST = constant int X; *) +and form = ANY | ID | LocalID | CONST (* form for MetaExp *) + +and expression = base_expression wrap + +and listlen = meta_name mcode * keep_binding * inherited + +and unaryOp = GetRef | DeRef | UnPlus | UnMinus | Tilde | Not +and assignOp = SimpleAssign | OpAssign of arithOp +and fixOp = Dec | Inc + +and binaryOp = Arith of arithOp | Logical of logicalOp +and arithOp = + Plus | Minus | Mul | Div | Mod | DecLeft | DecRight | And | Or | Xor +and logicalOp = Inf | Sup | InfEq | SupEq | Eq | NotEq | AndLog | OrLog + +and constant = + String of string + | Char of string + | Int of string + | Float of string + +(* --------------------------------------------------------------------- *) +(* Types *) + +and base_fullType = + Type of const_vol mcode option * typeC + | DisjType of fullType list (* only after iso *) + | OptType of fullType + | UniqueType of fullType + +and base_typeC = + BaseType of baseType mcode * sign mcode option + | ImplicitInt of sign mcode + | Pointer of fullType * string mcode (* * *) + | FunctionPointer of fullType * + string mcode(* ( *)*string mcode(* * *)*string mcode(* ) *)* + string mcode (* ( *)*parameter_list*string mcode(* ) *) + + (* used for the automatic managment of prototypes *) + | FunctionType of bool (* true if all minus for dropping return type *) * + fullType option * + string mcode (* ( *) * parameter_list * + string mcode (* ) *) + + | Array of fullType * string mcode (* [ *) * + expression option * string mcode (* ] *) + | StructUnionName of structUnion mcode * ident option (* name *) + | StructUnionDef of fullType (* either StructUnionName or metavar *) * + string mcode (* { *) * declaration dots * string mcode (* } *) + | TypeName of string mcode + + | MetaType of meta_name mcode * keep_binding * inherited + +and fullType = base_fullType wrap +and typeC = base_typeC wrap + +and baseType = VoidType | CharType | ShortType | IntType | DoubleType +| FloatType | LongType + +and structUnion = Struct | Union + +and sign = Signed | Unsigned + +and const_vol = Const | Volatile + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +and base_declaration = + Init of storage mcode option * fullType * ident * string mcode (*=*) * + initialiser * string mcode (*;*) + | UnInit of storage mcode option * fullType * ident * string mcode (* ; *) + | TyDecl of fullType * string mcode (* ; *) + | MacroDecl of ident (* name *) * string mcode (* ( *) * + expression dots * string mcode (* ) *) * string mcode (* ; *) + | Typedef of string mcode (*typedef*) * fullType * + typeC (* either TypeName or metavar *) * string mcode (*;*) + | DisjDecl of declaration list + (* Ddots is for a structure declaration *) + | Ddots of string mcode (* ... *) * declaration option (* whencode *) + + | MetaDecl of meta_name mcode * keep_binding * inherited + + | OptDecl of declaration + | UniqueDecl of declaration + +and declaration = base_declaration wrap + +(* --------------------------------------------------------------------- *) +(* Initializers *) + +and base_initialiser = + InitExpr of expression + | InitList of string mcode (*{*) * initialiser list * string mcode (*}*) * + initialiser list (* whencode: elements that shouldn't appear in init *) + | InitGccDotName of + string mcode (*.*) * ident (* name *) * string mcode (*=*) * + initialiser (* gccext: *) + | InitGccName of ident (* name *) * string mcode (*:*) * + initialiser + | InitGccIndex of + string mcode (*[*) * expression * string mcode (*]*) * + string mcode (*=*) * initialiser + | InitGccRange of + string mcode (*[*) * expression * string mcode (*...*) * + expression * string mcode (*]*) * string mcode (*=*) * initialiser + | IComma of string mcode (* , *) + + | OptIni of initialiser + | UniqueIni of initialiser + +and initialiser = base_initialiser wrap + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +and base_parameterTypeDef = + VoidParam of fullType + | Param of fullType * ident option + + | MetaParam of meta_name mcode * keep_binding * inherited + | MetaParamList of meta_name mcode * listlen option * keep_binding * + inherited + + | PComma of string mcode + + | Pdots of string mcode (* ... *) + | Pcircles of string mcode (* ooo *) + + | OptParam of parameterTypeDef + | UniqueParam of parameterTypeDef + +and parameterTypeDef = base_parameterTypeDef wrap + +and parameter_list = parameterTypeDef dots + +(* --------------------------------------------------------------------- *) +(* #define Parameters *) + +and base_define_param = + DParam of ident + | DPComma of string mcode + | DPdots of string mcode (* ... *) + | DPcircles of string mcode (* ooo *) + | OptDParam of define_param + | UniqueDParam of define_param + +and define_param = base_define_param wrap + +and base_define_parameters = + NoParams (* not parameter list, not an empty one *) + | DParams of string mcode(*( *) * define_param dots * string mcode(* )*) + +and define_parameters = base_define_parameters wrap + +(* --------------------------------------------------------------------- *) +(* positions *) + +(* PER = keep bindings separate, ALL = collect them *) +and meta_collect = PER | ALL + +and meta_pos = + MetaPos of meta_name mcode * meta_name list * + meta_collect * keep_binding * inherited + | NoMetaPos + +(* --------------------------------------------------------------------- *) +(* Function declaration *) + +and storage = Static | Auto | Register | Extern + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +and base_rule_elem = + FunHeader of mcodekind (* before the function header *) * + bool (* true if all minus, for dropping static, etc *) * + fninfo list * ident (* name *) * + string mcode (* ( *) * parameter_list * + string mcode (* ) *) + | Decl of mcodekind (* before the decl *) * + bool (* true if all minus *) * declaration + + | SeqStart of string mcode (* { *) + | SeqEnd of string mcode (* } *) + + | ExprStatement of expression * string mcode (*;*) + | IfHeader of string mcode (* if *) * string mcode (* ( *) * + expression * string mcode (* ) *) + | Else of string mcode (* else *) + | WhileHeader of string mcode (* while *) * string mcode (* ( *) * + expression * string mcode (* ) *) + | DoHeader of string mcode (* do *) + | WhileTail of string mcode (* while *) * string mcode (* ( *) * + expression * string mcode (* ) *) * + string mcode (* ; *) + | ForHeader of string mcode (* for *) * string mcode (* ( *) * + expression option * string mcode (*;*) * + expression option * string mcode (*;*) * + expression option * string mcode (* ) *) + | IteratorHeader of ident (* name *) * string mcode (* ( *) * + expression dots * string mcode (* ) *) + | SwitchHeader of string mcode (* switch *) * string mcode (* ( *) * + expression * string mcode (* ) *) + | Break of string mcode (* break *) * string mcode (* ; *) + | Continue of string mcode (* continue *) * string mcode (* ; *) + | Label of ident * string mcode (* : *) + | Goto of string mcode (* goto *) * ident * string mcode (* ; *) + | Return of string mcode (* return *) * string mcode (* ; *) + | ReturnExpr of string mcode (* return *) * expression * + string mcode (* ; *) + + | MetaRuleElem of meta_name mcode * keep_binding * inherited + | MetaStmt of meta_name mcode * keep_binding * metaStmtInfo * + inherited + | MetaStmtList of meta_name mcode * keep_binding * inherited + + | Exp of expression (* matches a subterm *) + | TopExp of expression (* for macros body, exp at top level, + not subexp *) + | Ty of fullType (* only at SP top level, matches a subterm *) + | Include of string mcode (*#include*) * inc_file mcode (*file *) + | DefineHeader of string mcode (* #define *) * ident (* name *) * + define_parameters (*params*) + | Case of string mcode (* case *) * expression * string mcode (*:*) + | Default of string mcode (* default *) * string mcode (*:*) + | DisjRuleElem of rule_elem list + +and fninfo = + FStorage of storage mcode + | FType of fullType + | FInline of string mcode + | FAttr of string mcode + +and metaStmtInfo = + NotSequencible | SequencibleAfterDots of dots_whencode list | Sequencible + +and rule_elem = base_rule_elem wrap + +and base_statement = + Seq of rule_elem (* { *) * statement dots * + statement dots * rule_elem (* } *) + | IfThen of rule_elem (* header *) * statement * end_info (* endif *) + | IfThenElse of rule_elem (* header *) * statement * + rule_elem (* else *) * statement * end_info (* endif *) + | While of rule_elem (* header *) * statement * end_info (*endwhile*) + | Do of rule_elem (* do *) * statement * rule_elem (* tail *) + | For of rule_elem (* header *) * statement * end_info (*endfor*) + | Iterator of rule_elem (* header *) * statement * end_info (*enditer*) + | Switch of rule_elem (* header *) * rule_elem (* { *) * + case_line list * rule_elem (* } *) + | Atomic of rule_elem + | Disj of statement dots list + | Nest of statement dots * + (statement dots,statement) whencode list * multi * + dots_whencode list * dots_whencode list + | FunDecl of rule_elem (* header *) * rule_elem (* { *) * + statement dots * statement dots * rule_elem (* } *) + | Define of rule_elem (* header *) * statement dots + | Dots of string mcode (* ... *) * + (statement dots,statement) whencode list * + dots_whencode list * dots_whencode list + | Circles of string mcode (* ooo *) * + (statement dots,statement) whencode list * + dots_whencode list * dots_whencode list + | Stars of string mcode (* *** *) * + (statement dots,statement) whencode list * + dots_whencode list * dots_whencode list + | OptStm of statement + | UniqueStm of statement + +and ('a,'b) whencode = + WhenNot of 'a + | WhenAlways of 'b + | WhenModifier of when_modifier + +and when_modifier = + (* The following removes the shortest path constraint. It can be used + with other when modifiers *) + WhenAny + (* The following removes the special consideration of error paths. It + can be used with other when modifiers *) + | WhenStrict + | WhenForall + | WhenExists + +(* only used with asttoctl *) +and dots_whencode = + WParen of rule_elem * meta_name (*pren_var*) + | Other of statement + | Other_dots of statement dots + +and statement = base_statement wrap + +and base_case_line = + CaseLine of rule_elem (* case/default header *) * statement dots + | OptCase of case_line + +and case_line = base_case_line wrap + +and inc_file = + Local of inc_elem list + | NonLocal of inc_elem list + +and inc_elem = + IncPath of string + | IncDots + +and base_top_level = + DECL of statement + | CODE of statement dots + | FILEINFO of string mcode (* old file *) * string mcode (* new file *) + | ERRORWORDS of expression list + +and top_level = base_top_level wrap + +and rulename = + CocciRulename of string option * dependency * + string list * string list * exists * bool + | ScriptRulename of string * dependency + +and rule = + CocciRule of string (* name *) * + (dependency * string list (* dropped isos *) * exists) * top_level list + * bool list + | ScriptRule of string * dependency * (string * meta_name) list * string + +and dependency = + Dep of string (* rule applies for the current binding *) + | AntiDep of string (* rule doesn't apply for the current binding *) + | EverDep of string (* rule applies for some binding *) + | NeverDep of string (* rule never applies for any binding *) + | AndDep of dependency * dependency + | OrDep of dependency * dependency + | NoDep + +and rule_with_metavars = metavar list * rule + +and anything = + FullTypeTag of fullType + | BaseTypeTag of baseType + | StructUnionTag of structUnion + | SignTag of sign + | IdentTag of ident + | ExpressionTag of expression + | ConstantTag of constant + | UnaryOpTag of unaryOp + | AssignOpTag of assignOp + | FixOpTag of fixOp + | BinaryOpTag of binaryOp + | ArithOpTag of arithOp + | LogicalOpTag of logicalOp + | DeclarationTag of declaration + | InitTag of initialiser + | StorageTag of storage + | IncFileTag of inc_file + | Rule_elemTag of rule_elem + | StatementTag of statement + | CaseLineTag of case_line + | ConstVolTag of const_vol + | Token of string * info option + | Code of top_level + | ExprDotsTag of expression dots + | ParamDotsTag of parameterTypeDef dots + | StmtDotsTag of statement dots + | DeclDotsTag of declaration dots + | TypeCTag of typeC + | ParamTag of parameterTypeDef + | SgrepStartTag of string + | SgrepEndTag of string + +(* --------------------------------------------------------------------- *) + +and exists = Exists | Forall | ReverseForall | Undetermined + +(* --------------------------------------------------------------------- *) + +let mkToken x = Token (x,None) + +(* --------------------------------------------------------------------- *) + +let rewrap model x = {model with node = x} +let rewrap_mcode (_,a,b,c) x = (x,a,b,c) +let unwrap x = x.node +let unwrap_mcode (x,_,_,_) = x +let get_mcodekind (_,_,x,_) = x +let get_line x = x.node_line +let get_mcode_line (_,l,_,_) = l.line +let get_fvs x = x.free_vars +let set_fvs fvs x = {x with free_vars = fvs} +let get_mfvs x = x.minus_free_vars +let set_mfvs mfvs x = {x with minus_free_vars = mfvs} +let get_fresh x = x.fresh_vars +let get_inherited x = x.inherited +let get_saved x = x.saved_witness +let get_dots_bef_aft x = x.bef_aft +let set_dots_bef_aft d x = {x with bef_aft = d} +let get_pos x = x.pos_info +let set_pos x pos = {x with pos_info = pos} +let get_test_exp x = x.true_if_test_exp +let set_test_exp x = {x with true_if_test_exp = true} +let get_isos x = x.iso_info +let set_isos x isos = {x with iso_info = isos} +let get_pos_var (_,_,_,p) = p +let set_pos_var vr (a,b,c,_) = (a,b,c,vr) +let drop_pos (a,b,c,_) = (a,b,c,NoMetaPos) + +let get_wcfvs (whencode : ('a wrap, 'b wrap) whencode list) = + Common.union_all + (List.map + (function + WhenNot(a) -> get_fvs a + | WhenAlways(a) -> get_fvs a + | WhenModifier(_) -> []) + whencode) + +(* --------------------------------------------------------------------- *) + +let get_meta_name = function + MetaIdDecl(ar,nm) -> nm + | MetaFreshIdDecl(ar,nm) -> nm + | MetaTypeDecl(ar,nm) -> nm + | MetaListlenDecl(nm) -> nm + | MetaParamDecl(ar,nm) -> nm + | MetaParamListDecl(ar,nm,nm1) -> nm + | MetaConstDecl(ar,nm,ty) -> nm + | MetaErrDecl(ar,nm) -> nm + | MetaExpDecl(ar,nm,ty) -> nm + | MetaIdExpDecl(ar,nm,ty) -> nm + | MetaLocalIdExpDecl(ar,nm,ty) -> nm + | MetaExpListDecl(ar,nm,nm1) -> nm + | MetaStmDecl(ar,nm) -> nm + | MetaStmListDecl(ar,nm) -> nm + | MetaFuncDecl(ar,nm) -> nm + | MetaLocalFuncDecl(ar,nm) -> nm + | MetaPosDecl(ar,nm) -> nm + | MetaDeclarerDecl(ar,nm) -> nm + | MetaIteratorDecl(ar,nm) -> nm + +(* --------------------------------------------------------------------- *) + +let no_info = { line = 0; column = 0; strbef = []; straft = [] } + +let make_term x = + {node = x; + node_line = 0; + free_vars = []; + minus_free_vars = []; + fresh_vars = []; + inherited = []; + saved_witness = []; + bef_aft = NoDots; + pos_info = None; + true_if_test_exp = false; + iso_info = [] } + +let make_meta_rule_elem s d (fvs,fresh,inh) = + {(make_term + (MetaRuleElem((("",s),no_info,d,NoMetaPos),Type_cocci.Unitary,false))) + with free_vars = fvs; fresh_vars = fresh; inherited = inh} + +let make_meta_decl s d (fvs,fresh,inh) = + {(make_term + (MetaDecl((("",s),no_info,d,NoMetaPos),Type_cocci.Unitary,false))) with + free_vars = fvs; fresh_vars = fresh; inherited = inh} + +let make_mcode x = (x,no_info,CONTEXT(NoPos,NOTHING),NoMetaPos) + +(* --------------------------------------------------------------------- *) + +let equal_pos x y = x = y + +(* --------------------------------------------------------------------- *) + +let undots x = + match unwrap x with + DOTS e -> e + | CIRCLES e -> e + | STARS e -> e diff --git a/parsing_cocci/ast_cocci.mli b/parsing_cocci/ast_cocci.mli new file mode 100644 index 0000000..0e5d0da --- /dev/null +++ b/parsing_cocci/ast_cocci.mli @@ -0,0 +1,579 @@ +(* --------------------------------------------------------------------- *) +(* Modified code *) + +type info = { line : int; column : int; + strbef : string list; straft : string list } +type line = int +type meta_name = string * string +type 'a wrap = + {node : 'a; + node_line : line; + free_vars : meta_name list; (*free vars*) + minus_free_vars : meta_name list; (*minus free vars*) + fresh_vars : meta_name list; (*fresh vars*) + inherited : meta_name list; (*inherited vars*) + saved_witness : meta_name list; (*witness vars*) + bef_aft : dots_bef_aft; + pos_info : meta_name mcode option; (* pos info, try not to duplicate *) + true_if_test_exp : bool;(* true if "test_exp from iso", only for exprs *) + (* isos relevant to the term; ultimately only used for rule_elems *) + iso_info : (string*anything) list } + +and 'a befaft = + BEFORE of 'a list list + | AFTER of 'a list list + | BEFOREAFTER of 'a list list * 'a list list + | NOTHING + +and 'a mcode = 'a * info * mcodekind * meta_pos (* pos variable *) + (* pos is an offset indicating where in the C code the mcodekind has an + effect *) + and mcodekind = + MINUS of pos * anything list list + | CONTEXT of pos * anything befaft + | PLUS + and fixpos = + Real of int (* charpos *) | Virt of int * int (* charpos + offset *) + and pos = NoPos | DontCarePos | FixPos of (fixpos * fixpos) + +and dots_bef_aft = + NoDots + | AddingBetweenDots of statement * int (*index of let var*) + | DroppingBetweenDots of statement * int (*index of let var*) + +and inherited = Type_cocci.inherited +and keep_binding = Type_cocci.keep_binding +and multi = bool (*true if a nest is one or more, false if it is zero or more*) + +and end_info = + meta_name list (*free vars*) * meta_name list (*inherited vars*) * + meta_name list (*witness vars*) * mcodekind + +(* --------------------------------------------------------------------- *) +(* Metavariables *) + +and arity = UNIQUE | OPT | MULTI | NONE + +and metavar = + MetaIdDecl of arity * meta_name (* name *) + | MetaFreshIdDecl of arity * meta_name (* name *) + | MetaTypeDecl of arity * meta_name (* name *) + | MetaListlenDecl of meta_name (* name *) + | MetaParamDecl of arity * meta_name (* name *) + | MetaParamListDecl of arity * meta_name (*name*) * meta_name option (*len*) + | MetaConstDecl of + arity * meta_name (* name *) * Type_cocci.typeC list option + | MetaErrDecl of arity * meta_name (* name *) + | MetaExpDecl of + arity * meta_name (* name *) * Type_cocci.typeC list option + | MetaIdExpDecl of + arity * meta_name (* name *) * Type_cocci.typeC list option + | MetaLocalIdExpDecl of + arity * meta_name (* name *) * Type_cocci.typeC list option + | MetaExpListDecl of arity * meta_name (*name*) * meta_name option (*len*) + | MetaStmDecl of arity * meta_name (* name *) + | MetaStmListDecl of arity * meta_name (* name *) + | MetaFuncDecl of arity * meta_name (* name *) + | MetaLocalFuncDecl of arity * meta_name (* name *) + | MetaPosDecl of arity * meta_name (* name *) + | MetaDeclarerDecl of arity * meta_name (* name *) + | MetaIteratorDecl of arity * meta_name (* name *) + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Dots *) + +and 'a base_dots = + DOTS of 'a list + | CIRCLES of 'a list + | STARS of 'a list + +and 'a dots = 'a base_dots wrap + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +and base_ident = + Id of string mcode + + | MetaId of meta_name mcode * ident list * keep_binding * inherited + | MetaFunc of meta_name mcode * ident list * keep_binding * inherited + | MetaLocalFunc of meta_name mcode * ident list * keep_binding * inherited + + | OptIdent of ident + | UniqueIdent of ident + +and ident = base_ident wrap + +(* --------------------------------------------------------------------- *) +(* Expression *) + +and base_expression = + Ident of ident + | Constant of constant mcode + | FunCall of expression * string mcode (* ( *) * + expression dots * string mcode (* ) *) + | Assignment of expression * assignOp mcode * expression * bool + | CondExpr of expression * string mcode (* ? *) * expression option * + string mcode (* : *) * expression + | Postfix of expression * fixOp mcode + | Infix of expression * fixOp mcode + | Unary of expression * unaryOp mcode + | Binary of expression * binaryOp mcode * expression + | Nested of expression * binaryOp mcode * expression + | ArrayAccess of expression * string mcode (* [ *) * expression * + string mcode (* ] *) + | RecordAccess of expression * string mcode (* . *) * ident + | RecordPtAccess of expression * string mcode (* -> *) * ident + | Cast of string mcode (* ( *) * fullType * string mcode (* ) *) * + expression + + | SizeOfExpr of string mcode (* sizeof *) * expression + | SizeOfType of string mcode (* sizeof *) * string mcode (* ( *) * + fullType * string mcode (* ) *) + | TypeExp of fullType + + | Paren of string mcode (* ( *) * expression * + string mcode (* ) *) + + | MetaErr of meta_name mcode * expression list * keep_binding * + inherited + | MetaExpr of meta_name mcode * expression list * keep_binding * + Type_cocci.typeC list option * form * inherited + | MetaExprList of meta_name mcode * listlen option * + keep_binding * inherited (* only in arg lists *) + + | EComma of string mcode (* only in arg lists *) + + | DisjExpr of expression list + | NestExpr of expression dots * expression option * multi + + (* can appear in arg lists, and also inside Nest, as in: + if(< ... X ... Y ...>) + In the following, the expression option is the WHEN *) + | Edots of string mcode (* ... *) * expression option + | Ecircles of string mcode (* ooo *) * expression option + | Estars of string mcode (* *** *) * expression option + + | OptExp of expression + | UniqueExp of expression + +and form = ANY | ID | LocalID | CONST (* form for MetaExp *) + +and expression = base_expression wrap + +and listlen = meta_name mcode * keep_binding * inherited + +and unaryOp = GetRef | DeRef | UnPlus | UnMinus | Tilde | Not +and assignOp = SimpleAssign | OpAssign of arithOp +and fixOp = Dec | Inc + +and binaryOp = Arith of arithOp | Logical of logicalOp +and arithOp = + Plus | Minus | Mul | Div | Mod | DecLeft | DecRight | And | Or | Xor +and logicalOp = Inf | Sup | InfEq | SupEq | Eq | NotEq | AndLog | OrLog + +and constant = + String of string + | Char of string + | Int of string + | Float of string + +(* --------------------------------------------------------------------- *) +(* Types *) + +and base_fullType = + Type of const_vol mcode option * typeC + | DisjType of fullType list (* only after iso *) + | OptType of fullType + | UniqueType of fullType + +and base_typeC = + BaseType of baseType mcode * sign mcode option + | ImplicitInt of sign mcode + | Pointer of fullType * string mcode (* * *) + | FunctionPointer of fullType * + string mcode(* ( *)*string mcode(* * *)*string mcode(* ) *)* + string mcode (* ( *)*parameter_list*string mcode(* ) *) + | FunctionType of bool (* true if all minus for dropping return type *) * + fullType option * + string mcode (* ( *) * parameter_list * + string mcode (* ) *) + | Array of fullType * string mcode (* [ *) * + expression option * string mcode (* ] *) + | StructUnionName of structUnion mcode * ident option (* name *) + | StructUnionDef of fullType (* either StructUnionName or metavar *) * + string mcode (* { *) * declaration dots * string mcode (* } *) + | TypeName of string mcode + + | MetaType of meta_name mcode * keep_binding * inherited + +and fullType = base_fullType wrap +and typeC = base_typeC wrap + +and baseType = VoidType | CharType | ShortType | IntType | DoubleType +| FloatType | LongType + +and structUnion = Struct | Union + +and sign = Signed | Unsigned + +and const_vol = Const | Volatile + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +and base_declaration = + Init of storage mcode option * fullType * ident * string mcode (*=*) * + initialiser * string mcode (*;*) + | UnInit of storage mcode option * fullType * ident * string mcode (* ; *) + | TyDecl of fullType * string mcode (* ; *) + | MacroDecl of ident (* name *) * string mcode (* ( *) * + expression dots * string mcode (* ) *) * string mcode (* ; *) + | Typedef of string mcode (*typedef*) * fullType * typeC * string mcode (*;*) + | DisjDecl of declaration list + | Ddots of string mcode (* ... *) * declaration option (* whencode *) + + | MetaDecl of meta_name mcode * keep_binding * inherited + + | OptDecl of declaration + | UniqueDecl of declaration + +and declaration = base_declaration wrap + +(* --------------------------------------------------------------------- *) +(* Initializers *) + +and base_initialiser = + InitExpr of expression + | InitList of string mcode (*{*) * initialiser list * string mcode (*}*) * + initialiser list (* whencode: elements that shouldn't appear in init *) + | InitGccDotName of + string mcode (*.*) * ident (* name *) * string mcode (*=*) * + initialiser (* gccext: *) + | InitGccName of ident (* name *) * string mcode (*:*) * + initialiser + | InitGccIndex of + string mcode (*[*) * expression * string mcode (*]*) * + string mcode (*=*) * initialiser + | InitGccRange of + string mcode (*[*) * expression * string mcode (*...*) * + expression * string mcode (*]*) * string mcode (*=*) * initialiser + | IComma of string mcode (* , *) + | OptIni of initialiser + | UniqueIni of initialiser + +and initialiser = base_initialiser wrap + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +and base_parameterTypeDef = + VoidParam of fullType + | Param of fullType * ident option + + | MetaParam of meta_name mcode * keep_binding * inherited + | MetaParamList of meta_name mcode * listlen option * keep_binding * + inherited + + | PComma of string mcode + + | Pdots of string mcode (* ... *) + | Pcircles of string mcode (* ooo *) + + | OptParam of parameterTypeDef + | UniqueParam of parameterTypeDef + +and parameterTypeDef = base_parameterTypeDef wrap + +and parameter_list = parameterTypeDef dots + +(* --------------------------------------------------------------------- *) +(* #define Parameters *) + +and base_define_param = + DParam of ident + | DPComma of string mcode + | DPdots of string mcode (* ... *) + | DPcircles of string mcode (* ooo *) + | OptDParam of define_param + | UniqueDParam of define_param + +and define_param = base_define_param wrap + +and base_define_parameters = + NoParams + | DParams of string mcode(*( *) * define_param dots * string mcode(* )*) + +and define_parameters = base_define_parameters wrap + +(* --------------------------------------------------------------------- *) +(* positions *) + +(* PER = keep bindings separate, ANY = collect them *) +and meta_collect = PER | ALL + +and meta_pos = + MetaPos of meta_name mcode * meta_name list * + meta_collect * keep_binding * inherited + | NoMetaPos + +(* --------------------------------------------------------------------- *) +(* Function declaration *) + +and storage = Static | Auto | Register | Extern + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +and base_rule_elem = + FunHeader of mcodekind (* before the function header *) * + bool (* true if all minus, for dropping static, etc *) * + fninfo list * ident (* name *) * + string mcode (* ( *) * parameter_list * + string mcode (* ) *) + | Decl of mcodekind (* before the decl *) * + bool (* true if all minus *) * declaration + + | SeqStart of string mcode (* { *) + | SeqEnd of string mcode (* } *) + + | ExprStatement of expression * string mcode (*;*) + | IfHeader of string mcode (* if *) * string mcode (* ( *) * + expression * string mcode (* ) *) + | Else of string mcode (* else *) + | WhileHeader of string mcode (* while *) * string mcode (* ( *) * + expression * string mcode (* ) *) + | DoHeader of string mcode (* do *) + | WhileTail of string mcode (* while *) * string mcode (* ( *) * + expression * string mcode (* ) *) * + string mcode (* ; *) + | ForHeader of string mcode (* for *) * string mcode (* ( *) * + expression option * string mcode (*;*) * + expression option * string mcode (*;*) * + expression option * string mcode (* ) *) + | IteratorHeader of ident (* name *) * string mcode (* ( *) * + expression dots * string mcode (* ) *) + | SwitchHeader of string mcode (* switch *) * string mcode (* ( *) * + expression * string mcode (* ) *) + | Break of string mcode (* break *) * string mcode (* ; *) + | Continue of string mcode (* continue *) * string mcode (* ; *) + | Label of ident * string mcode (* : *) + | Goto of string mcode (* goto *) * ident * string mcode (* ; *) + | Return of string mcode (* return *) * string mcode (* ; *) + | ReturnExpr of string mcode (* return *) * expression * + string mcode (* ; *) + + | MetaRuleElem of meta_name mcode * keep_binding * inherited + | MetaStmt of meta_name mcode * keep_binding * metaStmtInfo * + inherited + | MetaStmtList of meta_name mcode * keep_binding * inherited + + | Exp of expression + | TopExp of expression (* for macros body *) + | Ty of fullType (* only at top level *) + | Include of string mcode (*#include*) * inc_file mcode (*file *) + | DefineHeader of string mcode (* #define *) * ident (* name *) * + define_parameters (*params*) + | Case of string mcode (* case *) * expression * string mcode (*:*) + | Default of string mcode (* default *) * string mcode (*:*) + | DisjRuleElem of rule_elem list + +and fninfo = + FStorage of storage mcode + | FType of fullType + | FInline of string mcode + | FAttr of string mcode + +and metaStmtInfo = + NotSequencible | SequencibleAfterDots of dots_whencode list | Sequencible + +and rule_elem = base_rule_elem wrap + +and base_statement = + Seq of rule_elem (* { *) * statement dots * + statement dots * rule_elem (* } *) + | IfThen of rule_elem (* header *) * statement * end_info + | IfThenElse of rule_elem (* header *) * statement * + rule_elem (* else *) * statement * end_info + | While of rule_elem (* header *) * statement * end_info + | Do of rule_elem (* do *) * statement * rule_elem (* tail *) + | For of rule_elem (* header *) * statement * end_info + | Iterator of rule_elem (* header *) * statement * end_info (*enditer*) + | Switch of rule_elem (* header *) * rule_elem (* { *) * + case_line list * rule_elem (* } *) + | Atomic of rule_elem + | Disj of statement dots list + | Nest of statement dots * + (statement dots,statement) whencode list * multi * + dots_whencode list * dots_whencode list + | FunDecl of rule_elem (* header *) * rule_elem (* { *) * + statement dots * statement dots * rule_elem (* } *) + | Define of rule_elem (* header *) * statement dots + | Dots of string mcode (* ... *) * + (statement dots,statement) whencode list * + dots_whencode list * dots_whencode list + | Circles of string mcode (* ooo *) * + (statement dots,statement) whencode list * + dots_whencode list * dots_whencode list + | Stars of string mcode (* *** *) * + (statement dots,statement) whencode list * + dots_whencode list * dots_whencode list + | OptStm of statement + | UniqueStm of statement + +and ('a,'b) whencode = + WhenNot of 'a + | WhenAlways of 'b + | WhenModifier of when_modifier + +and when_modifier = + WhenAny + | WhenStrict + | WhenForall + | WhenExists + +and dots_whencode = + WParen of rule_elem * meta_name (*pren_var*) + | Other of statement + | Other_dots of statement dots + +and statement = base_statement wrap + +and base_case_line = + CaseLine of rule_elem (* case/default header *) * statement dots + | OptCase of case_line + +and case_line = base_case_line wrap + +and inc_file = + Local of inc_elem list + | NonLocal of inc_elem list + +and inc_elem = + IncPath of string + | IncDots + +and base_top_level = + DECL of statement + | CODE of statement dots + | FILEINFO of string mcode (* old file *) * string mcode (* new file *) + | ERRORWORDS of expression list + +and top_level = base_top_level wrap + +and rulename = + CocciRulename of string option * dependency * string list * string list * + exists * bool + (* true if the whole thing is an expression *) + | ScriptRulename of string * dependency + +and rule = + CocciRule of string (* name *) * + (dependency * string list (* dropped isos *) * exists) * + top_level list * bool list (* true if generates an exp *) + | ScriptRule of string * dependency * (string * meta_name) list * string + +and dependency = + Dep of string (* rule applies for the current binding *) + | AntiDep of string (* rule doesn't apply for the current binding *) + | EverDep of string (* rule applies for some binding *) + | NeverDep of string (* rule never applies for any binding *) + | AndDep of dependency * dependency + | OrDep of dependency * dependency + | NoDep + +and rule_with_metavars = metavar list * rule + +and anything = + FullTypeTag of fullType + | BaseTypeTag of baseType + | StructUnionTag of structUnion + | SignTag of sign + | IdentTag of ident + | ExpressionTag of expression + | ConstantTag of constant + | UnaryOpTag of unaryOp + | AssignOpTag of assignOp + | FixOpTag of fixOp + | BinaryOpTag of binaryOp + | ArithOpTag of arithOp + | LogicalOpTag of logicalOp + | DeclarationTag of declaration + | InitTag of initialiser + | StorageTag of storage + | IncFileTag of inc_file + | Rule_elemTag of rule_elem + | StatementTag of statement + | CaseLineTag of case_line + | ConstVolTag of const_vol + | Token of string * info option + | Code of top_level + | ExprDotsTag of expression dots + | ParamDotsTag of parameterTypeDef dots + | StmtDotsTag of statement dots + | DeclDotsTag of declaration dots + | TypeCTag of typeC + | ParamTag of parameterTypeDef + | SgrepStartTag of string + | SgrepEndTag of string + +(* --------------------------------------------------------------------- *) + +and exists = Exists | Forall | ReverseForall | Undetermined + +(* --------------------------------------------------------------------- *) + +val mkToken : string -> anything + +val undots : 'a dots -> 'a list + +(* --------------------------------------------------------------------- *) + +val rewrap : 'a wrap -> 'b -> 'b wrap +val rewrap_mcode : 'a mcode -> 'a -> 'a mcode +val unwrap : 'a wrap -> 'a +val unwrap_mcode : 'a mcode -> 'a +val get_mcodekind : 'a mcode -> mcodekind +val get_line : 'a wrap -> line +val get_mcode_line : 'a mcode -> line +val get_fvs : 'a wrap -> meta_name list +val get_wcfvs : ('a wrap,'b wrap) whencode list -> meta_name list +val set_fvs : meta_name list -> 'a wrap -> 'a wrap +val get_mfvs : 'a wrap -> meta_name list +val set_mfvs : meta_name list -> 'a wrap -> 'a wrap +val get_fresh : 'a wrap -> meta_name list +val get_inherited : 'a wrap -> meta_name list +val get_saved : 'a wrap -> meta_name list +val get_dots_bef_aft : statement -> dots_bef_aft +val set_dots_bef_aft : dots_bef_aft -> statement -> statement +val get_pos : 'a wrap -> meta_name mcode option +val set_pos : 'a wrap -> meta_name mcode option -> 'a wrap +val get_test_exp : 'a wrap -> bool +val set_test_exp : expression -> expression +val get_isos : 'a wrap -> (string*anything) list +val set_isos : 'a wrap -> (string*anything) list -> 'a wrap +val get_pos_var : 'a mcode -> meta_pos +val set_pos_var : meta_pos -> 'a mcode -> 'a mcode +val drop_pos : 'a mcode -> 'a mcode + +val get_meta_name : metavar -> meta_name + +val no_info : info + +val make_meta_rule_elem : + string -> mcodekind -> + (meta_name list * meta_name list * meta_name list) -> + rule_elem + +val make_meta_decl : + string -> mcodekind -> + (meta_name list * meta_name list * meta_name list) -> + declaration + +val make_term : 'a -> 'a wrap +val make_mcode : 'a -> 'a mcode + +val equal_pos : fixpos -> fixpos -> bool diff --git a/parsing_cocci/check_meta.ml b/parsing_cocci/check_meta.ml new file mode 100644 index 0000000..28da910 --- /dev/null +++ b/parsing_cocci/check_meta.ml @@ -0,0 +1,528 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* For minus fragment, checks that all of the identifier metavariables that +are used are not declared as fresh, and check that all declared variables +are used. For plus fragment, just check that the variables declared as +fresh are used. What is the issue about error variables? (don't remember) *) + +module Ast0 = Ast0_cocci +module Ast = Ast_cocci +module V0 = Visitor_ast0 + +(* all fresh identifiers *) +let fresh_table = (Hashtbl.create(50) : ((string * string), unit) Hashtbl.t) + +let warning s = Printf.fprintf stderr "warning: %s\n" s + +let promote name = (name,(),Ast0.default_info(),(),None) + +(* --------------------------------------------------------------------- *) + +let find_loop table name = + let rec loop = function + [] -> raise Not_found + | x::xs -> (try Hashtbl.find x name with Not_found -> loop xs) in + loop table + +let check_table table minus (name,_,info,_,_) = + let rl = info.Ast0.line_start in + if minus + then + (try (find_loop table name) := true + with + Not_found -> + (try + Hashtbl.find fresh_table name; + let (_,name) = name in + failwith + (Printf.sprintf + "%d: unexpected use of a fresh identifier %s" rl name) + with Not_found -> ())) + else (try (find_loop table name) := true with Not_found -> ()) + +let get_opt fn = Common.do_option fn + +(* --------------------------------------------------------------------- *) +(* Dots *) + +let dots fn d = + match Ast0.unwrap d with + Ast0.DOTS(x) -> List.iter fn x + | Ast0.CIRCLES(x) -> List.iter fn x + | Ast0.STARS(x) -> List.iter fn x + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +type context = ID | FIELD | FN | GLOBAL + +(* heuristic for distinguishing ifdef variables from undeclared metavariables*) +let is_ifdef name = + String.length name > 2 && String.uppercase name = name + +let ident context old_metas table minus i = + match Ast0.unwrap i with + Ast0.Id((name,_,info,_,_) : string Ast0.mcode) -> + let rl = info.Ast0.line_start in + let err = + if List.exists (function x -> x = name) old_metas + && (minus || Ast0.get_mcodekind i = Ast0.PLUS) + then + begin + warning + (Printf.sprintf + "line %d: %s, previously declared as a metavariable, is used as an identifier" rl name); + true + end + else false in + (match context with + ID -> + if not (is_ifdef name) && minus && not err(* warn only once per id *) + then + warning + (Printf.sprintf "line %d: should %s be a metavariable?" rl name) + | _ -> ()) + | Ast0.MetaId(name,_,_) -> check_table table minus name + | Ast0.MetaFunc(name,_,_) -> check_table table minus name + | Ast0.MetaLocalFunc(name,_,_) -> check_table table minus name + | Ast0.OptIdent(_) | Ast0.UniqueIdent(_) -> + failwith "unexpected code" + +(* --------------------------------------------------------------------- *) +(* Expression *) + +let rec expression context old_metas table minus e = + match Ast0.unwrap e with + Ast0.Ident(id) -> + ident context old_metas table minus id + | Ast0.FunCall(fn,lp,args,rp) -> + expression FN old_metas table minus fn; + dots (expression ID old_metas table minus) args + | Ast0.Assignment(left,op,right,_) -> + expression context old_metas table minus left; + expression ID old_metas table minus right + | Ast0.CondExpr(exp1,why,exp2,colon,exp3) -> + expression ID old_metas table minus exp1; + get_opt (expression ID old_metas table minus) exp2; + expression ID old_metas table minus exp3 + | Ast0.Postfix(exp,op) -> + expression ID old_metas table minus exp + | Ast0.Infix(exp,op) -> + expression ID old_metas table minus exp + | Ast0.Unary(exp,op) -> + expression ID old_metas table minus exp + | Ast0.Binary(left,op,right) -> + expression ID old_metas table minus left; + expression ID old_metas table minus right + | Ast0.Paren(lp,exp,rp) -> + expression ID old_metas table minus exp + | Ast0.ArrayAccess(exp1,lb,exp2,rb) -> + expression ID old_metas table minus exp1; + expression ID old_metas table minus exp2 + | Ast0.RecordAccess(exp,pt,field) -> + expression ID old_metas table minus exp; + ident FIELD old_metas table minus field + | Ast0.RecordPtAccess(exp,ar,field) -> + expression ID old_metas table minus exp; + ident FIELD old_metas table minus field + | Ast0.Cast(lp,ty,rp,exp) -> + typeC old_metas table minus ty; expression ID old_metas table minus exp + | Ast0.SizeOfExpr(szf,exp) -> expression ID old_metas table minus exp + | Ast0.SizeOfType(szf,lp,ty,rp) -> typeC old_metas table minus ty + | Ast0.TypeExp(ty) -> typeC old_metas table minus ty + | Ast0.MetaExpr(name,_,Some tys,_,_) -> + List.iter + (function x -> + match get_type_name x with + Some(ty) -> check_table table minus (promote ty) + | None -> ()) + tys; + check_table table minus name + | Ast0.MetaExpr(name,_,_,_,_) | Ast0.MetaErr(name,_,_) -> + check_table table minus name + | Ast0.MetaExprList(name,None,_) -> + check_table table minus name + | Ast0.MetaExprList(name,Some lenname,_) -> + check_table table minus name; + check_table table minus lenname + | Ast0.DisjExpr(_,exps,_,_) -> + List.iter (expression ID old_metas table minus) exps + | Ast0.NestExpr(_,exp_dots,_,w,_) -> + dots (expression ID old_metas table minus) exp_dots; + get_opt (expression ID old_metas table minus) w + | Ast0.Edots(_,Some x) | Ast0.Ecircles(_,Some x) | Ast0.Estars(_,Some x) -> + expression ID old_metas table minus x + | _ -> () (* no metavariable subterms *) + +and get_type_name = function + Type_cocci.ConstVol(_,ty) | Type_cocci.Pointer(ty) + | Type_cocci.FunctionPointer(ty) | Type_cocci.Array(ty) -> get_type_name ty + | Type_cocci.MetaType(nm,_,_) -> Some nm + | _ -> None + +(* --------------------------------------------------------------------- *) +(* Types *) + +and typeC old_metas table minus t = + match Ast0.unwrap t with + Ast0.ConstVol(cv,ty) -> typeC old_metas table minus ty + | Ast0.Pointer(ty,star) -> typeC old_metas table minus ty + | Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + typeC old_metas table minus ty; + parameter_list old_metas table minus params + | Ast0.FunctionType(ty,lp1,params,rp1) -> + get_opt (typeC old_metas table minus) ty; + parameter_list old_metas table minus params + | Ast0.Array(ty,lb,size,rb) -> + typeC old_metas table minus ty; + get_opt (expression ID old_metas table minus) size + | Ast0.MetaType(name,_) -> + check_table table minus name + | Ast0.DisjType(_,types,_,_) -> + List.iter (typeC old_metas table minus) types + | Ast0.StructUnionName(su,Some id) -> ident GLOBAL old_metas table minus id + | Ast0.StructUnionDef(ty,lb,decls,rb) -> + typeC old_metas table minus ty; + dots (declaration GLOBAL old_metas table minus) decls + | Ast0.OptType(ty) | Ast0.UniqueType(ty) -> + failwith "unexpected code" + | _ -> () (* no metavariable subterms *) + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +and declaration context old_metas table minus d = + match Ast0.unwrap d with + Ast0.Init(stg,ty,id,eq,ini,sem) -> + (match Ast0.unwrap ini with + Ast0.InitExpr exp -> + typeC old_metas table minus ty; + ident context old_metas table minus id; + expression ID old_metas table minus exp + | _ -> + (* + if minus + then + failwith "complex initializer specification not allowed in - code" + else*) + (typeC old_metas table minus ty; + ident context old_metas table minus id; + initialiser old_metas table minus ini)) + | Ast0.UnInit(stg,ty,id,sem) -> + typeC old_metas table minus ty; ident context old_metas table minus id + | Ast0.MacroDecl(name,lp,args,rp,sem) -> + ident ID old_metas table minus name; + dots (expression ID old_metas table minus) args + | Ast0.TyDecl(ty,sem) -> typeC old_metas table minus ty + | Ast0.Typedef(stg,ty,id,sem) -> + typeC old_metas table minus ty; + typeC old_metas table minus id + | Ast0.DisjDecl(_,decls,_,_) -> + List.iter (declaration ID old_metas table minus) decls + | Ast0.Ddots(_,Some x) -> declaration ID old_metas table minus x + | Ast0.Ddots(_,None) -> () + | Ast0.OptDecl(_) | Ast0.UniqueDecl(_) -> + failwith "unexpected code" + +(* --------------------------------------------------------------------- *) +(* Initialiser *) + +and initialiser old_metas table minus ini = + match Ast0.unwrap ini with + Ast0.InitExpr(exp) -> expression ID old_metas table minus exp + | Ast0.InitList(lb,initlist,rb) -> + dots (initialiser old_metas table minus) initlist + | Ast0.InitGccDotName(dot,name,eq,ini) -> + ident FIELD old_metas table minus name; + initialiser old_metas table minus ini + | Ast0.InitGccName(name,eq,ini) -> + ident FIELD old_metas table minus name; + initialiser old_metas table minus ini + | Ast0.InitGccIndex(lb,exp,rb,eq,ini) -> + expression ID old_metas table minus exp; + initialiser old_metas table minus ini + | Ast0.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> + expression ID old_metas table minus exp1; + expression ID old_metas table minus exp2; + initialiser old_metas table minus ini + | Ast0.Idots(_,Some x) -> initialiser old_metas table minus x + | Ast0.OptIni(_) | Ast0.UniqueIni(_) -> + failwith "unexpected code" + | _ -> () (* no metavariable subterms *) + +and initialiser_list old_metas table minus = + dots (initialiser old_metas table minus) + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +and parameterTypeDef old_metas table minus param = + match Ast0.unwrap param with + Ast0.Param(ty,id) -> + get_opt (ident ID old_metas table minus) id; + typeC old_metas table minus ty + | Ast0.MetaParam(name,_) -> + check_table table minus name + | Ast0.MetaParamList(name,None,_) -> + check_table table minus name + | Ast0.MetaParamList(name,Some lenname,_) -> + check_table table minus name; + check_table table minus lenname + | _ -> () (* no metavariable subterms *) + +and parameter_list old_metas table minus = + dots (parameterTypeDef old_metas table minus) + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +and statement old_metas table minus s = + match Ast0.unwrap s with + Ast0.Decl(_,decl) -> declaration ID old_metas table minus decl + | Ast0.Seq(lbrace,body,rbrace) -> dots (statement old_metas table minus) body + | Ast0.ExprStatement(exp,sem) -> expression ID old_metas table minus exp + | Ast0.IfThen(iff,lp,exp,rp,branch,_) -> + expression ID old_metas table minus exp; + statement old_metas table minus branch + | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,_) -> + expression ID old_metas table minus exp; + statement old_metas table minus branch1; + statement old_metas table minus branch2 + | Ast0.While(wh,lp,exp,rp,body,_) -> + expression ID old_metas table minus exp; + statement old_metas table minus body + | Ast0.Do(d,body,wh,lp,exp,rp,sem) -> + statement old_metas table minus body; + expression ID old_metas table minus exp + | Ast0.For(fr,lp,exp1,sem1,exp2,sem2,exp3,rp,body,_) -> + get_opt (expression ID old_metas table minus) exp1; + get_opt (expression ID old_metas table minus) exp2; + get_opt (expression ID old_metas table minus) exp3; + statement old_metas table minus body + | Ast0.Iterator(nm,lp,args,rp,body,_) -> + ident ID old_metas table minus nm; + dots (expression ID old_metas table minus) args; + statement old_metas table minus body + | Ast0.Switch(switch,lp,exp,rp,lb,cases,rb) -> + expression ID old_metas table minus exp; + dots (case_line old_metas table minus) cases + | Ast0.ReturnExpr(ret,exp,sem) -> expression ID old_metas table minus exp + | Ast0.MetaStmt(name,_) -> check_table table minus name + | Ast0.MetaStmtList(name,_) -> check_table table minus name + | Ast0.Exp(exp) -> expression ID old_metas table minus exp + | Ast0.TopExp(exp) -> expression ID old_metas table minus exp + | Ast0.Ty(ty) -> typeC old_metas table minus ty + | Ast0.Disj(_,rule_elem_dots_list,_,_) -> + List.iter (dots (statement old_metas table minus)) rule_elem_dots_list + | Ast0.Nest(_,rule_elem_dots,_,w,_) -> + dots (statement old_metas table minus) rule_elem_dots; + List.iter (whencode (dots (statement old_metas table minus)) + (statement old_metas table minus)) + w + | Ast0.Dots(_,x) | Ast0.Circles(_,x) | Ast0.Stars(_,x) -> + List.iter + (whencode (dots (statement old_metas table minus)) + (statement old_metas table minus)) x + | Ast0.FunDecl(_,fi,name,lp,params,rp,lbrace,body,rbrace) -> + ident FN old_metas table minus name; + List.iter (fninfo old_metas table minus) fi; + parameter_list old_metas table minus params; + dots (statement old_metas table minus) body + | Ast0.Include(inc,s) -> () (* no metavariables possible *) + | Ast0.Define(def,id,_,body) -> + ident GLOBAL old_metas table minus id; + dots (statement old_metas table minus) body + | Ast0.Goto(_,i,_) -> ident ID old_metas table minus i + | _ -> () (* no metavariable subterms *) + +and fninfo old_metas table minus = function + Ast0.FStorage(stg) -> () + | Ast0.FType(ty) -> typeC old_metas table minus ty + | Ast0.FInline(inline) -> () + | Ast0.FAttr(attr) -> () + +and whencode notfn alwaysfn = function + Ast0.WhenNot a -> notfn a + | Ast0.WhenAlways a -> alwaysfn a + | Ast0.WhenModifier(_) -> () + +and case_line old_metas table minus c = + match Ast0.unwrap c with + Ast0.Default(def,colon,code) -> + dots (statement old_metas table minus) code + | Ast0.Case(case,exp,colon,code) -> + dots (statement old_metas table minus) code + | Ast0.OptCase(case) -> failwith "unexpected code" + +(* --------------------------------------------------------------------- *) +(* Rules *) + +let top_level old_metas table minus t = + match Ast0.unwrap t with + Ast0.DECL(stmt) -> statement old_metas table minus stmt + | Ast0.CODE(stmt_dots) -> dots (statement old_metas table minus) stmt_dots + | Ast0.ERRORWORDS(exps) -> + List.iter (expression FN old_metas table minus) exps + | _ -> () (* no metavariables possible *) + +let rule old_metas table minus rules = + List.iter (top_level old_metas table minus) rules + +(* --------------------------------------------------------------------- *) + +let positions table rules = + let mcode x = + match Ast0.get_pos x with + Ast0.MetaPos(name,constraints,_) -> + let pos = Ast0.unwrap_mcode name in + (find_loop table pos) := true + | _ -> () in + let option_default = () in + let bind x y = () in + let donothing r k e = k e in + let fn = + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing donothing + donothing donothing in + + List.iter fn.V0.combiner_top_level rules + +let dup_positions rules = + let mcode x = + match Ast0.get_pos x with + Ast0.MetaPos(name,constraints,_) -> + let pos = Ast0.unwrap_mcode name in [pos] + | _ -> [] in + let option_default = [] in + let bind x y = x@y in + + (* Case for everything that has a disj. + Note, no positions on ( | ) of a disjunction, so no need to recurse on + these. *) + + let expression r k e = + match Ast0.unwrap e with + Ast0.DisjExpr(_,explist,_,_) -> + List.fold_left Common.union_set option_default + (List.map r.V0.combiner_expression explist) + | _ -> k e in + + let typeC r k e = (* not sure relevent because "only after iso" *) + match Ast0.unwrap e with + Ast0.DisjType(_,types,_,_) -> + List.fold_left Common.union_set option_default + (List.map r.V0.combiner_typeC types) + | _ -> k e in + + let declaration r k e = + match Ast0.unwrap e with + Ast0.DisjDecl(_,decls,_,_) -> + List.fold_left Common.union_set option_default + (List.map r.V0.combiner_declaration decls) + | _ -> k e in + + let statement r k e = + match Ast0.unwrap e with + Ast0.Disj(_,stmts,_,_) -> + List.fold_left Common.union_set option_default + (List.map r.V0.combiner_statement_dots stmts) + | _ -> k e in + + let donothing r k e = k e in + let fn = + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing expression typeC donothing donothing declaration statement + donothing donothing in + + let res = + List.sort compare + (List.fold_left Common.union_set option_default + (List.map fn.V0.combiner_top_level rules)) in + let rec loop = function + [] | [_] -> () + | ((rule,name) as x)::y::_ when x = y -> + failwith (Printf.sprintf "duplicate use of %s.%s" rule name) + | _::xs -> loop xs in + loop res + +(* --------------------------------------------------------------------- *) + +let make_table l = + let table = + (Hashtbl.create(List.length l) : + ((string * string), bool ref) Hashtbl.t) in + List.iter + (function x -> Hashtbl.add table (Ast.get_meta_name x) (ref false)) l; + table + +let add_to_fresh_table l = + List.iter + (function x -> + let name = Ast.get_meta_name x in Hashtbl.replace fresh_table name ()) + l + +let check_all_marked rname err table after_err = + Hashtbl.iter + (function name -> + function (cell) -> + if not (!cell) + then + let (_,name) = name in + warning + (Printf.sprintf "%s: %s %s not used %s" rname err name after_err)) + table + +let check_meta rname old_metas inherited_metavars metavars minus plus = + let old_metas = + List.map (function (_,x) -> x) (List.map Ast.get_meta_name old_metas) in + let (fresh,other) = + List.partition (function Ast.MetaFreshIdDecl(_,_) -> true | _ -> false) + metavars in + let (err,other) = + List.partition (function Ast.MetaErrDecl(_,_) -> true | _ -> false) + other in + let (ierr,iother) = + List.partition (function Ast.MetaErrDecl(_,_) -> true | _ -> false) + inherited_metavars in + let fresh_table = make_table fresh in + let err_table = make_table (err@ierr) in + let other_table = make_table other in + let iother_table = make_table iother in + add_to_fresh_table fresh; + rule old_metas [iother_table;other_table;err_table] true minus; + positions [iother_table;other_table] minus; + dup_positions minus; + check_all_marked rname "metavariable" other_table "in the - or context code"; + rule old_metas [iother_table;fresh_table;err_table] false plus; + check_all_marked rname "fresh identifier metavariable" iother_table + "in the -, +, or context code"; + check_all_marked rname "metavariable" fresh_table "in the + code"; + check_all_marked rname "error metavariable" err_table "" diff --git a/parsing_cocci/check_meta.mli b/parsing_cocci/check_meta.mli new file mode 100644 index 0000000..d239fc2 --- /dev/null +++ b/parsing_cocci/check_meta.mli @@ -0,0 +1,6 @@ +val check_meta : + string -> + Ast_cocci.metavar list (* old metavariables *) -> + Ast_cocci.metavar list (* explicitly inherited *) -> + Ast_cocci.metavar list (* declared locally *) -> + Ast0_cocci.rule -> Ast0_cocci.rule -> unit diff --git a/parsing_cocci/comm_assoc.ml b/parsing_cocci/comm_assoc.ml new file mode 100644 index 0000000..9266cd7 --- /dev/null +++ b/parsing_cocci/comm_assoc.ml @@ -0,0 +1,86 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* searches for E op ..., for any commutative and associative binary +operator. When this satisfies the isomorphism conditions (ie all minus, or +context for the op and ...), then this is converted to Nested(E,op). +Nested is not used before this phase. *) + +module Ast = Ast_cocci +module Ast0 = Ast0_cocci +module V0 = Visitor_ast0 + +let comm_assoc = + [Ast.Arith(Ast.Plus);Ast.Arith(Ast.Mul);Ast.Arith(Ast.And);Ast.Arith(Ast.Or); + Ast.Logical(Ast.AndLog);Ast.Logical(Ast.OrLog)] + +let is_minus e = + match Ast0.get_mcodekind e with Ast0.MINUS(cell) -> true | _ -> false + +let is_context e = + !Flag.sgrep_mode2 or (* everything is context for sgrep *) + (match Ast0.get_mcodekind e with + Ast0.CONTEXT(cell) -> true + | _ -> false) + +let nopos mc = + match Ast0.get_pos mc with Ast0.MetaPos _ -> false | Ast0.NoMetaPos -> true + +let process_binops rule_name = + let donothing r k e = k e in + let mcode x = x in + let expr r k e1 = + let e = k e1 in + match Ast0.unwrap e with + Ast0.Binary(left,op,right) + when List.mem (Ast0.unwrap_mcode op) comm_assoc -> + (match Ast0.unwrap right with + Ast0.Edots(d,None) -> + if (is_minus e || (is_context e && is_context right)) + && nopos op && nopos d + (* keep dots to record required modif *) + then Ast0.rewrap e (Ast0.Nested(left,op,right)) + else + (Printf.printf + "%s: position variables or mixed modifs interfere with comm_assoc iso" rule_name; + Unparse_ast0.expression e1; + Format.print_newline(); + e) + | Ast0.Edots(d,_) -> + (Printf.printf + "%s: whencode interferes with comm_assoc iso" rule_name; + Unparse_ast0.expression e1; + Format.print_newline(); + e) + | _ -> e) + | _ -> e in + V0.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing expr donothing donothing donothing donothing donothing + donothing donothing + +let comm_assoc rule rule_name dropped_isos = + if List.mem "comm_assoc" dropped_isos + then rule + else List.map (process_binops rule_name).V0.rebuilder_top_level rule diff --git a/parsing_cocci/comm_assoc.mli b/parsing_cocci/comm_assoc.mli new file mode 100644 index 0000000..351633b --- /dev/null +++ b/parsing_cocci/comm_assoc.mli @@ -0,0 +1,3 @@ +val comm_assoc : + Ast0_cocci.rule -> string (* rule name *) -> + string list (* dropped isos *) -> Ast0_cocci.rule diff --git a/parsing_cocci/compute_lines.ml b/parsing_cocci/compute_lines.ml new file mode 100644 index 0000000..5a08d1f --- /dev/null +++ b/parsing_cocci/compute_lines.ml @@ -0,0 +1,760 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* Computes starting and ending logical lines for statements and +expressions. every node gets an index as well. *) + +module Ast0 = Ast0_cocci +module Ast = Ast_cocci + +(* --------------------------------------------------------------------- *) +(* Result *) + +let mkres x e left right = + let lstart = Ast0.get_info left in + let lend = Ast0.get_info right in + let info = + { Ast0.line_start = lstart.Ast0.line_start; + Ast0.line_end = lend.Ast0.line_end; + Ast0.logical_start = lstart.Ast0.logical_start; + Ast0.logical_end = lend.Ast0.logical_end; + Ast0.attachable_start = lstart.Ast0.attachable_start; + Ast0.attachable_end = lend.Ast0.attachable_end; + Ast0.mcode_start = lstart.Ast0.mcode_start; + Ast0.mcode_end = lend.Ast0.mcode_end; + Ast0.column = lstart.Ast0.column; + Ast0.offset = lstart.Ast0.offset; + (* only for tokens, not inherited upwards *) + Ast0.strings_before = []; Ast0.strings_after = []} in + {x with Ast0.node = e; Ast0.info = info} + +let mkmultires x e left right (astart,start_mcodes) (aend,end_mcodes) = + let lstart = Ast0.get_info left in + let lend = Ast0.get_info right in + let info = + { Ast0.line_start = lstart.Ast0.line_start; + Ast0.line_end = lend.Ast0.line_end; + Ast0.logical_start = lstart.Ast0.logical_start; + Ast0.logical_end = lend.Ast0.logical_end; + Ast0.attachable_start = astart; + Ast0.attachable_end = aend; + Ast0.mcode_start = start_mcodes; + Ast0.mcode_end = end_mcodes; + Ast0.column = lstart.Ast0.column; + Ast0.offset = lstart.Ast0.offset; + (* only for tokens, not inherited upwards *) + Ast0.strings_before = []; Ast0.strings_after = [] } in + {x with Ast0.node = e; Ast0.info = info} + +(* --------------------------------------------------------------------- *) + +let get_option fn = function + None -> None + | Some x -> Some (fn x) + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Mcode *) + +let promote_mcode (_,_,info,mcodekind,_) = + let new_info = + {info with + Ast0.mcode_start = [mcodekind]; Ast0.mcode_end = [mcodekind]} in + {(Ast0.wrap ()) with Ast0.info = new_info; Ast0.mcodekind = ref mcodekind} + +let promote_mcode_plus_one (_,_,info,mcodekind,_) = + let new_info = + {info with + Ast0.line_start = info.Ast0.line_start + 1; + Ast0.logical_start = info.Ast0.logical_start + 1; + Ast0.line_end = info.Ast0.line_end + 1; + Ast0.logical_end = info.Ast0.logical_end + 1; + Ast0.mcode_start = [mcodekind]; Ast0.mcode_end = [mcodekind]} in + {(Ast0.wrap ()) with Ast0.info = new_info; Ast0.mcodekind = ref mcodekind} + +let promote_to_statement stm mcodekind = + let info = Ast0.get_info stm in + let new_info = + {info with + Ast0.logical_start = info.Ast0.logical_end; + Ast0.line_start = info.Ast0.line_end; + Ast0.mcode_start = [mcodekind]; Ast0.mcode_end = [mcodekind]; + Ast0.attachable_start = true; Ast0.attachable_end = true} in + {(Ast0.wrap ()) with Ast0.info = new_info; Ast0.mcodekind = ref mcodekind} + +let promote_to_statement_start stm mcodekind = + let info = Ast0.get_info stm in + let new_info = + {info with + Ast0.logical_end = info.Ast0.logical_start; + Ast0.line_end = info.Ast0.line_start; + Ast0.mcode_start = [mcodekind]; Ast0.mcode_end = [mcodekind]; + Ast0.attachable_start = true; Ast0.attachable_end = true} in + {(Ast0.wrap ()) with Ast0.info = new_info; Ast0.mcodekind = ref mcodekind} + +(* mcode is good by default *) +let bad_mcode (t,a,info,mcodekind,pos) = + let new_info = + {info with Ast0.attachable_start = false; Ast0.attachable_end = false} in + (t,a,new_info,mcodekind,pos) + +let get_all_start_info l = + (List.for_all (function x -> (Ast0.get_info x).Ast0.attachable_start) l, + List.concat (List.map (function x -> (Ast0.get_info x).Ast0.mcode_start) l)) + +let get_all_end_info l = + (List.for_all (function x -> (Ast0.get_info x).Ast0.attachable_end) l, + List.concat (List.map (function x -> (Ast0.get_info x).Ast0.mcode_end) l)) + +(* --------------------------------------------------------------------- *) +(* Dots *) + +(* for the logline classification and the mcode field, on both sides, skip +over initial minus dots, as they don't contribute anything *) +let dot_list is_dots fn = function + [] -> failwith "dots should not be empty" + | l -> + let get_node l fn = + let first = List.hd l in + let chosen = + match (is_dots first, l) with (true,_::x::_) -> x | _ -> first in + (* get the logline decorator and the mcodekind of the chosen node *) + fn (Ast0.get_info chosen) in + let forward = List.map fn l in + let backward = List.rev forward in + let (first_attachable,first_mcode) = + get_node forward + (function x -> (x.Ast0.attachable_start,x.Ast0.mcode_start)) in + let (last_attachable,last_mcode) = + get_node backward + (function x -> (x.Ast0.attachable_end,x.Ast0.mcode_end)) in + let first = List.hd forward in + let last = List.hd backward in + let first_info = + { (Ast0.get_info first) with + Ast0.attachable_start = first_attachable; + Ast0.mcode_start = first_mcode } in + let last_info = + { (Ast0.get_info last) with + Ast0.attachable_end = last_attachable; + Ast0.mcode_end = last_mcode } in + let first = Ast0.set_info first first_info in + let last = Ast0.set_info last last_info in + (forward,first,last) + +let dots is_dots prev fn d = + match (prev,Ast0.unwrap d) with + (Some prev,Ast0.DOTS([])) -> + mkres d (Ast0.DOTS []) prev prev + | (None,Ast0.DOTS([])) -> + Ast0.set_info d + {(Ast0.get_info d) + with Ast0.attachable_start = false; Ast0.attachable_end = false} + | (_,Ast0.DOTS(x)) -> + let (l,lstart,lend) = dot_list is_dots fn x in + mkres d (Ast0.DOTS l) lstart lend + | (_,Ast0.CIRCLES(x)) -> + let (l,lstart,lend) = dot_list is_dots fn x in + mkres d (Ast0.CIRCLES l) lstart lend + | (_,Ast0.STARS(x)) -> + let (l,lstart,lend) = dot_list is_dots fn x in + mkres d (Ast0.STARS l) lstart lend + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +let rec ident i = + match Ast0.unwrap i with + Ast0.Id(name) as ui -> + let name = promote_mcode name in mkres i ui name name + | Ast0.MetaId(name,_,_) + | Ast0.MetaFunc(name,_,_) | Ast0.MetaLocalFunc(name,_,_) as ui -> + let name = promote_mcode name in mkres i ui name name + | Ast0.OptIdent(id) -> + let id = ident id in mkres i (Ast0.OptIdent(id)) id id + | Ast0.UniqueIdent(id) -> + let id = ident id in mkres i (Ast0.UniqueIdent(id)) id id + +(* --------------------------------------------------------------------- *) +(* Expression *) + +let is_exp_dots e = + match Ast0.unwrap e with + Ast0.Edots(_,_) | Ast0.Ecircles(_,_) | Ast0.Estars(_,_) -> true + | _ -> false + +let rec expression e = + match Ast0.unwrap e with + Ast0.Ident(id) -> + let id = ident id in + mkres e (Ast0.Ident(id)) id id + | Ast0.Constant(const) as ue -> + let ln = promote_mcode const in + mkres e ue ln ln + | Ast0.FunCall(fn,lp,args,rp) -> + let fn = expression fn in + let args = dots is_exp_dots (Some(promote_mcode lp)) expression args in + mkres e (Ast0.FunCall(fn,lp,args,rp)) fn (promote_mcode rp) + | Ast0.Assignment(left,op,right,simple) -> + let left = expression left in + let right = expression right in + mkres e (Ast0.Assignment(left,op,right,simple)) left right + | Ast0.CondExpr(exp1,why,exp2,colon,exp3) -> + let exp1 = expression exp1 in + let exp2 = get_option expression exp2 in + let exp3 = expression exp3 in + mkres e (Ast0.CondExpr(exp1,why,exp2,colon,exp3)) exp1 exp3 + | Ast0.Postfix(exp,op) -> + let exp = expression exp in + mkres e (Ast0.Postfix(exp,op)) exp (promote_mcode op) + | Ast0.Infix(exp,op) -> + let exp = expression exp in + mkres e (Ast0.Infix(exp,op)) (promote_mcode op) exp + | Ast0.Unary(exp,op) -> + let exp = expression exp in + mkres e (Ast0.Unary(exp,op)) (promote_mcode op) exp + | Ast0.Binary(left,op,right) -> + let left = expression left in + let right = expression right in + mkres e (Ast0.Binary(left,op,right)) left right + | Ast0.Nested(left,op,right) -> + let left = expression left in + let right = expression right in + mkres e (Ast0.Nested(left,op,right)) left right + | Ast0.Paren(lp,exp,rp) -> + mkres e (Ast0.Paren(lp,expression exp,rp)) + (promote_mcode lp) (promote_mcode rp) + | Ast0.ArrayAccess(exp1,lb,exp2,rb) -> + let exp1 = expression exp1 in + let exp2 = expression exp2 in + mkres e (Ast0.ArrayAccess(exp1,lb,exp2,rb)) exp1 (promote_mcode rb) + | Ast0.RecordAccess(exp,pt,field) -> + let exp = expression exp in + let field = ident field in + mkres e (Ast0.RecordAccess(exp,pt,field)) exp field + | Ast0.RecordPtAccess(exp,ar,field) -> + let exp = expression exp in + let field = ident field in + mkres e (Ast0.RecordPtAccess(exp,ar,field)) exp field + | Ast0.Cast(lp,ty,rp,exp) -> + let exp = expression exp in + mkres e (Ast0.Cast(lp,typeC ty,rp,exp)) (promote_mcode lp) exp + | Ast0.SizeOfExpr(szf,exp) -> + let exp = expression exp in + mkres e (Ast0.SizeOfExpr(szf,exp)) (promote_mcode szf) exp + | Ast0.SizeOfType(szf,lp,ty,rp) -> + mkres e (Ast0.SizeOfType(szf,lp,typeC ty,rp)) + (promote_mcode szf) (promote_mcode rp) + | Ast0.TypeExp(ty) -> + let ty = typeC ty in mkres e (Ast0.TypeExp(ty)) ty ty + | Ast0.MetaErr(name,_,_) | Ast0.MetaExpr(name,_,_,_,_) + | Ast0.MetaExprList(name,_,_) as ue -> + let ln = promote_mcode name in mkres e ue ln ln + | Ast0.EComma(cm) -> + let cm = bad_mcode cm in + let ln = promote_mcode cm in + mkres e (Ast0.EComma(cm)) ln ln + | Ast0.DisjExpr(starter,exps,mids,ender) -> + let starter = bad_mcode starter in + let exps = List.map expression exps in + let mids = List.map bad_mcode mids in + let ender = bad_mcode ender in + mkmultires e (Ast0.DisjExpr(starter,exps,mids,ender)) + (promote_mcode starter) (promote_mcode ender) + (get_all_start_info exps) (get_all_end_info exps) + | Ast0.NestExpr(starter,exp_dots,ender,whencode,multi) -> + let exp_dots = dots is_exp_dots None expression exp_dots in + let starter = bad_mcode starter in + let ender = bad_mcode ender in + mkres e (Ast0.NestExpr(starter,exp_dots,ender,whencode,multi)) + (promote_mcode starter) (promote_mcode ender) + | Ast0.Edots(dots,whencode) -> + let dots = bad_mcode dots in + let ln = promote_mcode dots in + mkres e (Ast0.Edots(dots,whencode)) ln ln + | Ast0.Ecircles(dots,whencode) -> + let dots = bad_mcode dots in + let ln = promote_mcode dots in + mkres e (Ast0.Ecircles(dots,whencode)) ln ln + | Ast0.Estars(dots,whencode) -> + let dots = bad_mcode dots in + let ln = promote_mcode dots in + mkres e (Ast0.Estars(dots,whencode)) ln ln + | Ast0.OptExp(exp) -> + let exp = expression exp in + mkres e (Ast0.OptExp(exp)) exp exp + | Ast0.UniqueExp(exp) -> + let exp = expression exp in + mkres e (Ast0.UniqueExp(exp)) exp exp + +and expression_dots x = dots is_exp_dots None expression x + +(* --------------------------------------------------------------------- *) +(* Types *) + +and typeC t = + match Ast0.unwrap t with + Ast0.ConstVol(cv,ty) -> + let ty = typeC ty in + mkres t (Ast0.ConstVol(cv,ty)) (promote_mcode cv) ty + | Ast0.BaseType(ty,None) as ut -> + mkres t ut (promote_mcode ty) (promote_mcode ty) + | Ast0.BaseType(ty,Some sgn) as ut -> + mkres t ut (promote_mcode sgn) (promote_mcode ty) + | Ast0.ImplicitInt(sgn) as ut -> + mkres t ut (promote_mcode sgn) (promote_mcode sgn) + | Ast0.Pointer(ty,star) -> + let ty = typeC ty in + mkres t (Ast0.Pointer(ty,star)) ty (promote_mcode star) + | Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + let ty = typeC ty in + let params = parameter_list (Some(promote_mcode lp2)) params in + mkres t (Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2)) + ty (promote_mcode rp2) + | Ast0.FunctionType(Some ty,lp1,params,rp1) -> + let ty = typeC ty in + let params = parameter_list (Some(promote_mcode lp1)) params in + let res = Ast0.FunctionType(Some ty,lp1,params,rp1) in + mkres t res ty (promote_mcode rp1) + | Ast0.FunctionType(None,lp1,params,rp1) -> + let params = parameter_list (Some(promote_mcode lp1)) params in + let res = Ast0.FunctionType(None,lp1,params,rp1) in + mkres t res (promote_mcode lp1) (promote_mcode rp1) + | Ast0.Array(ty,lb,size,rb) -> + let ty = typeC ty in + mkres t (Ast0.Array(ty,lb,get_option expression size,rb)) + ty (promote_mcode rb) + | Ast0.StructUnionName(kind,Some name) -> + let name = ident name in + mkres t (Ast0.StructUnionName(kind,Some name)) (promote_mcode kind) name + | Ast0.StructUnionName(kind,None) -> + let mc = promote_mcode kind in + mkres t (Ast0.StructUnionName(kind,None)) mc mc + | Ast0.StructUnionDef(ty,lb,decls,rb) -> + let ty = typeC ty in + let decls = + dots is_decl_dots (Some(promote_mcode lb)) declaration decls in + mkres t (Ast0.StructUnionDef(ty,lb,decls,rb)) ty (promote_mcode rb) + | Ast0.TypeName(name) as ut -> + let ln = promote_mcode name in mkres t ut ln ln + | Ast0.MetaType(name,_) as ut -> + let ln = promote_mcode name in mkres t ut ln ln + | Ast0.DisjType(starter,types,mids,ender) -> + let starter = bad_mcode starter in + let types = List.map typeC types in + let mids = List.map bad_mcode mids in + let ender = bad_mcode ender in + mkmultires t (Ast0.DisjType(starter,types,mids,ender)) + (promote_mcode starter) (promote_mcode ender) + (get_all_start_info types) (get_all_end_info types) + | Ast0.OptType(ty) -> + let ty = typeC ty in mkres t (Ast0.OptType(ty)) ty ty + | Ast0.UniqueType(ty) -> + let ty = typeC ty in mkres t (Ast0.UniqueType(ty)) ty ty + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +and is_decl_dots s = + match Ast0.unwrap s with + Ast0.Ddots(_,_) -> true + | _ -> false + +and declaration d = + match Ast0.unwrap d with + Ast0.Init(stg,ty,id,eq,exp,sem) -> + let ty = typeC ty in + let id = ident id in + let exp = initialiser exp in + (match stg with + None -> + mkres d (Ast0.Init(stg,ty,id,eq,exp,sem)) ty (promote_mcode sem) + | Some x -> + mkres d (Ast0.Init(stg,ty,id,eq,exp,sem)) + (promote_mcode x) (promote_mcode sem)) + | Ast0.UnInit(stg,ty,id,sem) -> + let ty = typeC ty in + let id = ident id in + (match stg with + None -> + mkres d (Ast0.UnInit(stg,ty,id,sem)) ty (promote_mcode sem) + | Some x -> + mkres d (Ast0.UnInit(stg,ty,id,sem)) + (promote_mcode x) (promote_mcode sem)) + | Ast0.MacroDecl(name,lp,args,rp,sem) -> + let name = ident name in + let args = dots is_exp_dots (Some(promote_mcode lp)) expression args in + mkres d (Ast0.MacroDecl(name,lp,args,rp,sem)) name (promote_mcode sem) + | Ast0.TyDecl(ty,sem) -> + let ty = typeC ty in + mkres d (Ast0.TyDecl(ty,sem)) ty (promote_mcode sem) + | Ast0.Typedef(stg,ty,id,sem) -> + let ty = typeC ty in + let id = typeC id in + mkres d (Ast0.Typedef(stg,ty,id,sem)) + (promote_mcode stg) (promote_mcode sem) + | Ast0.DisjDecl(starter,decls,mids,ender) -> + let starter = bad_mcode starter in + let decls = List.map declaration decls in + let mids = List.map bad_mcode mids in + let ender = bad_mcode ender in + mkmultires d (Ast0.DisjDecl(starter,decls,mids,ender)) + (promote_mcode starter) (promote_mcode ender) + (get_all_start_info decls) (get_all_end_info decls) + | Ast0.Ddots(dots,whencode) -> + let dots = bad_mcode dots in + let ln = promote_mcode dots in + mkres d (Ast0.Ddots(dots,whencode)) ln ln + | Ast0.OptDecl(decl) -> + let decl = declaration decl in + mkres d (Ast0.OptDecl(declaration decl)) decl decl + | Ast0.UniqueDecl(decl) -> + let decl = declaration decl in + mkres d (Ast0.UniqueDecl(declaration decl)) decl decl + +(* --------------------------------------------------------------------- *) +(* Initializer *) + +and is_init_dots i = + match Ast0.unwrap i with + Ast0.Idots(_,_) -> true + | _ -> false + +and initialiser i = + match Ast0.unwrap i with + Ast0.InitExpr(exp) -> + let exp = expression exp in + mkres i (Ast0.InitExpr(exp)) exp exp + | Ast0.InitList(lb,initlist,rb) -> + let initlist = + dots is_init_dots (Some(promote_mcode lb)) initialiser initlist in + mkres i (Ast0.InitList(lb,initlist,rb)) + (promote_mcode lb) (promote_mcode rb) + | Ast0.InitGccDotName(dot,name,eq,ini) -> + let name = ident name in + let ini = initialiser ini in + mkres i (Ast0.InitGccDotName(dot,name,eq,ini)) (promote_mcode dot) ini + | Ast0.InitGccName(name,eq,ini) -> + let name = ident name in + let ini = initialiser ini in + mkres i (Ast0.InitGccName(name,eq,ini)) name ini + | Ast0.InitGccIndex(lb,exp,rb,eq,ini) -> + let exp = expression exp in + let ini = initialiser ini in + mkres i (Ast0.InitGccIndex(lb,exp,rb,eq,ini)) (promote_mcode lb) ini + | Ast0.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> + let exp1 = expression exp1 in + let exp2 = expression exp2 in + let ini = initialiser ini in + mkres i (Ast0.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini)) + (promote_mcode lb) ini + | Ast0.IComma(cm) as up -> + let ln = promote_mcode cm in mkres i up ln ln + | Ast0.Idots(dots,whencode) -> + let dots = bad_mcode dots in + let ln = promote_mcode dots in + mkres i (Ast0.Idots(dots,whencode)) ln ln + | Ast0.OptIni(ini) -> + let ini = initialiser ini in + mkres i (Ast0.OptIni(ini)) ini ini + | Ast0.UniqueIni(ini) -> + let ini = initialiser ini in + mkres i (Ast0.UniqueIni(ini)) ini ini + +and initialiser_list prev = dots is_init_dots prev initialiser + +(* for export *) +and initialiser_dots x = dots is_init_dots None initialiser x + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +and is_param_dots p = + match Ast0.unwrap p with + Ast0.Pdots(_) | Ast0.Pcircles(_) -> true + | _ -> false + +and parameterTypeDef p = + match Ast0.unwrap p with + Ast0.VoidParam(ty) -> + let ty = typeC ty in mkres p (Ast0.VoidParam(ty)) ty ty + | Ast0.Param(ty,Some id) -> + let id = ident id in + let ty = typeC ty in mkres p (Ast0.Param(ty,Some id)) ty id + | Ast0.Param(ty,None) -> + let ty = typeC ty in mkres p (Ast0.Param(ty,None)) ty ty + | Ast0.MetaParam(name,_) as up -> + let ln = promote_mcode name in mkres p up ln ln + | Ast0.MetaParamList(name,_,_) as up -> + let ln = promote_mcode name in mkres p up ln ln + | Ast0.PComma(cm) -> + let cm = bad_mcode cm in + let ln = promote_mcode cm in + mkres p (Ast0.PComma(cm)) ln ln + | Ast0.Pdots(dots) -> + let dots = bad_mcode dots in + let ln = promote_mcode dots in + mkres p (Ast0.Pdots(dots)) ln ln + | Ast0.Pcircles(dots) -> + let dots = bad_mcode dots in + let ln = promote_mcode dots in + mkres p (Ast0.Pcircles(dots)) ln ln + | Ast0.OptParam(param) -> + let res = parameterTypeDef param in + mkres p (Ast0.OptParam(res)) res res + | Ast0.UniqueParam(param) -> + let res = parameterTypeDef param in + mkres p (Ast0.UniqueParam(res)) res res + +and parameter_list prev = dots is_param_dots prev parameterTypeDef + +(* for export *) +let parameter_dots x = dots is_param_dots None parameterTypeDef x + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +let is_stm_dots s = + match Ast0.unwrap s with + Ast0.Dots(_,_) | Ast0.Circles(_,_) | Ast0.Stars(_,_) -> true + | _ -> false + +let rec statement s = + let res = + match Ast0.unwrap s with + Ast0.Decl((_,bef),decl) -> + let decl = declaration decl in + let left = promote_to_statement_start decl bef in + mkres s (Ast0.Decl((Ast0.get_info left,bef),decl)) decl decl + | Ast0.Seq(lbrace,body,rbrace) -> + let body = + dots is_stm_dots (Some(promote_mcode lbrace)) statement body in + mkres s (Ast0.Seq(lbrace,body,rbrace)) + (promote_mcode lbrace) (promote_mcode rbrace) + | Ast0.ExprStatement(exp,sem) -> + let exp = expression exp in + mkres s (Ast0.ExprStatement(exp,sem)) exp (promote_mcode sem) + | Ast0.IfThen(iff,lp,exp,rp,branch,(_,aft)) -> + let exp = expression exp in + let branch = statement branch in + let right = promote_to_statement branch aft in + mkres s (Ast0.IfThen(iff,lp,exp,rp,branch,(Ast0.get_info right,aft))) + (promote_mcode iff) right + | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,(_,aft)) -> + let exp = expression exp in + let branch1 = statement branch1 in + let branch2 = statement branch2 in + let right = promote_to_statement branch2 aft in + mkres s + (Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2, + (Ast0.get_info right,aft))) + (promote_mcode iff) right + | Ast0.While(wh,lp,exp,rp,body,(_,aft)) -> + let exp = expression exp in + let body = statement body in + let right = promote_to_statement body aft in + mkres s (Ast0.While(wh,lp,exp,rp,body,(Ast0.get_info right,aft))) + (promote_mcode wh) right + | Ast0.Do(d,body,wh,lp,exp,rp,sem) -> + let body = statement body in + let exp = expression exp in + mkres s (Ast0.Do(d,body,wh,lp,exp,rp,sem)) + (promote_mcode d) (promote_mcode sem) + | Ast0.For(fr,lp,exp1,sem1,exp2,sem2,exp3,rp,body,(_,aft)) -> + let exp1 = get_option expression exp1 in + let exp2 = get_option expression exp2 in + let exp3 = get_option expression exp3 in + let body = statement body in + let right = promote_to_statement body aft in + mkres s (Ast0.For(fr,lp,exp1,sem1,exp2,sem2,exp3,rp,body, + (Ast0.get_info right,aft))) + (promote_mcode fr) right + | Ast0.Iterator(nm,lp,args,rp,body,(_,aft)) -> + let nm = ident nm in + let args = dots is_exp_dots (Some(promote_mcode lp)) expression args in + let body = statement body in + let right = promote_to_statement body aft in + mkres s (Ast0.Iterator(nm,lp,args,rp,body,(Ast0.get_info right,aft))) + nm right + | Ast0.Switch(switch,lp,exp,rp,lb,cases,rb) -> + let exp = expression exp in + let cases = + dots (function _ -> false) (Some(promote_mcode lb)) case_line cases in + mkres s + (Ast0.Switch(switch,lp,exp,rp,lb,cases,rb)) + (promote_mcode switch) (promote_mcode rb) + | Ast0.Break(br,sem) as us -> + mkres s us (promote_mcode br) (promote_mcode sem) + | Ast0.Continue(cont,sem) as us -> + mkres s us (promote_mcode cont) (promote_mcode sem) + | Ast0.Label(l,dd) -> + let l = ident l in + mkres s (Ast0.Label(l,dd)) l (promote_mcode dd) + | Ast0.Goto(goto,id,sem) -> + let id = ident id in + mkres s (Ast0.Goto(goto,id,sem)) + (promote_mcode goto) (promote_mcode sem) + | Ast0.Return(ret,sem) as us -> + mkres s us (promote_mcode ret) (promote_mcode sem) + | Ast0.ReturnExpr(ret,exp,sem) -> + let exp = expression exp in + mkres s (Ast0.ReturnExpr(ret,exp,sem)) + (promote_mcode ret) (promote_mcode sem) + | Ast0.MetaStmt(name,_) + | Ast0.MetaStmtList(name,_) as us -> + let ln = promote_mcode name in mkres s us ln ln + | Ast0.Exp(exp) -> + let exp = expression exp in + mkres s (Ast0.Exp(exp)) exp exp + | Ast0.TopExp(exp) -> + let exp = expression exp in + mkres s (Ast0.TopExp(exp)) exp exp + | Ast0.Ty(ty) -> + let ty = typeC ty in + mkres s (Ast0.Ty(ty)) ty ty + | Ast0.Disj(starter,rule_elem_dots_list,mids,ender) -> + let starter = bad_mcode starter in + let mids = List.map bad_mcode mids in + let ender = bad_mcode ender in + let rec loop prevs = function + [] -> [] + | stm::stms -> + (dots is_stm_dots (Some(promote_mcode_plus_one(List.hd prevs))) + statement stm):: + (loop (List.tl prevs) stms) in + let elems = loop (starter::mids) rule_elem_dots_list in + mkmultires s (Ast0.Disj(starter,elems,mids,ender)) + (promote_mcode starter) (promote_mcode ender) + (get_all_start_info elems) (get_all_end_info elems) + | Ast0.Nest(starter,rule_elem_dots,ender,whencode,multi) -> + let starter = bad_mcode starter in + let ender = bad_mcode ender in + let rule_elem_dots = dots is_stm_dots None statement rule_elem_dots in + mkres s (Ast0.Nest(starter,rule_elem_dots,ender,whencode,multi)) + (promote_mcode starter) (promote_mcode ender) + | Ast0.Dots(dots,whencode) -> + let dots = bad_mcode dots in + let ln = promote_mcode dots in + mkres s (Ast0.Dots(dots,whencode)) ln ln + | Ast0.Circles(dots,whencode) -> + let dots = bad_mcode dots in + let ln = promote_mcode dots in + mkres s (Ast0.Circles(dots,whencode)) ln ln + | Ast0.Stars(dots,whencode) -> + let dots = bad_mcode dots in + let ln = promote_mcode dots in + mkres s (Ast0.Stars(dots,whencode)) ln ln + | Ast0.FunDecl((_,bef),fninfo,name,lp,params,rp,lbrace,body,rbrace) -> + let fninfo = + List.map + (function Ast0.FType(ty) -> Ast0.FType(typeC ty) | x -> x) + fninfo in + let name = ident name in + let params = parameter_list (Some(promote_mcode lp)) params in + let body = + dots is_stm_dots (Some(promote_mcode lbrace)) statement body in + let left = + (* cases on what is leftmost *) + match fninfo with + [] -> promote_to_statement_start name bef + | Ast0.FStorage(stg)::_ -> + promote_to_statement_start (promote_mcode stg) bef + | Ast0.FType(ty)::_ -> + promote_to_statement_start ty bef + | Ast0.FInline(inline)::_ -> + promote_to_statement_start (promote_mcode inline) bef + | Ast0.FAttr(attr)::_ -> + promote_to_statement_start (promote_mcode attr) bef in + (* pretend it is one line before the start of the function, so that it + will catch things defined at top level. We assume that these will not + be defined on the same line as the function. This is a HACK. + A better approach would be to attach top_level things to this node, + and other things to the node after, but that would complicate + insert_plus, which doesn't distinguish between different mcodekinds *) + let res = + Ast0.FunDecl((Ast0.get_info left,bef),fninfo,name,lp,params,rp,lbrace, + body,rbrace) in + (* have to do this test again, because of typing problems - can't save + the result, only use it *) + (match fninfo with + [] -> mkres s res name (promote_mcode rbrace) + | Ast0.FStorage(stg)::_ -> + mkres s res (promote_mcode stg) (promote_mcode rbrace) + | Ast0.FType(ty)::_ -> mkres s res ty (promote_mcode rbrace) + | Ast0.FInline(inline)::_ -> + mkres s res (promote_mcode inline) (promote_mcode rbrace) + | Ast0.FAttr(attr)::_ -> + mkres s res (promote_mcode attr) (promote_mcode rbrace)) + + | Ast0.Include(inc,stm) -> + mkres s (Ast0.Include(inc,stm)) (promote_mcode inc) (promote_mcode stm) + | Ast0.Define(def,id,params,body) -> + let id = ident id in + let body = dots is_stm_dots None statement body in + mkres s (Ast0.Define(def,id,params,body)) (promote_mcode def) body + | Ast0.OptStm(stm) -> + let stm = statement stm in mkres s (Ast0.OptStm(stm)) stm stm + | Ast0.UniqueStm(stm) -> + let stm = statement stm in mkres s (Ast0.UniqueStm(stm)) stm stm in + Ast0.set_dots_bef_aft res + (match Ast0.get_dots_bef_aft res with + Ast0.NoDots -> Ast0.NoDots + | Ast0.AddingBetweenDots s -> + Ast0.AddingBetweenDots(statement s) + | Ast0.DroppingBetweenDots s -> + Ast0.DroppingBetweenDots(statement s)) + +and case_line c = + match Ast0.unwrap c with + Ast0.Default(def,colon,code) -> + let code = dots is_stm_dots (Some(promote_mcode colon)) statement code in + mkres c (Ast0.Default(def,colon,code)) (promote_mcode def) code + | Ast0.Case(case,exp,colon,code) -> + let exp = expression exp in + let code = dots is_stm_dots (Some(promote_mcode colon)) statement code in + mkres c (Ast0.Case(case,exp,colon,code)) (promote_mcode case) code + | Ast0.OptCase(case) -> + let case = case_line case in mkres c (Ast0.OptCase(case)) case case + +and statement_dots x = dots is_stm_dots None statement x + +(* --------------------------------------------------------------------- *) +(* Function declaration *) + +let top_level t = + match Ast0.unwrap t with + Ast0.FILEINFO(old_file,new_file) -> t + | Ast0.DECL(stmt) -> + let stmt = statement stmt in mkres t (Ast0.DECL(stmt)) stmt stmt + | Ast0.CODE(rule_elem_dots) -> + let rule_elem_dots = dots is_stm_dots None statement rule_elem_dots in + mkres t (Ast0.CODE(rule_elem_dots)) rule_elem_dots rule_elem_dots + | Ast0.ERRORWORDS(exps) -> t + | Ast0.OTHER(_) -> failwith "eliminated by top_level" + +(* --------------------------------------------------------------------- *) +(* Entry points *) + +let compute_lines = List.map top_level + diff --git a/parsing_cocci/compute_lines.mli b/parsing_cocci/compute_lines.mli new file mode 100644 index 0000000..4c6f1b7 --- /dev/null +++ b/parsing_cocci/compute_lines.mli @@ -0,0 +1,23 @@ +val compute_lines : Ast0_cocci.rule -> Ast0_cocci.rule + +val expression_dots : + Ast0_cocci.expression Ast0_cocci.dots -> + Ast0_cocci.expression Ast0_cocci.dots +val parameter_dots : + Ast0_cocci.parameterTypeDef Ast0_cocci.dots -> + Ast0_cocci.parameterTypeDef Ast0_cocci.dots +val initialiser_dots : + Ast0_cocci.initialiser Ast0_cocci.dots -> + Ast0_cocci.initialiser Ast0_cocci.dots +val statement_dots : + Ast0_cocci.statement Ast0_cocci.dots -> + Ast0_cocci.statement Ast0_cocci.dots + +val ident : Ast0_cocci.ident -> Ast0_cocci.ident +val expression : Ast0_cocci.expression -> Ast0_cocci.expression +val typeC : Ast0_cocci.typeC -> Ast0_cocci.typeC +val declaration : Ast0_cocci.declaration -> Ast0_cocci.declaration +val parameterTypeDef : + Ast0_cocci.parameterTypeDef -> Ast0_cocci.parameterTypeDef +val statement : Ast0_cocci.statement -> Ast0_cocci.statement +val top_level : Ast0_cocci.top_level -> Ast0_cocci.top_level diff --git a/parsing_cocci/context_neg.ml b/parsing_cocci/context_neg.ml new file mode 100644 index 0000000..e20fe00 --- /dev/null +++ b/parsing_cocci/context_neg.ml @@ -0,0 +1,992 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* Detects subtrees that are all minus/plus and nodes that are "binding +context nodes". The latter is a node whose structure and immediate tokens +are the same in the minus and plus trees, and such that for every child, +the set of context nodes in the child subtree is the same in the minus and +plus subtrees. *) + +module Ast = Ast_cocci +module Ast0 = Ast0_cocci +module V0 = Visitor_ast0 +module U = Unparse_ast0 + +(* --------------------------------------------------------------------- *) +(* Generic access to code *) + +let set_mcodekind x mcodekind = + match x with + Ast0.DotsExprTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.DotsInitTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.DotsParamTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.DotsStmtTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.DotsDeclTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.DotsCaseTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.IdentTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.ExprTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.ArgExprTag(d) | Ast0.TestExprTag(d) -> + failwith "not possible - iso only" + | Ast0.TypeCTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.ParamTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.DeclTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.InitTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.StmtTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.CaseLineTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.TopTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.IsoWhenTag(_) -> failwith "only within iso phase" + | Ast0.MetaPosTag(p) -> failwith "metapostag only within iso phase" + +let set_index x index = + match x with + Ast0.DotsExprTag(d) -> Ast0.set_index d index + | Ast0.DotsInitTag(d) -> Ast0.set_index d index + | Ast0.DotsParamTag(d) -> Ast0.set_index d index + | Ast0.DotsStmtTag(d) -> Ast0.set_index d index + | Ast0.DotsDeclTag(d) -> Ast0.set_index d index + | Ast0.DotsCaseTag(d) -> Ast0.set_index d index + | Ast0.IdentTag(d) -> Ast0.set_index d index + | Ast0.ExprTag(d) -> Ast0.set_index d index + | Ast0.ArgExprTag(d) | Ast0.TestExprTag(d) -> + failwith "not possible - iso only" + | Ast0.TypeCTag(d) -> Ast0.set_index d index + | Ast0.ParamTag(d) -> Ast0.set_index d index + | Ast0.InitTag(d) -> Ast0.set_index d index + | Ast0.DeclTag(d) -> Ast0.set_index d index + | Ast0.StmtTag(d) -> Ast0.set_index d index + | Ast0.CaseLineTag(d) -> Ast0.set_index d index + | Ast0.TopTag(d) -> Ast0.set_index d index + | Ast0.IsoWhenTag(_) -> failwith "only within iso phase" + | Ast0.MetaPosTag(p) -> failwith "metapostag only within iso phase" + +let get_index = function + Ast0.DotsExprTag(d) -> Index.expression_dots d + | Ast0.DotsInitTag(d) -> Index.initialiser_dots d + | Ast0.DotsParamTag(d) -> Index.parameter_dots d + | Ast0.DotsStmtTag(d) -> Index.statement_dots d + | Ast0.DotsDeclTag(d) -> Index.declaration_dots d + | Ast0.DotsCaseTag(d) -> Index.case_line_dots d + | Ast0.IdentTag(d) -> Index.ident d + | Ast0.ExprTag(d) -> Index.expression d + | Ast0.ArgExprTag(d) | Ast0.TestExprTag(d) -> + failwith "not possible - iso only" + | Ast0.TypeCTag(d) -> Index.typeC d + | Ast0.ParamTag(d) -> Index.parameterTypeDef d + | Ast0.InitTag(d) -> Index.initialiser d + | Ast0.DeclTag(d) -> Index.declaration d + | Ast0.StmtTag(d) -> Index.statement d + | Ast0.CaseLineTag(d) -> Index.case_line d + | Ast0.TopTag(d) -> Index.top_level d + | Ast0.IsoWhenTag(_) -> failwith "only within iso phase" + | Ast0.MetaPosTag(p) -> failwith "metapostag only within iso phase" + +(* --------------------------------------------------------------------- *) +(* Collect the line numbers of the plus code. This is used for disjunctions. +It is not completely clear why this is necessary, but it seems like an easy +fix for whatever is the problem that is discussed in disj_cases *) + +let plus_lines = ref ([] : int list) + +let insert n = + let rec loop = function + [] -> [n] + | x::xs -> + match compare n x with + 1 -> x::(loop xs) + | 0 -> x::xs + | -1 -> n::x::xs + | _ -> failwith "not possible" in + plus_lines := loop !plus_lines + +let find n min max = + let rec loop = function + [] -> (min,max) + | [x] -> if n < x then (min,x) else (x,max) + | x1::x2::rest -> + if n < x1 + then (min,x1) + else if n > x1 && n < x2 then (x1,x2) else loop (x2::rest) in + loop !plus_lines + +let collect_plus_lines top = + plus_lines := []; + let bind x y = () in + let option_default = () in + let donothing r k e = k e in + let mcode (_,_,info,mcodekind,_) = + match mcodekind with + Ast0.PLUS -> insert info.Ast0.line_start + | _ -> () in + let fn = + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing donothing + donothing donothing in + fn.V0.combiner_top_level top + +(* --------------------------------------------------------------------- *) + +type kind = Neutral | AllMarked | NotAllMarked (* marked means + or - *) + +(* --------------------------------------------------------------------- *) +(* The first part analyzes each of the minus tree and the plus tree +separately *) + +(* ints are unique token indices (offset field) *) +type node = + Token (* tokens *) of kind * int (* unique index *) * Ast0.mcodekind * + int list (* context tokens *) + | Recursor (* children *) of kind * + int list (* indices of all tokens at the level below *) * + Ast0.mcodekind list (* tokens at the level below *) * + int list + | Bind (* neighbors *) of kind * + int list (* indices of all tokens at current level *) * + Ast0.mcodekind list (* tokens at current level *) * + int list (* indices of all tokens at the level below *) * + Ast0.mcodekind list (* tokens at the level below *) + * int list list + +let kind2c = function + Neutral -> "neutral" + | AllMarked -> "allmarked" + | NotAllMarked -> "notallmarked" + +let node2c = function + Token(k,_,_,_) -> Printf.sprintf "token %s\n" (kind2c k) + | Recursor(k,_,_,_) -> Printf.sprintf "recursor %s\n" (kind2c k) + | Bind(k,_,_,_,_,_) -> Printf.sprintf "bind %s\n" (kind2c k) + +(* goal: detect negative in both tokens and recursors, or context only in +tokens *) +let bind c1 c2 = + let lub = function + (k1,k2) when k1 = k2 -> k1 + | (Neutral,AllMarked) -> AllMarked + | (AllMarked,Neutral) -> AllMarked + | _ -> NotAllMarked in + match (c1,c2) with + (* token/token *) + (* there are tokens at this level, so ignore the level below *) + (Token(k1,i1,t1,l1),Token(k2,i2,t2,l2)) -> + Bind(lub(k1,k2),[i1;i2],[t1;t2],[],[],[l1;l2]) + + (* token/recursor *) + (* there are tokens at this level, so ignore the level below *) + | (Token(k1,i1,t1,l1),Recursor(k2,_,_,l2)) -> + Bind(lub(k1,k2),[i1],[t1],[],[],[l1;l2]) + | (Recursor(k1,_,_,l1),Token(k2,i2,t2,l2)) -> + Bind(lub(k1,k2),[i2],[t2],[],[],[l1;l2]) + + (* token/bind *) + (* there are tokens at this level, so ignore the level below *) + | (Token(k1,i1,t1,l1),Bind(k2,i2,t2,_,_,l2)) -> + Bind(lub(k1,k2),i1::i2,t1::t2,[],[],l1::l2) + | (Bind(k1,i1,t1,_,_,l1),Token(k2,i2,t2,l2)) -> + Bind(lub(k1,k2),i1@[i2],t1@[t2],[],[],l1@[l2]) + + (* recursor/bind *) + | (Recursor(k1,bi1,bt1,l1),Bind(k2,i2,t2,bi2,bt2,l2)) -> + Bind(lub(k1,k2),i2,t2,bi1@bi2,bt1@bt2,l1::l2) + | (Bind(k1,i1,t1,bi1,bt1,l1),Recursor(k2,bi2,bt2,l2)) -> + Bind(lub(k1,k2),i1,t1,bi1@bi2,bt1@bt2,l1@[l2]) + + (* recursor/recursor and bind/bind - not likely to ever occur *) + | (Recursor(k1,bi1,bt1,l1),Recursor(k2,bi2,bt2,l2)) -> + Bind(lub(k1,k2),[],[],bi1@bi2,bt1@bt2,[l1;l2]) + | (Bind(k1,i1,t1,bi1,bt1,l1),Bind(k2,i2,t2,bi2,bt2,l2)) -> + Bind(lub(k1,k2),i1@i2,t1@t2,bi1@bi2,bt1@bt2,l1@l2) + + +let option_default = (*Bind(Neutral,[],[],[],[],[])*) + Recursor(Neutral,[],[],[]) + +let mcode (_,_,info,mcodekind,pos) = + let offset = info.Ast0.offset in + match mcodekind with + Ast0.MINUS(_) -> Token(AllMarked,offset,mcodekind,[]) + | Ast0.PLUS -> Token(AllMarked,offset,mcodekind,[]) + | Ast0.CONTEXT(_) -> Token(NotAllMarked,offset,mcodekind,[offset]) + | _ -> failwith "not possible" + +let neutral_mcode (_,_,info,mcodekind,pos) = + let offset = info.Ast0.offset in + match mcodekind with + Ast0.MINUS(_) -> Token(Neutral,offset,mcodekind,[]) + | Ast0.PLUS -> Token(Neutral,offset,mcodekind,[]) + | Ast0.CONTEXT(_) -> Token(Neutral,offset,mcodekind,[offset]) + | _ -> failwith "not possible" + +let is_context = function Ast0.CONTEXT(_) -> true | _ -> false + +let union_all l = List.fold_left Common.union_set [] l + +(* is minus is true when we are processing minus code that might be +intermingled with plus code. it is used in disj_cases *) +let classify is_minus all_marked table code = + let mkres builder k il tl bil btl l e = + (if k = AllMarked + then Ast0.set_mcodekind e (all_marked()) (* definitive *) + else + let check_index il tl = + if List.for_all is_context tl + then + (let e1 = builder e in + let index = (get_index e1)@il in + try + let _ = Hashtbl.find table index in + failwith + (Printf.sprintf "%d: index %s already used\n" + (Ast0.get_info e).Ast0.line_start + (String.concat " " (List.map string_of_int index))) + with Not_found -> Hashtbl.add table index (e1,l)) in + if il = [] then check_index bil btl else check_index il tl); + if il = [] + then Recursor(k, bil, btl, union_all l) + else Recursor(k, il, tl, union_all l) in + + let compute_result builder e = function + Bind(k,il,tl,bil,btl,l) -> mkres builder k il tl bil btl l e + | Token(k,il,tl,l) -> mkres builder k [il] [tl] [] [] [l] e + | Recursor(k,bil,btl,l) -> mkres builder k [] [] bil btl [l] e in + + let make_not_marked = function + Bind(k,il,tl,bil,btl,l) -> Bind(NotAllMarked,il,tl,bil,btl,l) + | Token(k,il,tl,l) -> Token(NotAllMarked,il,tl,l) + | Recursor(k,bil,btl,l) -> Recursor(NotAllMarked,bil,btl,l) in + + let do_nothing builder r k e = compute_result builder e (k e) in + + let disj_cases disj starter code fn ender = + (* neutral_mcode used so starter and ender don't have an affect on + whether the code is considered all plus/minus, but so that they are + consider in the index list, which is needed to make a disj with + something in one branch and nothing in the other different from code + that just has the something (starter/ender enough, mids not needed + for this). Cannot agglomerate + code over | boundaries, because two - + cases might have different + code, and don't want to put the + code + together into one unit. *) + let make_not_marked = + if is_minus + then + (let min = Ast0.get_line disj in + let max = Ast0.get_line_end disj in + let (plus_min,plus_max) = find min (min-1) (max+1) in + if max > plus_max then make_not_marked else (function x -> x)) + else make_not_marked in + bind (neutral_mcode starter) + (bind (List.fold_right bind + (List.map make_not_marked (List.map fn code)) + option_default) + (neutral_mcode ender)) in + + (* no whencode in plus tree so have to drop it *) + (* need special cases for dots, nests, and disjs *) + let expression r k e = + compute_result Ast0.expr e + (match Ast0.unwrap e with + Ast0.NestExpr(starter,exp,ender,whencode,multi) -> + k (Ast0.rewrap e (Ast0.NestExpr(starter,exp,ender,None,multi))) + | Ast0.Edots(dots,whencode) -> + k (Ast0.rewrap e (Ast0.Edots(dots,None))) + | Ast0.Ecircles(dots,whencode) -> + k (Ast0.rewrap e (Ast0.Ecircles(dots,None))) + | Ast0.Estars(dots,whencode) -> + k (Ast0.rewrap e (Ast0.Estars(dots,None))) + | Ast0.DisjExpr(starter,expr_list,_,ender) -> + disj_cases e starter expr_list r.V0.combiner_expression ender + | _ -> k e) in + + (* not clear why we have the next two cases, since DisjDecl and + DisjType shouldn't have been constructed yet, as they only come from isos *) + let declaration r k e = + compute_result Ast0.decl e + (match Ast0.unwrap e with + Ast0.DisjDecl(starter,decls,_,ender) -> + disj_cases e starter decls r.V0.combiner_declaration ender + | Ast0.Ddots(dots,whencode) -> + k (Ast0.rewrap e (Ast0.Ddots(dots,None))) + (* Need special cases for the following so that the type will be + considered as a unit, rather than distributed around the + declared variable. This needs to be done because of the call to + compute_result, ie the processing of each term should make a + side-effect on the complete term structure as well as collecting + some information about it. So we have to visit each complete + term structure. In (all?) other such cases, we visit the terms + using rebuilder, which just visits the subterms, rather than + reordering their components. *) + | Ast0.Init(stg,ty,id,eq,ini,sem) -> + bind (match stg with Some stg -> mcode stg | _ -> option_default) + (bind (r.V0.combiner_typeC ty) + (bind (r.V0.combiner_ident id) + (bind (mcode eq) + (bind (r.V0.combiner_initialiser ini) (mcode sem))))) + | Ast0.UnInit(stg,ty,id,sem) -> + bind (match stg with Some stg -> mcode stg | _ -> option_default) + (bind (r.V0.combiner_typeC ty) + (bind (r.V0.combiner_ident id) (mcode sem))) + | _ -> k e) in + + let param r k e = + compute_result Ast0.param e + (match Ast0.unwrap e with + Ast0.Param(ty,Some id) -> + (* needed for the same reason as in the Init and UnInit cases *) + bind (r.V0.combiner_typeC ty) (r.V0.combiner_ident id) + | _ -> k e) in + + let typeC r k e = + compute_result Ast0.typeC e + (match Ast0.unwrap e with + Ast0.DisjType(starter,types,_,ender) -> + disj_cases e starter types r.V0.combiner_typeC ender + | _ -> k e) in + + let initialiser r k i = + compute_result Ast0.ini i + (match Ast0.unwrap i with + Ast0.Idots(dots,whencode) -> + k (Ast0.rewrap i (Ast0.Idots(dots,None))) + | _ -> k i) in + + let statement r k s = + compute_result Ast0.stmt s + (match Ast0.unwrap s with + Ast0.Nest(started,stm_dots,ender,whencode,multi) -> + k (Ast0.rewrap s (Ast0.Nest(started,stm_dots,ender,[],multi))) + | Ast0.Dots(dots,whencode) -> + k (Ast0.rewrap s (Ast0.Dots(dots,[]))) + | Ast0.Circles(dots,whencode) -> + k (Ast0.rewrap s (Ast0.Circles(dots,[]))) + | Ast0.Stars(dots,whencode) -> + k (Ast0.rewrap s (Ast0.Stars(dots,[]))) + | Ast0.Disj(starter,statement_dots_list,_,ender) -> + disj_cases s starter statement_dots_list r.V0.combiner_statement_dots + ender +(* Why? There is nothing there + (* cases for everything with extra mcode *) + | Ast0.FunDecl((info,bef),_,_,_,_,_,_,_,_) + | Ast0.Decl((info,bef),_) -> + bind (mcode ((),(),info,bef)) (k s) + | Ast0.IfThen(_,_,_,_,_,(info,aft)) + | Ast0.IfThenElse(_,_,_,_,_,_,_,(info,aft)) + | Ast0.While(_,_,_,_,_,(info,aft)) -> + | Ast0.For(_,_,_,_,_,_,_,_,_,(info,aft)) -> + bind (k s) (mcode ((),(),info,aft)) + | Ast0.Iterator(_,_,_,_,_,(info,aft)) +*) + | _ -> k s + +) in + + let do_top builder r k e = compute_result builder e (k e) in + + let combiner = + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + (do_nothing Ast0.dotsExpr) (do_nothing Ast0.dotsInit) + (do_nothing Ast0.dotsParam) (do_nothing Ast0.dotsStmt) + (do_nothing Ast0.dotsDecl) (do_nothing Ast0.dotsCase) + (do_nothing Ast0.ident) expression typeC initialiser param declaration + statement (do_nothing Ast0.case_line) (do_top Ast0.top) in + combiner.V0.combiner_top_level code + +(* --------------------------------------------------------------------- *) +(* Traverse the hash tables and find corresponding context nodes that have +the same context children *) + +(* this is just a sanity check - really only need to look at the top-level + structure *) +let equal_mcode (_,_,info1,_,_) (_,_,info2,_,_) = + info1.Ast0.offset = info2.Ast0.offset + +let equal_option e1 e2 = + match (e1,e2) with + (Some x, Some y) -> equal_mcode x y + | (None, None) -> true + | _ -> false + +let dots fn d1 d2 = + match (Ast0.unwrap d1,Ast0.unwrap d2) with + (Ast0.DOTS(l1),Ast0.DOTS(l2)) -> List.length l1 = List.length l2 + | (Ast0.CIRCLES(l1),Ast0.CIRCLES(l2)) -> List.length l1 = List.length l2 + | (Ast0.STARS(l1),Ast0.STARS(l2)) -> List.length l1 = List.length l2 + | _ -> false + +let rec equal_ident i1 i2 = + match (Ast0.unwrap i1,Ast0.unwrap i2) with + (Ast0.Id(name1),Ast0.Id(name2)) -> equal_mcode name1 name2 + | (Ast0.MetaId(name1,_,_),Ast0.MetaId(name2,_,_)) -> + equal_mcode name1 name2 + | (Ast0.MetaFunc(name1,_,_),Ast0.MetaFunc(name2,_,_)) -> + equal_mcode name1 name2 + | (Ast0.MetaLocalFunc(name1,_,_),Ast0.MetaLocalFunc(name2,_,_)) -> + equal_mcode name1 name2 + | (Ast0.OptIdent(_),Ast0.OptIdent(_)) -> true + | (Ast0.UniqueIdent(_),Ast0.UniqueIdent(_)) -> true + | _ -> false + +let rec equal_expression e1 e2 = + match (Ast0.unwrap e1,Ast0.unwrap e2) with + (Ast0.Ident(_),Ast0.Ident(_)) -> true + | (Ast0.Constant(const1),Ast0.Constant(const2)) -> equal_mcode const1 const2 + | (Ast0.FunCall(_,lp1,_,rp1),Ast0.FunCall(_,lp2,_,rp2)) -> + equal_mcode lp1 lp2 && equal_mcode rp1 rp2 + | (Ast0.Assignment(_,op1,_,_),Ast0.Assignment(_,op2,_,_)) -> + equal_mcode op1 op2 + | (Ast0.CondExpr(_,why1,_,colon1,_),Ast0.CondExpr(_,why2,_,colon2,_)) -> + equal_mcode why1 why2 && equal_mcode colon1 colon2 + | (Ast0.Postfix(_,op1),Ast0.Postfix(_,op2)) -> equal_mcode op1 op2 + | (Ast0.Infix(_,op1),Ast0.Infix(_,op2)) -> equal_mcode op1 op2 + | (Ast0.Unary(_,op1),Ast0.Unary(_,op2)) -> equal_mcode op1 op2 + | (Ast0.Binary(_,op1,_),Ast0.Binary(_,op2,_)) -> equal_mcode op1 op2 + | (Ast0.Paren(lp1,_,rp1),Ast0.Paren(lp2,_,rp2)) -> + equal_mcode lp1 lp2 && equal_mcode rp1 rp2 + | (Ast0.ArrayAccess(_,lb1,_,rb1),Ast0.ArrayAccess(_,lb2,_,rb2)) -> + equal_mcode lb1 lb2 && equal_mcode rb1 rb2 + | (Ast0.RecordAccess(_,pt1,_),Ast0.RecordAccess(_,pt2,_)) -> + equal_mcode pt1 pt2 + | (Ast0.RecordPtAccess(_,ar1,_),Ast0.RecordPtAccess(_,ar2,_)) -> + equal_mcode ar1 ar2 + | (Ast0.Cast(lp1,_,rp1,_),Ast0.Cast(lp2,_,rp2,_)) -> + equal_mcode lp1 lp2 && equal_mcode rp1 rp2 + | (Ast0.SizeOfExpr(szf1,_),Ast0.SizeOfExpr(szf2,_)) -> + equal_mcode szf1 szf2 + | (Ast0.SizeOfType(szf1,lp1,_,rp1),Ast0.SizeOfType(szf2,lp2,_,rp2)) -> + equal_mcode szf1 szf2 && equal_mcode lp1 lp2 && equal_mcode rp1 rp2 + | (Ast0.TypeExp(_),Ast0.TypeExp(_)) -> true + | (Ast0.MetaErr(name1,_,_),Ast0.MetaErr(name2,_,_)) + | (Ast0.MetaExpr(name1,_,_,_,_),Ast0.MetaExpr(name2,_,_,_,_)) + | (Ast0.MetaExprList(name1,_,_),Ast0.MetaExprList(name2,_,_)) -> + equal_mcode name1 name2 + | (Ast0.EComma(cm1),Ast0.EComma(cm2)) -> equal_mcode cm1 cm2 + | (Ast0.DisjExpr(starter1,_,mids1,ender1), + Ast0.DisjExpr(starter2,_,mids2,ender2)) -> + equal_mcode starter1 starter2 && + List.for_all2 equal_mcode mids1 mids2 && + equal_mcode ender1 ender2 + | (Ast0.NestExpr(starter1,_,ender1,_,m1), + Ast0.NestExpr(starter2,_,ender2,_,m2)) -> + equal_mcode starter1 starter2 && equal_mcode ender1 ender2 && m1 = m2 + | (Ast0.Edots(dots1,_),Ast0.Edots(dots2,_)) + | (Ast0.Ecircles(dots1,_),Ast0.Ecircles(dots2,_)) + | (Ast0.Estars(dots1,_),Ast0.Estars(dots2,_)) -> equal_mcode dots1 dots2 + | (Ast0.OptExp(_),Ast0.OptExp(_)) -> true + | (Ast0.UniqueExp(_),Ast0.UniqueExp(_)) -> true + | _ -> false + +let rec equal_typeC t1 t2 = + match (Ast0.unwrap t1,Ast0.unwrap t2) with + (Ast0.ConstVol(cv1,_),Ast0.ConstVol(cv2,_)) -> equal_mcode cv1 cv2 + | (Ast0.BaseType(ty1,sign1),Ast0.BaseType(ty2,sign2)) -> + equal_mcode ty1 ty2 && equal_option sign1 sign2 + | (Ast0.ImplicitInt(sign1),Ast0.ImplicitInt(sign2)) -> + equal_mcode sign1 sign2 + | (Ast0.Pointer(_,star1),Ast0.Pointer(_,star2)) -> + equal_mcode star1 star2 + | (Ast0.Array(_,lb1,_,rb1),Ast0.Array(_,lb2,_,rb2)) -> + equal_mcode lb1 lb2 && equal_mcode rb1 rb2 + | (Ast0.StructUnionName(kind1,_),Ast0.StructUnionName(kind2,_)) -> + equal_mcode kind1 kind2 + | (Ast0.FunctionType(ty1,lp1,p1,rp1),Ast0.FunctionType(ty2,lp2,p2,rp2)) -> + equal_mcode lp1 lp2 && equal_mcode rp1 rp2 + | (Ast0.StructUnionDef(_,lb1,_,rb1), + Ast0.StructUnionDef(_,lb2,_,rb2)) -> + equal_mcode lb1 lb2 && equal_mcode rb1 rb2 + | (Ast0.TypeName(name1),Ast0.TypeName(name2)) -> equal_mcode name1 name2 + | (Ast0.MetaType(name1,_),Ast0.MetaType(name2,_)) -> + equal_mcode name1 name2 + | (Ast0.DisjType(starter1,_,mids1,ender1), + Ast0.DisjType(starter2,_,mids2,ender2)) -> + equal_mcode starter1 starter2 && + List.for_all2 equal_mcode mids1 mids2 && + equal_mcode ender1 ender2 + | (Ast0.OptType(_),Ast0.OptType(_)) -> true + | (Ast0.UniqueType(_),Ast0.UniqueType(_)) -> true + | _ -> false + +let equal_declaration d1 d2 = + match (Ast0.unwrap d1,Ast0.unwrap d2) with + (Ast0.Init(stg1,_,_,eq1,_,sem1),Ast0.Init(stg2,_,_,eq2,_,sem2)) -> + equal_option stg1 stg2 && equal_mcode eq1 eq2 && equal_mcode sem1 sem2 + | (Ast0.UnInit(stg1,_,_,sem1),Ast0.UnInit(stg2,_,_,sem2)) -> + equal_option stg1 stg2 && equal_mcode sem1 sem2 + | (Ast0.MacroDecl(nm1,lp1,_,rp1,sem1),Ast0.MacroDecl(nm2,lp2,_,rp2,sem2)) -> + equal_mcode lp1 lp2 && equal_mcode rp1 rp2 && equal_mcode sem1 sem2 + | (Ast0.TyDecl(_,sem1),Ast0.TyDecl(_,sem2)) -> equal_mcode sem1 sem2 + | (Ast0.Ddots(dots1,_),Ast0.Ddots(dots2,_)) -> equal_mcode dots1 dots2 + | (Ast0.OptDecl(_),Ast0.OptDecl(_)) -> true + | (Ast0.UniqueDecl(_),Ast0.UniqueDecl(_)) -> true + | (Ast0.DisjDecl _,_) | (_,Ast0.DisjDecl _) -> + failwith "DisjDecl not expected here" + | _ -> false + +let equal_initialiser i1 i2 = + match (Ast0.unwrap i1,Ast0.unwrap i2) with + (Ast0.InitExpr(_),Ast0.InitExpr(_)) -> true + | (Ast0.InitList(lb1,_,rb1),Ast0.InitList(lb2,_,rb2)) -> + (equal_mcode lb1 lb2) && (equal_mcode rb1 rb2) + | (Ast0.InitGccDotName(dot1,_,eq1,_),Ast0.InitGccDotName(dot2,_,eq2,_)) -> + (equal_mcode dot1 dot2) && (equal_mcode eq1 eq2) + | (Ast0.InitGccName(_,eq1,_),Ast0.InitGccName(_,eq2,_)) -> + equal_mcode eq1 eq2 + | (Ast0.InitGccIndex(lb1,_,rb1,eq1,_),Ast0.InitGccIndex(lb2,_,rb2,eq2,_)) -> + (equal_mcode lb1 lb2) && (equal_mcode rb1 rb2) && (equal_mcode eq1 eq2) + | (Ast0.InitGccRange(lb1,_,dots1,_,rb1,eq1,_), + Ast0.InitGccRange(lb2,_,dots2,_,rb2,eq2,_)) -> + (equal_mcode lb1 lb2) && (equal_mcode dots1 dots2) && + (equal_mcode rb1 rb2) && (equal_mcode eq1 eq2) + | (Ast0.IComma(cm1),Ast0.IComma(cm2)) -> equal_mcode cm1 cm2 + | (Ast0.Idots(d1,_),Ast0.Idots(d2,_)) -> equal_mcode d1 d2 + | (Ast0.OptIni(_),Ast0.OptIni(_)) -> true + | (Ast0.UniqueIni(_),Ast0.UniqueIni(_)) -> true + | _ -> false + +let equal_parameterTypeDef p1 p2 = + match (Ast0.unwrap p1,Ast0.unwrap p2) with + (Ast0.VoidParam(_),Ast0.VoidParam(_)) -> true + | (Ast0.Param(_,_),Ast0.Param(_,_)) -> true + | (Ast0.MetaParam(name1,_),Ast0.MetaParam(name2,_)) + | (Ast0.MetaParamList(name1,_,_),Ast0.MetaParamList(name2,_,_)) -> + equal_mcode name1 name2 + | (Ast0.PComma(cm1),Ast0.PComma(cm2)) -> equal_mcode cm1 cm2 + | (Ast0.Pdots(dots1),Ast0.Pdots(dots2)) + | (Ast0.Pcircles(dots1),Ast0.Pcircles(dots2)) -> equal_mcode dots1 dots2 + | (Ast0.OptParam(_),Ast0.OptParam(_)) -> true + | (Ast0.UniqueParam(_),Ast0.UniqueParam(_)) -> true + | _ -> false + +let rec equal_statement s1 s2 = + match (Ast0.unwrap s1,Ast0.unwrap s2) with + (Ast0.FunDecl(_,fninfo1,_,lp1,_,rp1,lbrace1,_,rbrace1), + Ast0.FunDecl(_,fninfo2,_,lp2,_,rp2,lbrace2,_,rbrace2)) -> + (List.length fninfo1) = (List.length fninfo2) && + List.for_all2 equal_fninfo fninfo1 fninfo2 && + equal_mcode lp1 lp2 && equal_mcode rp1 rp2 && + equal_mcode lbrace1 lbrace2 && equal_mcode rbrace1 rbrace2 + | (Ast0.Decl(_,_),Ast0.Decl(_,_)) -> true + | (Ast0.Seq(lbrace1,_,rbrace1),Ast0.Seq(lbrace2,_,rbrace2)) -> + equal_mcode lbrace1 lbrace2 && equal_mcode rbrace1 rbrace2 + | (Ast0.ExprStatement(_,sem1),Ast0.ExprStatement(_,sem2)) -> + equal_mcode sem1 sem2 + | (Ast0.IfThen(iff1,lp1,_,rp1,_,_),Ast0.IfThen(iff2,lp2,_,rp2,_,_)) -> + equal_mcode iff1 iff2 && equal_mcode lp1 lp2 && equal_mcode rp1 rp2 + | (Ast0.IfThenElse(iff1,lp1,_,rp1,_,els1,_,_), + Ast0.IfThenElse(iff2,lp2,_,rp2,_,els2,_,_)) -> + equal_mcode iff1 iff2 && + equal_mcode lp1 lp2 && equal_mcode rp1 rp2 && equal_mcode els1 els2 + | (Ast0.While(whl1,lp1,_,rp1,_,_),Ast0.While(whl2,lp2,_,rp2,_,_)) -> + equal_mcode whl1 whl2 && equal_mcode lp1 lp2 && equal_mcode rp1 rp2 + | (Ast0.Do(d1,_,whl1,lp1,_,rp1,sem1),Ast0.Do(d2,_,whl2,lp2,_,rp2,sem2)) -> + equal_mcode whl1 whl2 && equal_mcode d1 d2 && + equal_mcode lp1 lp2 && equal_mcode rp1 rp2 && equal_mcode sem1 sem2 + | (Ast0.For(fr1,lp1,_,sem11,_,sem21,_,rp1,_,_), + Ast0.For(fr2,lp2,_,sem12,_,sem22,_,rp2,_,_)) -> + equal_mcode fr1 fr2 && equal_mcode lp1 lp2 && + equal_mcode sem11 sem12 && equal_mcode sem21 sem22 && + equal_mcode rp1 rp2 + | (Ast0.Iterator(nm1,lp1,_,rp1,_,_),Ast0.Iterator(nm2,lp2,_,rp2,_,_)) -> + equal_mcode lp1 lp2 && equal_mcode rp1 rp2 + | (Ast0.Switch(switch1,lp1,_,rp1,lb1,case1,rb1), + Ast0.Switch(switch2,lp2,_,rp2,lb2,case2,rb2)) -> + equal_mcode switch1 switch2 && equal_mcode lp1 lp2 && + equal_mcode rp1 rp2 && equal_mcode lb1 lb2 && + equal_mcode rb1 rb2 + | (Ast0.Break(br1,sem1),Ast0.Break(br2,sem2)) -> + equal_mcode br1 br2 && equal_mcode sem1 sem2 + | (Ast0.Continue(cont1,sem1),Ast0.Continue(cont2,sem2)) -> + equal_mcode cont1 cont2 && equal_mcode sem1 sem2 + | (Ast0.Label(_,dd1),Ast0.Label(_,dd2)) -> + equal_mcode dd1 dd2 + | (Ast0.Goto(g1,_,sem1),Ast0.Goto(g2,_,sem2)) -> + equal_mcode g1 g2 && equal_mcode sem1 sem2 + | (Ast0.Return(ret1,sem1),Ast0.Return(ret2,sem2)) -> + equal_mcode ret1 ret2 && equal_mcode sem1 sem2 + | (Ast0.ReturnExpr(ret1,_,sem1),Ast0.ReturnExpr(ret2,_,sem2)) -> + equal_mcode ret1 ret2 && equal_mcode sem1 sem2 + | (Ast0.MetaStmt(name1,_),Ast0.MetaStmt(name2,_)) + | (Ast0.MetaStmtList(name1,_),Ast0.MetaStmtList(name2,_)) -> + equal_mcode name1 name2 + | (Ast0.Disj(starter1,_,mids1,ender1),Ast0.Disj(starter2,_,mids2,ender2)) -> + equal_mcode starter1 starter2 && + List.for_all2 equal_mcode mids1 mids2 && + equal_mcode ender1 ender2 + | (Ast0.Nest(starter1,_,ender1,_,m1),Ast0.Nest(starter2,_,ender2,_,m2)) -> + equal_mcode starter1 starter2 && equal_mcode ender1 ender2 && m1 = m2 + | (Ast0.Exp(_),Ast0.Exp(_)) -> true + | (Ast0.TopExp(_),Ast0.TopExp(_)) -> true + | (Ast0.Ty(_),Ast0.Ty(_)) -> true + | (Ast0.Dots(d1,_),Ast0.Dots(d2,_)) + | (Ast0.Circles(d1,_),Ast0.Circles(d2,_)) + | (Ast0.Stars(d1,_),Ast0.Stars(d2,_)) -> equal_mcode d1 d2 + | (Ast0.Include(inc1,name1),Ast0.Include(inc2,name2)) -> + equal_mcode inc1 inc2 && equal_mcode name1 name2 + | (Ast0.Define(def1,_,_,_),Ast0.Define(def2,_,_,_)) -> + equal_mcode def1 def2 + | (Ast0.OptStm(_),Ast0.OptStm(_)) -> true + | (Ast0.UniqueStm(_),Ast0.UniqueStm(_)) -> true + | _ -> false + +and equal_fninfo x y = + match (x,y) with + (Ast0.FStorage(s1),Ast0.FStorage(s2)) -> equal_mcode s1 s2 + | (Ast0.FType(_),Ast0.FType(_)) -> true + | (Ast0.FInline(i1),Ast0.FInline(i2)) -> equal_mcode i1 i2 + | (Ast0.FAttr(i1),Ast0.FAttr(i2)) -> equal_mcode i1 i2 + | _ -> false + +let equal_case_line c1 c2 = + match (Ast0.unwrap c1,Ast0.unwrap c2) with + (Ast0.Default(def1,colon1,_),Ast0.Default(def2,colon2,_)) -> + equal_mcode def1 def2 && equal_mcode colon1 colon2 + | (Ast0.Case(case1,_,colon1,_),Ast0.Case(case2,_,colon2,_)) -> + equal_mcode case1 case2 && equal_mcode colon1 colon2 + | (Ast0.OptCase(_),Ast0.OptCase(_)) -> true + | _ -> false + +let rec equal_top_level t1 t2 = + match (Ast0.unwrap t1,Ast0.unwrap t2) with + (Ast0.DECL(_),Ast0.DECL(_)) -> true + | (Ast0.FILEINFO(old_file1,new_file1),Ast0.FILEINFO(old_file2,new_file2)) -> + equal_mcode old_file1 old_file2 && equal_mcode new_file1 new_file2 + | (Ast0.CODE(_),Ast0.CODE(_)) -> true + | (Ast0.ERRORWORDS(_),Ast0.ERRORWORDS(_)) -> true + | _ -> false + +let root_equal e1 e2 = + match (e1,e2) with + (Ast0.DotsExprTag(d1),Ast0.DotsExprTag(d2)) -> dots equal_expression d1 d2 + | (Ast0.DotsParamTag(d1),Ast0.DotsParamTag(d2)) -> + dots equal_parameterTypeDef d1 d2 + | (Ast0.DotsStmtTag(d1),Ast0.DotsStmtTag(d2)) -> dots equal_statement d1 d2 + | (Ast0.DotsDeclTag(d1),Ast0.DotsDeclTag(d2)) -> dots equal_declaration d1 d2 + | (Ast0.DotsCaseTag(d1),Ast0.DotsCaseTag(d2)) -> dots equal_case_line d1 d2 + | (Ast0.IdentTag(i1),Ast0.IdentTag(i2)) -> equal_ident i1 i2 + | (Ast0.ExprTag(e1),Ast0.ExprTag(e2)) -> equal_expression e1 e2 + | (Ast0.ArgExprTag(d),_) -> failwith "not possible - iso only" + | (Ast0.TypeCTag(t1),Ast0.TypeCTag(t2)) -> equal_typeC t1 t2 + | (Ast0.ParamTag(p1),Ast0.ParamTag(p2)) -> equal_parameterTypeDef p1 p2 + | (Ast0.InitTag(d1),Ast0.InitTag(d2)) -> equal_initialiser d1 d2 + | (Ast0.DeclTag(d1),Ast0.DeclTag(d2)) -> equal_declaration d1 d2 + | (Ast0.StmtTag(s1),Ast0.StmtTag(s2)) -> equal_statement s1 s2 + | (Ast0.TopTag(t1),Ast0.TopTag(t2)) -> equal_top_level t1 t2 + | (Ast0.IsoWhenTag(_),_) | (_,Ast0.IsoWhenTag(_)) -> + failwith "only within iso phase" + | _ -> false + +let default_context _ = + Ast0.CONTEXT(ref(Ast.NOTHING, + Ast0.default_token_info,Ast0.default_token_info)) + +let traverse minus_table plus_table = + Hashtbl.iter + (function key -> + function (e,l) -> + try + let (plus_e,plus_l) = Hashtbl.find plus_table key in + if root_equal e plus_e && + List.for_all (function x -> x) + (List.map2 Common.equal_set l plus_l) + then + let i = Ast0.fresh_index() in + (set_index e i; set_index plus_e i; + set_mcodekind e (default_context()); + set_mcodekind plus_e (default_context())) + with Not_found -> ()) + minus_table + +(* --------------------------------------------------------------------- *) +(* contextify the whencode *) + +let contextify_all = + let bind x y = () in + let option_default = () in + let mcode x = () in + let do_nothing r k e = Ast0.set_mcodekind e (default_context()); k e in + + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing + +let contextify_whencode = + let bind x y = () in + let option_default = () in + let mcode x = () in + let do_nothing r k e = k e in + + let expression r k e = + k e; + match Ast0.unwrap e with + Ast0.NestExpr(_,_,_,Some whencode,_) + | Ast0.Edots(_,Some whencode) + | Ast0.Ecircles(_,Some whencode) + | Ast0.Estars(_,Some whencode) -> + contextify_all.V0.combiner_expression whencode + | _ -> () in + + let initialiser r k i = + match Ast0.unwrap i with + Ast0.Idots(dots,Some whencode) -> + contextify_all.V0.combiner_initialiser whencode + | _ -> k i in + + let whencode = function + Ast0.WhenNot sd -> contextify_all.V0.combiner_statement_dots sd + | Ast0.WhenAlways s -> contextify_all.V0.combiner_statement s + | Ast0.WhenModifier(_) -> () in + + let statement r k (s : Ast0.statement) = + k s; + match Ast0.unwrap s with + Ast0.Nest(_,_,_,whn,_) + | Ast0.Dots(_,whn) | Ast0.Circles(_,whn) | Ast0.Stars(_,whn) -> + List.iter whencode whn + | _ -> () in + + let combiner = + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing + do_nothing + expression + do_nothing initialiser do_nothing do_nothing statement do_nothing + do_nothing in + combiner.V0.combiner_top_level + +(* --------------------------------------------------------------------- *) + +(* the first int list is the tokens in the node, the second is the tokens +in the descendents *) +let minus_table = + (Hashtbl.create(50) : (int list, Ast0.anything * int list list) Hashtbl.t) +let plus_table = + (Hashtbl.create(50) : (int list, Ast0.anything * int list list) Hashtbl.t) + +let iscode t = + match Ast0.unwrap t with + Ast0.DECL(_) -> true + | Ast0.FILEINFO(_) -> true + | Ast0.ERRORWORDS(_) -> false + | Ast0.CODE(_) -> true + | Ast0.OTHER(_) -> failwith "unexpected top level code" + +(* ------------------------------------------------------------------- *) +(* alignment of minus and plus *) + +let concat = function + [] -> [] + | [s] -> [s] + | l -> + let rec loop = function + [] -> [] + | x::rest -> + (match Ast0.unwrap x with + Ast0.DECL(s) -> let stms = loop rest in s::stms + | Ast0.CODE(ss) -> + let stms = loop rest in + (match Ast0.unwrap ss with + Ast0.DOTS(d) -> d@stms + | _ -> failwith "no dots allowed in pure plus code") + | _ -> failwith "plus code is being discarded") in + let res = + Compute_lines.statement_dots + (Ast0.rewrap (List.hd l) (Ast0.DOTS (loop l))) in + [Ast0.rewrap res (Ast0.CODE res)] + +let collect_up_to m plus = + let minfo = Ast0.get_info m in + let mend = minfo.Ast0.logical_end in + let rec loop = function + [] -> ([],[]) + | p::plus -> + let pinfo = Ast0.get_info p in + let pstart = pinfo.Ast0.logical_start in + if pstart > mend + then ([],p::plus) + else let (plus,rest) = loop plus in (p::plus,rest) in + let (plus,rest) = loop plus in + (concat plus,rest) + +let realign minus plus = + let rec loop = function + ([],_) -> failwith "not possible, some context required" + | ([m],p) -> ([m],concat p) + | (m::minus,plus) -> + let (p,plus) = collect_up_to m plus in + let (minus,plus) = loop (minus,plus) in + (m::minus,p@plus) in + loop (minus,plus) + +(* ------------------------------------------------------------------- *) +(* check compatible: check that at the top level the minus and plus code is +of the same kind. Could go further and make the correspondence between the +code between ...s. *) + +let isonly f l = match Ast0.undots l with [s] -> f s | _ -> false + +let isall f l = List.for_all (isonly f) l + +let rec is_exp s = + match Ast0.unwrap s with + Ast0.Exp(e) -> true + | Ast0.Disj(_,stmts,_,_) -> isall is_exp stmts + | _ -> false + +let rec is_ty s = + match Ast0.unwrap s with + Ast0.Ty(e) -> true + | Ast0.Disj(_,stmts,_,_) -> isall is_ty stmts + | _ -> false + +let rec is_decl s = + match Ast0.unwrap s with + Ast0.Decl(_,e) -> true + | Ast0.FunDecl(_,_,_,_,_,_,_,_,_) -> true + | Ast0.Disj(_,stmts,_,_) -> isall is_decl stmts + | _ -> false + +let rec is_fndecl s = + match Ast0.unwrap s with + Ast0.FunDecl(_,_,_,_,_,_,_,_,_) -> true + | Ast0.Disj(_,stmts,_,_) -> isall is_fndecl stmts + | _ -> false + +let rec is_toplevel s = + match Ast0.unwrap s with + Ast0.Decl(_,e) -> true + | Ast0.FunDecl(_,_,_,_,_,_,_,_,_) -> true + | Ast0.Disj(_,stmts,_,_) -> isall is_toplevel stmts + | Ast0.ExprStatement(fc,_) -> + (match Ast0.unwrap fc with + Ast0.FunCall(_,_,_,_) -> true + | _ -> false) + | Ast0.Include(_,_) -> true + | Ast0.Define(_,_,_,_) -> true + | _ -> false + +let check_compatible m p = + let fail _ = + failwith + (Printf.sprintf + "incompatible minus and plus code starting on lines %d and %d" + (Ast0.get_line m) (Ast0.get_line p)) in + match (Ast0.unwrap m, Ast0.unwrap p) with + (Ast0.DECL(decl1),Ast0.DECL(decl2)) -> + if not (is_decl decl1 && is_decl decl2) + then fail() + | (Ast0.DECL(decl1),Ast0.CODE(code2)) -> + let v1 = is_decl decl1 in + let v2 = List.for_all is_toplevel (Ast0.undots code2) in + if !Flag.make_hrule = None && v1 && not v2 then fail() + | (Ast0.CODE(code1),Ast0.DECL(decl2)) -> + let v1 = List.for_all is_toplevel (Ast0.undots code1) in + let v2 = is_decl decl2 in + if v1 && not v2 then fail() + | (Ast0.CODE(code1),Ast0.CODE(code2)) -> + let testers = [is_exp;is_ty] in + List.iter + (function tester -> + let v1 = isonly tester code1 in + let v2 = isonly tester code2 in + if (v1 && not v2) or (!Flag.make_hrule = None && v2 && not v1) + then fail()) + testers; + let v1 = isonly is_fndecl code1 in + let v2 = List.for_all is_toplevel (Ast0.undots code2) in + if !Flag.make_hrule = None && v1 && not v2 then fail() + | (Ast0.FILEINFO(_,_),Ast0.FILEINFO(_,_)) -> () + | (Ast0.OTHER(_),Ast0.OTHER(_)) -> () + | _ -> fail() + +(* ------------------------------------------------------------------- *) + +(* returns a list of corresponding minus and plus trees *) +let context_neg minus plus = + Hashtbl.clear minus_table; + Hashtbl.clear plus_table; + List.iter contextify_whencode minus; + let (minus,plus) = realign minus plus in + let rec loop = function + ([],[]) -> [] + | ([],l) -> + failwith (Printf.sprintf "%d plus things remaining" (List.length l)) + | (minus,[]) -> + plus_lines := []; + let _ = + List.map + (function m -> + classify true + (function _ -> Ast0.MINUS(ref([],Ast0.default_token_info))) + minus_table m) + minus in + [] + | (((m::minus) as mall),((p::plus) as pall)) -> + let minfo = Ast0.get_info m in + let pinfo = Ast0.get_info p in + let mstart = minfo.Ast0.logical_start in + let mend = minfo.Ast0.logical_end in + let pstart = pinfo.Ast0.logical_start in + let pend = pinfo.Ast0.logical_end in + if (iscode m or iscode p) && + (mend + 1 = pstart or pend + 1 = mstart or (* adjacent *) + (mstart <= pstart && mend >= pstart) or + (pstart <= mstart && pend >= mstart)) (* overlapping or nested *) + then + begin + (* ensure that the root of each tree has a unique index, + although it might get overwritten if the node is a context + node *) + let i = Ast0.fresh_index() in + Ast0.set_index m i; Ast0.set_index p i; + check_compatible m p; + collect_plus_lines p; + let _ = + classify true + (function _ -> Ast0.MINUS(ref([],Ast0.default_token_info))) + minus_table m in + let _ = classify false (function _ -> Ast0.PLUS) plus_table p in + traverse minus_table plus_table; + (m,p)::loop(minus,plus) + end + else + if not(iscode m or iscode p) + then loop(minus,plus) + else + if mstart < pstart + then + begin + plus_lines := []; + let _ = + classify true + (function _ -> Ast0.MINUS(ref([],Ast0.default_token_info))) + minus_table m in + loop(minus,pall) + end + else loop(mall,plus) in + loop(minus,plus) diff --git a/parsing_cocci/context_neg.mli b/parsing_cocci/context_neg.mli new file mode 100644 index 0000000..acdb4b4 --- /dev/null +++ b/parsing_cocci/context_neg.mli @@ -0,0 +1,8 @@ +val context_neg : + Ast0_cocci.rule -> Ast0_cocci.rule -> + (Ast0_cocci.top_level * Ast0_cocci.top_level) list + +val minus_table : + (int list, Ast0_cocci.anything * int Common.set list) Hashtbl.t +val plus_table : + (int list, Ast0_cocci.anything * int Common.set list) Hashtbl.t diff --git a/parsing_cocci/data.ml b/parsing_cocci/data.ml new file mode 100644 index 0000000..5805dea --- /dev/null +++ b/parsing_cocci/data.ml @@ -0,0 +1,147 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast0 = Ast0_cocci +module Ast = Ast_cocci + +(* types that clutter the .mly file *) +(* for iso metavariables, true if they can only match nonmodified, unitary + metavariables *) +type fresh = bool + +type clt = + line_type * int * int * int * int (* starting spaces *) * + string list (* code before *) * string list (* code after *) * + Ast0.meta_pos (* position variable, minus only *) + +(* ---------------------------------------------------------------------- *) + +(* Things that need to be seen by the lexer and parser. *) + +and line_type = + MINUS | OPTMINUS | UNIQUEMINUS + | PLUS + | CONTEXT | UNIQUE | OPT + +type iconstraints = Ast0.ident list +type econstraints = Ast0.expression list +type pconstraints = Ast.meta_name list + +let in_rule_name = ref false +let in_meta = ref false +let in_iso = ref false +let in_prolog = ref false +let inheritable_positions = + ref ([] : string list) (* rules from which posns can be inherited *) + +let all_metadecls = + (Hashtbl.create(100) : (string, Ast.metavar list) Hashtbl.t) + +let clear_meta: (unit -> unit) ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_id_meta: + (Ast.meta_name -> iconstraints -> Ast0.pure -> unit) ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_type_meta: (Ast.meta_name -> Ast0.pure -> unit) ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_param_meta: (Ast.meta_name -> Ast0.pure -> unit) ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_paramlist_meta: + (Ast.meta_name -> Ast.meta_name option -> Ast0.pure -> unit) ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_const_meta: + (Type_cocci.typeC list option -> Ast.meta_name -> econstraints -> + Ast0.pure -> unit) + ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_err_meta: + (Ast.meta_name -> econstraints -> Ast0.pure -> unit) ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_exp_meta: + (Type_cocci.typeC list option -> Ast.meta_name -> econstraints -> + Ast0.pure -> unit) + ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_idexp_meta: + (Type_cocci.typeC list option -> Ast.meta_name -> econstraints -> + Ast0.pure -> unit) + ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_local_idexp_meta: + (Type_cocci.typeC list option -> Ast.meta_name -> econstraints -> + Ast0.pure -> unit) + ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_explist_meta: + (Ast.meta_name -> Ast.meta_name option -> Ast0.pure -> unit) ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_stm_meta: (Ast.meta_name -> Ast0.pure -> unit) ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_stmlist_meta: (Ast.meta_name -> Ast0.pure -> unit) ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_func_meta: + (Ast.meta_name -> iconstraints -> Ast0.pure -> unit) ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_local_func_meta: + (Ast.meta_name -> iconstraints -> Ast0.pure -> unit) ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_declarer_meta: + (Ast.meta_name -> iconstraints -> Ast0.pure -> unit) ref = + ref (fun _ -> failwith "uninitialized add_decl") + +let add_iterator_meta: + (Ast.meta_name -> iconstraints -> Ast0.pure -> unit) ref = + ref (fun _ -> failwith "uninitialized add_iter") + +let add_pos_meta: + (Ast.meta_name -> pconstraints -> Ast.meta_collect -> unit) ref = + ref (fun _ -> failwith "uninitialized add_meta") + +let add_type_name: (string -> unit) ref = + ref (fun _ -> failwith "uninitialized add_type") + +let add_declarer_name: (string -> unit) ref = + ref (fun _ -> failwith "uninitialized add_decl") + +let add_iterator_name: (string -> unit) ref = + ref (fun _ -> failwith "uninitialized add_iter") + +let init_rule: (unit -> unit) ref = + ref (fun _ -> failwith "uninitialized install_bindings") + +let install_bindings: (string -> unit) ref = + ref (fun _ -> failwith "uninitialized install_bindings") diff --git a/parsing_cocci/data.mli b/parsing_cocci/data.mli new file mode 100644 index 0000000..3f725b8 --- /dev/null +++ b/parsing_cocci/data.mli @@ -0,0 +1,93 @@ +(* types that clutter the .mly file *) +(* for iso metavariables, true if they can only match nonmodified, unitary + metavariables *) +type fresh = bool + +type clt = + line_type * int * int * int * int (* starting spaces *) * + string list (* code before *) * string list (* code after *) * + Ast0_cocci.meta_pos (* position variable, minus only *) + +(* ---------------------------------------------------------------------- *) + +and line_type = + MINUS | OPTMINUS | UNIQUEMINUS + | PLUS + | CONTEXT | UNIQUE | OPT + +type iconstraints = Ast0_cocci.ident list +type econstraints = Ast0_cocci.expression list +type pconstraints = Ast_cocci.meta_name list + +val in_rule_name : bool ref (* true if parsing the rule name *) +val in_meta : bool ref (* true if parsing the metavariable decls *) +val in_iso : bool ref (* true if parsing the isomorphisms *) +val in_prolog : bool ref (* true if parsing the beginning of an SP *) +val inheritable_positions : string list ref + +val all_metadecls : (string, Ast_cocci.metavar list) Hashtbl.t + +val clear_meta: (unit -> unit) ref + +val add_id_meta: + (Ast_cocci.meta_name -> iconstraints -> Ast0_cocci.pure -> unit) ref + +val add_type_meta: (Ast_cocci.meta_name -> Ast0_cocci.pure -> unit) ref + +val add_param_meta: (Ast_cocci.meta_name -> Ast0_cocci.pure -> unit) ref + +val add_paramlist_meta: + (Ast_cocci.meta_name -> Ast_cocci.meta_name option -> Ast0_cocci.pure -> + unit) ref + +val add_const_meta: + (Type_cocci.typeC list option -> Ast_cocci.meta_name -> econstraints -> + Ast0_cocci.pure -> unit) ref + +val add_err_meta: + (Ast_cocci.meta_name -> econstraints -> Ast0_cocci.pure -> unit) ref + +val add_exp_meta: + (Type_cocci.typeC list option -> Ast_cocci.meta_name -> econstraints -> + Ast0_cocci.pure -> unit) ref + +val add_idexp_meta: + (Type_cocci.typeC list option -> Ast_cocci.meta_name -> + econstraints -> Ast0_cocci.pure -> unit) ref + +val add_local_idexp_meta: + (Type_cocci.typeC list option -> Ast_cocci.meta_name -> + econstraints -> Ast0_cocci.pure -> unit) ref + +val add_explist_meta: + (Ast_cocci.meta_name -> Ast_cocci.meta_name option -> Ast0_cocci.pure -> + unit) ref + +val add_stm_meta: (Ast_cocci.meta_name -> Ast0_cocci.pure -> unit) ref + +val add_stmlist_meta: (Ast_cocci.meta_name -> Ast0_cocci.pure -> unit) ref + +val add_func_meta: + (Ast_cocci.meta_name -> iconstraints -> Ast0_cocci.pure -> unit) ref + +val add_local_func_meta: + (Ast_cocci.meta_name -> iconstraints -> Ast0_cocci.pure -> unit) ref + +val add_declarer_meta: + (Ast_cocci.meta_name -> iconstraints -> Ast0_cocci.pure -> unit) ref + +val add_iterator_meta: + (Ast_cocci.meta_name -> iconstraints -> Ast0_cocci.pure -> unit) ref + +val add_pos_meta: + (Ast_cocci.meta_name -> pconstraints -> Ast_cocci.meta_collect -> unit) ref + +val add_type_name: (string -> unit) ref + +val add_declarer_name: (string -> unit) ref + +val add_iterator_name: (string -> unit) ref + +val init_rule: (unit -> unit) ref + +val install_bindings: (string -> unit) ref diff --git a/parsing_cocci/disjdistr.ml b/parsing_cocci/disjdistr.ml new file mode 100644 index 0000000..c624418 --- /dev/null +++ b/parsing_cocci/disjdistr.ml @@ -0,0 +1,393 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast = Ast_cocci +module V = Visitor_ast + +let disjmult2 e1 e2 k = + List.concat + (List.map (function e1 -> List.map (function e2 -> k e1 e2) e2) e1) + +let disjmult3 e1 e2 e3 k = + List.concat + (List.map + (function e1 -> + List.concat + (List.map + (function e2 -> List.map (function e3 -> k e1 e2 e3) e3) + e2)) + e1) + +let rec disjmult f = function + [] -> [[]] + | x::xs -> + let cur = f x in + let rest = disjmult f xs in + disjmult2 cur rest (function cur -> function rest -> cur :: rest) + +let disjoption f = function + None -> [None] + | Some x -> List.map (function x -> Some x) (f x) + +let disjdots f d = + match Ast.unwrap d with + Ast.DOTS(l) -> + List.map (function l -> Ast.rewrap d (Ast.DOTS(l))) (disjmult f l) + | Ast.CIRCLES(l) -> + List.map (function l -> Ast.rewrap d (Ast.CIRCLES(l))) (disjmult f l) + | Ast.STARS(l) -> + List.map (function l -> Ast.rewrap d (Ast.STARS(l))) (disjmult f l) + +let rec disjty ft = + match Ast.unwrap ft with + Ast.Type(cv,ty) -> + let ty = disjtypeC ty in + List.map (function ty -> Ast.rewrap ft (Ast.Type(cv,ty))) ty + | Ast.DisjType(types) -> List.concat (List.map disjty types) + | Ast.OptType(ty) -> + let ty = disjty ty in + List.map (function ty -> Ast.rewrap ft (Ast.OptType(ty))) ty + | Ast.UniqueType(ty) -> + let ty = disjty ty in + List.map (function ty -> Ast.rewrap ft (Ast.UniqueType(ty))) ty + +and disjtypeC bty = + match Ast.unwrap bty with + Ast.BaseType(_,_) | Ast.ImplicitInt(_) -> [bty] + | Ast.Pointer(ty,star) -> + let ty = disjty ty in + List.map (function ty -> Ast.rewrap bty (Ast.Pointer(ty,star))) ty + | Ast.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + let ty = disjty ty in + List.map + (function ty -> + Ast.rewrap bty (Ast.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2))) + ty + | Ast.FunctionType (s,ty,lp1,params,rp1) -> + let ty = disjoption disjty ty in + List.map + (function ty -> + Ast.rewrap bty (Ast.FunctionType (s,ty,lp1,params,rp1))) + ty + | Ast.Array(ty,lb,size,rb) -> + disjmult2 (disjty ty) (disjoption disjexp size) + (function ty -> function size -> + Ast.rewrap bty (Ast.Array(ty,lb,size,rb))) + | Ast.StructUnionName(kind,name) -> [bty] + | Ast.StructUnionDef(ty,lb,decls,rb) -> + disjmult2 (disjty ty) (disjdots disjdecl decls) + (function ty -> function decls -> + Ast.rewrap bty (Ast.StructUnionDef(ty,lb,decls,rb))) + | Ast.TypeName(_) | Ast.MetaType(_,_,_) -> [bty] + +and disjexp e = + match Ast.unwrap e with + Ast.Ident(_) | Ast.Constant(_) -> [e] + | Ast.FunCall(fn,lp,args,rp) -> + disjmult2 (disjexp fn) (disjdots disjexp args) + (function fn -> function args -> + Ast.rewrap e (Ast.FunCall(fn,lp,args,rp))) + | Ast.Assignment(left,op,right,simple) -> + disjmult2 (disjexp left) (disjexp right) + (function left -> function right -> + Ast.rewrap e (Ast.Assignment(left,op,right,simple))) + | Ast.CondExpr(exp1,why,Some exp2,colon,exp3) -> + let res = disjmult disjexp [exp1;exp2;exp3] in + List.map + (function + [exp1;exp2;exp3] -> + Ast.rewrap e (Ast.CondExpr(exp1,why,Some exp2,colon,exp3)) + | _ -> failwith "not possible") + res + | Ast.CondExpr(exp1,why,None,colon,exp3) -> + disjmult2 (disjexp exp1) (disjexp exp3) + (function exp1 -> function exp3 -> + Ast.rewrap e (Ast.CondExpr(exp1,why,None,colon,exp3))) + | Ast.Postfix(exp,op) -> + let exp = disjexp exp in + List.map (function exp -> Ast.rewrap e (Ast.Postfix(exp,op))) exp + | Ast.Infix(exp,op) -> + let exp = disjexp exp in + List.map (function exp -> Ast.rewrap e (Ast.Infix(exp,op))) exp + | Ast.Unary(exp,op) -> + let exp = disjexp exp in + List.map (function exp -> Ast.rewrap e (Ast.Unary(exp,op))) exp + | Ast.Binary(left,op,right) -> + disjmult2 (disjexp left) (disjexp right) + (function left -> function right -> + Ast.rewrap e (Ast.Binary(left,op,right))) + | Ast.Nested(exp,op,right) -> + (* disj not possible in right *) + let exp = disjexp exp in + List.map (function exp -> Ast.rewrap e (Ast.Nested(exp,op,right))) exp + | Ast.Paren(lp,exp,rp) -> + let exp = disjexp exp in + List.map (function exp -> Ast.rewrap e (Ast.Paren(lp,exp,rp))) exp + | Ast.ArrayAccess(exp1,lb,exp2,rb) -> + disjmult2 (disjexp exp1) (disjexp exp2) + (function exp1 -> function exp2 -> + Ast.rewrap e (Ast.ArrayAccess(exp1,lb,exp2,rb))) + | Ast.RecordAccess(exp,pt,field) -> + let exp = disjexp exp in + List.map + (function exp -> Ast.rewrap e (Ast.RecordAccess(exp,pt,field))) exp + | Ast.RecordPtAccess(exp,ar,field) -> + let exp = disjexp exp in + List.map + (function exp -> Ast.rewrap e (Ast.RecordPtAccess(exp,ar,field))) exp + | Ast.Cast(lp,ty,rp,exp) -> + disjmult2 (disjty ty) (disjexp exp) + (function ty -> function exp -> Ast.rewrap e (Ast.Cast(lp,ty,rp,exp))) + | Ast.SizeOfExpr(szf,exp) -> + let exp = disjexp exp in + List.map (function exp -> Ast.rewrap e (Ast.SizeOfExpr(szf,exp))) exp + | Ast.SizeOfType(szf,lp,ty,rp) -> + let ty = disjty ty in + List.map + (function ty -> Ast.rewrap e (Ast.SizeOfType(szf,lp,ty,rp))) ty + | Ast.TypeExp(ty) -> + let ty = disjty ty in + List.map (function ty -> Ast.rewrap e (Ast.TypeExp(ty))) ty + | Ast.MetaErr(_,_,_,_) | Ast.MetaExpr(_,_,_,_,_,_) + | Ast.MetaExprList(_,_,_,_) | Ast.EComma(_) -> [e] + | Ast.DisjExpr(exp_list) -> List.concat (List.map disjexp exp_list) + | Ast.NestExpr(expr_dots,whencode,multi) -> + (* not sure what to do here, so ambiguities still possible *) + [e] + | Ast.Edots(dots,_) | Ast.Ecircles(dots,_) | Ast.Estars(dots,_) -> [e] + | Ast.OptExp(exp) -> + let exp = disjexp exp in + List.map (function exp -> Ast.rewrap e (Ast.OptExp(exp))) exp + | Ast.UniqueExp(exp) -> + let exp = disjexp exp in + List.map (function exp -> Ast.rewrap e (Ast.UniqueExp(exp))) exp + +and disjparam p = + match Ast.unwrap p with + Ast.VoidParam(ty) -> [p] (* void is the only possible value *) + | Ast.Param(ty,id) -> + let ty = disjty ty in + List.map (function ty -> Ast.rewrap p (Ast.Param(ty,id))) ty + | Ast.MetaParam(_,_,_) | Ast.MetaParamList(_,_,_,_) | Ast.PComma(_) -> [p] + | Ast.Pdots(dots) | Ast.Pcircles(dots) -> [p] + | Ast.OptParam(param) -> + let param = disjparam param in + List.map (function param -> Ast.rewrap p (Ast.OptParam(param))) param + | Ast.UniqueParam(param) -> + let param = disjparam param in + List.map (function param -> Ast.rewrap p (Ast.UniqueParam(param))) param + +and disjini i = + match Ast.unwrap i with + Ast.InitExpr(exp) -> + let exp = disjexp exp in + List.map (function exp -> Ast.rewrap i (Ast.InitExpr(exp))) exp + | Ast.InitList(lb,initlist,rb,whencode) -> + List.map + (function initlist -> + Ast.rewrap i (Ast.InitList(lb,initlist,rb,whencode))) + (disjmult disjini initlist) + | Ast.InitGccDotName(dot,name,eq,ini) -> + let ini = disjini ini in + List.map + (function ini -> Ast.rewrap i (Ast.InitGccDotName(dot,name,eq,ini))) + ini + | Ast.InitGccName(name,eq,ini) -> + let ini = disjini ini in + List.map + (function ini -> Ast.rewrap i (Ast.InitGccName(name,eq,ini))) + ini + | Ast.InitGccIndex(lb,exp,rb,eq,ini) -> + disjmult2 (disjexp exp) (disjini ini) + (function exp -> function ini -> + Ast.rewrap i (Ast.InitGccIndex(lb,exp,rb,eq,ini))) + | Ast.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> + disjmult3 (disjexp exp1) (disjexp exp2) (disjini ini) + (function exp1 -> function exp2 -> function ini -> + Ast.rewrap i (Ast.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini))) + | Ast.IComma(comma) -> [i] + | Ast.OptIni(ini) -> + let ini = disjini ini in + List.map (function ini -> Ast.rewrap i (Ast.OptIni(ini))) ini + | Ast.UniqueIni(ini) -> + let ini = disjini ini in + List.map (function ini -> Ast.rewrap i (Ast.UniqueIni(ini))) ini + +and disjdecl d = + match Ast.unwrap d with + Ast.Init(stg,ty,id,eq,ini,sem) -> + disjmult2 (disjty ty) (disjini ini) + (function ty -> function ini -> + Ast.rewrap d (Ast.Init(stg,ty,id,eq,ini,sem))) + | Ast.UnInit(stg,ty,id,sem) -> + let ty = disjty ty in + List.map (function ty -> Ast.rewrap d (Ast.UnInit(stg,ty,id,sem))) ty + | Ast.MacroDecl(name,lp,args,rp,sem) -> + List.map + (function args -> Ast.rewrap d (Ast.MacroDecl(name,lp,args,rp,sem))) + (disjdots disjexp args) + | Ast.TyDecl(ty,sem) -> + let ty = disjty ty in + List.map (function ty -> Ast.rewrap d (Ast.TyDecl(ty,sem))) ty + | Ast.Typedef(stg,ty,id,sem) -> + let ty = disjty ty in (* disj not allowed in id *) + List.map (function ty -> Ast.rewrap d (Ast.Typedef(stg,ty,id,sem))) ty + | Ast.DisjDecl(decls) -> List.concat (List.map disjdecl decls) + | Ast.Ddots(_,_) | Ast.MetaDecl(_,_,_) -> [d] + | Ast.OptDecl(decl) -> + let decl = disjdecl decl in + List.map (function decl -> Ast.rewrap d (Ast.OptDecl(decl))) decl + | Ast.UniqueDecl(decl) -> + let decl = disjdecl decl in + List.map (function decl -> Ast.rewrap d (Ast.UniqueDecl(decl))) decl + +let generic_orify_rule_elem f re exp rebuild = + match f exp with + [exp] -> re + | orexps -> Ast.rewrap re (Ast.DisjRuleElem (List.map rebuild orexps)) + +let orify_rule_elem re exp rebuild = + generic_orify_rule_elem disjexp re exp rebuild + +let orify_rule_elem_ty = generic_orify_rule_elem disjty +let orify_rule_elem_param = generic_orify_rule_elem disjparam +let orify_rule_elem_decl = generic_orify_rule_elem disjdecl + +let disj_rule_elem r k re = + match Ast.unwrap re with + Ast.FunHeader(bef,allminus,fninfo,name,lp,params,rp) -> + generic_orify_rule_elem (disjdots disjparam) re params + (function params -> + Ast.rewrap re + (Ast.FunHeader(bef,allminus,fninfo,name,lp,params,rp))) + | Ast.Decl(bef,allminus,decl) -> + orify_rule_elem_decl re decl + (function decl -> Ast.rewrap re (Ast.Decl(bef,allminus,decl))) + | Ast.SeqStart(brace) -> re + | Ast.SeqEnd(brace) -> re + | Ast.ExprStatement(exp,sem) -> + orify_rule_elem re exp + (function exp -> Ast.rewrap re (Ast.ExprStatement(exp,sem))) + | Ast.IfHeader(iff,lp,exp,rp) -> + orify_rule_elem re exp + (function exp -> Ast.rewrap re (Ast.IfHeader(iff,lp,exp,rp))) + | Ast.Else(els) -> re + | Ast.WhileHeader(whl,lp,exp,rp) -> + orify_rule_elem re exp + (function exp -> Ast.rewrap re (Ast.WhileHeader(whl,lp,exp,rp))) + | Ast.DoHeader(d) -> re + | Ast.WhileTail(whl,lp,exp,rp,sem) -> + orify_rule_elem re exp + (function exp -> Ast.rewrap re (Ast.WhileTail(whl,lp,exp,rp,sem))) + | Ast.ForHeader(fr,lp,e1,sem1,e2,sem2,e3,rp) -> + generic_orify_rule_elem (disjmult (disjoption disjexp)) re [e1;e2;e3] + (function + [exp1;exp2;exp3] -> + Ast.rewrap re (Ast.ForHeader(fr,lp,exp1,sem1,exp2,sem2,exp3,rp)) + | _ -> failwith "not possible") + | Ast.IteratorHeader(whl,lp,args,rp) -> + generic_orify_rule_elem (disjdots disjexp) re args + (function args -> Ast.rewrap re (Ast.IteratorHeader(whl,lp,args,rp))) + | Ast.SwitchHeader(switch,lp,exp,rp) -> + orify_rule_elem re exp + (function exp -> Ast.rewrap re (Ast.SwitchHeader(switch,lp,exp,rp))) + | Ast.Break(_,_) | Ast.Continue(_,_) | Ast.Label(_,_) | Ast.Goto(_,_,_) + | Ast.Return(_,_) -> re + | Ast.ReturnExpr(ret,exp,sem) -> + orify_rule_elem re exp + (function exp -> Ast.rewrap re (Ast.ReturnExpr(ret,exp,sem))) + | Ast.MetaRuleElem(_,_,_) | Ast.MetaStmt(_,_,_,_) + | Ast.MetaStmtList(_,_,_) -> re + | Ast.Exp(exp) -> + orify_rule_elem re exp (function exp -> Ast.rewrap exp (Ast.Exp(exp))) + | Ast.TopExp(exp) -> + orify_rule_elem re exp (function exp -> Ast.rewrap exp (Ast.TopExp(exp))) + | Ast.Ty(ty) -> + orify_rule_elem_ty re ty (function ty -> Ast.rewrap ty (Ast.Ty(ty))) + | Ast.Include(inc,s) -> re + | Ast.DefineHeader(def,id,params) -> re + | Ast.Default(def,colon) -> re + | Ast.Case(case,exp,colon) -> + orify_rule_elem re exp + (function exp -> Ast.rewrap re (Ast.Case(case,exp,colon))) + | Ast.DisjRuleElem(_) -> failwith "not possible" + +let disj_all = + let mcode x = x in + let donothing r k e = k e in + V.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing donothing + disj_rule_elem donothing donothing donothing donothing + +(* ----------------------------------------------------------------------- *) +(* collect iso information at the rule_elem level *) + +let collect_all_isos = + let bind = (@) in + let option_default = [] in + let mcode r x = [] in + let donothing r k e = Common.union_set (Ast.get_isos e) (k e) in + let doanything r k e = k e in + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing donothing + donothing doanything + +let collect_iso_info = + let mcode x = x in + let donothing r k e = k e in + let rule_elem r k e = + match Ast.unwrap e with + Ast.DisjRuleElem(l) -> k e + | _ -> + let isos = collect_all_isos.V.combiner_rule_elem e in + Ast.set_isos e isos in + V.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing rule_elem donothing donothing + donothing donothing + +(* ----------------------------------------------------------------------- *) + +let disj rules = + List.map + (function (mv,r) -> + match r with + Ast.ScriptRule _ -> (mv, r) + | Ast.CocciRule (nm, rule_info, r, isexp) -> + let res = + List.map + (function x -> + let res = disj_all.V.rebuilder_top_level x in + if !Flag.track_iso_usage + then collect_iso_info.V.rebuilder_top_level res + else res) + r in + (mv, Ast.CocciRule (nm,rule_info,res,isexp))) + rules diff --git a/parsing_cocci/disjdistr.mli b/parsing_cocci/disjdistr.mli new file mode 100644 index 0000000..ae9c339 --- /dev/null +++ b/parsing_cocci/disjdistr.mli @@ -0,0 +1,2 @@ +val disj : + Ast_cocci.rule_with_metavars list -> Ast_cocci.rule_with_metavars list diff --git a/parsing_cocci/flag_parsing_cocci.ml b/parsing_cocci/flag_parsing_cocci.ml new file mode 100644 index 0000000..baecee0 --- /dev/null +++ b/parsing_cocci/flag_parsing_cocci.ml @@ -0,0 +1,29 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* uses E rather than A and adds comments indicating the start and end of +each matched term *) + +let sgrep_mode = ref false (* no longer supported, subsumed by sgrep2 *) + +let show_SP = ref false +let show_iso_failures = ref true diff --git a/parsing_cocci/free_vars.ml b/parsing_cocci/free_vars.ml new file mode 100644 index 0000000..2ff5545 --- /dev/null +++ b/parsing_cocci/free_vars.ml @@ -0,0 +1,789 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* For each rule return the list of variables that are used after it. +Also augment various parts of each rule with unitary, inherited, and freshness +informations *) + +module Ast = Ast_cocci +module V = Visitor_ast +module TC = Type_cocci + +let rec nub = function + [] -> [] + | (x::xs) when (List.mem x xs) -> nub xs + | (x::xs) -> x::(nub xs) + +(* Collect all variable references in a minirule. For a disj, we collect +the maximum number (2 is enough) of references in any branch. *) + +let collect_unitary_nonunitary free_usage = + let free_usage = List.sort compare free_usage in + let rec loop1 todrop = function (* skips multiple occurrences *) + [] -> [] + | (x::xs) as all -> if x = todrop then loop1 todrop xs else all in + let rec loop2 = function + [] -> ([],[]) + | [x] -> ([x],[]) + | x::y::xs -> + if x = y (* occurs more than once in free_usage *) + then + let (unitary,non_unitary) = loop2(loop1 x xs) in + (unitary,x::non_unitary) + else (* occurs only once in free_usage *) + let (unitary,non_unitary) = loop2 (y::xs) in + (x::unitary,non_unitary) in + loop2 free_usage + +let collect_refs include_constraints = + let bind x y = x @ y in + let option_default = [] in + + let donothing recursor k e = k e in (* just combine in the normal way *) + + let donothing_a recursor k e = (* anything is not wrapped *) + k e in (* just combine in the normal way *) + + (* the following considers that anything that occurs non-unitarily in one + branch occurs nonunitarily in all branches. This is not optimal, but + doing better seems to require a breadth-first traversal, which is + perhaps better to avoid. Also, unitarily is represented as occuring once, + while nonunitarily is represented as twice - more is irrelevant *) + (* cases for disjs and metavars *) + let bind_disj refs_branches = + let (unitary,nonunitary) = + List.split (List.map collect_unitary_nonunitary refs_branches) in + let unitary = nub (List.concat unitary) in + let nonunitary = nub (List.concat nonunitary) in + let unitary = + List.filter (function x -> not (List.mem x nonunitary)) unitary in + unitary@nonunitary@nonunitary in + + let metaid (x,_,_,_) = x in + + let astfvident recursor k i = + bind (k i) + (match Ast.unwrap i with + Ast.MetaId(name,_,_,_) | Ast.MetaFunc(name,_,_,_) + | Ast.MetaLocalFunc(name,_,_,_) -> [metaid name] + | _ -> option_default) in + + let rec type_collect res = function + TC.ConstVol(_,ty) | TC.Pointer(ty) | TC.FunctionPointer(ty) + | TC.Array(ty) -> type_collect res ty + | TC.MetaType(tyname,_,_) -> bind [tyname] res + | ty -> res in + + let astfvexpr recursor k e = + bind (k e) + (match Ast.unwrap e with + Ast.MetaExpr(name,_,_,Some type_list,_,_) -> + let types = List.fold_left type_collect option_default type_list in + bind [metaid name] types + | Ast.MetaErr(name,_,_,_) | Ast.MetaExpr(name,_,_,_,_,_) -> [metaid name] + | Ast.MetaExprList(name,None,_,_) -> [metaid name] + | Ast.MetaExprList(name,Some (lenname,_,_),_,_) -> + [metaid name;metaid lenname] + | Ast.DisjExpr(exps) -> bind_disj (List.map k exps) + | _ -> option_default) in + + let astfvdecls recursor k d = + bind (k d) + (match Ast.unwrap d with + Ast.DisjDecl(decls) -> bind_disj (List.map k decls) + | _ -> option_default) in + + let astfvfullType recursor k ty = + bind (k ty) + (match Ast.unwrap ty with + Ast.DisjType(types) -> bind_disj (List.map k types) + | _ -> option_default) in + + let astfvtypeC recursor k ty = + bind (k ty) + (match Ast.unwrap ty with + Ast.MetaType(name,_,_) -> [metaid name] + | _ -> option_default) in + + let astfvparam recursor k p = + bind (k p) + (match Ast.unwrap p with + Ast.MetaParam(name,_,_) -> [metaid name] + | Ast.MetaParamList(name,None,_,_) -> [metaid name] + | Ast.MetaParamList(name,Some(lenname,_,_),_,_) -> + [metaid name;metaid lenname] + | _ -> option_default) in + + let astfvrule_elem recursor k re = + (*within a rule_elem, pattern3 manages the coherence of the bindings*) + bind (k re) + (nub + (match Ast.unwrap re with + Ast.MetaRuleElem(name,_,_) | Ast.MetaStmt(name,_,_,_) + | Ast.MetaStmtList(name,_,_) -> [metaid name] + | _ -> option_default)) in + + let astfvstatement recursor k s = + bind (k s) + (match Ast.unwrap s with + Ast.Disj(stms) -> + bind_disj (List.map recursor.V.combiner_statement_dots stms) + | _ -> option_default) in + + let mcode r mc = + if include_constraints + then + match Ast.get_pos_var mc with + Ast.MetaPos(name,constraints,_,_,_) -> (metaid name)::constraints + | _ -> option_default + else option_default in + + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + astfvident astfvexpr astfvfullType astfvtypeC donothing astfvparam + astfvdecls astfvrule_elem astfvstatement donothing donothing donothing_a + +let collect_all_refs = collect_refs true +let collect_non_constraint_refs = collect_refs false + +let collect_all_rule_refs minirules = + List.fold_left (@) [] + (List.map collect_all_refs.V.combiner_top_level minirules) + +let collect_all_minirule_refs = collect_all_refs.V.combiner_top_level + +(* ---------------------------------------------------------------- *) + +let collect_saved = + let bind = Common.union_set in + let option_default = [] in + + let donothing recursor k e = k e in (* just combine in the normal way *) + + let metaid (x,_,_,_) = x in + + (* cases for metavariables *) + let astfvident recursor k i = + bind (k i) + (match Ast.unwrap i with + Ast.MetaId(name,_,TC.Saved,_) | Ast.MetaFunc(name,_,TC.Saved,_) + | Ast.MetaLocalFunc(name,_,TC.Saved,_) -> [metaid name] + | _ -> option_default) in + + let rec type_collect res = function + TC.ConstVol(_,ty) | TC.Pointer(ty) | TC.FunctionPointer(ty) + | TC.Array(ty) -> type_collect res ty + | TC.MetaType(tyname,TC.Saved,_) -> bind [tyname] res + | ty -> res in + + let astfvexpr recursor k e = + let tymetas = + match Ast.unwrap e with + Ast.MetaExpr(name,_,_,Some type_list,_,_) -> + List.fold_left type_collect option_default type_list + | _ -> [] in + let vars = + bind (k e) + (match Ast.unwrap e with + Ast.MetaErr(name,_,TC.Saved,_) | Ast.MetaExpr(name,_,TC.Saved,_,_,_) + | Ast.MetaExprList(name,None,TC.Saved,_) -> [metaid name] + | Ast.MetaExprList(name,Some (lenname,ls,_),ns,_) -> + let namesaved = + match ns with TC.Saved -> [metaid name] | _ -> [] in + let lensaved = + match ls with TC.Saved -> [metaid lenname] | _ -> [] in + lensaved @ namesaved + | _ -> option_default) in + bind tymetas vars in + + let astfvtypeC recursor k ty = + bind (k ty) + (match Ast.unwrap ty with + Ast.MetaType(name,TC.Saved,_) -> [metaid name] + | _ -> option_default) in + + let astfvparam recursor k p = + bind (k p) + (match Ast.unwrap p with + Ast.MetaParam(name,TC.Saved,_) + | Ast.MetaParamList(name,None,_,_) -> [metaid name] + | Ast.MetaParamList(name,Some (lenname,ls,_),ns,_) -> + let namesaved = + match ns with TC.Saved -> [metaid name] | _ -> [] in + let lensaved = + match ls with TC.Saved -> [metaid lenname] | _ -> [] in + lensaved @ namesaved + | _ -> option_default) in + + let astfvrule_elem recursor k re = + (*within a rule_elem, pattern3 manages the coherence of the bindings*) + bind (k re) + (nub + (match Ast.unwrap re with + Ast.MetaRuleElem(name,TC.Saved,_) | Ast.MetaStmt(name,TC.Saved,_,_) + | Ast.MetaStmtList(name,TC.Saved,_) -> [metaid name] + | _ -> option_default)) in + + let mcode r e = + match Ast.get_pos_var e with + Ast.MetaPos(name,_,_,TC.Saved,_) -> [metaid name] + | _ -> option_default in + + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + astfvident astfvexpr donothing astfvtypeC donothing astfvparam + donothing astfvrule_elem donothing donothing donothing donothing + +(* ---------------------------------------------------------------- *) + +(* For the rules under a given metavariable declaration, collect all of the +variables that occur in the plus code *) + +let cip_mcodekind r mck = + let process_anything_list_list anythings = + let astfvs = collect_all_refs.V.combiner_anything in + List.fold_left (@) [] + (List.map (function l -> List.fold_left (@) [] (List.map astfvs l)) + anythings) in + match mck with + Ast.MINUS(_,anythings) -> process_anything_list_list anythings + | Ast.CONTEXT(_,befaft) -> + (match befaft with + Ast.BEFORE(ll) -> process_anything_list_list ll + | Ast.AFTER(ll) -> process_anything_list_list ll + | Ast.BEFOREAFTER(llb,lla) -> + (process_anything_list_list lla) @ + (process_anything_list_list llb) + | Ast.NOTHING -> []) + | Ast.PLUS -> [] + +let collect_in_plus_term = + let bind x y = x @ y in + let option_default = [] in + let donothing r k e = k e in + + (* no positions in the + code *) + let mcode r (_,_,mck,_) = cip_mcodekind r mck in + + (* case for things with bef/aft mcode *) + + let astfvrule_elem recursor k re = + match Ast.unwrap re with + Ast.FunHeader(bef,_,fi,nm,_,params,_) -> + let fi_metas = + List.concat + (List.map + (function + Ast.FType(ty) -> collect_all_refs.V.combiner_fullType ty + | _ -> []) + fi) in + let nm_metas = collect_all_refs.V.combiner_ident nm in + let param_metas = + match Ast.unwrap params with + Ast.DOTS(params) | Ast.CIRCLES(params) -> + List.concat + (List.map + (function p -> + match Ast.unwrap p with + Ast.VoidParam(t) | Ast.Param(t,_) -> + collect_all_refs.V.combiner_fullType t + | _ -> []) + params) + | _ -> failwith "not allowed for params" in + bind fi_metas + (bind nm_metas + (bind param_metas + (bind (cip_mcodekind recursor bef) (k re)))) + | Ast.Decl(bef,_,_) -> + bind (cip_mcodekind recursor bef) (k re) + | _ -> k re in + + let astfvstatement recursor k s = + match Ast.unwrap s with + Ast.IfThen(_,_,(_,_,_,aft)) | Ast.IfThenElse(_,_,_,_,(_,_,_,aft)) + | Ast.While(_,_,(_,_,_,aft)) | Ast.For(_,_,(_,_,_,aft)) + | Ast.Iterator(_,_,(_,_,_,aft)) -> + bind (k s) (cip_mcodekind recursor aft) + | _ -> k s in + + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing + donothing astfvrule_elem astfvstatement donothing donothing donothing + +let collect_in_plus minirules = + nub + (List.concat + (List.map collect_in_plus_term.V.combiner_top_level minirules)) + +(* ---------------------------------------------------------------- *) + +(* For the rules under a given metavariable declaration, collect all of the +variables that occur only once and more than once in the minus code *) + +let collect_all_multirefs minirules = + let refs = List.map collect_all_refs.V.combiner_top_level minirules in + collect_unitary_nonunitary (List.concat refs) + +(* ---------------------------------------------------------------- *) + +(* classify as unitary (no binding) or nonunitary (env binding) or saved +(witness binding) *) + +let classify_variables metavars minirules used_after = + let metavars = List.map Ast.get_meta_name metavars in + let (unitary,nonunitary) = collect_all_multirefs minirules in + let inplus = collect_in_plus minirules in + + let donothing r k e = k e in + let check_unitary name inherited = + if List.mem name inplus or List.mem name used_after + then TC.Saved + else if not inherited && List.mem name unitary + then TC.Unitary + else TC.Nonunitary in + + let get_option f = function Some x -> Some (f x) | None -> None in + + let classify (name,_,_,_) = + let inherited = not (List.mem name metavars) in + (check_unitary name inherited,inherited) in + + let mcode mc = + match Ast.get_pos_var mc with + Ast.MetaPos(name,constraints,per,unitary,inherited) -> + let (unitary,inherited) = classify name in + Ast.set_pos_var (Ast.MetaPos(name,constraints,per,unitary,inherited)) + mc + | _ -> mc in + + let ident r k e = + let e = k e in + match Ast.unwrap e with + Ast.MetaId(name,constraints,_,_) -> + let (unitary,inherited) = classify name in + Ast.rewrap e (Ast.MetaId(name,constraints,unitary,inherited)) + | Ast.MetaFunc(name,constraints,_,_) -> + let (unitary,inherited) = classify name in + Ast.rewrap e (Ast.MetaFunc(name,constraints,unitary,inherited)) + | Ast.MetaLocalFunc(name,constraints,_,_) -> + let (unitary,inherited) = classify name in + Ast.rewrap e (Ast.MetaLocalFunc(name,constraints,unitary,inherited)) + | _ -> e in + + let rec type_infos = function + TC.ConstVol(cv,ty) -> TC.ConstVol(cv,type_infos ty) + | TC.Pointer(ty) -> TC.Pointer(type_infos ty) + | TC.FunctionPointer(ty) -> TC.FunctionPointer(type_infos ty) + | TC.Array(ty) -> TC.Array(type_infos ty) + | TC.MetaType(name,_,_) -> + let (unitary,inherited) = classify (name,(),(),Ast.NoMetaPos) in + Type_cocci.MetaType(name,unitary,inherited) + | ty -> ty in + + let expression r k e = + let e = k e in + match Ast.unwrap e with + Ast.MetaErr(name,constraints,_,_) -> + let (unitary,inherited) = classify name in + Ast.rewrap e (Ast.MetaErr(name,constraints,unitary,inherited)) + | Ast.MetaExpr(name,constraints,_,ty,form,_) -> + let (unitary,inherited) = classify name in + let ty = get_option (List.map type_infos) ty in + Ast.rewrap e (Ast.MetaExpr(name,constraints,unitary,ty,form,inherited)) + | Ast.MetaExprList(name,None,_,_) -> + (* lenname should have the same properties of being unitary or + inherited as name *) + let (unitary,inherited) = classify name in + Ast.rewrap e (Ast.MetaExprList(name,None,unitary,inherited)) + | Ast.MetaExprList(name,Some(lenname,_,_),_,_) -> + (* lenname should have the same properties of being unitary or + inherited as name *) + let (unitary,inherited) = classify name in + let (lenunitary,leninherited) = classify lenname in + Ast.rewrap e + (Ast.MetaExprList + (name,Some(lenname,lenunitary,leninherited),unitary,inherited)) + | _ -> e in + + let typeC r k e = + let e = k e in + match Ast.unwrap e with + Ast.MetaType(name,_,_) -> + let (unitary,inherited) = classify name in + Ast.rewrap e (Ast.MetaType(name,unitary,inherited)) + | _ -> e in + + let param r k e = + let e = k e in + match Ast.unwrap e with + Ast.MetaParam(name,_,_) -> + let (unitary,inherited) = classify name in + Ast.rewrap e (Ast.MetaParam(name,unitary,inherited)) + | Ast.MetaParamList(name,None,_,_) -> + let (unitary,inherited) = classify name in + Ast.rewrap e (Ast.MetaParamList(name,None,unitary,inherited)) + | Ast.MetaParamList(name,Some (lenname,_,_),_,_) -> + let (unitary,inherited) = classify name in + let (lenunitary,leninherited) = classify lenname in + Ast.rewrap e + (Ast.MetaParamList + (name,Some (lenname,lenunitary,leninherited),unitary,inherited)) + | _ -> e in + + let rule_elem r k e = + let e = k e in + match Ast.unwrap e with + Ast.MetaStmt(name,_,msi,_) -> + let (unitary,inherited) = classify name in + Ast.rewrap e (Ast.MetaStmt(name,unitary,msi,inherited)) + | Ast.MetaStmtList(name,_,_) -> + let (unitary,inherited) = classify name in + Ast.rewrap e (Ast.MetaStmtList(name,unitary,inherited)) + | _ -> e in + + let fn = V.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + ident expression donothing typeC donothing param donothing rule_elem + donothing donothing donothing donothing in + + List.map fn.V.rebuilder_top_level minirules + +(* ---------------------------------------------------------------- *) + +(* For a minirule, collect the set of non-local (not in "bound") variables that +are referenced. Store them in a hash table. *) + +(* bound means the metavariable was declared previously, not locally *) + +(* Highly inefficient, because we call collect_all_refs on nested code +multiple times. But we get the advantage of not having too many variants +of the same functions. *) + +(* Inherited doesn't include position constraints. If they are not bound +then there is no constraint. *) + +let astfvs metavars bound = + let fresh = + List.fold_left + (function prev -> + function + Ast.MetaFreshIdDecl(_,_) as x -> (Ast.get_meta_name x)::prev + | _ -> prev) + [] metavars in + + let collect_fresh = List.filter (function x -> List.mem x fresh) in + + (* cases for the elements of anything *) + let astfvrule_elem recursor k re = + let minus_free = nub (collect_all_refs.V.combiner_rule_elem re) in + let minus_nc_free = + nub (collect_non_constraint_refs.V.combiner_rule_elem re) in + let plus_free = collect_in_plus_term.V.combiner_rule_elem re in + let free = Common.union_set minus_free plus_free in + let nc_free = Common.union_set minus_nc_free plus_free in + let unbound = + List.filter (function x -> not(List.mem x bound)) free in + let inherited = + List.filter (function x -> List.mem x bound) nc_free in + let munbound = + List.filter (function x -> not(List.mem x bound)) minus_free in + {(k re) with + Ast.free_vars = unbound; + Ast.minus_free_vars = munbound; + Ast.fresh_vars = collect_fresh unbound; + Ast.inherited = inherited; + Ast.saved_witness = []} in + + let astfvstatement recursor k s = + let minus_free = nub (collect_all_refs.V.combiner_statement s) in + let minus_nc_free = + nub (collect_non_constraint_refs.V.combiner_statement s) in + let plus_free = collect_in_plus_term.V.combiner_statement s in + let free = Common.union_set minus_free plus_free in + let nc_free = Common.union_set minus_nc_free plus_free in + let classify free minus_free = + let (unbound,inherited) = + List.partition (function x -> not(List.mem x bound)) free in + let munbound = + List.filter (function x -> not(List.mem x bound)) minus_free in + (unbound,munbound,collect_fresh unbound,inherited) in + let res = k s in + let s = + match Ast.unwrap res with + Ast.IfThen(header,branch,(_,_,_,aft)) -> + let (unbound,_,fresh,inherited) = + classify (cip_mcodekind collect_in_plus_term aft) [] in + Ast.IfThen(header,branch,(unbound,fresh,inherited,aft)) + | Ast.IfThenElse(header,branch1,els,branch2,(_,_,_,aft)) -> + let (unbound,_,fresh,inherited) = + classify (cip_mcodekind collect_in_plus_term aft) [] in + Ast.IfThenElse(header,branch1,els,branch2, + (unbound,fresh,inherited,aft)) + | Ast.While(header,body,(_,_,_,aft)) -> + let (unbound,_,fresh,inherited) = + classify (cip_mcodekind collect_in_plus_term aft) [] in + Ast.While(header,body,(unbound,fresh,inherited,aft)) + | Ast.For(header,body,(_,_,_,aft)) -> + let (unbound,_,fresh,inherited) = + classify (cip_mcodekind collect_in_plus_term aft) [] in + Ast.For(header,body,(unbound,fresh,inherited,aft)) + | Ast.Iterator(header,body,(_,_,_,aft)) -> + let (unbound,_,fresh,inherited) = + classify (cip_mcodekind collect_in_plus_term aft) [] in + Ast.Iterator(header,body,(unbound,fresh,inherited,aft)) + | s -> s in + + let (unbound,munbound,fresh,_) = classify free minus_free in + let inherited = + List.filter (function x -> List.mem x bound) nc_free in + {res with + Ast.node = s; + Ast.free_vars = unbound; + Ast.minus_free_vars = munbound; + Ast.fresh_vars = collect_fresh unbound; + Ast.inherited = inherited; + Ast.saved_witness = []} in + + let astfvstatement_dots recursor k sd = + let minus_free = nub (collect_all_refs.V.combiner_statement_dots sd) in + let minus_nc_free = + nub (collect_non_constraint_refs.V.combiner_statement_dots sd) in + let plus_free = collect_in_plus_term.V.combiner_statement_dots sd in + let free = Common.union_set minus_free plus_free in + let nc_free = Common.union_set minus_nc_free plus_free in + let unbound = + List.filter (function x -> not(List.mem x bound)) free in + let inherited = + List.filter (function x -> List.mem x bound) nc_free in + let munbound = + List.filter (function x -> not(List.mem x bound)) minus_free in + {(k sd) with + Ast.free_vars = unbound; + Ast.minus_free_vars = munbound; + Ast.fresh_vars = collect_fresh unbound; + Ast.inherited = inherited; + Ast.saved_witness = []} in + + let astfvtoplevel recursor k tl = + let saved = collect_saved.V.combiner_top_level tl in + {(k tl) with Ast.saved_witness = saved} in + + let mcode x = x in + let donothing r k e = k e in + + V.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing astfvstatement_dots donothing + donothing donothing donothing donothing donothing donothing donothing + astfvrule_elem astfvstatement donothing astfvtoplevel donothing + +(* +let collect_astfvs rules = + let rec loop bound = function + [] -> [] + | (metavars,(nm,rule_info,minirules))::rules -> + let bound = + Common.minus_set bound (List.map Ast.get_meta_name metavars) in + (nm,rule_info, + (List.map (astfvs metavars bound).V.rebuilder_top_level minirules)):: + (loop ((List.map Ast.get_meta_name metavars)@bound) rules) in + loop [] rules +*) + +let collect_astfvs rules = + let rec loop bound = function + [] -> [] + | (metavars, rule)::rules -> + match rule with + Ast.ScriptRule (_,_,_,_) -> + (* bound stays as is because script rules have no names, so no + inheritance is possible *) + rule::(loop bound rules) + | Ast.CocciRule (nm, rule_info, minirules, isexp) -> + let bound = + Common.minus_set bound (List.map Ast.get_meta_name metavars) in + (Ast.CocciRule + (nm, rule_info, + (List.map (astfvs metavars bound).V.rebuilder_top_level + minirules), + isexp)):: + (loop ((List.map Ast.get_meta_name metavars)@bound) rules) in + loop [] rules + +(* ---------------------------------------------------------------- *) +(* position variables that appear as a constraint on another position variable. +a position variable also cannot appear both positively and negatively in a +single rule. *) + +let get_neg_pos_list (_,rule) used_after_list = + let donothing r k e = k e in + let bind (p1,np1) (p2,np2) = + (Common.union_set p1 p2, Common.union_set np1 np2) in + let option_default = ([],[]) in + let metaid (x,_,_,_) = x in + let mcode r mc = + match Ast.get_pos_var mc with + Ast.MetaPos(name,constraints,Ast.PER,_,_) -> + ([metaid name],constraints) + | Ast.MetaPos(name,constraints,Ast.ALL,_,_) -> + ([],(metaid name)::constraints) + | _ -> option_default in + let v = + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing in + match rule with + Ast.CocciRule(_,_,minirules,_) -> + List.map + (function toplevel -> + let (positions,neg_positions) = v.V.combiner_top_level toplevel in + (if List.exists (function p -> List.mem p neg_positions) positions + then + failwith + "a variable cannot be used both as a position and a constraint"); + neg_positions) + minirules + | Ast.ScriptRule _ -> [] (*no negated positions*) + +(* ---------------------------------------------------------------- *) + +(* collect used after lists, per minirule *) + +(* defined is a list of variables that were declared in a previous metavar +declaration *) + +(* Top-level used after: For each rule collect the set of variables that +are inherited, ie used but not defined. These are accumulated back to +their point of definition. *) + + +let collect_top_level_used_after metavar_rule_list = + let (used_after,used_after_lists) = + List.fold_right + (function (metavar_list,r) -> + function (used_after,used_after_lists) -> + let locally_defined = List.map Ast.get_meta_name metavar_list in + let continue_propagation = + List.filter (function x -> not(List.mem x locally_defined)) + used_after in + let free_vars = + match r with + Ast.ScriptRule (_,_,mv,_) -> + List.map (function (_,(r,v)) -> (r,v)) mv + | Ast.CocciRule (_,_,rule,_) -> + Common.union_set (nub (collect_all_rule_refs rule)) + (collect_in_plus rule) in + let inherited = + List.filter (function x -> not (List.mem x locally_defined)) + free_vars in + (Common.union_set inherited continue_propagation, + used_after::used_after_lists)) + metavar_rule_list ([],[]) in + match used_after with + [] -> used_after_lists + | _ -> + failwith + (Printf.sprintf "collect_top_level_used_after: unbound variables %s" + (String.concat " " (List.map (function (_,x) -> x) used_after))) + +let collect_local_used_after metavars minirules used_after = + let locally_defined = List.map Ast.get_meta_name metavars in + let rec loop defined = function + [] -> (used_after,[],[]) + | minirule::rest -> + let free_vars = + Common.union_set + (nub (collect_all_minirule_refs minirule)) + (collect_in_plus_term.V.combiner_top_level minirule) in + let local_free_vars = + List.filter (function x -> List.mem x locally_defined) free_vars in + let new_defined = Common.union_set local_free_vars defined in + let (mini_used_after,fvs_lists,mini_used_after_lists) = + loop new_defined rest in + let local_used = Common.union_set local_free_vars mini_used_after in + let (new_used_after,new_list) = + List.partition (function x -> List.mem x defined) mini_used_after in + let new_used_after = Common.union_set local_used new_used_after in + (new_used_after,free_vars::fvs_lists, + new_list::mini_used_after_lists) in + let (_,fvs_lists,used_after_lists) = loop [] minirules in + (fvs_lists,used_after_lists) + + +let collect_used_after metavar_rule_list = + let used_after_lists = collect_top_level_used_after metavar_rule_list in + List.map2 + (function (metavars,r) -> + function used_after -> + match r with + Ast.ScriptRule (_,_,mv,_) -> ([], [used_after]) + | Ast.CocciRule (name, rule_info, minirules, _) -> + collect_local_used_after metavars minirules used_after + ) + metavar_rule_list used_after_lists + +(* ---------------------------------------------------------------- *) +(* entry point *) + +let free_vars rules = + let metavars = List.map (function (mv,rule) -> mv) rules in + let (fvs_lists,used_after_lists) = List.split (collect_used_after rules) in + let neg_pos_lists = List.map2 get_neg_pos_list rules used_after_lists in + let positions_list = (* for all rules, assume all positions are used after *) + List.map + (function (mv, r) -> + match r with + Ast.ScriptRule _ -> [] + | Ast.CocciRule (_,_,rule,_) -> + let positions = + List.fold_left + (function prev -> + function Ast.MetaPosDecl(_,nm) -> nm::prev | _ -> prev) + [] mv in + List.map (function _ -> positions) rule) + rules in + let new_rules = + List.map2 + (function (mv,r) -> + function ua -> + match r with + Ast.ScriptRule _ -> r + | Ast.CocciRule (nm, rule_info, r, is_exp) -> + Ast.CocciRule + (nm, rule_info, classify_variables mv r (List.concat ua), + is_exp)) + rules used_after_lists in + let new_rules = collect_astfvs (List.combine metavars new_rules) in + (new_rules,fvs_lists,neg_pos_lists,used_after_lists,positions_list) diff --git a/parsing_cocci/free_vars.mli b/parsing_cocci/free_vars.mli new file mode 100644 index 0000000..65918d6 --- /dev/null +++ b/parsing_cocci/free_vars.mli @@ -0,0 +1,10 @@ +(* Used after things can only have one binding. Positions can have many +bindings. These are combined in ctlcocciintegration, ie after the CTL +generation. *) + +val free_vars : Ast_cocci.rule_with_metavars list -> + (Ast_cocci.rule list) * + (((Ast_cocci.meta_name list) list) list) (*fvs of the rule*) * + (((Ast_cocci.meta_name list) list) list) (*negated position vars*) * + (((Ast_cocci.meta_name list) list) list) (*used after list*) * + (((Ast_cocci.meta_name list) list) list) (*positions list*) diff --git a/parsing_cocci/function_prototypes.ml b/parsing_cocci/function_prototypes.ml new file mode 100644 index 0000000..dcc255e --- /dev/null +++ b/parsing_cocci/function_prototypes.ml @@ -0,0 +1,426 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast0 = Ast0_cocci +module Ast = Ast_cocci +module V0 = Visitor_ast0 + +type id = Id of string | Meta of (string * string) + +let rec get_name name = + match Ast0.unwrap name with + Ast0.Id(nm) -> Id(Ast0.unwrap_mcode nm) + | Ast0.MetaId(nm,_,_) | Ast0.MetaFunc(nm,_,_) + | Ast0.MetaLocalFunc(nm,_,_) -> Meta(Ast0.unwrap_mcode nm) + | Ast0.OptIdent(id) | Ast0.UniqueIdent(id) -> + get_name id + +(* --------------------------------------------------------------------- *) +(* collect all of the functions *) + +let brace_to_semi (_,arity,info,mcodekind,pos) = + (";",Ast0.NONE,info,mcodekind,pos) + +let collect_function (stm : Ast0.statement) = + match Ast0.unwrap stm with + Ast0.FunDecl(_,fninfo,name,lp,params,rp,lbrace,body,rbrace) -> + let stg = + match + List.filter (function Ast0.FStorage(_) -> true | _ -> false) + fninfo with [Ast0.FStorage(s)] -> Some s | _ -> None in + let ty = + match + List.filter (function Ast0.FType(_) -> true | _ -> false) + fninfo with [Ast0.FType(t)] -> Some t | _ -> None in + [(get_name name,stm, + Ast0.copywrap stm + (Ast0.Decl((Ast0.default_info(),Ast0.context_befaft()), + Ast0.copywrap stm + (Ast0.UnInit + (stg, + Ast0.copywrap stm + (Ast0.FunctionType(ty,lp,params,rp)), + name,brace_to_semi lbrace)))))] + | _ -> [] + +let collect_functions stmt_dots = + List.concat (List.map collect_function (Ast0.undots stmt_dots)) + +let get_all_functions rule = + let res = + match Ast0.unwrap rule with + Ast0.DECL(stmt) -> collect_function stmt + | Ast0.CODE(rule_elem_dots) -> collect_functions rule_elem_dots + | _ -> [] in + List.map + (function (nm,def,vl) -> + (nm,(def,(Iso_pattern.rebuild_mcode None).V0.rebuilder_statement vl))) + res + +(* --------------------------------------------------------------------- *) +(* try to match up the functions *) + +(* pass through the - and + functions in lockstep, until one runs out. +Then process the remaining minuses, if any. If we can find another +function of the same name for either the current - or + function, take that +one. Otherwise, align the two current ones. *) + +let rec align all_minus all_plus = + let rec loop = function + ([],_) -> [] + | ((mname,(mdef,mproto))::minus,[]) -> + (try + let (_,pproto) = List.assoc mname all_plus in + (mname,mdef,mproto,Some pproto)::(loop (minus,[])) + with Not_found -> (mname,mdef,mproto,None)::(loop (minus, []))) + | ((mname,(mdef,mproto))::minus,(pname,(pdef,pproto))::plus) -> + if mname = pname + then (mname,mdef,mproto,Some pproto)::(loop (minus, [])) + else + (try + let (_,pproto_for_minus) = List.assoc mname all_plus in + (try + let _ = List.assoc mname all_plus in + (* protos that match both *) + (mname,mdef,mproto,Some pproto_for_minus)::(loop (minus, plus)) + with Not_found -> + (* proto that matches only minus *) + (mname,mdef,mproto,Some pproto_for_minus):: + (loop (minus, ((pname,(pdef,pproto))::plus)))) + with Not_found -> + (try + let _ = List.assoc mname all_plus in + (* proto only for plus *) + (mname,mdef,mproto,None)::(loop (minus, plus)) + with Not_found -> + (* protos for no one *) + (mname,mdef,mproto,Some pproto)::(loop (minus, plus)))) in + List.filter changed_proto (loop (all_minus, all_plus)) + +(* --------------------------------------------------------------------- *) + +and strip = + let donothing r k e = + {(Ast0.wrap (Ast0.unwrap (k e))) with Ast0.mcodekind = ref Ast0.PLUS} in + let mcode (mc,_,_,_,_) = + (mc,Ast0.NONE,Ast0.default_info(),Ast0.PLUS,ref Ast0.NoMetaPos) in + + (* need a case for everything that has an unvisited component and can be in + a function prototype *) + + let ident r k e = + donothing r k + (Ast0.rewrap e + (match Ast0.unwrap e with + Ast0.MetaId(nm,constraints,pure) -> + Ast0.MetaId(nm,constraints,Ast0.Pure) + | Ast0.MetaFunc(nm,constraints,pure) -> + Ast0.MetaFunc(nm,constraints,Ast0.Pure) + | Ast0.MetaLocalFunc(nm,constraints,pure) -> + Ast0.MetaLocalFunc(nm,constraints,Ast0.Pure) + | e -> e)) in + + let typeC r k e = + donothing r k + (Ast0.rewrap e + (match Ast0.unwrap e with + Ast0.MetaType(nm,pure) -> Ast0.MetaType(nm,Ast0.Pure) + | e -> e)) in + + let param r k e = + donothing r k + (Ast0.rewrap e + (match Ast0.unwrap e with + Ast0.MetaParam(nm,pure) -> + Ast0.MetaParam(nm,Ast0.Pure) + | Ast0.MetaParamList(nm,lenname,pure) -> + Ast0.MetaParamList(nm,lenname,Ast0.Pure) + | e -> e)) in + + V0.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + ident donothing typeC donothing param donothing donothing + donothing donothing + +and changed_proto = function + (mname,mdef,mproto,None) -> true + | (mname,mdef,mproto,Some pproto) -> + not ((strip.V0.rebuilder_statement mproto) = + (strip.V0.rebuilder_statement pproto)) + +(* --------------------------------------------------------------------- *) +(* make rules *) + +let rec drop_param_name p = + Ast0.rewrap p + (match Ast0.unwrap p with + Ast0.Param(p,_) -> Ast0.Param(p,None) + | Ast0.OptParam(p) -> Ast0.OptParam(drop_param_name p) + | Ast0.UniqueParam(p) -> Ast0.UniqueParam(p) + | p -> p) + +let drop_names dec = + let dec = (Iso_pattern.rebuild_mcode None).V0.rebuilder_statement dec in + match Ast0.unwrap dec with + Ast0.Decl(info,uninit) -> + (match Ast0.unwrap uninit with + Ast0.UnInit(stg,typ,name,sem) -> + (match Ast0.unwrap typ with + Ast0.FunctionType(ty,lp,params,rp) -> + let params = + match Ast0.unwrap params with + Ast0.DOTS(l) -> + Ast0.rewrap params (Ast0.DOTS(List.map drop_param_name l)) + | Ast0.CIRCLES(l) -> + Ast0.rewrap params + (Ast0.CIRCLES(List.map drop_param_name l)) + | Ast0.STARS(l) -> failwith "unexpected stars" in + Ast0.rewrap dec + (Ast0.Decl + (info, + Ast0.rewrap uninit + (Ast0.UnInit + (stg, + Ast0.rewrap typ + (Ast0.FunctionType(ty,lp,params,rp)), + name,sem)))) + | _ -> failwith "function prototypes: unexpected type") + | _ -> failwith "unexpected declaration") + | _ -> failwith "unexpected term" + +let ct = ref 0 + +let new_name name = + let n = !ct in + ct := !ct + 1; + name^"__"^(string_of_int n) + +let rec rename_param old_name all param = + match Ast0.unwrap param with + Ast0.Param(ty,Some id) when all -> + (match Ast0.unwrap id with + Ast0.MetaId(((_,name),arity,info,mcodekind,pos),constraints,pure) -> + let nm = ("__no_name__",new_name name) in + let new_id = + Ast0.rewrap id + (Ast0.MetaId + ((nm,arity,info,mcodekind,pos),constraints,Ast0.Pure)) in + ([Ast.MetaIdDecl(Ast.NONE,nm)], + Ast0.rewrap param (Ast0.Param(ty,Some new_id))) + | _ -> ([],param)) + | Ast0.Pdots(d) -> + let nm = (old_name,new_name "__P") in + let nml = (old_name,new_name "__n") in + let new_id = + Ast0.rewrap param + (Ast0.MetaParamList(Ast0.rewrap_mcode d nm, + Some (Ast0.rewrap_mcode d nml), + Ast0.Pure)) in + ([Ast.MetaParamListDecl(Ast.NONE,nm,Some nml);Ast.MetaListlenDecl(nml)], + new_id) + | Ast0.OptParam(p) -> + let (metavars,p) = rename_param old_name all p in + (metavars,Ast0.rewrap param (Ast0.OptParam(p))) + | Ast0.UniqueParam(p) -> + let (metavars,p) = rename_param old_name all p in + (metavars,Ast0.rewrap param (Ast0.UniqueParam(p))) + | _ -> ([],param) + +(* try to convert names in the - parameter list to new metavariables, to +account for spelling mistakes on the part of the programmer *) +let fresh_names old_name mdef dec = + let res = ([],[],dec,mdef) in + match Ast0.unwrap dec with + Ast0.Decl(info,uninit) -> + (match Ast0.unwrap uninit with + Ast0.UnInit(stg,typ,name,sem) -> + (match Ast0.unwrap typ with + Ast0.FunctionType(ty,lp,params,rp) -> + let (metavars,newdec) = + let (metavars,l) = + List.split + (List.map (rename_param old_name true) + (Ast0.undots params)) in + (List.concat metavars, + Ast0.rewrap dec + (Ast0.Decl + (info, + Ast0.rewrap uninit + (Ast0.UnInit + (stg, + Ast0.rewrap typ + (Ast0.FunctionType + (ty,lp,Ast0.rewrap params (Ast0.DOTS(l)), + rp)), + name,sem))))) in + let (def_metavars,newdef) = + match Ast0.unwrap mdef with + Ast0.FunDecl(x,fninfo,name,lp,params,rp,lb,body,rb) -> + let (def_metavars,def_l) = + List.split + (List.map (rename_param old_name false) + (Ast0.undots params)) in + (List.concat def_metavars, + Ast0.rewrap mdef + (Ast0.FunDecl(x,fninfo,name,lp, + Ast0.rewrap params (Ast0.DOTS(def_l)), + rp,lb,body,rb))) + | _ -> failwith "unexpected function definition" in + (metavars,def_metavars,newdec,newdef) + | _ -> res) + | _ -> res) + | _ -> res + +(* since there is no + counterpart, the function must be completely deleted *) +let no_names dec = + match Ast0.unwrap dec with + Ast0.Decl(info,uninit) -> + (match Ast0.unwrap uninit with + Ast0.UnInit(stg,typ,name,sem) -> + (match Ast0.unwrap typ with + Ast0.FunctionType(ty,lp,params,rp) -> + Ast0.rewrap dec + (Ast0.Decl + (info, + Ast0.rewrap uninit + (Ast0.UnInit + (stg, + Ast0.rewrap typ + (Ast0.FunctionType + (ty,lp, + Ast0.rewrap params + (let info = Ast0.get_info params in + let mcodekind = + (* use the mcodekind of an atomic minused + thing *) + Ast0.get_mcode_mcodekind lp in + let pdots = + ("...",Ast0.NONE,info,mcodekind, + ref Ast0.NoMetaPos) in + Ast0.DOTS + ([Ast0.rewrap params + (Ast0.Pdots(pdots))])), + rp)), + name,sem)))) + | _ -> dec) + | _ -> dec) + | _ -> dec + +let merge mproto pproto = + let mproto = + Compute_lines.compute_lines [Ast0.copywrap mproto (Ast0.DECL mproto)] in + let pproto = + Compute_lines.compute_lines [Ast0.copywrap pproto (Ast0.DECL pproto)] in + let (m,p) = List.split(Context_neg.context_neg mproto pproto) in + Insert_plus.insert_plus m p; + (* convert to ast so that the + code will fall down to the tokens + and off the artificially added Ast0.DECL *) + let mproto = Ast0toast.ast0toast_toplevel (List.hd mproto) in + (* clean up the wrapping added above *) + match Ast.unwrap mproto with + Ast.DECL mproto -> mproto + | _ -> failwith "not possible" + +let make_rule rule_name = function + (mname,mdef,mproto,Some pproto) -> + let (metavars,mdef_metavars,mproto,mdef) = + fresh_names rule_name mdef mproto in + let no_name_mproto = drop_names mproto in + let no_name_pproto = drop_names pproto in + (metavars,mdef_metavars, + [merge mproto pproto; merge no_name_mproto no_name_pproto],mdef) + | (mname,mdef,mproto,None) -> + ([],[],[Ast0toast.statement(no_names mproto)],mdef) + +(* --------------------------------------------------------------------- *) + +let reinsert mdefs minus = + let table = + List.map + (function x -> + match Ast0.unwrap x with + Ast0.FunDecl(_,fninfo,name,lp,params,rp,lbrace,body,rbrace) -> + (name,x) + | _ -> failwith "bad mdef") + mdefs in + List.map + (function x -> + match Ast0.unwrap x with + Ast0.DECL(stmt) -> + (match Ast0.unwrap stmt with + Ast0.FunDecl(_,fninfo,name,lp,params,rp,lbrace,body,rbrace) -> + (try Ast0.rewrap x (Ast0.DECL(List.assoc name table)) + with Not_found -> x) + | _ -> x) + | Ast0.CODE(rule_elem_dots) -> + (* let's hope there are no functions in here... *) + x + | _ -> x) + minus + +(* --------------------------------------------------------------------- *) +(* entry point *) + +let rec split4 = function + [] -> ([],[],[],[]) + | (a,b,c,d)::rest -> + let (ax,bx,cx,dx) = split4 rest in (a::ax,b::bx,c::cx,d::dx) + +let process rule_name rule_metavars dropped_isos minus plus = + let minus_functions = List.concat (List.map get_all_functions minus) in + match minus_functions with + [] -> ((rule_metavars,minus),None) + | _ -> + let plus_functions = + List.concat (List.map get_all_functions plus) in + let protos = align minus_functions plus_functions in + let (metavars,mdef_metavars,rules,mdefs) = + split4(List.map (make_rule rule_name) protos) in + let metavars = List.concat metavars in + let mdef_metavars = (List.concat mdef_metavars) @ rule_metavars in + let rules = List.concat rules in + let minus = reinsert mdefs minus in + match rules with + [] -> ((rule_metavars,minus),None) + | [x] -> + (* probably not possible, since there is always the version with + variables and the version without *) + ((mdef_metavars,minus), + Some + (metavars, + Ast.CocciRule + ("proto for "^rule_name, + (Ast.Dep rule_name,dropped_isos,Ast.Forall), + [Ast.rewrap x (Ast.DECL x)], + [false]))) + | x::_ -> + let drules = + List.map (function x -> Ast.rewrap x (Ast.DOTS [x])) rules in + let res = + Ast.CocciRule + ("proto for "^rule_name, + (Ast.Dep rule_name,dropped_isos,Ast.Forall), + [Ast.rewrap x (Ast.DECL (Ast.rewrap x (Ast.Disj drules)))], + [false]) in + ((mdef_metavars,minus),Some(metavars,res)) diff --git a/parsing_cocci/function_prototypes.mli b/parsing_cocci/function_prototypes.mli new file mode 100644 index 0000000..4bcd346 --- /dev/null +++ b/parsing_cocci/function_prototypes.mli @@ -0,0 +1,5 @@ +val process : string (* name *) -> Ast_cocci.metavar list -> + string list (* dropped isos *) -> + Ast0_cocci.rule -> Ast0_cocci.rule -> + ((Ast_cocci.metavar list * Ast0_cocci.rule) * + Ast_cocci.rule_with_metavars option) diff --git a/parsing_cocci/get_constants.ml b/parsing_cocci/get_constants.ml new file mode 100644 index 0000000..3cd8f90 --- /dev/null +++ b/parsing_cocci/get_constants.ml @@ -0,0 +1,322 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* get a list of all of the constants in the - slice of a SmPL file, to be +used to select which files to process *) + +(* This could be made more efficient, by finding only the important things. +eg, if we have a function and its arguments, we could just pick the function. +And we could try to pick only the things annotated with -, and only pick +something else if there is no -. In general, we only want the most important +constant, not all the constants. *) + +module Ast = Ast_cocci +module V = Visitor_ast +module TC = Type_cocci + +let keep_some_bind x y = match x with [] -> y | _ -> x +let or_bind x y = match x with [] -> [] | _ -> x +let keep_all_bind = Common.union_set + +let get_minus_constants bind orbind = + let donothing r k e = k e in + let option_default = [] in + let mcode _ _ = option_default in + + (* if one branch gives no information, then we have to take anything *) + let disj_union_all l = + if List.exists (function [] -> true | _ -> false) l + then orbind [] (Common.union_all l) + else Common.union_all l in + + (* need special cases for everything with a disj, because the bind above + would throw away all but the first disj *) + + let ident r k e = + match Ast.unwrap e with + Ast.Id(name) -> + (match Ast.unwrap_mcode name with + "NULL" -> [] (* special case, because this is too generic *) + | nm -> [nm]) + | _ -> k e in + + let expression r k e = + match Ast.unwrap e with + Ast.RecordAccess(exp,_,fld) | Ast.RecordPtAccess(exp,_,fld) -> + bind + (Common.union_all + (List.map (function id -> ["."^id;"->"^id]) + (r.V.combiner_ident fld))) + (r.V.combiner_expression exp) + | Ast.SizeOfExpr(sizeof,_) | Ast.SizeOfType(sizeof,_,_,_) -> + bind (k e) [Ast.unwrap_mcode sizeof] + | Ast.DisjExpr(exps) -> + disj_union_all (List.map r.V.combiner_expression exps) + | Ast.Edots(_,_) | Ast.Ecircles(_,_) | Ast.Estars(_,_) -> [] + | Ast.NestExpr(expr_dots,whencode,false) -> [] + | Ast.NestExpr(expr_dots,whencode,true) -> + r.V.combiner_expression_dots expr_dots + | _ -> k e in + + let typeC r k e = + match Ast.unwrap e with + Ast.TypeName(ty) -> + if !Flag.sgrep_mode2 + then + match ty with + (_,_,Ast.MINUS(_,_),_) -> [Ast.unwrap_mcode ty] + | _ -> [] + else [Ast.unwrap_mcode ty] + | _ -> k e in + + let fullType r k e = + match Ast.unwrap e with + Ast.DisjType(types) -> + disj_union_all (List.map r.V.combiner_fullType types) + | _ -> k e in + + let declaration r k e = + match Ast.unwrap e with + Ast.DisjDecl(decls) -> + disj_union_all (List.map r.V.combiner_declaration decls) + | Ast.Ddots(dots,whencode) -> [] + | _ -> k e in + + let rule_elem r k e = + match Ast.unwrap e with + Ast.DisjRuleElem(res) -> + disj_union_all (List.map r.V.combiner_rule_elem res) + | _ -> k e in + + let statement r k e = + match Ast.unwrap e with + Ast.Disj(stmt_dots) -> + disj_union_all (List.map r.V.combiner_statement_dots stmt_dots) + | Ast.Dots(d,whn,_,_) | Ast.Circles(d,whn,_,_) | Ast.Stars(d,whn,_,_) -> [] + | Ast.Nest(stmt_dots,whn,false,_,_) -> [] + | Ast.Nest(stmt_dots,whn,true,_,_) -> r.V.combiner_statement_dots stmt_dots + | _ -> k e in + + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + ident expression fullType typeC donothing donothing declaration + rule_elem statement donothing donothing donothing + +(* ------------------------------------------------------------------------ *) + +let get_all_minus_constants = + let donothing r k e = k e in + let bind = Common.union_set in + let option_default = [] in + let mcode r (x,_,mcodekind,_) = + match mcodekind with + Ast.MINUS(_,_) -> [x] + | _ -> [] in + let other r (x,_,mcodekind,_) = [] in + + V.combiner bind option_default + other mcode other other other other other other other other other other + other + + donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing +(* ------------------------------------------------------------------------ *) + +let get_plus_constants = + let donothing r k e = k e in + let bind = Common.union_set in + let option_default = [] in + let mcode r (_,_,mcodekind,_) = + let recurse l = + List.fold_left + (List.fold_left + (function prev -> + function cur -> + let fn = get_minus_constants keep_all_bind keep_all_bind in + bind (fn.V.combiner_anything cur) prev)) + [] l in + match mcodekind with + Ast.MINUS(_,anythings) -> recurse anythings + | Ast.CONTEXT(_,Ast.BEFORE(a)) -> recurse a + | Ast.CONTEXT(_,Ast.AFTER(a)) -> recurse a + | Ast.CONTEXT(_,Ast.BEFOREAFTER(a1,a2)) -> + Common.union_set (recurse a1) (recurse a2) + | _ -> [] in + + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing + +(* ------------------------------------------------------------------------ *) +(* see if there are any inherited variables that must be bound for this rule +to match *) + +let check_inherited nm = + let donothing r k e = k e in + let option_default = false in + let bind x y = x or y in + let inherited (nm1,_) = not(nm = nm1) in + let minherited mc = inherited (Ast.unwrap_mcode mc) in + let mcode _ x = + match Ast.get_pos_var x with + Ast.MetaPos(name,constraints,_,keep,inh) -> minherited name + | _ -> option_default in + + (* a case for everything for there is a metavariable, also disjunctions + or optional things *) + + let strictident recursor k i = + match Ast.unwrap i with + Ast.MetaId(name,_,_,_) | Ast.MetaFunc(name,_,_,_) + | Ast.MetaLocalFunc(name,_,_,_) -> bind (k i) (minherited name) + | _ -> k i in + + let rec type_collect res = function + TC.ConstVol(_,ty) | TC.Pointer(ty) | TC.FunctionPointer(ty) + | TC.Array(ty) -> type_collect res ty + | TC.MetaType(tyname,_,_) -> inherited tyname + | ty -> res in + + let strictexpr recursor k e = + match Ast.unwrap e with + Ast.MetaExpr(name,_,_,Some type_list,_,_) -> + let types = List.fold_left type_collect option_default type_list in + bind (minherited name) types + | Ast.MetaErr(name,_,_,_) | Ast.MetaExpr(name,_,_,_,_,_) -> + bind (k e) (minherited name) + | Ast.MetaExprList(name,None,_,_) -> bind (k e) (minherited name) + | Ast.MetaExprList(name,Some (lenname,_,_),_,_) -> + bind (k e) (bind (minherited name) (minherited lenname)) + | Ast.DisjExpr(exps) -> + (* could see if there are any variables that appear in all branches, + but perhaps not worth it *) + option_default + | _ -> k e in + + let strictdecls recursor k d = + match Ast.unwrap d with + Ast.DisjDecl(decls) -> option_default + | _ -> k d in + + let strictfullType recursor k ty = + match Ast.unwrap ty with + Ast.DisjType(types) -> option_default + | _ -> k ty in + + let stricttypeC recursor k ty = + match Ast.unwrap ty with + Ast.MetaType(name,_,_) -> bind (k ty) (minherited name) + | _ -> k ty in + + let strictparam recursor k p = + match Ast.unwrap p with + Ast.MetaParam(name,_,_) -> bind (k p) (minherited name) + | Ast.MetaParamList(name,None,_,_) -> bind (k p) (minherited name) + | Ast.MetaParamList(name,Some(lenname,_,_),_,_) -> + bind (k p) (bind (minherited name) (minherited lenname)) + | _ -> k p in + + let strictrule_elem recursor k re = + (*within a rule_elem, pattern3 manages the coherence of the bindings*) + match Ast.unwrap re with + Ast.MetaRuleElem(name,_,_) | Ast.MetaStmt(name,_,_,_) + | Ast.MetaStmtList(name,_,_) -> bind (k re) (minherited name) + | _ -> k re in + + let strictstatement recursor k s = + match Ast.unwrap s with + Ast.Disj(stms) -> option_default + | _ -> k s in + + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + strictident strictexpr strictfullType stricttypeC donothing strictparam + strictdecls strictrule_elem strictstatement donothing donothing donothing + +(* ------------------------------------------------------------------------ *) + +let rec dependent = function + Ast.Dep s -> true + | Ast.AntiDep s -> false + | Ast.EverDep s -> true + | Ast.NeverDep s -> false + | Ast.AndDep (d1,d2) -> dependent d1 or dependent d2 + | Ast.OrDep (d1,d2) -> dependent d1 && dependent d2 + | Ast.NoDep -> false + +(* ------------------------------------------------------------------------ *) + +let rule_fn tls in_plus = + List.fold_left + (function (rest_info,in_plus) -> + function cur -> + let mfn = get_minus_constants keep_some_bind or_bind in + let minuses = mfn.V.combiner_top_level cur in + let all_minuses = + if !Flag.sgrep_mode2 + then [] (* nothing removed for sgrep *) + else get_all_minus_constants.V.combiner_top_level cur in + let plusses = get_plus_constants.V.combiner_top_level cur in + (* the following is for eg -foo(2) +foo(x) then in another rule + -foo(10); don't want to consider that foo is guaranteed to be + created by the rule. not sure this works completely: what if foo is + in both - and +, but in an or, so the cases aren't related? + not sure this whole thing is a good idea. how do we know that + something that is only in plus is really freshly created? *) + let plusses = Common.minus_set plusses all_minuses in + let new_minuses = Common.minus_set minuses in_plus in + let new_plusses = Common.union_set plusses in_plus in + (Common.union_set new_minuses rest_info, new_plusses)) + ([],in_plus) tls + +exception No_info + +let get_constants rules = + try + let (info,_) = + List.fold_left + (function (rest_info,in_plus) -> + function r -> + match r with + Ast.ScriptRule (_,mv,deps,_) -> (rest_info, in_plus) + | Ast.CocciRule (nm, (dep,_,_), cur, _) -> + let (cur_info,cur_plus) = rule_fn cur in_plus in + let cur_info = + (* no dependencies if dependent on another rule; then we + need to find the constants of that rule *) + if dependent dep or + List.for_all (check_inherited nm).V.combiner_top_level cur + then [] + else + if cur_info = [] then raise No_info else cur_info in + (Common.union_set [cur_info] rest_info,cur_plus)) + ([],[]) rules in + List.rev info + with No_info -> List.map (function _ -> []) rules diff --git a/parsing_cocci/get_constants.mli b/parsing_cocci/get_constants.mli new file mode 100644 index 0000000..657faf5 --- /dev/null +++ b/parsing_cocci/get_constants.mli @@ -0,0 +1 @@ +val get_constants : Ast_cocci.rule list -> string list list diff --git a/parsing_cocci/get_constants2.ml b/parsing_cocci/get_constants2.ml new file mode 100644 index 0000000..6d66cf6 --- /dev/null +++ b/parsing_cocci/get_constants2.ml @@ -0,0 +1,494 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast = Ast_cocci +module V = Visitor_ast +module TC = Type_cocci + +(* Issues: + +1. If a rule X depends on a rule Y (in a positive way), then we can ignore + the constants in X. + +2. If a rule X contains a metavariable that is not under a disjunction and + that is inherited from rule Y, then we can ignore the constants in X. + +3. If a rule contains a constant x in + code then subsequent rules that + have it in - or context should not include it in their list of required + constants. +*) + +(* ----------------------------------------------------------------------- *) +(* This phase collects everything. One can then filter out what it not +wanted *) + +(* True means nothing was found + False should never drift to the top, it is the neutral element of or + and an or is never empty *) +type combine = + And of combine list | Or of combine list | Elem of string | False | True + +let interpret strict x = + let rec loop = function + Elem x -> x + | And [x] -> loop x + | Or [x] -> loop x + | And l -> Printf.sprintf "{%s}" (String.concat ";" (List.map loop l)) + | Or l -> Printf.sprintf "{%s}" (String.concat "," (List.map loop l)) + | True -> "True" + | False -> + if strict + then failwith "False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code" + else "False" in + match x with + True -> None + | False when strict -> + failwith "False should not be in the final result. Perhaps your rule doesn't contain any +/-/* code" + | _ -> Some (loop x) + +let combine2c x = + match interpret false x with + None -> "None" + | Some x -> x + +let norm = function + And l -> And (List.sort compare l) + | Or l -> Or (List.sort compare l) + | x -> x + +let rec merge l1 l2 = + match (l1,l2) with + ([],l2) -> l2 + | (l1,[]) -> l1 + | (x::xs,y::ys) -> + (match compare x y with + -1 -> x::(merge xs l2) + | 0 -> x::(merge xs ys) + | 1 -> y::(merge l1 ys) + | _ -> failwith "not possible") + +let intersect l1 l2 = List.filter (function l1e -> List.mem l1e l2) l1 + +let minus_set l1 l2 = List.filter (function l1e -> not (List.mem l1e l2)) l1 + +let rec insert x l = merge [x] l + +let rec build_and x y = + if x = y + then x + else + match (x,y) with + (True,x) | (x,True) -> x + | (False,x) | (x,False) -> False + | (And l1,And l2) -> And (merge l1 l2) + | (x,Or l) when List.mem x l -> x + | (Or l,x) when List.mem x l -> x + | (Or l1,Or l2) when not ((intersect l1 l2) = []) -> + let inner = + build_and + (List.fold_left build_or False (minus_set l1 l2)) + (List.fold_left build_or False (minus_set l2 l1)) in + List.fold_left build_or inner (intersect l1 l2) + | (x,And l) | (And l,x) -> + if List.mem x l + then And l + else + let others = + List.filter + (function + Or l -> not(List.mem x l) + | _ -> true) + l in + And (insert x others) + | (x,y) -> norm(And [x;y]) + +and build_or x y = + if x = y + then x + else + match (x,y) with + (True,x) | (x,True) -> True + | (False,x) | (x,False) -> x + | (Or l1,Or l2) -> Or (merge l1 l2) + | (x,And l) when List.mem x l -> x + | (And l,x) when List.mem x l -> x + | (And l1,And l2) when not ((intersect l1 l2) = []) -> + let inner = + build_or + (List.fold_left build_and True (minus_set l1 l2)) + (List.fold_left build_and True (minus_set l2 l1)) in + List.fold_left build_and inner (intersect l1 l2) + | (x,Or l) | (Or l,x) -> + if List.mem x l + then Or l + else + let others = + List.filter + (function + And l -> not(List.mem x l) + | _ -> true) + l in + Or (insert x others) + | (x,y) -> norm(Or [x;y]) + +let keep x = Elem x +let drop x = True + +let do_get_constants constants keywords env neg_pos = + let donothing r k e = k e in + let option_default = True in + let bind = build_and in + let inherited ((nm1,_) as x) = + (* perhaps inherited, but value not required, so no constraints *) + if List.mem x neg_pos then option_default + else try List.assoc nm1 env with Not_found -> False in + let minherited name = inherited (Ast.unwrap_mcode name) in + let mcode _ x = + match Ast.get_pos_var x with + Ast.MetaPos(name,constraints,_,keep,inh) -> minherited name + | _ -> option_default in + + (* if one branch gives no information, then we have to take anything *) + let disj_union_all = List.fold_left build_or False in + + let ident r k i = + match Ast.unwrap i with + Ast.Id(name) -> + bind (k i) + (match Ast.unwrap_mcode name with + "NULL" -> keywords "NULL" + | nm -> constants nm) + | Ast.MetaId(name,_,_,_) | Ast.MetaFunc(name,_,_,_) + | Ast.MetaLocalFunc(name,_,_,_) -> bind (k i) (minherited name) + | _ -> k i in + + let rec type_collect res = function + TC.ConstVol(_,ty) | TC.Pointer(ty) | TC.FunctionPointer(ty) + | TC.Array(ty) -> type_collect res ty + | TC.MetaType(tyname,_,_) -> inherited tyname + | TC.TypeName(s) -> constants s + | TC.StructUnionName(_,false,s) -> constants s + | ty -> res in + + (* no point to do anything special for records because glimpse is + word-oriented *) + let expression r k e = + match Ast.unwrap e with + Ast.Constant(const) -> + bind (k e) + (match Ast.unwrap_mcode const with + Ast.String s -> constants s + | Ast.Char "\\0" -> option_default (* glimpse doesn't like it *) + | Ast.Char s -> constants s + (* the following were eg keywords "1", but not good for glimpse *) + | Ast.Int "0" -> option_default (* glimpse doesn't like it *) + | Ast.Int "1" -> option_default (* glimpse doesn't like it *) + | Ast.Int s -> constants s + | Ast.Float s -> constants s) + | Ast.MetaExpr(name,_,_,Some type_list,_,_) -> + let types = List.fold_left type_collect option_default type_list in + bind (k e) (bind (minherited name) types) + | Ast.MetaErr(name,_,_,_) | Ast.MetaExpr(name,_,_,_,_,_) -> + bind (k e) (minherited name) + | Ast.MetaExprList(name,None,_,_) -> minherited name + | Ast.MetaExprList(name,Some (lenname,_,_),_,_) -> + bind (k e) (bind (minherited name) (minherited lenname)) + | Ast.SizeOfExpr(sizeof,exp) -> bind (keywords "sizeof") (k e) + | Ast.SizeOfType(sizeof,lp,ty,rp) -> bind (keywords "sizeof") (k e) + | Ast.NestExpr(expr_dots,wc,false) -> option_default + | Ast.NestExpr(expr_dots,wc,true) -> + r.V.combiner_expression_dots expr_dots + | Ast.DisjExpr(exps) -> + disj_union_all (List.map r.V.combiner_expression exps) + | Ast.OptExp(exp) -> option_default + | Ast.Edots(_,_) | Ast.Ecircles(_,_) | Ast.Estars(_,_) -> option_default + | _ -> k e in + + let fullType r k ft = + match Ast.unwrap ft with + Ast.DisjType(decls) -> + disj_union_all (List.map r.V.combiner_fullType decls) + | Ast.OptType(ty) -> option_default + | _ -> k ft in + + let baseType = function + Ast.VoidType -> keywords "void " + | Ast.CharType -> keywords "char " + | Ast.ShortType -> keywords "short " + | Ast.IntType -> keywords "int " + | Ast.DoubleType -> keywords "double " + | Ast.FloatType -> keywords "float " + | Ast.LongType -> keywords "long " in + + let typeC r k ty = + match Ast.unwrap ty with + Ast.BaseType(ty1,sgn) -> bind (k ty) (baseType (Ast.unwrap_mcode ty1)) + | Ast.TypeName(name) -> bind (k ty) (constants (Ast.unwrap_mcode name)) + | Ast.MetaType(name,_,_) -> bind (minherited name) (k ty) + | _ -> k ty in + + let declaration r k d = + match Ast.unwrap d with + Ast.DisjDecl(decls) -> + disj_union_all (List.map r.V.combiner_declaration decls) + | Ast.OptDecl(decl) -> option_default + | Ast.Ddots(dots,whencode) -> option_default + | _ -> k d in + + let initialiser r k i = + match Ast.unwrap i with + Ast.OptIni(ini) -> option_default + | _ -> k i in + + let parameter r k p = + match Ast.unwrap p with + Ast.OptParam(param) -> option_default + | Ast.MetaParam(name,_,_) -> bind (k p) (minherited name) + | Ast.MetaParamList(name,None,_,_) -> bind (k p) (minherited name) + | Ast.MetaParamList(name,Some(lenname,_,_),_,_) -> + bind (minherited name) (bind (minherited lenname) (k p)) + | _ -> k p in + + let rule_elem r k re = + match Ast.unwrap re with + Ast.MetaRuleElem(name,_,_) | Ast.MetaStmt(name,_,_,_) + | Ast.MetaStmtList(name,_,_) -> bind (minherited name) (k re) + | Ast.WhileHeader(whl,lp,exp,rp) -> + bind (keywords "while") (k re) + | Ast.WhileTail(whl,lp,exp,rp,sem) -> + bind (keywords "do") (k re) + | Ast.ForHeader(fr,lp,e1,sem1,e2,sem2,e3,rp) -> + bind (keywords "for") (k re) + | Ast.SwitchHeader(switch,lp,exp,rp) -> + bind (keywords "switch") (k re) + | Ast.Break(br,sem) -> + bind (keywords "break") (k re) + | Ast.Continue(cont,sem) -> + bind (keywords "continue") (k re) + | Ast.Goto(_,i,_) -> + bind (keywords "goto") (k re) + | Ast.Default(def,colon) -> + bind (keywords "default") (k re) + | Ast.Include(inc,s) -> + bind (k re) + (match Ast.unwrap_mcode s with + Ast.Local l | Ast.NonLocal l -> + let strings = + List.fold_left + (function prev -> + function + (* just take the last thing, probably the most + specific. everything is necessary anyway. *) + Ast.IncPath s -> [Elem s] + | Ast.IncDots -> prev) + [] l in + (match strings with + [] -> True + | x::xs -> List.fold_left bind x xs)) + | Ast.DisjRuleElem(res) -> + disj_union_all (List.map r.V.combiner_rule_elem res) + | _ -> k re in + + let statement r k s = + match Ast.unwrap s with + Ast.Disj(stmt_dots) -> + disj_union_all (List.map r.V.combiner_statement_dots stmt_dots) + | Ast.Nest(stmt_dots,whn,false,_,_) -> option_default + | Ast.Nest(stmt_dots,whn,true,_,_) -> + r.V.combiner_statement_dots stmt_dots + | Ast.OptStm(s) -> option_default + | Ast.Dots(d,whn,_,_) | Ast.Circles(d,whn,_,_) | Ast.Stars(d,whn,_,_) -> + option_default + | _ -> k s in + + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + ident expression fullType typeC initialiser parameter declaration + rule_elem statement donothing donothing donothing + +(* ------------------------------------------------------------------------ *) + +let filter_combine combine to_drop = + let rec and_loop = function + Elem x when List.mem x to_drop -> True + | Or l -> List.fold_left build_or False (List.map or_loop l) + | x -> x + and or_loop = function + Elem x when List.mem x to_drop -> False + | And l -> List.fold_left build_and True (List.map and_loop l) + | x -> x in + or_loop combine + +(* ------------------------------------------------------------------------ *) + +let get_all_constants minus_only = + let donothing r k e = k e in + let bind = Common.union_set in + let option_default = [] in + let mcode r (x,_,mcodekind,_) = + match mcodekind with + Ast.MINUS(_,_) -> [x] + | _ when minus_only -> [] + | _ -> [x] in + let other r _ = [] in + + V.combiner bind option_default + other mcode other other other other other other other other other other + other + + donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing + +(* ------------------------------------------------------------------------ *) + +let get_plus_constants = + let donothing r k e = k e in + let bind = Common.union_set in + let option_default = [] in + let mcode r mc = + let mcodekind = Ast.get_mcodekind mc in + let recurse l = + List.fold_left + (List.fold_left + (function prev -> + function cur -> + bind ((get_all_constants false).V.combiner_anything cur) prev)) + [] l in + match mcodekind with + Ast.MINUS(_,anythings) -> recurse anythings + | Ast.CONTEXT(_,Ast.BEFORE(a)) -> recurse a + | Ast.CONTEXT(_,Ast.AFTER(a)) -> recurse a + | Ast.CONTEXT(_,Ast.BEFOREAFTER(a1,a2)) -> + Common.union_set (recurse a1) (recurse a2) + | _ -> [] in + + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing + +(* ------------------------------------------------------------------------ *) + +(* true means the rule should be analyzed, false means it should be ignored *) +let rec dependencies env = function + Ast.Dep s -> (try List.assoc s env with Not_found -> False) + | Ast.AntiDep s -> True + | Ast.EverDep s -> (try List.assoc s env with Not_found -> False) + | Ast.NeverDep s -> True + | Ast.AndDep (d1,d2) -> build_and (dependencies env d1) (dependencies env d2) + | Ast.OrDep (d1,d2) -> build_or (dependencies env d1) (dependencies env d2) + | Ast.NoDep -> True + +(* ------------------------------------------------------------------------ *) + +let all_context = + let bind x y = x && y in + let option_default = true in + + let donothing recursor k e = k e in + + let mcode r e = + match Ast.get_mcodekind e with + Ast.CONTEXT(_,Ast.NOTHING) -> true + | _ -> false in + + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing + +(* ------------------------------------------------------------------------ *) + +let rule_fn tls in_plus env neg_pos = + List.fold_left + (function (rest_info,in_plus) -> + function (cur,neg_pos) -> + let minuses = + (do_get_constants keep drop env neg_pos).V.combiner_top_level cur in + let all_minuses = + if !Flag.sgrep_mode2 + then [] (* nothing removed for sgrep *) + else (get_all_constants true).V.combiner_top_level cur in + let plusses = get_plus_constants.V.combiner_top_level cur in + (* the following is for eg -foo(2) +foo(x) then in another rule + -foo(10); don't want to consider that foo is guaranteed to be + created by the rule. not sure this works completely: what if foo is + in both - and +, but in an or, so the cases aren't related? + not sure this whole thing is a good idea. how do we know that + something that is only in plus is really freshly created? *) + let plusses = Common.minus_set plusses all_minuses in + let was_bot = minuses = True in + let new_minuses = filter_combine minuses in_plus in + let new_plusses = Common.union_set plusses in_plus in + (* perhaps it should be build_and here? we don't realy have multiple + minirules anymore anyway. *) + match new_minuses with + True -> + let retry = + (do_get_constants drop keep env neg_pos).V.combiner_top_level + cur in + (match retry with + True when not was_bot -> (rest_info, new_plusses) + | x -> (build_or x rest_info, new_plusses)) + | x -> (build_or x rest_info, new_plusses)) + (False,in_plus) (List.combine tls neg_pos) + +let get_constants rules neg_pos_vars = + if not !Flag.use_glimpse + then None + else + let (info,_,_,_) = + List.fold_left + (function (rest_info,in_plus,env,locals(*dom of env*)) -> + function + (Ast.ScriptRule (_,deps,mv,_),_) -> + let extra_deps = + List.fold_left + (function prev -> + function (_,(rule,_)) -> Ast.AndDep (Ast.Dep rule,prev)) + deps mv in + (match dependencies env extra_deps with + False -> (rest_info, in_plus, env, locals) + | dependencies -> + (build_or dependencies rest_info, in_plus, env, locals)) + | (Ast.CocciRule (nm,(dep,_,_),cur,_),neg_pos_vars) -> + let (cur_info,cur_plus) = + rule_fn cur in_plus ((nm,True)::env) neg_pos_vars in + if List.for_all all_context.V.combiner_top_level cur + then (rest_info,cur_plus,(nm,cur_info)::env,nm::locals) + else + (* no constants if dependent on another rule; then we need to + find the constants of that rule *) + match dependencies env dep with + False -> (rest_info,cur_plus,env,locals) + | dependencies -> + (build_or (build_and dependencies cur_info) rest_info, + cur_plus,env,locals)) + (False,[],[],[]) (List.combine (rules : Ast.rule list) neg_pos_vars) in + interpret true info diff --git a/parsing_cocci/get_constants2.mli b/parsing_cocci/get_constants2.mli new file mode 100644 index 0000000..ec735e1 --- /dev/null +++ b/parsing_cocci/get_constants2.mli @@ -0,0 +1,4 @@ +val get_constants : + Ast_cocci.rule list -> + (((Ast_cocci.meta_name list) list) list) (*negated pos vars*) -> + string option diff --git a/parsing_cocci/index.ml b/parsing_cocci/index.ml new file mode 100644 index 0000000..e4b98a2 --- /dev/null +++ b/parsing_cocci/index.ml @@ -0,0 +1,220 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* create an index for each constructor *) +(* current max is 145 *) + +(* doesn't really work - requires that identical terms with no token +subterms (eg dots) not appear on the same line *) + +module Ast = Ast_cocci +module Ast0 = Ast0_cocci + +(* if a dot list is empty, add the starting line of the dot list to the +address. Otherwise add 0. An empty dot list should only match with another +empty one. *) +let expression_dots d = + let ln = (Ast0.get_info d).Ast0.line_start in + match Ast0.unwrap d with + Ast0.DOTS(l) -> 1::(if l = [] then [ln] else [0]) + | Ast0.CIRCLES(l) -> 2::(if l = [] then [ln] else [0]) + | Ast0.STARS(l) -> 3::(if l = [] then [ln] else [0]) + +let initialiser_dots d = + let ln = (Ast0.get_info d).Ast0.line_start in + match Ast0.unwrap d with + Ast0.DOTS(l) -> 113::(if l = [] then [ln] else [0]) + | Ast0.CIRCLES(l) -> 114::(if l = [] then [ln] else [0]) + | Ast0.STARS(l) -> 115::(if l = [] then [ln] else [0]) + +let parameter_dots d = + let ln = (Ast0.get_info d).Ast0.line_start in + match Ast0.unwrap d with + Ast0.DOTS(l) -> 4::(if l = [] then [ln] else [0]) + | Ast0.CIRCLES(l) -> 5::(if l = [] then [ln] else [0]) + | Ast0.STARS(l) -> 6::(if l = [] then [ln] else [0]) + +let statement_dots d = + let ln = (Ast0.get_info d).Ast0.line_start in + match Ast0.unwrap d with + Ast0.DOTS(l) -> 7::(if l = [] then [ln] else [0]) + | Ast0.CIRCLES(l) -> 8::(if l = [] then [ln] else [0]) + | Ast0.STARS(l) -> 9::(if l = [] then [ln] else [0]) + +let declaration_dots d = + let ln = (Ast0.get_info d).Ast0.line_start in + match Ast0.unwrap d with + Ast0.DOTS(l) -> 134::(if l = [] then [ln] else [0]) + | Ast0.CIRCLES(l) -> 135::(if l = [] then [ln] else [0]) + | Ast0.STARS(l) -> 136::(if l = [] then [ln] else [0]) + +let case_line_dots d = + let ln = (Ast0.get_info d).Ast0.line_start in + match Ast0.unwrap d with + Ast0.DOTS(l) -> 138::(if l = [] then [ln] else [0]) + | Ast0.CIRCLES(l) -> 139::(if l = [] then [ln] else [0]) + | Ast0.STARS(l) -> 140::(if l = [] then [ln] else [0]) + +let ident i = + match Ast0.unwrap i with + Ast0.Id(name) -> [10] + | Ast0.MetaId(name,_,_) -> [11] + | Ast0.MetaFunc(name,_,_) -> [12] + | Ast0.MetaLocalFunc(name,_,_) -> [13] + | Ast0.OptIdent(id) -> [14] + | Ast0.UniqueIdent(id) -> [15] + +let expression e = + match Ast0.unwrap e with + Ast0.Ident(id) -> [17] + | Ast0.Constant(const) -> [18] + | Ast0.FunCall(fn,lp,args,rp) -> [19] + | Ast0.Assignment(left,op,right,simple) -> [20] + | Ast0.CondExpr(exp1,why,exp2,colon,exp3) -> [21] + | Ast0.Postfix(exp,op) -> [22] + | Ast0.Infix(exp,op) -> [23] + | Ast0.Unary(exp,op) -> [24] + | Ast0.Binary(left,op,right) -> [25] + | Ast0.Nested(left,op,right) -> failwith "nested in index not possible" + | Ast0.Paren(lp,exp,rp) -> [26] + | Ast0.ArrayAccess(exp1,lb,exp2,rb) -> [27] + | Ast0.RecordAccess(exp,pt,field) -> [28] + | Ast0.RecordPtAccess(exp,ar,field) -> [29] + | Ast0.Cast(lp,ty,rp,exp) -> [30] + | Ast0.SizeOfExpr(szf,exp) -> [98] (* added after *) + | Ast0.SizeOfType(szf,lp,ty,rp) -> [99] (* added after *) + | Ast0.TypeExp(ty) -> [123] (* added after *) + | Ast0.MetaErr(name,_,_) -> [32] + | Ast0.MetaExpr(name,_,ty,_,_) -> [33] + | Ast0.MetaExprList(name,_,_) -> [34] + | Ast0.EComma(cm) -> [35] + | Ast0.DisjExpr(_,expr_list,_,_) -> [36] + | Ast0.NestExpr(_,expr_dots,_,_,_) -> [37] + | Ast0.Edots(dots,whencode) -> [38] + | Ast0.Ecircles(dots,whencode) -> [39] + | Ast0.Estars(dots,whencode) -> [40] + | Ast0.OptExp(exp) -> [41] + | Ast0.UniqueExp(exp) -> [42] + +let typeC t = + match Ast0.unwrap t with + Ast0.ConstVol(cv,ty) -> [44] + | Ast0.BaseType(ty,sign) -> [48] + | Ast0.ImplicitInt(sign) -> [129] + | Ast0.Pointer(ty,star) -> [49] + | Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> [131] + | Ast0.FunctionType(ty,lp1,params,rp1) -> [132] + | Ast0.Array(ty,lb,size,rb) -> [50] + | Ast0.StructUnionName(kind,name) -> [51] + | Ast0.StructUnionDef(ty,lb,decls,rb) -> [117] + | Ast0.TypeName(name) -> [52] + | Ast0.MetaType(name,_) -> [53] + | Ast0.DisjType(_,type_list,_,_) -> [130] + | Ast0.OptType(ty) -> [45] + | Ast0.UniqueType(ty) -> [46] + +let declaration d = + match Ast0.unwrap d with + Ast0.Init(stg,ty,id,eq,exp,sem) -> [54] + | Ast0.UnInit(stg,ty,id,sem) -> [55] + | Ast0.MacroDecl(name,lp,args,rp,sem) -> [137] + | Ast0.TyDecl(ty,sem) -> [116] + | Ast0.Typedef(stg,ty,id,sem) -> [143] + | Ast0.DisjDecl(_,decls,_,_) -> [97] (* added after *) + | Ast0.Ddots(dots,whencode) -> [133] + | Ast0.OptDecl(decl) -> [56] + | Ast0.UniqueDecl(decl) -> [57] + +let initialiser i = + match Ast0.unwrap i with + Ast0.InitExpr(exp) -> [102] (* added after *) + | Ast0.InitList(lb,initlist,rb) -> [103] + | Ast0.InitGccDotName(dot,name,eq,ini) -> [104] + | Ast0.InitGccName(name,eq,ini) -> [105] + | Ast0.InitGccIndex(lb,exp,rb,eq,ini) -> [106] + | Ast0.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> [107] + | Ast0.IComma(cm) -> [108] + | Ast0.Idots(d,whencode) -> [109] + | Ast0.OptIni(id) -> [110] + | Ast0.UniqueIni(id) -> [111] + +let parameterTypeDef p = + match Ast0.unwrap p with + Ast0.VoidParam(ty) -> [59] + | Ast0.Param(ty,id) -> [60] + | Ast0.MetaParam(name,_) -> [61] + | Ast0.MetaParamList(name,_,_) -> [62] + | Ast0.PComma(cm) -> [63] + | Ast0.Pdots(dots) -> [64] + | Ast0.Pcircles(dots) -> [65] + | Ast0.OptParam(param) -> [66] + | Ast0.UniqueParam(param) -> [67] + +let statement s = + match Ast0.unwrap s with + Ast0.FunDecl(bef,fninfo,name,lp,params,rp,lbrace,body,rbrace) -> [68] + | Ast0.Decl(bef,decl) -> [69] + | Ast0.Seq(lbrace,body,rbrace) -> [70] + | Ast0.ExprStatement(exp,sem) -> [71] + | Ast0.IfThen(iff,lp,exp,rp,branch1,aft) -> [72] + | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,aft) -> [73] + | Ast0.While(whl,lp,exp,rp,body,_) -> [74] + | Ast0.Do(d,body,whl,lp,exp,rp,sem) -> [75] + | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,_) -> [76] + | Ast0.Iterator(nm,lp,args,rp,body,_) -> [142] + | Ast0.Switch(switch,lp,exp,rp,lb,cases,rb) -> [125] + | Ast0.Break(br,sem) -> [100] + | Ast0.Continue(cont,sem) -> [101] + | Ast0.Label(l,dd) -> [144] + | Ast0.Goto(goto,l,sem) -> [145] + | Ast0.Return(ret,sem) -> [77] + | Ast0.ReturnExpr(ret,exp,sem) -> [78] + | Ast0.MetaStmt(name,_) -> [79] + | Ast0.MetaStmtList(name,_) -> [80] + | Ast0.Disj(_,statement_dots_list,_,_) -> [81] + | Ast0.Nest(_,stmt_dots,_,_,_) -> [82] + | Ast0.Exp(exp) -> [83] + | Ast0.TopExp(exp) -> [141] + | Ast0.Ty(ty) -> [124] + | Ast0.Dots(d,whencode) -> [84] + | Ast0.Circles(d,whencode) -> [85] + | Ast0.Stars(d,whencode) -> [86] + | Ast0.Include(inc,name) -> [118] + | Ast0.Define(def,id,params,body) -> [119] + | Ast0.OptStm(re) -> [87] + | Ast0.UniqueStm(re) -> [88] + +let case_line c = + match Ast0.unwrap c with + Ast0.Default(def,colon,code) -> [126] + | Ast0.Case(case,exp,colon,code) -> [127] + | Ast0.OptCase(case) -> [128] + +let top_level t = + match Ast0.unwrap t with + Ast0.DECL(stmt) -> [90] + | Ast0.FILEINFO(old_file,new_file) -> [92] + | Ast0.CODE(stmt_dots) -> [94] + | Ast0.ERRORWORDS(exps) -> [95] + | Ast0.OTHER(_) -> [96] + +(* 99-101 already used *) diff --git a/parsing_cocci/index.mli b/parsing_cocci/index.mli new file mode 100644 index 0000000..cf6fdbf --- /dev/null +++ b/parsing_cocci/index.mli @@ -0,0 +1,15 @@ +val expression_dots : Ast0_cocci.expression Ast0_cocci.dots -> int list +val initialiser_dots : Ast0_cocci.initialiser Ast0_cocci.dots -> int list +val parameter_dots : Ast0_cocci.parameterTypeDef Ast0_cocci.dots -> int list +val statement_dots : Ast0_cocci.statement Ast0_cocci.dots -> int list +val declaration_dots : Ast0_cocci.declaration Ast0_cocci.dots -> int list +val case_line_dots : Ast0_cocci.case_line Ast0_cocci.dots -> int list +val ident : Ast0_cocci.ident -> int list +val expression : Ast0_cocci.expression -> int list +val typeC : Ast0_cocci.typeC -> int list +val declaration : Ast0_cocci.declaration -> int list +val initialiser : Ast0_cocci.initialiser -> int list +val parameterTypeDef : Ast0_cocci.parameterTypeDef -> int list +val statement : Ast0_cocci.statement -> int list +val case_line : Ast0_cocci.case_line -> int list +val top_level : Ast0_cocci.top_level -> int list diff --git a/parsing_cocci/insert_plus.ml b/parsing_cocci/insert_plus.ml new file mode 100644 index 0000000..12009c7 --- /dev/null +++ b/parsing_cocci/insert_plus.ml @@ -0,0 +1,941 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* The error message "no available token to attach to" often comes in an +argument list of unbounded length. In this case, one should move a comma so +that there is a comma after the + code. *) + +(* Start at all of the corresponding BindContext nodes in the minus and +plus trees, and traverse their children. We take the same strategy as +before: collect the list of minus/context nodes/tokens and the list of plus +tokens, and then merge them. *) + +module Ast = Ast_cocci +module Ast0 = Ast0_cocci +module V0 = Visitor_ast0 +module CN = Context_neg + +let get_option f = function + None -> [] + | Some x -> f x + +(* --------------------------------------------------------------------- *) +(* Collect root and all context nodes in a tree *) + +let collect_context e = + let bind x y = x @ y in + let option_default = [] in + + let mcode _ = [] in + + let donothing builder r k e = + match Ast0.get_mcodekind e with + Ast0.CONTEXT(_) -> (builder e) :: (k e) + | _ -> k e in + +(* special case for everything that contains whencode, so that we skip over +it *) + let expression r k e = + donothing Ast0.expr r k + (Ast0.rewrap e + (match Ast0.unwrap e with + Ast0.NestExpr(starter,exp,ender,whencode,multi) -> + Ast0.NestExpr(starter,exp,ender,None,multi) + | Ast0.Edots(dots,whencode) -> Ast0.Edots(dots,None) + | Ast0.Ecircles(dots,whencode) -> Ast0.Ecircles(dots,None) + | Ast0.Estars(dots,whencode) -> Ast0.Estars(dots,None) + | e -> e)) in + + let initialiser r k i = + donothing Ast0.ini r k + (Ast0.rewrap i + (match Ast0.unwrap i with + Ast0.Idots(dots,whencode) -> Ast0.Idots(dots,None) + | i -> i)) in + + let statement r k s = + donothing Ast0.stmt r k + (Ast0.rewrap s + (match Ast0.unwrap s with + Ast0.Nest(started,stm_dots,ender,whencode,multi) -> + Ast0.Nest(started,stm_dots,ender,[],multi) + | Ast0.Dots(dots,whencode) -> Ast0.Dots(dots,[]) + | Ast0.Circles(dots,whencode) -> Ast0.Circles(dots,[]) + | Ast0.Stars(dots,whencode) -> Ast0.Stars(dots,[]) + | s -> s)) in + + let topfn r k e = Ast0.TopTag(e) :: (k e) in + + let res = + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + (donothing Ast0.dotsExpr) (donothing Ast0.dotsInit) + (donothing Ast0.dotsParam) (donothing Ast0.dotsStmt) + (donothing Ast0.dotsDecl) (donothing Ast0.dotsCase) + (donothing Ast0.ident) expression (donothing Ast0.typeC) initialiser + (donothing Ast0.param) (donothing Ast0.decl) statement + (donothing Ast0.case_line) topfn in + res.V0.combiner_top_level e + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* collect the possible join points, in order, among the children of a +BindContext. Dots are not allowed. Nests and disjunctions are no problem, +because their delimiters take up a line by themselves *) + +(* An Unfavored token is one that is in a BindContext node; using this causes + the node to become Neither, meaning that isomorphisms can't be applied *) +(* Toplevel is for the bef token of a function declaration and is for +attaching top-level definitions that should come before the complete +declaration *) +type minus_join_point = Favored | Unfavored | Toplevel | Decl + +(* Maps the index of a node to the indices of the mcodes it contains *) +let root_token_table = (Hashtbl.create(50) : (int, int list) Hashtbl.t) + +let create_root_token_table minus = + Hashtbl.iter + (function tokens -> + function (node,_) -> + let key = + match node with + Ast0.DotsExprTag(d) -> Ast0.get_index d + | Ast0.DotsInitTag(d) -> Ast0.get_index d + | Ast0.DotsParamTag(d) -> Ast0.get_index d + | Ast0.DotsStmtTag(d) -> Ast0.get_index d + | Ast0.DotsDeclTag(d) -> Ast0.get_index d + | Ast0.DotsCaseTag(d) -> Ast0.get_index d + | Ast0.IdentTag(d) -> Ast0.get_index d + | Ast0.ExprTag(d) -> Ast0.get_index d + | Ast0.ArgExprTag(d) | Ast0.TestExprTag(d) -> + failwith "not possible - iso only" + | Ast0.TypeCTag(d) -> Ast0.get_index d + | Ast0.ParamTag(d) -> Ast0.get_index d + | Ast0.InitTag(d) -> Ast0.get_index d + | Ast0.DeclTag(d) -> Ast0.get_index d + | Ast0.StmtTag(d) -> Ast0.get_index d + | Ast0.CaseLineTag(d) -> Ast0.get_index d + | Ast0.TopTag(d) -> Ast0.get_index d + | Ast0.IsoWhenTag(_) -> failwith "only within iso phase" + | Ast0.MetaPosTag(p) -> failwith "metapostag only within iso phase" + in + Hashtbl.add root_token_table key tokens) + CN.minus_table; + List.iter + (function r -> + let index = Ast0.get_index r in + try let _ = Hashtbl.find root_token_table index in () + with Not_found -> Hashtbl.add root_token_table index []) + minus + +let collect_minus_join_points root = + let root_index = Ast0.get_index root in + let unfavored_tokens = Hashtbl.find root_token_table root_index in + let bind x y = x @ y in + let option_default = [] in + + let mcode (_,_,info,mcodekind,_) = + if List.mem (info.Ast0.offset) unfavored_tokens + then [(Unfavored,info,mcodekind)] + else [(Favored,info,mcodekind)] in + + let do_nothing r k e = + let info = Ast0.get_info e in + let index = Ast0.get_index e in + match Ast0.get_mcodekind e with + (Ast0.MINUS(_)) as mc -> [(Favored,info,mc)] + | (Ast0.CONTEXT(_)) as mc when not(index = root_index) -> + (* This was unfavored at one point, but I don't remember why *) + [(Favored,info,mc)] + | _ -> k e in + +(* don't want to attach to the outside of DOTS, because metavariables can't +bind to that; not good for isomorphisms *) + + let dots f k d = + let multibind l = + let rec loop = function + [] -> option_default + | [x] -> x + | x::xs -> bind x (loop xs) in + loop l in + + match Ast0.unwrap d with + Ast0.DOTS(l) -> multibind (List.map f l) + | Ast0.CIRCLES(l) -> multibind (List.map f l) + | Ast0.STARS(l) -> multibind (List.map f l) in + + let edots r k d = dots r.V0.combiner_expression k d in + let idots r k d = dots r.V0.combiner_initialiser k d in + let pdots r k d = dots r.V0.combiner_parameter k d in + let sdots r k d = dots r.V0.combiner_statement k d in + let ddots r k d = dots r.V0.combiner_declaration k d in + let cdots r k d = dots r.V0.combiner_case_line k d in + + (* a case for everything that has a Opt *) + + let statement r k s = + (* + let redo_branched res (ifinfo,aftmc) = + let redo fv info mc rest = + let new_info = {info with Ast0.attachable_end = false} in + List.rev ((Favored,ifinfo,aftmc)::(fv,new_info,mc)::rest) in + match List.rev res with + [(fv,info,mc)] -> + (match mc with + Ast0.MINUS(_) | Ast0.CONTEXT(_) -> + (* even for -, better for isos not to integrate code after an + if into the if body. + but the problem is that this can extend the region in + which a variable is bound, because a variable bound in the + aft node would seem to have to be live in the whole if, + whereas we might like it to be live in only one branch. + ie ideally, if we can keep the minus code in the right + order, we would like to drop it as close to the bindings + of its free variables. This could be anywhere in the minus + code. Perhaps we would like to do this after the + application of isomorphisms, though. + *) + redo fv info mc [] + | _ -> res) + | (fv,info,mc)::rest -> + (match mc with + Ast0.CONTEXT(_) -> redo fv info mc rest + | _ -> res) + | _ -> failwith "unexpected empty code" in *) + match Ast0.unwrap s with + (* Ast0.IfThen(_,_,_,_,_,aft) + | Ast0.IfThenElse(_,_,_,_,_,_,_,aft) + | Ast0.While(_,_,_,_,_,aft) + | Ast0.For(_,_,_,_,_,_,_,_,_,aft) + | Ast0.Iterator(_,_,_,_,_,aft) -> + redo_branched (do_nothing r k s) aft*) + | Ast0.FunDecl((info,bef),fninfo,name,lp,params,rp,lbrace,body,rbrace) -> + (Toplevel,info,bef)::(k s) + | Ast0.Decl((info,bef),decl) -> (Decl,info,bef)::(k s) + | Ast0.Nest(starter,stmt_dots,ender,whencode,multi) -> + mcode starter @ r.V0.combiner_statement_dots stmt_dots @ mcode ender + | Ast0.Dots(d,whencode) | Ast0.Circles(d,whencode) + | Ast0.Stars(d,whencode) -> mcode d (* ignore whencode *) + | Ast0.OptStm s | Ast0.UniqueStm s -> + (* put the + code on the thing, not on the opt *) + r.V0.combiner_statement s + | _ -> do_nothing r k s in + + let expression r k e = + match Ast0.unwrap e with + Ast0.NestExpr(starter,expr_dots,ender,whencode,multi) -> + mcode starter @ + r.V0.combiner_expression_dots expr_dots @ mcode ender + | Ast0.Edots(d,whencode) | Ast0.Ecircles(d,whencode) + | Ast0.Estars(d,whencode) -> mcode d (* ignore whencode *) + | Ast0.OptExp e | Ast0.UniqueExp e -> + (* put the + code on the thing, not on the opt *) + r.V0.combiner_expression e + | _ -> do_nothing r k e in + + let ident r k e = + match Ast0.unwrap e with + Ast0.OptIdent i | Ast0.UniqueIdent i -> + (* put the + code on the thing, not on the opt *) + r.V0.combiner_ident i + | _ -> do_nothing r k e in + + let typeC r k e = + match Ast0.unwrap e with + Ast0.OptType t | Ast0.UniqueType t -> + (* put the + code on the thing, not on the opt *) + r.V0.combiner_typeC t + | _ -> do_nothing r k e in + + let decl r k e = + match Ast0.unwrap e with + Ast0.OptDecl d | Ast0.UniqueDecl d -> + (* put the + code on the thing, not on the opt *) + r.V0.combiner_declaration d + | _ -> do_nothing r k e in + + let initialiser r k e = + match Ast0.unwrap e with + Ast0.Idots(d,whencode) -> mcode d (* ignore whencode *) + | Ast0.OptIni i | Ast0.UniqueIni i -> + (* put the + code on the thing, not on the opt *) + r.V0.combiner_initialiser i + | _ -> do_nothing r k e in + + let param r k e = + match Ast0.unwrap e with + Ast0.OptParam p | Ast0.UniqueParam p -> + (* put the + code on the thing, not on the opt *) + r.V0.combiner_parameter p + | _ -> do_nothing r k e in + + let case_line r k e = + match Ast0.unwrap e with + Ast0.OptCase c -> + (* put the + code on the thing, not on the opt *) + r.V0.combiner_case_line c + | _ -> do_nothing r k e in + + let do_top r k (e: Ast0.top_level) = k e in + + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + edots idots pdots sdots ddots cdots + ident expression typeC initialiser param decl statement case_line do_top + + +let call_collect_minus context_nodes : + (int * (minus_join_point * Ast0.info * Ast0.mcodekind) list) list = + List.map + (function e -> + match e with + Ast0.DotsExprTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_expression_dots e) + | Ast0.DotsInitTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_initialiser_list e) + | Ast0.DotsParamTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_parameter_list e) + | Ast0.DotsStmtTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_statement_dots e) + | Ast0.DotsDeclTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_declaration_dots e) + | Ast0.DotsCaseTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_case_line_dots e) + | Ast0.IdentTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_ident e) + | Ast0.ExprTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_expression e) + | Ast0.ArgExprTag(e) | Ast0.TestExprTag(e) -> + failwith "not possible - iso only" + | Ast0.TypeCTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_typeC e) + | Ast0.ParamTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_parameter e) + | Ast0.InitTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_initialiser e) + | Ast0.DeclTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_declaration e) + | Ast0.StmtTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_statement e) + | Ast0.CaseLineTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_case_line e) + | Ast0.TopTag(e) -> + (Ast0.get_index e, + (collect_minus_join_points e).V0.combiner_top_level e) + | Ast0.IsoWhenTag(_) -> failwith "only within iso phase" + | Ast0.MetaPosTag(p) -> failwith "metapostag only within iso phase") + context_nodes + +(* result of collecting the join points should be sorted in nondecreasing + order by line *) +let verify l = + let get_info = function + (Favored,info,_) | (Unfavored,info,_) | (Toplevel,info,_) + | (Decl,info,_) -> info in + let token_start_line x = (get_info x).Ast0.logical_start in + let token_end_line x = (get_info x).Ast0.logical_end in + let token_real_start_line x = (get_info x).Ast0.line_start in + let token_real_end_line x = (get_info x).Ast0.line_end in + List.iter + (function + (index,((_::_) as l1)) -> + let _ = + List.fold_left + (function (prev,real_prev) -> + function cur -> + let ln = token_start_line cur in + if ln < prev + then + failwith + (Printf.sprintf + "error in collection of - tokens %d less than %d" + (token_real_start_line cur) real_prev); + (token_end_line cur,token_real_end_line cur)) + (token_end_line (List.hd l1), token_real_end_line (List.hd l1)) + (List.tl l1) in + () + | _ -> ()) (* dots, in eg f() has no join points *) + l + +let process_minus minus = + create_root_token_table minus; + List.concat + (List.map + (function x -> + let res = call_collect_minus (collect_context x) in + verify res; + res) + minus) + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* collect the plus tokens *) + +let mk_baseType x = Ast.BaseTypeTag x +let mk_structUnion x = Ast.StructUnionTag x +let mk_sign x = Ast.SignTag x +let mk_ident x = Ast.IdentTag (Ast0toast.ident x) +let mk_expression x = Ast.ExpressionTag (Ast0toast.expression x) +let mk_constant x = Ast.ConstantTag x +let mk_unaryOp x = Ast.UnaryOpTag x +let mk_assignOp x = Ast.AssignOpTag x +let mk_fixOp x = Ast.FixOpTag x +let mk_binaryOp x = Ast.BinaryOpTag x +let mk_arithOp x = Ast.ArithOpTag x +let mk_logicalOp x = Ast.LogicalOpTag x +let mk_declaration x = Ast.DeclarationTag (Ast0toast.declaration x) +let mk_topdeclaration x = Ast.DeclarationTag (Ast0toast.declaration x) +let mk_storage x = Ast.StorageTag x +let mk_inc_file x = Ast.IncFileTag x +let mk_statement x = Ast.StatementTag (Ast0toast.statement x) +let mk_case_line x = Ast.CaseLineTag (Ast0toast.case_line x) +let mk_const_vol x = Ast.ConstVolTag x +let mk_token x info = Ast.Token (x,Some info) +let mk_meta (_,x) info = Ast.Token (x,Some info) +let mk_code x = Ast.Code (Ast0toast.top_level x) + +let mk_exprdots x = Ast.ExprDotsTag (Ast0toast.expression_dots x) +let mk_paramdots x = Ast.ParamDotsTag (Ast0toast.parameter_list x) +let mk_stmtdots x = Ast.StmtDotsTag (Ast0toast.statement_dots x) +let mk_decldots x = Ast.DeclDotsTag (Ast0toast.declaration_dots x) +let mk_casedots x = failwith "+ case lines not supported" +let mk_typeC x = Ast.FullTypeTag (Ast0toast.typeC x) +let mk_init x = Ast.InitTag (Ast0toast.initialiser x) +let mk_param x = Ast.ParamTag (Ast0toast.parameterTypeDef x) + +let collect_plus_nodes root = + let root_index = Ast0.get_index root in + + let bind x y = x @ y in + let option_default = [] in + + let mcode fn (term,_,info,mcodekind,_) = + match mcodekind with Ast0.PLUS -> [(info,fn term)] | _ -> [] in + + let imcode fn (term,_,info,mcodekind,_) = + match mcodekind with + Ast0.PLUS -> [(info,fn term (Ast0toast.convert_info info))] + | _ -> [] in + + let do_nothing fn r k e = + match Ast0.get_mcodekind e with + (Ast0.CONTEXT(_)) when not(Ast0.get_index e = root_index) -> [] + | Ast0.PLUS -> [(Ast0.get_info e,fn e)] + | _ -> k e in + + (* case for everything that is just a wrapper for a simpler thing *) + let stmt r k e = + match Ast0.unwrap e with + Ast0.Exp(exp) -> r.V0.combiner_expression exp + | Ast0.TopExp(exp) -> r.V0.combiner_expression exp + | Ast0.Ty(ty) -> r.V0.combiner_typeC ty + | Ast0.Decl(_,decl) -> r.V0.combiner_declaration decl + | _ -> do_nothing mk_statement r k e in + + (* statementTag is preferred, because it indicates that one statement is + replaced by one statement, in single_statement *) + let stmt_dots r k e = + match Ast0.unwrap e with + Ast0.DOTS([s]) | Ast0.CIRCLES([s]) | Ast0.STARS([s]) -> + r.V0.combiner_statement s + | _ -> do_nothing mk_stmtdots r k e in + + let toplevel r k e = + match Ast0.unwrap e with + Ast0.DECL(s) -> r.V0.combiner_statement s + | Ast0.CODE(sdots) -> r.V0.combiner_statement_dots sdots + | _ -> do_nothing mk_code r k e in + + let initdots r k e = k e in + + V0.combiner bind option_default + (imcode mk_meta) (imcode mk_token) (mcode mk_constant) (mcode mk_assignOp) + (mcode mk_fixOp) + (mcode mk_unaryOp) (mcode mk_binaryOp) (mcode mk_const_vol) + (mcode mk_baseType) (mcode mk_sign) (mcode mk_structUnion) + (mcode mk_storage) (mcode mk_inc_file) + (do_nothing mk_exprdots) initdots + (do_nothing mk_paramdots) stmt_dots (do_nothing mk_decldots) + (do_nothing mk_casedots) + (do_nothing mk_ident) (do_nothing mk_expression) + (do_nothing mk_typeC) (do_nothing mk_init) (do_nothing mk_param) + (do_nothing mk_declaration) + stmt (do_nothing mk_case_line) toplevel + +let call_collect_plus context_nodes : + (int * (Ast0.info * Ast.anything) list) list = + List.map + (function e -> + match e with + Ast0.DotsExprTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_expression_dots e) + | Ast0.DotsInitTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_initialiser_list e) + | Ast0.DotsParamTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_parameter_list e) + | Ast0.DotsStmtTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_statement_dots e) + | Ast0.DotsDeclTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_declaration_dots e) + | Ast0.DotsCaseTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_case_line_dots e) + | Ast0.IdentTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_ident e) + | Ast0.ExprTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_expression e) + | Ast0.ArgExprTag(_) | Ast0.TestExprTag(_) -> + failwith "not possible - iso only" + | Ast0.TypeCTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_typeC e) + | Ast0.InitTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_initialiser e) + | Ast0.ParamTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_parameter e) + | Ast0.DeclTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_declaration e) + | Ast0.StmtTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_statement e) + | Ast0.CaseLineTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_case_line e) + | Ast0.TopTag(e) -> + (Ast0.get_index e, + (collect_plus_nodes e).V0.combiner_top_level e) + | Ast0.IsoWhenTag(_) -> failwith "only within iso phase" + | Ast0.MetaPosTag(p) -> failwith "metapostag only within iso phase") + context_nodes + +(* The plus fragments are converted to a list of lists of lists. +Innermost list: Elements have type anything. For any pair of successive +elements, n and n+1, the ending line of n is the same as the starting line +of n+1. +Middle lists: For any pair of successive elements, n and n+1, the ending +line of n is one less than the starting line of n+1. +Outer list: For any pair of successive elements, n and n+1, the ending +line of n is more than one less than the starting line of n+1. *) + +let logstart info = info.Ast0.logical_start +let logend info = info.Ast0.logical_end + +let redo info start finish = + {{info with Ast0.logical_start = start} with Ast0.logical_end = finish} + +let rec find_neighbors (index,l) : + int * (Ast0.info * (Ast.anything list list)) list = + let rec loop = function + [] -> [] + | (i,x)::rest -> + (match loop rest with + ((i1,(x1::rest_inner))::rest_middle)::rest_outer -> + let finish1 = logend i in + let start2 = logstart i1 in + if finish1 = start2 + then + ((redo i (logstart i) (logend i1),(x::x1::rest_inner)) + ::rest_middle) + ::rest_outer + else if finish1 + 1 = start2 + then ((i,[x])::(i1,(x1::rest_inner))::rest_middle)::rest_outer + else [(i,[x])]::((i1,(x1::rest_inner))::rest_middle)::rest_outer + | _ -> [[(i,[x])]]) (* rest must be [] *) in + let res = + List.map + (function l -> + let (start_info,_) = List.hd l in + let (end_info,_) = List.hd (List.rev l) in + (redo start_info (logstart start_info) (logend end_info), + List.map (function (_,x) -> x) l)) + (loop l) in + (index,res) + +let process_plus plus : + (int * (Ast0.info * Ast.anything list list) list) list = + List.concat + (List.map + (function x -> + List.map find_neighbors (call_collect_plus (collect_context x))) + plus) + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* merge *) +(* +let merge_one = function + (m1::m2::minus_info,p::plus_info) -> + if p < m1, then + attach p to the beginning of m1.bef if m1 is Good, fail if it is bad + if p > m1 && p < m2, then consider the following possibilities, in order + m1 is Good and favored: attach to the beginning of m1.aft + m2 is Good and favored: attach to the beginning of m2.bef; drop m1 + m1 is Good and unfavored: attach to the beginning of m1.aft + m2 is Good and unfavored: attach to the beginning of m2.bef; drop m1 + also flip m1.bef if the first where > m1 + if we drop m1, then flip m1.aft first + if p > m2 + m2 is Good and favored: attach to the beginning of m2.aft; drop m1 +*) + +(* end of first argument < start/end of second argument *) +let less_than_start info1 info2 = + info1.Ast0.logical_end < info2.Ast0.logical_start +let less_than_end info1 info2 = + info1.Ast0.logical_end < info2.Ast0.logical_end +let greater_than_end info1 info2 = + info1.Ast0.logical_start > info2.Ast0.logical_end +let good_start info = info.Ast0.attachable_start +let good_end info = info.Ast0.attachable_end + +let toplevel = function Toplevel -> true | Favored | Unfavored | Decl -> false +let decl = function Decl -> true | Favored | Unfavored | Toplevel -> false +let favored = function Favored -> true | Unfavored | Toplevel | Decl -> false + +let top_code = + List.for_all (List.for_all (function Ast.Code _ -> true | _ -> false)) + +(* The following is probably not correct. The idea is to detect what +should be placed completely before the declaration. So type/storage +related things do not fall into this category, and complete statements do +fall into this category. But perhaps other things should be in this +category as well, such as { or ;? *) +let predecl_code = + let tester = function + (* the following should definitely be true *) + Ast.DeclarationTag _ + | Ast.StatementTag _ + | Ast.Rule_elemTag _ + | Ast.StmtDotsTag _ + | Ast.Code _ -> true + (* the following should definitely be false *) + | Ast.FullTypeTag _ | Ast.BaseTypeTag _ | Ast.StructUnionTag _ + | Ast.SignTag _ + | Ast.StorageTag _ | Ast.ConstVolTag _ | Ast.TypeCTag _ -> false + (* not sure about the rest *) + | _ -> false in + List.for_all (List.for_all tester) + +let pr = Printf.sprintf + +let insert thing thinginfo into intoinfo = + let get_last l = let l = List.rev l in (List.rev(List.tl l),List.hd l) in + let get_first l = (List.hd l,List.tl l) in + let thing_start = thinginfo.Ast0.logical_start in + let thing_end = thinginfo.Ast0.logical_end in + let thing_offset = thinginfo.Ast0.offset in + let into_start = intoinfo.Ast0.tline_start in + let into_end = intoinfo.Ast0.tline_end in + let into_left_offset = intoinfo.Ast0.left_offset in + let into_right_offset = intoinfo.Ast0.right_offset in + Printf.printf "thing start %d thing end %d into start %d into end %d\n" + thing_start thing_end into_start into_end; + if thing_end < into_start && thing_start < into_start + then (thing@into, + {{intoinfo with Ast0.tline_start = thing_start} + with Ast0.left_offset = thing_offset}) + else if thing_end = into_start && thing_offset < into_left_offset + then + let (prev,last) = get_last thing in + let (first,rest) = get_first into in + (prev@[last@first]@rest, + {{intoinfo with Ast0.tline_start = thing_start} + with Ast0.left_offset = thing_offset}) + else if thing_start > into_end && thing_end > into_end + then (into@thing, + {{intoinfo with Ast0.tline_end = thing_end} + with Ast0.right_offset = thing_offset}) + else if thing_start = into_end && thing_offset > into_right_offset + then + let (first,rest) = get_first thing in + let (prev,last) = get_last into in + (prev@[last@first]@rest, + {{intoinfo with Ast0.tline_end = thing_end} + with Ast0.right_offset = thing_offset}) + else + begin + Printf.printf "thing start %d thing end %d into start %d into end %d\n" + thing_start thing_end into_start into_end; + Printf.printf "thing offset %d left offset %d right offset %d\n" + thing_offset into_left_offset into_right_offset; + Pretty_print_cocci.print_anything "" thing; + failwith "can't figure out where to put the + code" + end + +let init thing info = + (thing, + {Ast0.tline_start = info.Ast0.logical_start; + Ast0.tline_end = info.Ast0.logical_end; + Ast0.left_offset = info.Ast0.offset; + Ast0.right_offset = info.Ast0.offset}) + +let attachbefore (infop,p) = function + Ast0.MINUS(replacements) -> + (match !replacements with + ([],ti) -> replacements := init p infop + | (repl,ti) -> replacements := insert p infop repl ti) + | Ast0.CONTEXT(neighbors) -> + let (repl,ti1,ti2) = !neighbors in + (match repl with + Ast.BEFORE(bef) -> + let (bef,ti1) = insert p infop bef ti1 in + neighbors := (Ast.BEFORE(bef),ti1,ti2) + | Ast.AFTER(aft) -> + let (bef,ti1) = init p infop in + neighbors := (Ast.BEFOREAFTER(bef,aft),ti1,ti2) + | Ast.BEFOREAFTER(bef,aft) -> + let (bef,ti1) = insert p infop bef ti1 in + neighbors := (Ast.BEFOREAFTER(bef,aft),ti1,ti2) + | Ast.NOTHING -> + let (bef,ti1) = init p infop in + neighbors := (Ast.BEFORE(bef),ti1,ti2)) + | _ -> failwith "not possible for attachbefore" + +let attachafter (infop,p) = function + Ast0.MINUS(replacements) -> + (match !replacements with + ([],ti) -> replacements := init p infop + | (repl,ti) -> replacements := insert p infop repl ti) + | Ast0.CONTEXT(neighbors) -> + let (repl,ti1,ti2) = !neighbors in + (match repl with + Ast.BEFORE(bef) -> + let (aft,ti2) = init p infop in + neighbors := (Ast.BEFOREAFTER(bef,aft),ti1,ti2) + | Ast.AFTER(aft) -> + let (aft,ti2) = insert p infop aft ti2 in + neighbors := (Ast.AFTER(aft),ti1,ti2) + | Ast.BEFOREAFTER(bef,aft) -> + let (aft,ti2) = insert p infop aft ti2 in + neighbors := (Ast.BEFOREAFTER(bef,aft),ti1,ti2) + | Ast.NOTHING -> + let (aft,ti2) = init p infop in + neighbors := (Ast.AFTER(aft),ti1,ti2)) + | _ -> failwith "not possible for attachbefore" + +let attach_all_before ps m = + List.iter (function x -> attachbefore x m) ps + +let attach_all_after ps m = + List.iter (function x -> attachafter x m) ps + +let split_at_end info ps = + let split_point = info.Ast0.logical_end in + List.partition + (function (info,_) -> info.Ast0.logical_end < split_point) + ps + +let allminus = function + Ast0.MINUS(_) -> true + | _ -> false + +let rec before_m1 ((f1,infom1,m1) as x1) ((f2,infom2,m2) as x2) rest = function + [] -> () + | (((infop,_) as p) :: ps) as all -> + if less_than_start infop infom1 or + (allminus m1 && less_than_end infop infom1) (* account for trees *) + then + if good_start infom1 + then (attachbefore p m1; before_m1 x1 x2 rest ps) + else + failwith + (pr "%d: no available token to attach to" infop.Ast0.line_start) + else after_m1 x1 x2 rest all + +and after_m1 ((f1,infom1,m1) as x1) ((f2,infom2,m2) as x2) rest = function + [] -> () + | (((infop,pcode) as p) :: ps) as all -> + (* if the following is false, then some + code is stuck in the middle + of some context code (m1). could drop down to the token level. + this might require adjustments in ast0toast as well, when + code on + expressions is dropped down to + code on expressions. it might + also break some invariants on which iso depends, particularly on + what it can infer from something being CONTEXT with no top-level + modifications. for the moment, we thus give an error, asking the + user to rewrite the semantic patch. *) + if greater_than_end infop infom1 + then + if less_than_start infop infom2 + then + if predecl_code pcode && good_end infom1 && decl f1 + then (attachafter p m1; after_m1 x1 x2 rest ps) + else if predecl_code pcode && good_start infom2 && decl f2 + then before_m2 x2 rest all + else if top_code pcode && good_end infom1 && toplevel f1 + then (attachafter p m1; after_m1 x1 x2 rest ps) + else if top_code pcode && good_start infom2 && toplevel f2 + then before_m2 x2 rest all + else if good_end infom1 && favored f1 + then (attachafter p m1; after_m1 x1 x2 rest ps) + else if good_start infom2 && favored f2 + then before_m2 x2 rest all + else if good_end infom1 + then (attachafter p m1; after_m1 x1 x2 rest ps) + else if good_start infom2 + then before_m2 x2 rest all + else + failwith + (pr "%d: no available token to attach to" infop.Ast0.line_start) + else after_m2 x2 rest all + else + begin + Printf.printf "between: p start %d p end %d m1 start %d m1 end %d m2 start %d m2 end %d\n" + infop.Ast0.line_start infop.Ast0.line_end + infom1.Ast0.line_start infom1.Ast0.line_end + infom2.Ast0.line_start infom2.Ast0.line_end; + Pretty_print_cocci.print_anything "" pcode; + failwith + "The semantic patch is structured in a way that may give bad results with isomorphisms. Please try to rewrite it by moving + code out from -/context terms." + end + +and before_m2 ((f2,infom2,m2) as x2) rest + (p : (Ast0.info * Ast.anything list list) list) = + match (rest,p) with + (_,[]) -> () + | ([],((infop,_)::_)) -> + let (bef_m2,aft_m2) = split_at_end infom2 p in (* bef_m2 isn't empty *) + if good_start infom2 + then (attach_all_before bef_m2 m2; after_m2 x2 rest aft_m2) + else + failwith + (pr "%d: no available token to attach to" infop.Ast0.line_start) + | (m::ms,_) -> before_m1 x2 m ms p + +and after_m2 ((f2,infom2,m2) as x2) rest + (p : (Ast0.info * Ast.anything list list) list) = + match (rest,p) with + (_,[]) -> () + | ([],((infop,_)::_)) -> + if good_end infom2 + then attach_all_after p m2 + else + failwith + (pr "%d: no available token to attach to" infop.Ast0.line_start) + | (m::ms,_) -> after_m1 x2 m ms p + +let merge_one : (minus_join_point * Ast0.info * 'a) list * + (Ast0.info * Ast.anything list list) list -> unit = function (m,p) -> + (* + Printf.printf "minus code\n"; + List.iter + (function (_,info,_) -> + Printf.printf "start %d end %d real_start %d real_end %d\n" + info.Ast0.logical_start info.Ast0.logical_end + info.Ast0.line_start info.Ast0.line_end) + m; + Printf.printf "plus code\n"; + List.iter + (function (info,p) -> + Printf.printf "start %d end %d real_start %d real_end %d\n" + info.Ast0.logical_start info.Ast0.logical_end + info.Ast0.line_end info.Ast0.line_end; + Pretty_print_cocci.print_anything "" p; + Format.print_newline()) + p; + *) + match (m,p) with + (_,[]) -> () + | (m1::m2::restm,p) -> before_m1 m1 m2 restm p + | ([m],p) -> before_m2 m [] p + | ([],_) -> failwith "minus tree ran out before the plus tree" + +let merge minus_list plus_list = + (* + Printf.printf "minus list %s\n" + (String.concat " " + (List.map (function (x,_) -> string_of_int x) minus_list)); + Printf.printf "plus list %s\n" + (String.concat " " + (List.map (function (x,_) -> string_of_int x) plus_list)); + *) + List.iter + (function (index,minus_info) -> + let plus_info = List.assoc index plus_list in + merge_one (minus_info,plus_info)) + minus_list + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Need to check that CONTEXT nodes have nothing attached to their tokens. +If they do, they become MIXED *) + +let reevaluate_contextness = + let bind = (@) in + let option_default = [] in + + let mcode (_,_,_,mc,_) = + match mc with + Ast0.CONTEXT(mc) -> let (ba,_,_) = !mc in [ba] + | _ -> [] in + + let donothing r k e = + match Ast0.get_mcodekind e with + Ast0.CONTEXT(mc) -> + if List.exists (function Ast.NOTHING -> false | _ -> true) (k e) + then Ast0.set_mcodekind e (Ast0.MIXED(mc)); + [] + | _ -> let _ = k e in [] in + + let res = + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing donothing + donothing + donothing donothing donothing donothing donothing donothing donothing in + res.V0.combiner_top_level + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) + +let insert_plus minus plus = + let minus_stream = process_minus minus in + let plus_stream = process_plus plus in + merge minus_stream plus_stream; + List.iter (function x -> let _ = reevaluate_contextness x in ()) minus diff --git a/parsing_cocci/insert_plus.mli b/parsing_cocci/insert_plus.mli new file mode 100644 index 0000000..16899dc --- /dev/null +++ b/parsing_cocci/insert_plus.mli @@ -0,0 +1 @@ +val insert_plus : Ast0_cocci.rule -> Ast0_cocci.rule -> unit diff --git a/parsing_cocci/iso_compile.ml b/parsing_cocci/iso_compile.ml new file mode 100644 index 0000000..ba8497c --- /dev/null +++ b/parsing_cocci/iso_compile.ml @@ -0,0 +1,105 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module V0 = Visitor_ast0 +module Ast0 = Ast0_cocci +module Ast = Ast_cocci + +(* Detects where position variables can be present in the match of an +isomorpshims. This is allowed if all elements of an isomorphism have only +one token or if we can somehow match up equal tokens of all of the +isomorphic variants. *) + +let sequence_tokens = + let mcode x = + (* sort of unpleasant to convert the token representation to a string + but we can't make a list of mcodes otherwise because the types are all + different *) + [(Common.dump (Ast0.unwrap_mcode x),Ast0.get_pos_ref x)] in + let donothing r k e = k e in + let bind x y = x @ y in + let option_default = [] in + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing donothing + donothing donothing donothing donothing donothing donothing donothing + +(* In general, we will get a list of lists: + +[[tokens1;tokens2;tokens3];[tokens4;tokens5;tokens6];[tokens7;tokens8]] + +If all of the lists tokens contain only one element, we are done. + +Otherwise, we focus on tokens1. For each of its elements, if they are +present in all of the others, then a position is assigned, and if not then +a position is not. The order of the elements in the other lists is +irrelevant; we just take the first unannotated element that matches. Once +we are done with the elements of tokens1, we skip to tokens 4 and repeat, +including considering the one-element special case. *) + +let pctr = ref 0 +let get_p _ = + let c = !pctr in + pctr := c + 1; + let name = ("",Printf.sprintf "p%d" c) in + Ast0.MetaPos(Ast0.make_mcode name,[],Ast.PER) + +let process_info l = + let rec loop = function + [] -> () + | ((f::r)::xs) as a -> + if List.for_all (List.for_all (function e -> List.length e = 1)) a + then + let p = get_p() in + List.iter (List.iter (List.iter (function (_,pos) -> pos := p))) a + else + let all = r @ List.concat xs in + let rec find_first_available a = function + [] -> raise Not_found + | (str,pos)::xs -> + if str = a && !pos = Ast0.NoMetaPos + then pos + else find_first_available a xs in + List.iter + (function (str,pos) -> + match !pos with + Ast0.NoMetaPos -> + (try + let entries = List.map (find_first_available str) all in + let p = get_p() in + pos := p; + List.iter (function pos -> pos := p) entries + with Not_found -> ()) + | _ -> (* already have a variable *) ()) + f; + loop xs + | _ -> failwith "bad iso" in + loop l + +(* Entry point *) + +let process (metavars,alts,name) = + let toks = + List.map (List.map sequence_tokens.V0.combiner_anything) alts in + process_info toks diff --git a/parsing_cocci/iso_compile.mli b/parsing_cocci/iso_compile.mli new file mode 100644 index 0000000..6b336f5 --- /dev/null +++ b/parsing_cocci/iso_compile.mli @@ -0,0 +1,2 @@ +val process : Iso_pattern.isomorphism -> unit + diff --git a/parsing_cocci/iso_pattern.ml b/parsing_cocci/iso_pattern.ml new file mode 100644 index 0000000..6bbf1a7 --- /dev/null +++ b/parsing_cocci/iso_pattern.ml @@ -0,0 +1,2306 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* Potential problem: offset of mcode is not updated when an iso is +instantiated, implying that a term may end up with many mcodes with the +same offset. On the other hand, at the moment offset only seems to be used +before this phase. Furthermore add_dot_binding relies on the offset to +remain the same between matching an iso and instantiating it with bindings. *) + +(* --------------------------------------------------------------------- *) +(* match a SmPL expression against a SmPL abstract syntax tree, +either - or + *) + +module Ast = Ast_cocci +module Ast0 = Ast0_cocci +module V0 = Visitor_ast0 + +let current_rule = ref "" + +(* --------------------------------------------------------------------- *) + +type isomorphism = + Ast_cocci.metavar list * Ast0_cocci.anything list list * string (* name *) + +let strip_info = + let mcode (term,_,_,_,_) = + (term,Ast0.NONE,Ast0.default_info(),Ast0.PLUS,ref Ast0.NoMetaPos) in + let donothing r k e = + let x = k e in + {(Ast0.wrap (Ast0.unwrap x)) with + Ast0.mcodekind = ref Ast0.PLUS; + Ast0.true_if_test = x.Ast0.true_if_test} in + V0.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing donothing + donothing donothing + +let anything_equal = function + (Ast0.DotsExprTag(d1),Ast0.DotsExprTag(d2)) -> + failwith "not a possible variable binding" (*not sure why these are pbs*) + | (Ast0.DotsInitTag(d1),Ast0.DotsInitTag(d2)) -> + failwith "not a possible variable binding" + | (Ast0.DotsParamTag(d1),Ast0.DotsParamTag(d2)) -> + failwith "not a possible variable binding" + | (Ast0.DotsStmtTag(d1),Ast0.DotsStmtTag(d2)) -> + (strip_info.V0.rebuilder_statement_dots d1) = + (strip_info.V0.rebuilder_statement_dots d2) + | (Ast0.DotsDeclTag(d1),Ast0.DotsDeclTag(d2)) -> + failwith "not a possible variable binding" + | (Ast0.DotsCaseTag(d1),Ast0.DotsCaseTag(d2)) -> + failwith "not a possible variable binding" + | (Ast0.IdentTag(d1),Ast0.IdentTag(d2)) -> + (strip_info.V0.rebuilder_ident d1) = (strip_info.V0.rebuilder_ident d2) + | (Ast0.ExprTag(d1),Ast0.ExprTag(d2)) -> + (strip_info.V0.rebuilder_expression d1) = + (strip_info.V0.rebuilder_expression d2) + | (Ast0.ArgExprTag(_),_) | (_,Ast0.ArgExprTag(_)) -> + failwith "not possible - only in isos1" + | (Ast0.TestExprTag(_),_) | (_,Ast0.TestExprTag(_)) -> + failwith "not possible - only in isos1" + | (Ast0.TypeCTag(d1),Ast0.TypeCTag(d2)) -> + (strip_info.V0.rebuilder_typeC d1) = + (strip_info.V0.rebuilder_typeC d2) + | (Ast0.InitTag(d1),Ast0.InitTag(d2)) -> + (strip_info.V0.rebuilder_initialiser d1) = + (strip_info.V0.rebuilder_initialiser d2) + | (Ast0.ParamTag(d1),Ast0.ParamTag(d2)) -> + (strip_info.V0.rebuilder_parameter d1) = + (strip_info.V0.rebuilder_parameter d2) + | (Ast0.DeclTag(d1),Ast0.DeclTag(d2)) -> + (strip_info.V0.rebuilder_declaration d1) = + (strip_info.V0.rebuilder_declaration d2) + | (Ast0.StmtTag(d1),Ast0.StmtTag(d2)) -> + (strip_info.V0.rebuilder_statement d1) = + (strip_info.V0.rebuilder_statement d2) + | (Ast0.CaseLineTag(d1),Ast0.CaseLineTag(d2)) -> + (strip_info.V0.rebuilder_case_line d1) = + (strip_info.V0.rebuilder_case_line d2) + | (Ast0.TopTag(d1),Ast0.TopTag(d2)) -> + (strip_info.V0.rebuilder_top_level d1) = + (strip_info.V0.rebuilder_top_level d2) + | (Ast0.IsoWhenTag(_),_) | (_,Ast0.IsoWhenTag(_)) -> + failwith "only for isos within iso phase" + | _ -> false + +let term (var1,_,_,_,_) = var1 +let dot_term (var1,_,info,_,_) = ("", var1 ^ (string_of_int info.Ast0.offset)) + + +type reason = + NotPure of Ast0.pure * (string * string) * Ast0.anything + | NotPureLength of (string * string) + | ContextRequired of Ast0.anything + | NonMatch + | Braces of Ast0.statement + | Position of string * string + +let interpret_reason name line reason printer = + Printf.printf + "warning: iso %s does not match the code below on line %d\n" name line; + printer(); Format.print_newline(); + match reason with + NotPure(Ast0.Pure,(_,var),nonpure) -> + Printf.printf + "pure metavariable %s is matched against the following nonpure code:\n" + var; + Unparse_ast0.unparse_anything nonpure + | NotPure(Ast0.Context,(_,var),nonpure) -> + Printf.printf + "context metavariable %s is matched against the following\nnoncontext code:\n" + var; + Unparse_ast0.unparse_anything nonpure + | NotPure(Ast0.PureContext,(_,var),nonpure) -> + Printf.printf + "pure context metavariable %s is matched against the following\nnonpure or noncontext code:\n" + var; + Unparse_ast0.unparse_anything nonpure + | NotPureLength((_,var)) -> + Printf.printf + "pure metavariable %s is matched against too much or too little code\n" + var; + | ContextRequired(term) -> + Printf.printf + "the following code matched is not uniformly minus or context,\nor contains a disjunction:\n"; + Unparse_ast0.unparse_anything term + | Braces(s) -> + Printf.printf "braces must be all minus (plus code allowed) or all\ncontext (plus code not allowed in the body) to match:\n"; + Unparse_ast0.statement "" s; + Format.print_newline() + | Position(rule,name) -> + Printf.printf "position variable %s.%s conflicts with an isomorphism\n" + rule name; + | _ -> failwith "not possible" + +type 'a either = OK of 'a | Fail of reason + +let add_binding var exp bindings = + let var = term var in + let attempt bindings = + try + let cur = List.assoc var bindings in + if anything_equal(exp,cur) then [bindings] else [] + with Not_found -> [((var,exp)::bindings)] in + match List.concat(List.map attempt bindings) with + [] -> Fail NonMatch + | x -> OK x + +let add_dot_binding var exp bindings = + let var = dot_term var in + let attempt bindings = + try + let cur = List.assoc var bindings in + if anything_equal(exp,cur) then [bindings] else [] + with Not_found -> [((var,exp)::bindings)] in + match List.concat(List.map attempt bindings) with + [] -> Fail NonMatch + | x -> OK x + +(* multi-valued *) +let add_multi_dot_binding var exp bindings = + let var = dot_term var in + let attempt bindings = [((var,exp)::bindings)] in + match List.concat(List.map attempt bindings) with + [] -> Fail NonMatch + | x -> OK x + +let rec nub ls = + match ls with + [] -> [] + | (x::xs) when (List.mem x xs) -> nub xs + | (x::xs) -> x::(nub xs) + +(* --------------------------------------------------------------------- *) + +let init_env = [[]] + +let debug str m binding = + let res = m binding in + (match res with + None -> Printf.printf "%s: failed\n" str + | Some binding -> + List.iter + (function binding -> + Printf.printf "%s: %s\n" str + (String.concat " " (List.map (function (x,_) -> x) binding))) + binding); + res + +let conjunct_bindings + (m1 : 'binding -> 'binding either) + (m2 : 'binding -> 'binding either) + (binding : 'binding) : 'binding either = + match m1 binding with Fail(reason) -> Fail(reason) | OK binding -> m2 binding + +let rec conjunct_many_bindings = function + [] -> failwith "not possible" + | [x] -> x + | x::xs -> conjunct_bindings x (conjunct_many_bindings xs) + +let mcode_equal (x,_,_,_,_) (y,_,_,_,_) = x = y + +let return b binding = if b then OK binding else Fail NonMatch +let return_false reason binding = Fail reason + +let match_option f t1 t2 = + match (t1,t2) with + (Some t1, Some t2) -> f t1 t2 + | (None, None) -> return true + | _ -> return false + +let bool_match_option f t1 t2 = + match (t1,t2) with + (Some t1, Some t2) -> f t1 t2 + | (None, None) -> true + | _ -> false + +(* context_required is for the example + if ( ++ (int * ) + x == NULL) + where we can't change x == NULL to eg NULL == x. So there can either be + nothing attached to the root or the term has to be all removed. + if would be nice if we knew more about the relationship between the - and + + code, because in the case where the + code is a separate statement in a + sequence, this is not a problem. Perhaps something could be done in + insert_plus + + The example seems strange. Why isn't the cast attached to x? + *) +let is_context e = + !Flag.sgrep_mode2 or (* everything is context for sgrep *) + (match Ast0.get_mcodekind e with + Ast0.CONTEXT(cell) -> true + | _ -> false) + +(* needs a special case when there is a Disj or an empty DOTS + the following stops at the statement level, and gives true if one + statement is replaced by another *) +let rec is_pure_context s = + !Flag.sgrep_mode2 or (* everything is context for sgrep *) + (match Ast0.unwrap s with + Ast0.Disj(starter,statement_dots_list,mids,ender) -> + List.for_all + (function x -> + match Ast0.undots x with + [s] -> is_pure_context s + | _ -> false (* could we do better? *)) + statement_dots_list + | _ -> + (match Ast0.get_mcodekind s with + Ast0.CONTEXT(mc) -> + (match !mc with + (Ast.NOTHING,_,_) -> true + | _ -> false) + | Ast0.MINUS(mc) -> + (match !mc with + (* do better for the common case of replacing a stmt by another one *) + ([[Ast.StatementTag(s)]],_) -> + (match Ast.unwrap s with + Ast.IfThen(_,_,_) -> false (* potentially dangerous *) + | _ -> true) + | (_,_) -> false) + | _ -> false)) + +let is_minus e = + match Ast0.get_mcodekind e with Ast0.MINUS(cell) -> true | _ -> false + +let match_list matcher is_list_matcher do_list_match la lb = + let rec loop = function + ([],[]) -> return true + | ([x],lb) when is_list_matcher x -> do_list_match x lb + | (x::xs,y::ys) -> conjunct_bindings (matcher x y) (loop (xs,ys)) + | _ -> return false in + loop (la,lb) + +let match_maker checks_needed context_required whencode_allowed = + + let check_mcode pmc cmc binding = + if checks_needed + then + match Ast0.get_pos cmc with + (Ast0.MetaPos (name,_,_)) as x -> + (match Ast0.get_pos pmc with + Ast0.MetaPos (name1,_,_) -> + add_binding name1 (Ast0.MetaPosTag x) binding + | Ast0.NoMetaPos -> + let (rule,name) = Ast0.unwrap_mcode name in + Fail (Position(rule,name))) + | Ast0.NoMetaPos -> OK binding + else OK binding in + + let match_dots matcher is_list_matcher do_list_match d1 d2 = + match (Ast0.unwrap d1, Ast0.unwrap d2) with + (Ast0.DOTS(la),Ast0.DOTS(lb)) + | (Ast0.CIRCLES(la),Ast0.CIRCLES(lb)) + | (Ast0.STARS(la),Ast0.STARS(lb)) -> + match_list matcher is_list_matcher (do_list_match d2) la lb + | _ -> return false in + + let is_elist_matcher el = + match Ast0.unwrap el with Ast0.MetaExprList(_,_,_) -> true | _ -> false in + + let is_plist_matcher pl = + match Ast0.unwrap pl with Ast0.MetaParamList(_,_,_) -> true | _ -> false in + + let is_slist_matcher pl = + match Ast0.unwrap pl with Ast0.MetaStmtList(_,_) -> true | _ -> false in + + let no_list _ = false in + + let build_dots pattern data = + match Ast0.unwrap pattern with + Ast0.DOTS(_) -> Ast0.rewrap pattern (Ast0.DOTS(data)) + | Ast0.CIRCLES(_) -> Ast0.rewrap pattern (Ast0.CIRCLES(data)) + | Ast0.STARS(_) -> Ast0.rewrap pattern (Ast0.STARS(data)) in + + let pure_sp_code = + let bind = Ast0.lub_pure in + let option_default = Ast0.Context in + let pure_mcodekind = function + Ast0.CONTEXT(mc) -> + (match !mc with + (Ast.NOTHING,_,_) -> Ast0.PureContext + | _ -> Ast0.Context) + | Ast0.MINUS(mc) -> + (match !mc with ([],_) -> Ast0.Pure | _ -> Ast0.Impure) + | _ -> Ast0.Impure in + let donothing r k e = + bind (pure_mcodekind (Ast0.get_mcodekind e)) (k e) in + + let mcode m = pure_mcodekind (Ast0.get_mcode_mcodekind m) in + + (* a case for everything that has a metavariable *) + (* pure is supposed to match only unitary metavars, not anything that + contains only unitary metavars *) + let ident r k i = + bind (bind (pure_mcodekind (Ast0.get_mcodekind i)) (k i)) + (match Ast0.unwrap i with + Ast0.MetaId(name,_,pure) | Ast0.MetaFunc(name,_,pure) + | Ast0.MetaLocalFunc(name,_,pure) -> pure + | _ -> Ast0.Impure) in + + let expression r k e = + bind (bind (pure_mcodekind (Ast0.get_mcodekind e)) (k e)) + (match Ast0.unwrap e with + Ast0.MetaErr(name,_,pure) + | Ast0.MetaExpr(name,_,_,_,pure) | Ast0.MetaExprList(name,_,pure) -> + pure + | _ -> Ast0.Impure) in + + let typeC r k t = + bind (bind (pure_mcodekind (Ast0.get_mcodekind t)) (k t)) + (match Ast0.unwrap t with + Ast0.MetaType(name,pure) -> pure + | _ -> Ast0.Impure) in + + let param r k p = + bind (bind (pure_mcodekind (Ast0.get_mcodekind p)) (k p)) + (match Ast0.unwrap p with + Ast0.MetaParam(name,pure) | Ast0.MetaParamList(name,_,pure) -> pure + | _ -> Ast0.Impure) in + + let stmt r k s = + bind (bind (pure_mcodekind (Ast0.get_mcodekind s)) (k s)) + (match Ast0.unwrap s with + Ast0.MetaStmt(name,pure) | Ast0.MetaStmtList(name,pure) -> pure + | _ -> Ast0.Impure) in + + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + ident expression typeC donothing param donothing stmt donothing + donothing in + + let add_pure_list_binding name pure is_pure builder1 builder2 lst = + match (checks_needed,pure) with + (true,Ast0.Pure) | (true,Ast0.Context) | (true,Ast0.PureContext) -> + (match lst with + [x] -> + if (Ast0.lub_pure (is_pure x) pure) = pure + then add_binding name (builder1 lst) + else return_false (NotPure (pure,term name,builder1 lst)) + | _ -> return_false (NotPureLength (term name))) + | (false,_) | (_,Ast0.Impure) -> add_binding name (builder2 lst) in + + let add_pure_binding name pure is_pure builder x = + match (checks_needed,pure) with + (true,Ast0.Pure) | (true,Ast0.Context) | (true,Ast0.PureContext) -> + if (Ast0.lub_pure (is_pure x) pure) = pure + then add_binding name (builder x) + else return_false (NotPure (pure,term name, builder x)) + | (false,_) | (_,Ast0.Impure) -> add_binding name (builder x) in + + let do_elist_match builder el lst = + match Ast0.unwrap el with + Ast0.MetaExprList(name,lenname,pure) -> + (*how to handle lenname? should it be an option type and always None?*) + failwith "expr list pattern not supported in iso" + (*add_pure_list_binding name pure + pure_sp_code.V0.combiner_expression + (function lst -> Ast0.ExprTag(List.hd lst)) + (function lst -> Ast0.DotsExprTag(build_dots builder lst)) + lst*) + | _ -> failwith "not possible" in + + let do_plist_match builder pl lst = + match Ast0.unwrap pl with + Ast0.MetaParamList(name,lename,pure) -> + failwith "param list pattern not supported in iso" + (*add_pure_list_binding name pure + pure_sp_code.V0.combiner_parameter + (function lst -> Ast0.ParamTag(List.hd lst)) + (function lst -> Ast0.DotsParamTag(build_dots builder lst)) + lst*) + | _ -> failwith "not possible" in + + let do_slist_match builder sl lst = + match Ast0.unwrap sl with + Ast0.MetaStmtList(name,pure) -> + add_pure_list_binding name pure + pure_sp_code.V0.combiner_statement + (function lst -> Ast0.StmtTag(List.hd lst)) + (function lst -> Ast0.DotsStmtTag(build_dots builder lst)) + lst + | _ -> failwith "not possible" in + + let do_nolist_match _ _ = failwith "not possible" in + + let rec match_ident pattern id = + match Ast0.unwrap pattern with + Ast0.MetaId(name,_,pure) -> + (add_pure_binding name pure pure_sp_code.V0.combiner_ident + (function id -> Ast0.IdentTag id) id) + | Ast0.MetaFunc(name,_,pure) -> failwith "metafunc not supported" + | Ast0.MetaLocalFunc(name,_,pure) -> failwith "metalocalfunc not supported" + | up -> + if not(checks_needed) or not(context_required) or is_context id + then + match (up,Ast0.unwrap id) with + (Ast0.Id(namea),Ast0.Id(nameb)) -> + if mcode_equal namea nameb + then check_mcode namea nameb + else return false + | (Ast0.OptIdent(ida),Ast0.OptIdent(idb)) + | (Ast0.UniqueIdent(ida),Ast0.UniqueIdent(idb)) -> + match_ident ida idb + | (_,Ast0.OptIdent(idb)) + | (_,Ast0.UniqueIdent(idb)) -> match_ident pattern idb + | _ -> return false + else return_false (ContextRequired (Ast0.IdentTag id)) in + + (* should we do something about matching metavars against ...? *) + let rec match_expr pattern expr = + match Ast0.unwrap pattern with + Ast0.MetaExpr(name,_,ty,form,pure) -> + let form_ok = + match (form,expr) with + (Ast.ANY,_) -> true + | (Ast.CONST,e) -> + let rec matches e = + match Ast0.unwrap e with + Ast0.Constant(c) -> true + | Ast0.Cast(lp,ty,rp,e) -> matches e + | Ast0.SizeOfExpr(se,exp) -> true + | Ast0.SizeOfType(se,lp,ty,rp) -> true + | Ast0.MetaExpr(nm,_,_,Ast.CONST,p) -> + (Ast0.lub_pure p pure) = pure + | _ -> false in + matches e + | (Ast.ID,e) | (Ast.LocalID,e) -> + let rec matches e = + match Ast0.unwrap e with + Ast0.Ident(c) -> true + | Ast0.Cast(lp,ty,rp,e) -> matches e + | Ast0.MetaExpr(nm,_,_,Ast.ID,p) -> + (Ast0.lub_pure p pure) = pure + | _ -> false in + matches e in + if form_ok + then + match ty with + Some ts -> + if List.exists + (function Type_cocci.MetaType(_,_,_) -> true | _ -> false) + ts + then + (match ts with + [Type_cocci.MetaType(tyname,_,_)] -> + let expty = + match (Ast0.unwrap expr,Ast0.get_type expr) with + (* easier than updating type inferencer to manage multiple + types *) + (Ast0.MetaExpr(_,_,Some tts,_,_),_) -> Some tts + | (_,Some ty) -> Some [ty] + | _ -> None in + (match expty with + Some expty -> + let tyname = Ast0.rewrap_mcode name tyname in + (function bindings -> + let attempts = + List.map + (function expty -> + (try + conjunct_bindings + (add_pure_binding tyname Ast0.Impure + (function _ -> Ast0.Impure) + (function ty -> Ast0.TypeCTag ty) + (Ast0.rewrap expr + (Ast0.reverse_type expty))) + (add_pure_binding name pure + pure_sp_code.V0.combiner_expression + (function expr -> Ast0.ExprTag expr) + expr) + bindings + with Ast0.TyConv -> + Printf.printf "warning: unconvertible type"; + return false bindings)) + expty in + match + List.concat + (List.map (function Fail _ -> [] | OK x -> x) + attempts) + with + [] -> Fail NonMatch + | x -> OK x) + | _ -> + (*Printf.printf + "warning: type metavar can only match one type";*) + return false) + | _ -> + failwith + "mixture of metatype and other types not supported") + else + let expty = Ast0.get_type expr in + if List.exists (function t -> Type_cocci.compatible t expty) ts + then + add_pure_binding name pure + pure_sp_code.V0.combiner_expression + (function expr -> Ast0.ExprTag expr) + expr + else return false + | None -> + add_pure_binding name pure pure_sp_code.V0.combiner_expression + (function expr -> Ast0.ExprTag expr) + expr + else return false + | Ast0.MetaErr(namea,_,pure) -> failwith "metaerr not supported" + | Ast0.MetaExprList(_,_,_) -> failwith "metaexprlist not supported" + | up -> + if not(checks_needed) or not(context_required) or is_context expr + then + match (up,Ast0.unwrap expr) with + (Ast0.Ident(ida),Ast0.Ident(idb)) -> + match_ident ida idb + | (Ast0.Constant(consta),Ast0.Constant(constb)) -> + if mcode_equal consta constb + then check_mcode consta constb + else return false + | (Ast0.FunCall(fna,lp1,argsa,rp1),Ast0.FunCall(fnb,lp,argsb,rp)) -> + conjunct_many_bindings + [check_mcode lp1 lp; check_mcode rp1 rp; match_expr fna fnb; + match_dots match_expr is_elist_matcher do_elist_match + argsa argsb] + | (Ast0.Assignment(lefta,opa,righta,_), + Ast0.Assignment(leftb,opb,rightb,_)) -> + if mcode_equal opa opb + then + conjunct_many_bindings + [check_mcode opa opb; match_expr lefta leftb; + match_expr righta rightb] + else return false + | (Ast0.CondExpr(exp1a,lp1,exp2a,rp1,exp3a), + Ast0.CondExpr(exp1b,lp,exp2b,rp,exp3b)) -> + conjunct_many_bindings + [check_mcode lp1 lp; check_mcode rp1 rp; + match_expr exp1a exp1b; match_option match_expr exp2a exp2b; + match_expr exp3a exp3b] + | (Ast0.Postfix(expa,opa),Ast0.Postfix(expb,opb)) -> + if mcode_equal opa opb + then + conjunct_bindings (check_mcode opa opb) (match_expr expa expb) + else return false + | (Ast0.Infix(expa,opa),Ast0.Infix(expb,opb)) -> + if mcode_equal opa opb + then + conjunct_bindings (check_mcode opa opb) (match_expr expa expb) + else return false + | (Ast0.Unary(expa,opa),Ast0.Unary(expb,opb)) -> + if mcode_equal opa opb + then + conjunct_bindings (check_mcode opa opb) (match_expr expa expb) + else return false + | (Ast0.Binary(lefta,opa,righta),Ast0.Binary(leftb,opb,rightb)) -> + if mcode_equal opa opb + then + conjunct_many_bindings + [check_mcode opa opb; match_expr lefta leftb; + match_expr righta rightb] + else return false + | (Ast0.Paren(lp1,expa,rp1),Ast0.Paren(lp,expb,rp)) -> + conjunct_many_bindings + [check_mcode lp1 lp; check_mcode rp1 rp; match_expr expa expb] + | (Ast0.ArrayAccess(exp1a,lb1,exp2a,rb1), + Ast0.ArrayAccess(exp1b,lb,exp2b,rb)) -> + conjunct_many_bindings + [check_mcode lb1 lb; check_mcode rb1 rb; + match_expr exp1a exp1b; match_expr exp2a exp2b] + | (Ast0.RecordAccess(expa,opa,fielda), + Ast0.RecordAccess(expb,op,fieldb)) + | (Ast0.RecordPtAccess(expa,opa,fielda), + Ast0.RecordPtAccess(expb,op,fieldb)) -> + conjunct_many_bindings + [check_mcode opa op; match_expr expa expb; + match_ident fielda fieldb] + | (Ast0.Cast(lp1,tya,rp1,expa),Ast0.Cast(lp,tyb,rp,expb)) -> + conjunct_many_bindings + [check_mcode lp1 lp; check_mcode rp1 rp; + match_typeC tya tyb; match_expr expa expb] + | (Ast0.SizeOfExpr(szf1,expa),Ast0.SizeOfExpr(szf,expb)) -> + conjunct_bindings (check_mcode szf1 szf) (match_expr expa expb) + | (Ast0.SizeOfType(szf1,lp1,tya,rp1), + Ast0.SizeOfType(szf,lp,tyb,rp)) -> + conjunct_many_bindings + [check_mcode lp1 lp; check_mcode rp1 rp; + check_mcode szf1 szf; match_typeC tya tyb] + | (Ast0.TypeExp(tya),Ast0.TypeExp(tyb)) -> + match_typeC tya tyb + | (Ast0.EComma(cm1),Ast0.EComma(cm)) -> check_mcode cm1 cm + | (Ast0.DisjExpr(_,expsa,_,_),_) -> + failwith "not allowed in the pattern of an isomorphism" + | (Ast0.NestExpr(_,exp_dotsa,_,_,_),_) -> + failwith "not allowed in the pattern of an isomorphism" + | (Ast0.Edots(d,None),Ast0.Edots(d1,None)) + | (Ast0.Ecircles(d,None),Ast0.Ecircles(d1,None)) + | (Ast0.Estars(d,None),Ast0.Estars(d1,None)) -> check_mcode d d1 + | (Ast0.Edots(ed,None),Ast0.Edots(ed1,Some wc)) + | (Ast0.Ecircles(ed,None),Ast0.Ecircles(ed1,Some wc)) + | (Ast0.Estars(ed,None),Ast0.Estars(ed1,Some wc)) -> + (* hope that mcode of edots is unique somehow *) + conjunct_bindings (check_mcode ed ed1) + (let (edots_whencode_allowed,_,_) = whencode_allowed in + if edots_whencode_allowed + then add_dot_binding ed (Ast0.ExprTag wc) + else + (Printf.printf + "warning: not applying iso because of whencode"; + return false)) + | (Ast0.Edots(_,Some _),_) | (Ast0.Ecircles(_,Some _),_) + | (Ast0.Estars(_,Some _),_) -> + failwith "whencode not allowed in a pattern1" + | (Ast0.OptExp(expa),Ast0.OptExp(expb)) + | (Ast0.UniqueExp(expa),Ast0.UniqueExp(expb)) -> match_expr expa expb + | (_,Ast0.OptExp(expb)) + | (_,Ast0.UniqueExp(expb)) -> match_expr pattern expb + | _ -> return false + else return_false (ContextRequired (Ast0.ExprTag expr)) + +(* the special case for function types prevents the eg T X; -> T X = E; iso + from applying, which doesn't seem very relevant, but it also avoids a + mysterious bug that is obtained with eg int attach(...); *) + and match_typeC pattern t = + match Ast0.unwrap pattern with + Ast0.MetaType(name,pure) -> + (match Ast0.unwrap t with + Ast0.FunctionType(tya,lp1a,paramsa,rp1a) -> return false + | _ -> + add_pure_binding name pure pure_sp_code.V0.combiner_typeC + (function ty -> Ast0.TypeCTag ty) + t) + | up -> + if not(checks_needed) or not(context_required) or is_context t + then + match (up,Ast0.unwrap t) with + (Ast0.ConstVol(cva,tya),Ast0.ConstVol(cvb,tyb)) -> + if mcode_equal cva cvb + then + conjunct_bindings (check_mcode cva cvb) (match_typeC tya tyb) + else return false + | (Ast0.BaseType(tya,signa),Ast0.BaseType(tyb,signb)) -> + if (mcode_equal tya tyb && + bool_match_option mcode_equal signa signb) + then + conjunct_bindings (check_mcode tya tyb) + (match_option check_mcode signa signb) + else return false + | (Ast0.ImplicitInt(signa),Ast0.ImplicitInt(signb)) -> + if mcode_equal signa signb + then check_mcode signa signb + else return false + | (Ast0.Pointer(tya,star1),Ast0.Pointer(tyb,star)) -> + conjunct_bindings (check_mcode star1 star) (match_typeC tya tyb) + | (Ast0.FunctionPointer(tya,lp1a,stara,rp1a,lp2a,paramsa,rp2a), + Ast0.FunctionPointer(tyb,lp1b,starb,rp1b,lp2b,paramsb,rp2b)) -> + conjunct_many_bindings + [check_mcode stara starb; check_mcode lp1a lp1b; + check_mcode rp1a rp1b; check_mcode lp2a lp2b; + check_mcode rp2a rp2b; match_typeC tya tyb; + match_dots match_param is_plist_matcher + do_plist_match paramsa paramsb] + | (Ast0.FunctionType(tya,lp1a,paramsa,rp1a), + Ast0.FunctionType(tyb,lp1b,paramsb,rp1b)) -> + conjunct_many_bindings + [check_mcode lp1a lp1b; check_mcode rp1a rp1b; + match_option match_typeC tya tyb; + match_dots match_param is_plist_matcher do_plist_match + paramsa paramsb] + | (Ast0.Array(tya,lb1,sizea,rb1),Ast0.Array(tyb,lb,sizeb,rb)) -> + conjunct_many_bindings + [check_mcode lb1 lb; check_mcode rb1 rb; + match_typeC tya tyb; match_option match_expr sizea sizeb] + | (Ast0.StructUnionName(kinda,Some namea), + Ast0.StructUnionName(kindb,Some nameb)) -> + if mcode_equal kinda kindb + then + conjunct_bindings (check_mcode kinda kindb) + (match_ident namea nameb) + else return false + | (Ast0.StructUnionDef(tya,lb1,declsa,rb1), + Ast0.StructUnionDef(tyb,lb,declsb,rb)) -> + conjunct_many_bindings + [check_mcode lb1 lb; check_mcode rb1 rb; + match_typeC tya tyb; + match_dots match_decl no_list do_nolist_match declsa declsb] + | (Ast0.TypeName(namea),Ast0.TypeName(nameb)) -> + if mcode_equal namea nameb + then check_mcode namea nameb + else return false + | (Ast0.DisjType(_,typesa,_,_),Ast0.DisjType(_,typesb,_,_)) -> + failwith "not allowed in the pattern of an isomorphism" + | (Ast0.OptType(tya),Ast0.OptType(tyb)) + | (Ast0.UniqueType(tya),Ast0.UniqueType(tyb)) -> match_typeC tya tyb + | (_,Ast0.OptType(tyb)) + | (_,Ast0.UniqueType(tyb)) -> match_typeC pattern tyb + | _ -> return false + else return_false (ContextRequired (Ast0.TypeCTag t)) + + and match_decl pattern d = + if not(checks_needed) or not(context_required) or is_context d + then + match (Ast0.unwrap pattern,Ast0.unwrap d) with + (Ast0.Init(stga,tya,ida,eq1,inia,sc1), + Ast0.Init(stgb,tyb,idb,eq,inib,sc)) -> + if bool_match_option mcode_equal stga stgb + then + conjunct_many_bindings + [check_mcode eq1 eq; check_mcode sc1 sc; + match_option check_mcode stga stgb; + match_typeC tya tyb; match_ident ida idb; + match_init inia inib] + else return false + | (Ast0.UnInit(stga,tya,ida,sc1),Ast0.UnInit(stgb,tyb,idb,sc)) -> + if bool_match_option mcode_equal stga stgb + then + conjunct_many_bindings + [check_mcode sc1 sc; match_option check_mcode stga stgb; + match_typeC tya tyb; match_ident ida idb] + else return false + | (Ast0.MacroDecl(namea,lp1,argsa,rp1,sc1), + Ast0.MacroDecl(nameb,lp,argsb,rp,sc)) -> + conjunct_many_bindings + [match_ident namea nameb; + check_mcode lp1 lp; check_mcode rp1 rp; + check_mcode sc1 sc; + match_dots match_expr is_elist_matcher do_elist_match + argsa argsb] + | (Ast0.TyDecl(tya,sc1),Ast0.TyDecl(tyb,sc)) -> + conjunct_bindings (check_mcode sc1 sc) (match_typeC tya tyb) + | (Ast0.Typedef(stga,tya,ida,sc1),Ast0.Typedef(stgb,tyb,idb,sc)) -> + conjunct_bindings (check_mcode sc1 sc) + (conjunct_bindings (match_typeC tya tyb) (match_typeC ida idb)) + | (Ast0.DisjDecl(_,declsa,_,_),Ast0.DisjDecl(_,declsb,_,_)) -> + failwith "not allowed in the pattern of an isomorphism" + | (Ast0.Ddots(d1,None),Ast0.Ddots(d,None)) -> check_mcode d1 d + | (Ast0.Ddots(dd,None),Ast0.Ddots(d,Some wc)) -> + conjunct_bindings (check_mcode dd d) + (* hope that mcode of ddots is unique somehow *) + (let (ddots_whencode_allowed,_,_) = whencode_allowed in + if ddots_whencode_allowed + then add_dot_binding dd (Ast0.DeclTag wc) + else + (Printf.printf "warning: not applying iso because of whencode"; + return false)) + | (Ast0.Ddots(_,Some _),_) -> + failwith "whencode not allowed in a pattern1" + + | (Ast0.OptDecl(decla),Ast0.OptDecl(declb)) + | (Ast0.UniqueDecl(decla),Ast0.UniqueDecl(declb)) -> + match_decl decla declb + | (_,Ast0.OptDecl(declb)) + | (_,Ast0.UniqueDecl(declb)) -> + match_decl pattern declb + | _ -> return false + else return_false (ContextRequired (Ast0.DeclTag d)) + + and match_init pattern i = + if not(checks_needed) or not(context_required) or is_context i + then + match (Ast0.unwrap pattern,Ast0.unwrap i) with + (Ast0.InitExpr(expa),Ast0.InitExpr(expb)) -> + match_expr expa expb + | (Ast0.InitList(lb1,initlista,rb1),Ast0.InitList(lb,initlistb,rb)) -> + conjunct_many_bindings + [check_mcode lb1 lb; check_mcode rb1 rb; + match_dots match_init no_list do_nolist_match + initlista initlistb] + | (Ast0.InitGccDotName(d1,namea,e1,inia), + Ast0.InitGccDotName(d,nameb,e,inib)) -> + conjunct_many_bindings + [check_mcode d1 d; check_mcode e1 e; + match_ident namea nameb; match_init inia inib] + | (Ast0.InitGccName(namea,c1,inia),Ast0.InitGccName(nameb,c,inib)) -> + conjunct_many_bindings + [check_mcode c1 c; match_ident namea nameb; + match_init inia inib] + | (Ast0.InitGccIndex(lb1,expa,rb1,e1,inia), + Ast0.InitGccIndex(lb2,expb,rb2,e2,inib)) -> + conjunct_many_bindings + [check_mcode lb1 lb2; check_mcode rb1 rb2; check_mcode e1 e2; + match_expr expa expb; match_init inia inib] + | (Ast0.InitGccRange(lb1,exp1a,d1,exp2a,rb1,e1,inia), + Ast0.InitGccRange(lb2,exp1b,d2,exp2b,rb2,e2,inib)) -> + conjunct_many_bindings + [check_mcode lb1 lb2; check_mcode d1 d2; + check_mcode rb1 rb2; check_mcode e1 e2; + match_expr exp1a exp1b; match_expr exp2a exp2b; + match_init inia inib] + | (Ast0.IComma(c1),Ast0.IComma(c)) -> check_mcode c1 c + | (Ast0.Idots(d1,None),Ast0.Idots(d,None)) -> check_mcode d1 d + | (Ast0.Idots(id,None),Ast0.Idots(d,Some wc)) -> + conjunct_bindings (check_mcode id d) + (* hope that mcode of edots is unique somehow *) + (let (_,idots_whencode_allowed,_) = whencode_allowed in + if idots_whencode_allowed + then add_dot_binding id (Ast0.InitTag wc) + else + (Printf.printf "warning: not applying iso because of whencode"; + return false)) + | (Ast0.Idots(_,Some _),_) -> + failwith "whencode not allowed in a pattern2" + | (Ast0.OptIni(ia),Ast0.OptIni(ib)) + | (Ast0.UniqueIni(ia),Ast0.UniqueIni(ib)) -> match_init ia ib + | (_,Ast0.OptIni(ib)) + | (_,Ast0.UniqueIni(ib)) -> match_init pattern ib + | _ -> return false + else return_false (ContextRequired (Ast0.InitTag i)) + + and match_param pattern p = + match Ast0.unwrap pattern with + Ast0.MetaParam(name,pure) -> + add_pure_binding name pure pure_sp_code.V0.combiner_parameter + (function p -> Ast0.ParamTag p) + p + | Ast0.MetaParamList(name,_,pure) -> failwith "metaparamlist not supported" + | up -> + if not(checks_needed) or not(context_required) or is_context p + then + match (up,Ast0.unwrap p) with + (Ast0.VoidParam(tya),Ast0.VoidParam(tyb)) -> match_typeC tya tyb + | (Ast0.Param(tya,ida),Ast0.Param(tyb,idb)) -> + conjunct_bindings (match_typeC tya tyb) + (match_option match_ident ida idb) + | (Ast0.PComma(c1),Ast0.PComma(c)) -> check_mcode c1 c + | (Ast0.Pdots(d1),Ast0.Pdots(d)) + | (Ast0.Pcircles(d1),Ast0.Pcircles(d)) -> check_mcode d1 d + | (Ast0.OptParam(parama),Ast0.OptParam(paramb)) + | (Ast0.UniqueParam(parama),Ast0.UniqueParam(paramb)) -> + match_param parama paramb + | (_,Ast0.OptParam(paramb)) + | (_,Ast0.UniqueParam(paramb)) -> match_param pattern paramb + | _ -> return false + else return_false (ContextRequired (Ast0.ParamTag p)) + + and match_statement pattern s = + match Ast0.unwrap pattern with + Ast0.MetaStmt(name,pure) -> + (match Ast0.unwrap s with + Ast0.Dots(_,_) | Ast0.Circles(_,_) | Ast0.Stars(_,_) -> + return false (* ... is not a single statement *) + | _ -> + add_pure_binding name pure pure_sp_code.V0.combiner_statement + (function ty -> Ast0.StmtTag ty) + s) + | Ast0.MetaStmtList(name,pure) -> failwith "metastmtlist not supported" + | up -> + if not(checks_needed) or not(context_required) or is_context s + then + match (up,Ast0.unwrap s) with + (Ast0.FunDecl(_,fninfoa,namea,lp1,paramsa,rp1,lb1,bodya,rb1), + Ast0.FunDecl(_,fninfob,nameb,lp,paramsb,rp,lb,bodyb,rb)) -> + conjunct_many_bindings + [check_mcode lp1 lp; check_mcode rp1 rp; + check_mcode lb1 lb; check_mcode rb1 rb; + match_fninfo fninfoa fninfob; match_ident namea nameb; + match_dots match_param is_plist_matcher do_plist_match + paramsa paramsb; + match_dots match_statement is_slist_matcher do_slist_match + bodya bodyb] + | (Ast0.Decl(_,decla),Ast0.Decl(_,declb)) -> + match_decl decla declb + | (Ast0.Seq(lb1,bodya,rb1),Ast0.Seq(lb,bodyb,rb)) -> + (* seqs can only match if they are all minus (plus code + allowed) or all context (plus code not allowed in the body). + we could be more permissive if the expansions of the isos are + also all seqs, but this would be hard to check except at top + level, and perhaps not worth checking even in that case. + Overall, the issue is that braces are used where single + statements are required, and something not satisfying these + conditions can cause a single statement to become a + non-single statement after the transformation. + + example: if { ... -foo(); ... } + if we let the sequence convert to just -foo(); + then we produce invalid code. For some reason, + single_statement can't deal with this case, perhaps because + it starts introducing too many braces? don't remember the + exact problem... + *) + conjunct_bindings (check_mcode lb1 lb) + (conjunct_bindings (check_mcode rb1 rb) + (if not(checks_needed) or is_minus s or + (is_context s && + List.for_all is_pure_context (Ast0.undots bodyb)) + then + match_dots match_statement is_slist_matcher do_slist_match + bodya bodyb + else return_false (Braces(s)))) + | (Ast0.ExprStatement(expa,sc1),Ast0.ExprStatement(expb,sc)) -> + conjunct_bindings (check_mcode sc1 sc) (match_expr expa expb) + | (Ast0.IfThen(if1,lp1,expa,rp1,branch1a,_), + Ast0.IfThen(if2,lp2,expb,rp2,branch1b,_)) -> + conjunct_many_bindings + [check_mcode if1 if2; check_mcode lp1 lp2; + check_mcode rp1 rp2; + match_expr expa expb; + match_statement branch1a branch1b] + | (Ast0.IfThenElse(if1,lp1,expa,rp1,branch1a,e1,branch2a,_), + Ast0.IfThenElse(if2,lp2,expb,rp2,branch1b,e2,branch2b,_)) -> + conjunct_many_bindings + [check_mcode if1 if2; check_mcode lp1 lp2; + check_mcode rp1 rp2; check_mcode e1 e2; + match_expr expa expb; + match_statement branch1a branch1b; + match_statement branch2a branch2b] + | (Ast0.While(w1,lp1,expa,rp1,bodya,_), + Ast0.While(w,lp,expb,rp,bodyb,_)) -> + conjunct_many_bindings + [check_mcode w1 w; check_mcode lp1 lp; + check_mcode rp1 rp; match_expr expa expb; + match_statement bodya bodyb] + | (Ast0.Do(d1,bodya,w1,lp1,expa,rp1,_), + Ast0.Do(d,bodyb,w,lp,expb,rp,_)) -> + conjunct_many_bindings + [check_mcode d1 d; check_mcode w1 w; check_mcode lp1 lp; + check_mcode rp1 rp; match_statement bodya bodyb; + match_expr expa expb] + | (Ast0.For(f1,lp1,e1a,sc1a,e2a,sc2a,e3a,rp1,bodya,_), + Ast0.For(f,lp,e1b,sc1b,e2b,sc2b,e3b,rp,bodyb,_)) -> + conjunct_many_bindings + [check_mcode f1 f; check_mcode lp1 lp; check_mcode sc1a sc1b; + check_mcode sc2a sc2b; check_mcode rp1 rp; + match_option match_expr e1a e1b; + match_option match_expr e2a e2b; + match_option match_expr e3a e3b; + match_statement bodya bodyb] + | (Ast0.Iterator(nma,lp1,argsa,rp1,bodya,_), + Ast0.Iterator(nmb,lp,argsb,rp,bodyb,_)) -> + conjunct_many_bindings + [match_ident nma nmb; + check_mcode lp1 lp; check_mcode rp1 rp; + match_dots match_expr is_elist_matcher do_elist_match + argsa argsb; + match_statement bodya bodyb] + | (Ast0.Switch(s1,lp1,expa,rp1,lb1,casesa,rb1), + Ast0.Switch(s,lp,expb,rp,lb,casesb,rb)) -> + conjunct_many_bindings + [check_mcode s1 s; check_mcode lp1 lp; check_mcode rp1 rp; + check_mcode lb1 lb; check_mcode rb1 rb; + match_expr expa expb; + match_dots match_case_line no_list do_nolist_match + casesa casesb] + | (Ast0.Break(b1,sc1),Ast0.Break(b,sc)) + | (Ast0.Continue(b1,sc1),Ast0.Continue(b,sc)) -> + conjunct_bindings (check_mcode b1 b) (check_mcode sc1 sc) + | (Ast0.Label(l1,c1),Ast0.Label(l2,c)) -> + conjunct_bindings (match_ident l1 l2) (check_mcode c1 c) + | (Ast0.Goto(g1,l1,sc1),Ast0.Goto(g,l2,sc)) -> + conjunct_many_bindings + [check_mcode g1 g; check_mcode sc1 sc; match_ident l1 l2] + | (Ast0.Return(r1,sc1),Ast0.Return(r,sc)) -> + conjunct_bindings (check_mcode r1 r) (check_mcode sc1 sc) + | (Ast0.ReturnExpr(r1,expa,sc1),Ast0.ReturnExpr(r,expb,sc)) -> + conjunct_many_bindings + [check_mcode r1 r; check_mcode sc1 sc; match_expr expa expb] + | (Ast0.Disj(_,statement_dots_lista,_,_),_) -> + failwith "disj not supported in patterns" + | (Ast0.Nest(_,stmt_dotsa,_,_,_),_) -> + failwith "nest not supported in patterns" + | (Ast0.Exp(expa),Ast0.Exp(expb)) -> match_expr expa expb + | (Ast0.TopExp(expa),Ast0.TopExp(expb)) -> match_expr expa expb + | (Ast0.Exp(expa),Ast0.TopExp(expb)) -> match_expr expa expb + | (Ast0.Ty(tya),Ast0.Ty(tyb)) -> match_typeC tya tyb + | (Ast0.Dots(d,[]),Ast0.Dots(d1,wc)) + | (Ast0.Circles(d,[]),Ast0.Circles(d1,wc)) + | (Ast0.Stars(d,[]),Ast0.Stars(d1,wc)) -> + (match wc with + [] -> check_mcode d d1 + | _ -> + let (_,_,dots_whencode_allowed) = whencode_allowed in + if dots_whencode_allowed + then + conjunct_bindings (check_mcode d d1) + (List.fold_left + (function prev -> + function + | Ast0.WhenNot wc -> + conjunct_bindings prev + (add_multi_dot_binding d + (Ast0.DotsStmtTag wc)) + | Ast0.WhenAlways wc -> + conjunct_bindings prev + (add_multi_dot_binding d (Ast0.StmtTag wc)) + | Ast0.WhenModifier(x) -> + conjunct_bindings prev + (add_multi_dot_binding d + (Ast0.IsoWhenTag x))) + (return true) wc) + else + (Printf.printf + "warning: not applying iso because of whencode"; + return false)) + | (Ast0.Dots(_,_::_),_) | (Ast0.Circles(_,_::_),_) + | (Ast0.Stars(_,_::_),_) -> + failwith "whencode not allowed in a pattern3" + | (Ast0.OptStm(rea),Ast0.OptStm(reb)) + | (Ast0.UniqueStm(rea),Ast0.UniqueStm(reb)) -> + match_statement rea reb + | (_,Ast0.OptStm(reb)) + | (_,Ast0.UniqueStm(reb)) -> match_statement pattern reb + | _ -> return false + else return_false (ContextRequired (Ast0.StmtTag s)) + + (* first should provide a subset of the information in the second *) + and match_fninfo patterninfo cinfo = + let patterninfo = List.sort compare patterninfo in + let cinfo = List.sort compare cinfo in + let rec loop = function + (Ast0.FStorage(sta)::resta,Ast0.FStorage(stb)::restb) -> + if mcode_equal sta stb + then conjunct_bindings (check_mcode sta stb) (loop (resta,restb)) + else return false + | (Ast0.FType(tya)::resta,Ast0.FType(tyb)::restb) -> + conjunct_bindings (match_typeC tya tyb) (loop (resta,restb)) + | (Ast0.FInline(ia)::resta,Ast0.FInline(ib)::restb) -> + if mcode_equal ia ib + then conjunct_bindings (check_mcode ia ib) (loop (resta,restb)) + else return false + | (Ast0.FAttr(ia)::resta,Ast0.FAttr(ib)::restb) -> + if mcode_equal ia ib + then conjunct_bindings (check_mcode ia ib) (loop (resta,restb)) + else return false + | (x::resta,((y::_) as restb)) -> + (match compare x y with + -1 -> return false + | 1 -> loop (resta,restb) + | _ -> failwith "not possible") + | _ -> return false in + loop (patterninfo,cinfo) + + and match_case_line pattern c = + if not(checks_needed) or not(context_required) or is_context c + then + match (Ast0.unwrap pattern,Ast0.unwrap c) with + (Ast0.Default(d1,c1,codea),Ast0.Default(d,c,codeb)) -> + conjunct_many_bindings + [check_mcode d1 d; check_mcode c1 c; + match_dots match_statement is_slist_matcher do_slist_match + codea codeb] + | (Ast0.Case(ca1,expa,c1,codea),Ast0.Case(ca,expb,c,codeb)) -> + conjunct_many_bindings + [check_mcode ca1 ca; check_mcode c1 c; match_expr expa expb; + match_dots match_statement is_slist_matcher do_slist_match + codea codeb] + | (Ast0.OptCase(ca),Ast0.OptCase(cb)) -> match_case_line ca cb + | (_,Ast0.OptCase(cb)) -> match_case_line pattern cb + | _ -> return false + else return_false (ContextRequired (Ast0.CaseLineTag c)) in + + let match_statement_dots x y = + match_dots match_statement is_slist_matcher do_slist_match x y in + + (match_expr, match_decl, match_statement, match_typeC, + match_statement_dots) + +let match_expr dochecks context_required whencode_allowed = + let (fn,_,_,_,_) = match_maker dochecks context_required whencode_allowed in + fn + +let match_decl dochecks context_required whencode_allowed = + let (_,fn,_,_,_) = match_maker dochecks context_required whencode_allowed in + fn + +let match_statement dochecks context_required whencode_allowed = + let (_,_,fn,_,_) = match_maker dochecks context_required whencode_allowed in + fn + +let match_typeC dochecks context_required whencode_allowed = + let (_,_,_,fn,_) = match_maker dochecks context_required whencode_allowed in + fn + +let match_statement_dots dochecks context_required whencode_allowed = + let (_,_,_,_,fn) = match_maker dochecks context_required whencode_allowed in + fn + +(* --------------------------------------------------------------------- *) +(* make an entire tree MINUS *) + +let make_minus = + let mcode (term,arity,info,mcodekind,pos) = + let new_mcodekind = + match mcodekind with + Ast0.CONTEXT(mc) -> + (match !mc with + (Ast.NOTHING,_,_) -> Ast0.MINUS(ref([],Ast0.default_token_info)) + | _ -> failwith "make_minus: unexpected befaft") + | Ast0.MINUS(mc) -> mcodekind (* in the part copied from the src term *) + | _ -> failwith "make_minus mcode: unexpected mcodekind" in + (term,arity,info,new_mcodekind,pos) in + + let update_mc mcodekind e = + match !mcodekind with + Ast0.CONTEXT(mc) -> + (match !mc with + (Ast.NOTHING,_,_) -> + mcodekind := Ast0.MINUS(ref([],Ast0.default_token_info)) + | _ -> failwith "make_minus: unexpected befaft") + | Ast0.MINUS(_mc) -> () (* in the part copied from the src term *) + | Ast0.PLUS -> failwith "make_minus donothing: unexpected plus mcodekind" + | _ -> failwith "make_minus donothing: unexpected mcodekind" in + + let donothing r k e = + let mcodekind = Ast0.get_mcodekind_ref e in + let e = k e in update_mc mcodekind e; e in + + (* special case for whencode, because it isn't processed by contextneg, + since it doesn't appear in the + code *) + (* cases for dots and nests *) + let expression r k e = + let mcodekind = Ast0.get_mcodekind_ref e in + match Ast0.unwrap e with + Ast0.Edots(d,whencode) -> + (*don't recurse because whencode hasn't been processed by context_neg*) + update_mc mcodekind e; Ast0.rewrap e (Ast0.Edots(mcode d,whencode)) + | Ast0.Ecircles(d,whencode) -> + (*don't recurse because whencode hasn't been processed by context_neg*) + update_mc mcodekind e; Ast0.rewrap e (Ast0.Ecircles(mcode d,whencode)) + | Ast0.Estars(d,whencode) -> + (*don't recurse because whencode hasn't been processed by context_neg*) + update_mc mcodekind e; Ast0.rewrap e (Ast0.Estars(mcode d,whencode)) + | Ast0.NestExpr(starter,expr_dots,ender,whencode,multi) -> + update_mc mcodekind e; + Ast0.rewrap e + (Ast0.NestExpr(mcode starter, + r.V0.rebuilder_expression_dots expr_dots, + mcode ender,whencode,multi)) + | _ -> donothing r k e in + + let declaration r k e = + let mcodekind = Ast0.get_mcodekind_ref e in + match Ast0.unwrap e with + Ast0.Ddots(d,whencode) -> + (*don't recurse because whencode hasn't been processed by context_neg*) + update_mc mcodekind e; Ast0.rewrap e (Ast0.Ddots(mcode d,whencode)) + | _ -> donothing r k e in + + let statement r k e = + let mcodekind = Ast0.get_mcodekind_ref e in + match Ast0.unwrap e with + Ast0.Dots(d,whencode) -> + (*don't recurse because whencode hasn't been processed by context_neg*) + update_mc mcodekind e; Ast0.rewrap e (Ast0.Dots(mcode d,whencode)) + | Ast0.Circles(d,whencode) -> + update_mc mcodekind e; Ast0.rewrap e (Ast0.Circles(mcode d,whencode)) + | Ast0.Stars(d,whencode) -> + update_mc mcodekind e; Ast0.rewrap e (Ast0.Stars(mcode d,whencode)) + | Ast0.Nest(starter,stmt_dots,ender,whencode,multi) -> + update_mc mcodekind e; + Ast0.rewrap e + (Ast0.Nest(mcode starter,r.V0.rebuilder_statement_dots stmt_dots, + mcode ender,whencode,multi)) + | _ -> donothing r k e in + + let initialiser r k e = + let mcodekind = Ast0.get_mcodekind_ref e in + match Ast0.unwrap e with + Ast0.Idots(d,whencode) -> + (*don't recurse because whencode hasn't been processed by context_neg*) + update_mc mcodekind e; Ast0.rewrap e (Ast0.Idots(mcode d,whencode)) + | _ -> donothing r k e in + + let dots r k e = + let info = Ast0.get_info e in + let mcodekind = Ast0.get_mcodekind_ref e in + match Ast0.unwrap e with + Ast0.DOTS([]) -> + (* if context is - this should be - as well. There are no tokens + here though, so the bottom-up minusifier in context_neg leaves it + as mixed. It would be better to fix context_neg, but that would + require a special case for each term with a dots subterm. *) + (match !mcodekind with + Ast0.MIXED(mc) -> + (match !mc with + (Ast.NOTHING,_,_) -> + mcodekind := Ast0.MINUS(ref([],Ast0.default_token_info)); + e + | _ -> failwith "make_minus: unexpected befaft") + (* code already processed by an enclosing iso *) + | Ast0.MINUS(mc) -> e + | _ -> + failwith + (Printf.sprintf + "%d: make_minus donothingxxx: unexpected mcodekind" + info.Ast0.line_start)) + | _ -> donothing r k e in + + V0.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + dots dots dots dots dots dots + donothing expression donothing initialiser donothing declaration + statement donothing donothing + +(* --------------------------------------------------------------------- *) +(* rebuild mcode cells in an instantiated alt *) + +(* mcodes will be side effected later with plus code, so we have to copy + them on instantiating an isomorphism. One could wonder whether it would + be better not to use side-effects, but they are convenient for insert_plus + where is it useful to manipulate a list of the mcodes but side-effect a + tree *) +(* hmm... Insert_plus is called before Iso_pattern... *) +let rebuild_mcode start_line = + let copy_mcodekind = function + Ast0.CONTEXT(mc) -> Ast0.CONTEXT(ref (!mc)) + | Ast0.MINUS(mc) -> Ast0.MINUS(ref (!mc)) + | Ast0.MIXED(mc) -> Ast0.MIXED(ref (!mc)) + | Ast0.PLUS -> + (* this function is used elsewhere where we need to rebuild the + indices, and so we allow PLUS code as well *) + Ast0.PLUS in + + let mcode (term,arity,info,mcodekind,pos) = + let info = + match start_line with + Some x -> {info with Ast0.line_start = x; Ast0.line_end = x} + | None -> info in + (term,arity,info,copy_mcodekind mcodekind,pos) in + + let copy_one x = + let old_info = Ast0.get_info x in + let info = + match start_line with + Some x -> {old_info with Ast0.line_start = x; Ast0.line_end = x} + | None -> old_info in + {x with Ast0.info = info; Ast0.index = ref(Ast0.get_index x); + Ast0.mcodekind = ref (copy_mcodekind (Ast0.get_mcodekind x))} in + + let donothing r k e = copy_one (k e) in + + (* case for control operators (if, etc) *) + let statement r k e = + let s = k e in + let res = + copy_one + (Ast0.rewrap s + (match Ast0.unwrap s with + Ast0.Decl((info,mc),decl) -> + Ast0.Decl((info,copy_mcodekind mc),decl) + | Ast0.IfThen(iff,lp,tst,rp,branch,(info,mc)) -> + Ast0.IfThen(iff,lp,tst,rp,branch,(info,copy_mcodekind mc)) + | Ast0.IfThenElse(iff,lp,tst,rp,branch1,els,branch2,(info,mc)) -> + Ast0.IfThenElse(iff,lp,tst,rp,branch1,els,branch2, + (info,copy_mcodekind mc)) + | Ast0.While(whl,lp,exp,rp,body,(info,mc)) -> + Ast0.While(whl,lp,exp,rp,body,(info,copy_mcodekind mc)) + | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,(info,mc)) -> + Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body, + (info,copy_mcodekind mc)) + | Ast0.Iterator(nm,lp,args,rp,body,(info,mc)) -> + Ast0.Iterator(nm,lp,args,rp,body,(info,copy_mcodekind mc)) + | Ast0.FunDecl + ((info,mc),fninfo,name,lp,params,rp,lbrace,body,rbrace) -> + Ast0.FunDecl + ((info,copy_mcodekind mc), + fninfo,name,lp,params,rp,lbrace,body,rbrace) + | s -> s)) in + Ast0.set_dots_bef_aft res + (match Ast0.get_dots_bef_aft res with + Ast0.NoDots -> Ast0.NoDots + | Ast0.AddingBetweenDots s -> + Ast0.AddingBetweenDots(r.V0.rebuilder_statement s) + | Ast0.DroppingBetweenDots s -> + Ast0.DroppingBetweenDots(r.V0.rebuilder_statement s)) in + + V0.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing + donothing statement donothing donothing + +(* --------------------------------------------------------------------- *) +(* The problem of whencode. If an isomorphism contains dots in multiple + rules, then the code that is matched cannot contain whencode, because we + won't know which dots it goes with. Should worry about nests, but they + aren't allowed in isomorphisms for the moment. *) + +let count_edots = + let mcode x = 0 in + let option_default = 0 in + let bind x y = x + y in + let donothing r k e = k e in + let exprfn r k e = + match Ast0.unwrap e with + Ast0.Edots(_,_) | Ast0.Ecircles(_,_) | Ast0.Estars(_,_) -> 1 + | _ -> 0 in + + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing exprfn donothing donothing donothing donothing donothing + donothing donothing + +let count_idots = + let mcode x = 0 in + let option_default = 0 in + let bind x y = x + y in + let donothing r k e = k e in + let initfn r k e = + match Ast0.unwrap e with Ast0.Idots(_,_) -> 1 | _ -> 0 in + + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing donothing donothing initfn donothing donothing donothing + donothing donothing + +let count_dots = + let mcode x = 0 in + let option_default = 0 in + let bind x y = x + y in + let donothing r k e = k e in + let stmtfn r k e = + match Ast0.unwrap e with + Ast0.Dots(_,_) | Ast0.Circles(_,_) | Ast0.Stars(_,_) -> 1 + | _ -> 0 in + + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing stmtfn + donothing donothing + +(* --------------------------------------------------------------------- *) + +let lookup name bindings mv_bindings = + try Common.Left (List.assoc (term name) bindings) + with + Not_found -> + (* failure is not possible anymore *) + Common.Right (List.assoc (term name) mv_bindings) + +(* mv_bindings is for the fresh metavariables that are introduced by the +isomorphism *) +let instantiate bindings mv_bindings = + let mcode x = + match Ast0.get_pos x with + Ast0.MetaPos(name,_,_) -> + (try + match lookup name bindings mv_bindings with + Common.Left(Ast0.MetaPosTag(id)) -> Ast0.set_pos id x + | _ -> failwith "not possible" + with Not_found -> Ast0.set_pos Ast0.NoMetaPos x) + | _ -> x in + let donothing r k e = k e in + + (* cases where metavariables can occur *) + let identfn r k e = + let e = k e in + match Ast0.unwrap e with + Ast0.MetaId(name,constraints,pure) -> + (rebuild_mcode None).V0.rebuilder_ident + (match lookup name bindings mv_bindings with + Common.Left(Ast0.IdentTag(id)) -> id + | Common.Left(_) -> failwith "not possible 1" + | Common.Right(new_mv) -> + Ast0.rewrap e + (Ast0.MetaId + (Ast0.set_mcode_data new_mv name,constraints,pure))) + | Ast0.MetaFunc(name,_,pure) -> failwith "metafunc not supported" + | Ast0.MetaLocalFunc(name,_,pure) -> failwith "metalocalfunc not supported" + | _ -> e in + + (* case for list metavariables *) + let rec elist r same_dots = function + [] -> [] + | [x] -> + (match Ast0.unwrap x with + Ast0.MetaExprList(name,lenname,pure) -> + failwith "meta_expr_list in iso not supported" + (*match lookup name bindings mv_bindings with + Common.Left(Ast0.DotsExprTag(exp)) -> + (match same_dots exp with + Some l -> l + | None -> failwith "dots put in incompatible context") + | Common.Left(Ast0.ExprTag(exp)) -> [exp] + | Common.Left(_) -> failwith "not possible 1" + | Common.Right(new_mv) -> + failwith "MetaExprList in SP not supported"*) + | _ -> [r.V0.rebuilder_expression x]) + | x::xs -> (r.V0.rebuilder_expression x)::(elist r same_dots xs) in + + let rec plist r same_dots = function + [] -> [] + | [x] -> + (match Ast0.unwrap x with + Ast0.MetaParamList(name,lenname,pure) -> + failwith "meta_param_list in iso not supported" + (*match lookup name bindings mv_bindings with + Common.Left(Ast0.DotsParamTag(param)) -> + (match same_dots param with + Some l -> l + | None -> failwith "dots put in incompatible context") + | Common.Left(Ast0.ParamTag(param)) -> [param] + | Common.Left(_) -> failwith "not possible 1" + | Common.Right(new_mv) -> + failwith "MetaExprList in SP not supported"*) + | _ -> [r.V0.rebuilder_parameter x]) + | x::xs -> (r.V0.rebuilder_parameter x)::(plist r same_dots xs) in + + let rec slist r same_dots = function + [] -> [] + | [x] -> + (match Ast0.unwrap x with + Ast0.MetaStmtList(name,pure) -> + (match lookup name bindings mv_bindings with + Common.Left(Ast0.DotsStmtTag(stm)) -> + (match same_dots stm with + Some l -> l + | None -> failwith "dots put in incompatible context") + | Common.Left(Ast0.StmtTag(stm)) -> [stm] + | Common.Left(_) -> failwith "not possible 1" + | Common.Right(new_mv) -> + failwith "MetaExprList in SP not supported") + | _ -> [r.V0.rebuilder_statement x]) + | x::xs -> (r.V0.rebuilder_statement x)::(slist r same_dots xs) in + + let same_dots d = + match Ast0.unwrap d with Ast0.DOTS(l) -> Some l |_ -> None in + let same_circles d = + match Ast0.unwrap d with Ast0.CIRCLES(l) -> Some l |_ -> None in + let same_stars d = + match Ast0.unwrap d with Ast0.STARS(l) -> Some l |_ -> None in + + let dots list_fn r k d = + Ast0.rewrap d + (match Ast0.unwrap d with + Ast0.DOTS(l) -> Ast0.DOTS(list_fn r same_dots l) + | Ast0.CIRCLES(l) -> Ast0.CIRCLES(list_fn r same_circles l) + | Ast0.STARS(l) -> Ast0.STARS(list_fn r same_stars l)) in + + let exprfn r k old_e = (* need to keep the original code for ! optim *) + let e = k old_e in + let e1 = + match Ast0.unwrap e with + Ast0.MetaExpr(name,constraints,x,form,pure) -> + (rebuild_mcode None).V0.rebuilder_expression + (match lookup name bindings mv_bindings with + Common.Left(Ast0.ExprTag(exp)) -> exp + | Common.Left(_) -> failwith "not possible 1" + | Common.Right(new_mv) -> + let new_types = + match x with + None -> None + | Some types -> + let rec renamer = function + Type_cocci.MetaType(name,keep,inherited) -> + (match + lookup (name,(),(),(),None) bindings mv_bindings + with + Common.Left(Ast0.TypeCTag(t)) -> + Ast0.ast0_type_to_type t + | Common.Left(_) -> + failwith "iso pattern: unexpected type" + | Common.Right(new_mv) -> + Type_cocci.MetaType(new_mv,keep,inherited)) + | Type_cocci.ConstVol(cv,ty) -> + Type_cocci.ConstVol(cv,renamer ty) + | Type_cocci.Pointer(ty) -> + Type_cocci.Pointer(renamer ty) + | Type_cocci.FunctionPointer(ty) -> + Type_cocci.FunctionPointer(renamer ty) + | Type_cocci.Array(ty) -> + Type_cocci.Array(renamer ty) + | t -> t in + Some(List.map renamer types) in + Ast0.rewrap e + (Ast0.MetaExpr + (Ast0.set_mcode_data new_mv name,constraints, + new_types,form,pure))) + | Ast0.MetaErr(namea,_,pure) -> failwith "metaerr not supported" + | Ast0.MetaExprList(namea,lenname,pure) -> + failwith "metaexprlist not supported" + | Ast0.Unary(exp,unop) -> + (match Ast0.unwrap_mcode unop with + Ast.Not -> + let was_meta = + (* k e doesn't change the outer structure of the term, + only the metavars *) + match Ast0.unwrap old_e with + Ast0.Unary(exp,_) -> + (match Ast0.unwrap exp with + Ast0.MetaExpr(name,constraints,x,form,pure) -> true + | _ -> false) + | _ -> failwith "not possible" in + let nomodif e = + let mc = Ast0.get_mcodekind exp in + match mc with + Ast0.MINUS(x) -> + (match !x with + ([],_) -> true + | _ -> false) + | Ast0.CONTEXT(x) | Ast0.MIXED(x) -> + (match !x with + (Ast.NOTHING,_,_) -> true + | _ -> false) + | _ -> failwith "plus not possible" in + if was_meta && nomodif exp && nomodif e + then + let rec negate e (*for rewrapping*) res (*code to process*) = + match Ast0.unwrap res with + Ast0.Unary(e1,op) when Ast0.unwrap_mcode op = Ast.Not -> + Ast0.rewrap e (Ast0.unwrap e1) + | Ast0.Edots(_,_) -> Ast0.rewrap e (Ast0.unwrap res) + | Ast0.Paren(lp,e,rp) -> + Ast0.rewrap res (Ast0.Paren(lp,negate e e,rp)) + | Ast0.Binary(e1,op,e2) -> + let reb nop = Ast0.rewrap_mcode op (Ast.Logical(nop)) in + let invop = + match Ast0.unwrap_mcode op with + Ast.Logical(Ast.Inf) -> + Ast0.Binary(e1,reb Ast.SupEq,e2) + | Ast.Logical(Ast.Sup) -> + Ast0.Binary(e1,reb Ast.InfEq,e2) + | Ast.Logical(Ast.InfEq) -> + Ast0.Binary(e1,reb Ast.Sup,e2) + | Ast.Logical(Ast.SupEq) -> + Ast0.Binary(e1,reb Ast.Inf,e2) + | Ast.Logical(Ast.Eq) -> + Ast0.Binary(e1,reb Ast.NotEq,e2) + | Ast.Logical(Ast.NotEq) -> + Ast0.Binary(e1,reb Ast.Eq,e2) + | Ast.Logical(Ast.AndLog) -> + Ast0.Binary(negate e1 e1,reb Ast.OrLog, + negate e2 e2) + | Ast.Logical(Ast.OrLog) -> + Ast0.Binary(negate e1 e1,reb Ast.AndLog, + negate e2 e2) + | _ -> Ast0.Unary(res,Ast0.rewrap_mcode op Ast.Not) in + Ast0.rewrap e invop + | Ast0.DisjExpr(lp,exps,mids,rp) -> + (* use res because it is the transformed argument *) + let exps = List.map (function e -> negate e e) exps in + Ast0.rewrap res (Ast0.DisjExpr(lp,exps,mids,rp)) + | _ -> + (*use e, because this might be the toplevel expression*) + Ast0.rewrap e + (Ast0.Unary(res,Ast0.rewrap_mcode unop Ast.Not)) in + negate e exp + else e + | _ -> e) + | Ast0.Edots(d,_) -> + (try + (match List.assoc (dot_term d) bindings with + Ast0.ExprTag(exp) -> Ast0.rewrap e (Ast0.Edots(d,Some exp)) + | _ -> failwith "unexpected binding") + with Not_found -> e) + | Ast0.Ecircles(d,_) -> + (try + (match List.assoc (dot_term d) bindings with + Ast0.ExprTag(exp) -> Ast0.rewrap e (Ast0.Ecircles(d,Some exp)) + | _ -> failwith "unexpected binding") + with Not_found -> e) + | Ast0.Estars(d,_) -> + (try + (match List.assoc (dot_term d) bindings with + Ast0.ExprTag(exp) -> Ast0.rewrap e (Ast0.Estars(d,Some exp)) + | _ -> failwith "unexpected binding") + with Not_found -> e) + | _ -> e in + if Ast0.get_test_exp old_e then Ast0.set_test_exp e1 else e1 in + + let tyfn r k e = + let e = k e in + match Ast0.unwrap e with + Ast0.MetaType(name,pure) -> + (rebuild_mcode None).V0.rebuilder_typeC + (match lookup name bindings mv_bindings with + Common.Left(Ast0.TypeCTag(ty)) -> ty + | Common.Left(_) -> failwith "not possible 1" + | Common.Right(new_mv) -> + Ast0.rewrap e + (Ast0.MetaType(Ast0.set_mcode_data new_mv name,pure))) + | _ -> e in + + let declfn r k e = + let e = k e in + match Ast0.unwrap e with + Ast0.Ddots(d,_) -> + (try + (match List.assoc (dot_term d) bindings with + Ast0.DeclTag(exp) -> Ast0.rewrap e (Ast0.Ddots(d,Some exp)) + | _ -> failwith "unexpected binding") + with Not_found -> e) + | _ -> e in + + let paramfn r k e = + let e = k e in + match Ast0.unwrap e with + Ast0.MetaParam(name,pure) -> + (rebuild_mcode None).V0.rebuilder_parameter + (match lookup name bindings mv_bindings with + Common.Left(Ast0.ParamTag(param)) -> param + | Common.Left(_) -> failwith "not possible 1" + | Common.Right(new_mv) -> + Ast0.rewrap e + (Ast0.MetaParam(Ast0.set_mcode_data new_mv name, pure))) + | Ast0.MetaParamList(name,lenname,pure) -> + failwith "metaparamlist not supported" + | _ -> e in + + let stmtfn r k e = + let e = k e in + match Ast0.unwrap e with + Ast0.MetaStmt(name,pure) -> + (rebuild_mcode None).V0.rebuilder_statement + (match lookup name bindings mv_bindings with + Common.Left(Ast0.StmtTag(stm)) -> stm + | Common.Left(_) -> failwith "not possible 1" + | Common.Right(new_mv) -> + Ast0.rewrap e + (Ast0.MetaStmt(Ast0.set_mcode_data new_mv name,pure))) + | Ast0.MetaStmtList(name,pure) -> failwith "metastmtlist not supported" + | Ast0.Dots(d,_) -> + Ast0.rewrap e + (Ast0.Dots + (d, + List.map + (function (_,v) -> + match v with + Ast0.DotsStmtTag(stms) -> Ast0.WhenNot stms + | Ast0.StmtTag(stm) -> Ast0.WhenAlways stm + | Ast0.IsoWhenTag(x) -> Ast0.WhenModifier(x) + | _ -> failwith "unexpected binding") + (List.filter (function (x,v) -> x = (dot_term d)) bindings))) + | Ast0.Circles(d,_) -> + Ast0.rewrap e + (Ast0.Circles + (d, + List.map + (function (_,v) -> + match v with + Ast0.DotsStmtTag(stms) -> Ast0.WhenNot stms + | Ast0.StmtTag(stm) -> Ast0.WhenAlways stm + | Ast0.IsoWhenTag(x) -> Ast0.WhenModifier(x) + | _ -> failwith "unexpected binding") + (List.filter (function (x,v) -> x = (dot_term d)) bindings))) + | Ast0.Stars(d,_) -> + Ast0.rewrap e + (Ast0.Stars + (d, + List.map + (function (_,v) -> + match v with + Ast0.DotsStmtTag(stms) -> Ast0.WhenNot stms + | Ast0.StmtTag(stm) -> Ast0.WhenAlways stm + | Ast0.IsoWhenTag(x) -> Ast0.WhenModifier(x) + | _ -> failwith "unexpected binding") + (List.filter (function (x,v) -> x = (dot_term d)) bindings))) + | _ -> e in + + V0.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + (dots elist) donothing (dots plist) (dots slist) donothing donothing + identfn exprfn tyfn donothing paramfn declfn stmtfn donothing donothing + +(* --------------------------------------------------------------------- *) + +let is_minus e = + match Ast0.get_mcodekind e with Ast0.MINUS(cell) -> true | _ -> false + +let context_required e = not(is_minus e) && not !Flag.sgrep_mode2 + +let disj_fail bindings e = + match bindings with + Some x -> Printf.fprintf stderr "no disj available at this type"; e + | None -> e + +(* isomorphism code is by default CONTEXT *) +let merge_plus model_mcode e_mcode = + match model_mcode with + Ast0.MINUS(mc) -> + (* add the replacement information at the root *) + (match e_mcode with + Ast0.MINUS(emc) -> + emc := + (match (!mc,!emc) with + (([],_),(x,t)) | ((x,_),([],t)) -> (x,t) + | _ -> failwith "how can we combine minuses?") + | _ -> failwith "not possible 6") + | Ast0.CONTEXT(mc) -> + (match e_mcode with + Ast0.CONTEXT(emc) -> + (* keep the logical line info as in the model *) + let (mba,tb,ta) = !mc in + let (eba,_,_) = !emc in + (* merging may be required when a term is replaced by a subterm *) + let merged = + match (mba,eba) with + (x,Ast.NOTHING) | (Ast.NOTHING,x) -> x + | (Ast.BEFORE(b1),Ast.BEFORE(b2)) -> Ast.BEFORE(b1@b2) + | (Ast.BEFORE(b),Ast.AFTER(a)) -> Ast.BEFOREAFTER(b,a) + | (Ast.BEFORE(b1),Ast.BEFOREAFTER(b2,a)) -> + Ast.BEFOREAFTER(b1@b2,a) + | (Ast.AFTER(a),Ast.BEFORE(b)) -> Ast.BEFOREAFTER(b,a) + | (Ast.AFTER(a1),Ast.AFTER(a2)) ->Ast.AFTER(a2@a1) + | (Ast.AFTER(a1),Ast.BEFOREAFTER(b,a2)) -> Ast.BEFOREAFTER(b,a2@a1) + | (Ast.BEFOREAFTER(b1,a),Ast.BEFORE(b2)) -> + Ast.BEFOREAFTER(b1@b2,a) + | (Ast.BEFOREAFTER(b,a1),Ast.AFTER(a2)) -> + Ast.BEFOREAFTER(b,a2@a1) + | (Ast.BEFOREAFTER(b1,a1),Ast.BEFOREAFTER(b2,a2)) -> + Ast.BEFOREAFTER(b1@b2,a2@a1) in + emc := (merged,tb,ta) + | Ast0.MINUS(emc) -> + let (anything_bef_aft,_,_) = !mc in + let (anythings,t) = !emc in + emc := + (match anything_bef_aft with + Ast.BEFORE(b) -> (b@anythings,t) + | Ast.AFTER(a) -> (anythings@a,t) + | Ast.BEFOREAFTER(b,a) -> (b@anythings@a,t) + | Ast.NOTHING -> (anythings,t)) + | _ -> failwith "not possible 7") + | Ast0.MIXED(_) -> failwith "not possible 8" + | Ast0.PLUS -> failwith "not possible 9" + +let copy_plus printer minusify model e = + if !Flag.sgrep_mode2 + then e (* no plus code, can cause a "not possible" error, so just avoid it *) + else + let e = + match Ast0.get_mcodekind model with + Ast0.MINUS(mc) -> minusify e + | Ast0.CONTEXT(mc) -> e + | _ -> failwith "not possible: copy_plus\n" in + merge_plus (Ast0.get_mcodekind model) (Ast0.get_mcodekind e); + e + +let copy_minus printer minusify model e = + match Ast0.get_mcodekind model with + Ast0.MINUS(mc) -> minusify e + | Ast0.CONTEXT(mc) -> e + | Ast0.MIXED(_) -> + if !Flag.sgrep_mode2 + then e + else failwith "not possible 8" + | Ast0.PLUS -> failwith "not possible 9" + +let whencode_allowed prev_ecount prev_icount prev_dcount + ecount icount dcount rest = + (* actually, if ecount or dcount is 0, the flag doesn't matter, because it + won't be tested *) + let other_ecount = (* number of edots *) + List.fold_left (function rest -> function (_,ec,ic,dc) -> ec + rest) + prev_ecount rest in + let other_icount = (* number of dots *) + List.fold_left (function rest -> function (_,ec,ic,dc) -> ic + rest) + prev_icount rest in + let other_dcount = (* number of dots *) + List.fold_left (function rest -> function (_,ec,ic,dc) -> dc + rest) + prev_dcount rest in + (ecount = 0 or other_ecount = 0, icount = 0 or other_icount = 0, + dcount = 0 or other_dcount = 0) + +(* copy the befores and afters to the instantiated code *) +let extra_copy_stmt_plus model e = + (if not !Flag.sgrep_mode2 (* sgrep has no plus code, so nothing to do *) + then + (match Ast0.unwrap model with + Ast0.FunDecl((info,bef),_,_,_,_,_,_,_,_) + | Ast0.Decl((info,bef),_) -> + (match Ast0.unwrap e with + Ast0.FunDecl((info,bef1),_,_,_,_,_,_,_,_) + | Ast0.Decl((info,bef1),_) -> + merge_plus bef bef1 + | _ -> merge_plus bef (Ast0.get_mcodekind e)) + | Ast0.IfThen(_,_,_,_,_,(info,aft)) + | Ast0.IfThenElse(_,_,_,_,_,_,_,(info,aft)) + | Ast0.While(_,_,_,_,_,(info,aft)) + | Ast0.For(_,_,_,_,_,_,_,_,_,(info,aft)) + | Ast0.Iterator(_,_,_,_,_,(info,aft)) -> + (match Ast0.unwrap e with + Ast0.IfThen(_,_,_,_,_,(info,aft1)) + | Ast0.IfThenElse(_,_,_,_,_,_,_,(info,aft1)) + | Ast0.While(_,_,_,_,_,(info,aft1)) + | Ast0.For(_,_,_,_,_,_,_,_,_,(info,aft1)) + | Ast0.Iterator(_,_,_,_,_,(info,aft1)) -> + merge_plus aft aft1 + | _ -> merge_plus aft (Ast0.get_mcodekind e)) + | _ -> ())); + e + +let extra_copy_other_plus model e = e + +(* --------------------------------------------------------------------- *) + +let mv_count = ref 0 +let new_mv (_,s) = + let ct = !mv_count in + mv_count := !mv_count + 1; + "_"^s^"_"^(string_of_int ct) + +let get_name = function + Ast.MetaIdDecl(ar,nm) -> + (nm,function nm -> Ast.MetaIdDecl(ar,nm)) + | Ast.MetaFreshIdDecl(ar,nm) -> + (nm,function nm -> Ast.MetaFreshIdDecl(ar,nm)) + | Ast.MetaTypeDecl(ar,nm) -> + (nm,function nm -> Ast.MetaTypeDecl(ar,nm)) + | Ast.MetaListlenDecl(nm) -> + failwith "should not be rebuilt" + | Ast.MetaParamDecl(ar,nm) -> + (nm,function nm -> Ast.MetaParamDecl(ar,nm)) + | Ast.MetaParamListDecl(ar,nm,nm1) -> + (nm,function nm -> Ast.MetaParamListDecl(ar,nm,nm1)) + | Ast.MetaConstDecl(ar,nm,ty) -> + (nm,function nm -> Ast.MetaConstDecl(ar,nm,ty)) + | Ast.MetaErrDecl(ar,nm) -> + (nm,function nm -> Ast.MetaErrDecl(ar,nm)) + | Ast.MetaExpDecl(ar,nm,ty) -> + (nm,function nm -> Ast.MetaExpDecl(ar,nm,ty)) + | Ast.MetaIdExpDecl(ar,nm,ty) -> + (nm,function nm -> Ast.MetaIdExpDecl(ar,nm,ty)) + | Ast.MetaLocalIdExpDecl(ar,nm,ty) -> + (nm,function nm -> Ast.MetaLocalIdExpDecl(ar,nm,ty)) + | Ast.MetaExpListDecl(ar,nm,nm1) -> + (nm,function nm -> Ast.MetaExpListDecl(ar,nm,nm1)) + | Ast.MetaStmDecl(ar,nm) -> + (nm,function nm -> Ast.MetaStmDecl(ar,nm)) + | Ast.MetaStmListDecl(ar,nm) -> + (nm,function nm -> Ast.MetaStmListDecl(ar,nm)) + | Ast.MetaFuncDecl(ar,nm) -> + (nm,function nm -> Ast.MetaFuncDecl(ar,nm)) + | Ast.MetaLocalFuncDecl(ar,nm) -> + (nm,function nm -> Ast.MetaLocalFuncDecl(ar,nm)) + | Ast.MetaPosDecl(ar,nm) -> + (nm,function nm -> Ast.MetaPosDecl(ar,nm)) + | Ast.MetaDeclarerDecl(ar,nm) -> + (nm,function nm -> Ast.MetaDeclarerDecl(ar,nm)) + | Ast.MetaIteratorDecl(ar,nm) -> + (nm,function nm -> Ast.MetaIteratorDecl(ar,nm)) + +let make_new_metavars metavars bindings = + let new_metavars = + List.filter + (function mv -> + let (s,_) = get_name mv in + try let _ = List.assoc s bindings in false with Not_found -> true) + metavars in + List.split + (List.map + (function mv -> + let (s,rebuild) = get_name mv in + let new_s = (!current_rule,new_mv s) in + (rebuild new_s, (s,new_s))) + new_metavars) + +(* --------------------------------------------------------------------- *) + +let do_nothing x = x + +let mkdisj matcher metavars alts e instantiater mkiso disj_maker minusify + rebuild_mcodes name printer extra_plus update_others = + let call_instantiate bindings mv_bindings alts = + List.concat + (List.map + (function (a,_,_,_) -> + nub + (* no need to create duplicates when the bindings have no effect *) + (List.map + (function bindings -> + Ast0.set_iso + (copy_plus printer minusify e + (extra_plus e + (instantiater bindings mv_bindings + (rebuild_mcodes a)))) + (Common.union_set [(name,mkiso a)] (Ast0.get_iso e))) + bindings)) + alts) in + let rec inner_loop all_alts prev_ecount prev_icount prev_dcount = function + [] -> Common.Left (prev_ecount, prev_icount, prev_dcount) + | ((pattern,ecount,icount,dcount)::rest) -> + let wc = + whencode_allowed prev_ecount prev_icount prev_dcount + ecount dcount icount rest in + (match matcher true (context_required e) wc pattern e init_env with + Fail(reason) -> + if reason = NonMatch || not !Flag_parsing_cocci.show_iso_failures + then () + else + (match matcher false false wc pattern e init_env with + OK _ -> + interpret_reason name (Ast0.get_line e) reason + (function () -> printer e) + | _ -> ()); + inner_loop all_alts (prev_ecount + ecount) (prev_icount + icount) + (prev_dcount + dcount) rest + | OK (bindings : (((string * string) * 'a) list list)) -> + let all_alts = + (* apply update_others to all patterns other than the matched + one. This is used to desigate the others as test + expressions in the TestExpression case *) + (List.map + (function (x,e,i,d) as all -> + if x = pattern + then all + else (update_others x,e,i,d)) + (List.hd all_alts)) :: + (List.map + (List.map (function (x,e,i,d) -> (update_others x,e,i,d))) + (List.tl all_alts)) in + (match List.concat all_alts with + [x] -> Common.Left (prev_ecount, prev_icount, prev_dcount) + | all_alts -> + let (new_metavars,mv_bindings) = + make_new_metavars metavars (nub(List.concat bindings)) in + Common.Right + (new_metavars, + call_instantiate bindings mv_bindings all_alts))) in + let rec outer_loop prev_ecount prev_icount prev_dcount = function + [] | [[_]] (*only one alternative*) -> ([],e) (* nothing matched *) + | (alts::rest) as all_alts -> + match inner_loop all_alts prev_ecount prev_icount prev_dcount alts with + Common.Left(prev_ecount, prev_icount, prev_dcount) -> + outer_loop prev_ecount prev_icount prev_dcount rest + | Common.Right (new_metavars,res) -> + (new_metavars, + copy_minus printer minusify e (disj_maker res)) in + outer_loop 0 0 0 alts + +(* no one should ever look at the information stored in these mcodes *) +let disj_starter lst = + let old_info = Ast0.get_info(List.hd lst) in + let info = + { old_info with + Ast0.line_end = old_info.Ast0.line_start; + Ast0.logical_end = old_info.Ast0.logical_start; + Ast0.attachable_start = false; Ast0.attachable_end = false; + Ast0.mcode_start = []; Ast0.mcode_end = []; + Ast0.strings_before = []; Ast0.strings_after = [] } in + Ast0.make_mcode_info "(" info + +let disj_ender lst = + let old_info = Ast0.get_info(List.hd lst) in + let info = + { old_info with + Ast0.line_start = old_info.Ast0.line_end; + Ast0.logical_start = old_info.Ast0.logical_end; + Ast0.attachable_start = false; Ast0.attachable_end = false; + Ast0.mcode_start = []; Ast0.mcode_end = []; + Ast0.strings_before = []; Ast0.strings_after = [] } in + Ast0.make_mcode_info ")" info + +let disj_mid _ = Ast0.make_mcode "|" + +let make_disj_type tl = + let mids = + match tl with + [] -> failwith "bad disjunction" + | x::xs -> List.map disj_mid xs in + Ast0.context_wrap (Ast0.DisjType(disj_starter tl,tl,mids,disj_ender tl)) +let make_disj_stmt_list tl = + let mids = + match tl with + [] -> failwith "bad disjunction" + | x::xs -> List.map disj_mid xs in + Ast0.context_wrap (Ast0.Disj(disj_starter tl,tl,mids,disj_ender tl)) +let make_disj_expr model el = + let mids = + match el with + [] -> failwith "bad disjunction" + | x::xs -> List.map disj_mid xs in + let update_arg x = + if Ast0.get_arg_exp model then Ast0.set_arg_exp x else x in + let update_test x = + let x = if Ast0.get_test_pos model then Ast0.set_test_pos x else x in + if Ast0.get_test_exp model then Ast0.set_test_exp x else x in + let el = List.map update_arg (List.map update_test el) in + Ast0.context_wrap (Ast0.DisjExpr(disj_starter el,el,mids,disj_ender el)) +let make_disj_decl dl = + let mids = + match dl with + [] -> failwith "bad disjunction" + | x::xs -> List.map disj_mid xs in + Ast0.context_wrap (Ast0.DisjDecl(disj_starter dl,dl,mids,disj_ender dl)) +let make_disj_stmt sl = + let dotify x = Ast0.context_wrap (Ast0.DOTS[x]) in + let mids = + match sl with + [] -> failwith "bad disjunction" + | x::xs -> List.map disj_mid xs in + Ast0.context_wrap + (Ast0.Disj(disj_starter sl,List.map dotify sl,mids,disj_ender sl)) + +let transform_type (metavars,alts,name) e = + match alts with + (Ast0.TypeCTag(_)::_)::_ -> + (* start line is given to any leaves in the iso code *) + let start_line = Some ((Ast0.get_info e).Ast0.line_start) in + let alts = + List.map + (List.map + (function + Ast0.TypeCTag(p) -> + (p,count_edots.V0.combiner_typeC p, + count_idots.V0.combiner_typeC p, + count_dots.V0.combiner_typeC p) + | _ -> failwith "invalid alt")) + alts in + mkdisj match_typeC metavars alts e + (function b -> function mv_b -> + (instantiate b mv_b).V0.rebuilder_typeC) + (function t -> Ast0.TypeCTag t) + make_disj_type make_minus.V0.rebuilder_typeC + (rebuild_mcode start_line).V0.rebuilder_typeC + name Unparse_ast0.typeC extra_copy_other_plus do_nothing + | _ -> ([],e) + + +let transform_expr (metavars,alts,name) e = + let process update_others = + (* start line is given to any leaves in the iso code *) + let start_line = Some ((Ast0.get_info e).Ast0.line_start) in + let alts = + List.map + (List.map + (function + Ast0.ExprTag(p) | Ast0.ArgExprTag(p) | Ast0.TestExprTag(p) -> + (p,count_edots.V0.combiner_expression p, + count_idots.V0.combiner_expression p, + count_dots.V0.combiner_expression p) + | _ -> failwith "invalid alt")) + alts in + mkdisj match_expr metavars alts e + (function b -> function mv_b -> + (instantiate b mv_b).V0.rebuilder_expression) + (function e -> Ast0.ExprTag e) + (make_disj_expr e) make_minus.V0.rebuilder_expression + (rebuild_mcode start_line).V0.rebuilder_expression + name Unparse_ast0.expression extra_copy_other_plus update_others in + match alts with + (Ast0.ExprTag(_)::_)::_ -> process do_nothing + | (Ast0.ArgExprTag(_)::_)::_ when Ast0.get_arg_exp e -> process do_nothing + | (Ast0.TestExprTag(_)::_)::_ when Ast0.get_test_pos e -> + process Ast0.set_test_exp + | _ -> ([],e) + +let transform_decl (metavars,alts,name) e = + match alts with + (Ast0.DeclTag(_)::_)::_ -> + (* start line is given to any leaves in the iso code *) + let start_line = Some (Ast0.get_info e).Ast0.line_start in + let alts = + List.map + (List.map + (function + Ast0.DeclTag(p) -> + (p,count_edots.V0.combiner_declaration p, + count_idots.V0.combiner_declaration p, + count_dots.V0.combiner_declaration p) + | _ -> failwith "invalid alt")) + alts in + mkdisj match_decl metavars alts e + (function b -> function mv_b -> + (instantiate b mv_b).V0.rebuilder_declaration) + (function d -> Ast0.DeclTag d) + make_disj_decl + make_minus.V0.rebuilder_declaration + (rebuild_mcode start_line).V0.rebuilder_declaration + name Unparse_ast0.declaration extra_copy_other_plus do_nothing + | _ -> ([],e) + +let transform_stmt (metavars,alts,name) e = + match alts with + (Ast0.StmtTag(_)::_)::_ -> + (* start line is given to any leaves in the iso code *) + let start_line = Some (Ast0.get_info e).Ast0.line_start in + let alts = + List.map + (List.map + (function + Ast0.StmtTag(p) -> + (p,count_edots.V0.combiner_statement p, + count_idots.V0.combiner_statement p, + count_dots.V0.combiner_statement p) + | _ -> failwith "invalid alt")) + alts in + mkdisj match_statement metavars alts e + (function b -> function mv_b -> + (instantiate b mv_b).V0.rebuilder_statement) + (function s -> Ast0.StmtTag s) + make_disj_stmt make_minus.V0.rebuilder_statement + (rebuild_mcode start_line).V0.rebuilder_statement + name (Unparse_ast0.statement "") extra_copy_stmt_plus do_nothing + | _ -> ([],e) + +(* sort of a hack, because there is no disj at top level *) +let transform_top (metavars,alts,name) e = + match Ast0.unwrap e with + Ast0.DECL(declstm) -> + (try + let strip alts = + List.map + (List.map + (function + Ast0.DotsStmtTag(d) -> + (match Ast0.unwrap d with + Ast0.DOTS([s]) -> Ast0.StmtTag(s) + | _ -> raise (Failure "")) + | _ -> raise (Failure ""))) + alts in + let (mv,s) = transform_stmt (metavars,strip alts,name) declstm in + (mv,Ast0.rewrap e (Ast0.DECL(s))) + with Failure _ -> ([],e)) + | Ast0.CODE(stmts) -> + let (mv,res) = + match alts with + (Ast0.DotsStmtTag(_)::_)::_ -> + (* start line is given to any leaves in the iso code *) + let start_line = Some ((Ast0.get_info e).Ast0.line_start) in + let alts = + List.map + (List.map + (function + Ast0.DotsStmtTag(p) -> + (p,count_edots.V0.combiner_statement_dots p, + count_idots.V0.combiner_statement_dots p, + count_dots.V0.combiner_statement_dots p) + | _ -> failwith "invalid alt")) + alts in + mkdisj match_statement_dots metavars alts stmts + (function b -> function mv_b -> + (instantiate b mv_b).V0.rebuilder_statement_dots) + (function s -> Ast0.DotsStmtTag s) + (function x -> + Ast0.rewrap e (Ast0.DOTS([make_disj_stmt_list x]))) + make_minus.V0.rebuilder_statement_dots + (rebuild_mcode start_line).V0.rebuilder_statement_dots + name Unparse_ast0.statement_dots extra_copy_other_plus do_nothing + | _ -> ([],stmts) in + (mv,Ast0.rewrap e (Ast0.CODE res)) + | _ -> ([],e) + +(* --------------------------------------------------------------------- *) + +let transform (alts : isomorphism) t = + (* the following ugliness is because rebuilder only returns a new term *) + let extra_meta_decls = ref ([] : Ast_cocci.metavar list) in + let mcode x = x in + let donothing r k e = k e in + let exprfn r k e = + let (extra_meta,exp) = transform_expr alts (k e) in + extra_meta_decls := extra_meta @ !extra_meta_decls; + exp in + + let declfn r k e = + let (extra_meta,dec) = transform_decl alts (k e) in + extra_meta_decls := extra_meta @ !extra_meta_decls; + dec in + + let stmtfn r k e = + let (extra_meta,stm) = transform_stmt alts (k e) in + extra_meta_decls := extra_meta @ !extra_meta_decls; + stm in + + let typefn r k e = + let (extra_meta,ty) = transform_type alts (k e) in + extra_meta_decls := extra_meta @ !extra_meta_decls; + ty in + + let topfn r k e = + let (extra_meta,ty) = transform_top alts (k e) in + extra_meta_decls := extra_meta @ !extra_meta_decls; + ty in + + let res = + V0.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing exprfn typefn donothing donothing declfn stmtfn + donothing topfn in + let res = res.V0.rebuilder_top_level t in + (!extra_meta_decls,res) + +(* --------------------------------------------------------------------- *) + +(* should be done by functorizing the parser to use wrap or context_wrap *) +let rewrap = + let mcode (x,a,i,mc,pos) = (x,a,i,Ast0.context_befaft(),pos) in + let donothing r k e = Ast0.context_wrap(Ast0.unwrap(k e)) in + V0.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing donothing + donothing donothing + +let rewrap_anything = function + Ast0.DotsExprTag(d) -> + Ast0.DotsExprTag(rewrap.V0.rebuilder_expression_dots d) + | Ast0.DotsInitTag(d) -> + Ast0.DotsInitTag(rewrap.V0.rebuilder_initialiser_list d) + | Ast0.DotsParamTag(d) -> + Ast0.DotsParamTag(rewrap.V0.rebuilder_parameter_list d) + | Ast0.DotsStmtTag(d) -> + Ast0.DotsStmtTag(rewrap.V0.rebuilder_statement_dots d) + | Ast0.DotsDeclTag(d) -> + Ast0.DotsDeclTag(rewrap.V0.rebuilder_declaration_dots d) + | Ast0.DotsCaseTag(d) -> + Ast0.DotsCaseTag(rewrap.V0.rebuilder_case_line_dots d) + | Ast0.IdentTag(d) -> Ast0.IdentTag(rewrap.V0.rebuilder_ident d) + | Ast0.ExprTag(d) -> Ast0.ExprTag(rewrap.V0.rebuilder_expression d) + | Ast0.ArgExprTag(d) -> Ast0.ArgExprTag(rewrap.V0.rebuilder_expression d) + | Ast0.TestExprTag(d) -> Ast0.TestExprTag(rewrap.V0.rebuilder_expression d) + | Ast0.TypeCTag(d) -> Ast0.TypeCTag(rewrap.V0.rebuilder_typeC d) + | Ast0.InitTag(d) -> Ast0.InitTag(rewrap.V0.rebuilder_initialiser d) + | Ast0.ParamTag(d) -> Ast0.ParamTag(rewrap.V0.rebuilder_parameter d) + | Ast0.DeclTag(d) -> Ast0.DeclTag(rewrap.V0.rebuilder_declaration d) + | Ast0.StmtTag(d) -> Ast0.StmtTag(rewrap.V0.rebuilder_statement d) + | Ast0.CaseLineTag(d) -> Ast0.CaseLineTag(rewrap.V0.rebuilder_case_line d) + | Ast0.TopTag(d) -> Ast0.TopTag(rewrap.V0.rebuilder_top_level d) + | Ast0.IsoWhenTag(_) -> failwith "only for isos within iso phase" + | Ast0.MetaPosTag(p) -> Ast0.MetaPosTag(p) + +(* --------------------------------------------------------------------- *) + +let apply_isos isos rule rule_name = + if isos = [] + then ([],rule) + else + begin + current_rule := rule_name; + let isos = + List.map + (function (metavars,iso,name) -> + (metavars,List.map (List.map rewrap_anything) iso,name)) + isos in + let (extra_meta,rule) = + List.split + (List.map + (function t -> + List.fold_left + (function (extra_meta,t) -> function iso -> + let (new_extra_meta,t) = transform iso t in + (new_extra_meta@extra_meta,t)) + ([],t) isos) + rule) in + (List.concat extra_meta, Compute_lines.compute_lines rule) + end diff --git a/parsing_cocci/iso_pattern.mli b/parsing_cocci/iso_pattern.mli new file mode 100644 index 0000000..32b4655 --- /dev/null +++ b/parsing_cocci/iso_pattern.mli @@ -0,0 +1,8 @@ +type isomorphism = + Ast_cocci.metavar list * Ast0_cocci.anything list list * string(*iso name*) + +val apply_isos : + isomorphism list -> Ast0_cocci.rule -> string (* rule name *) -> + Ast_cocci.metavar list * Ast0_cocci.rule + +val rebuild_mcode : int option -> Visitor_ast0.rebuilder diff --git a/parsing_cocci/lexer_cocci.mll b/parsing_cocci/lexer_cocci.mll new file mode 100644 index 0000000..c066d1d --- /dev/null +++ b/parsing_cocci/lexer_cocci.mll @@ -0,0 +1,700 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +{ +open Parser_cocci_menhir +module D = Data +module Ast = Ast_cocci +module Ast0 = Ast0_cocci +module P = Parse_aux +exception Lexical of string +let tok = Lexing.lexeme + +let line = ref 1 +let logical_line = ref 0 + +(* ---------------------------------------------------------------------- *) +(* control codes *) + +(* Defined in data.ml +type line_type = MINUS | OPTMINUS | UNIQUEMINUS | PLUS | CONTEXT | UNIQUE | OPT +*) + +let current_line_type = ref (D.CONTEXT,!line,!logical_line) + +let prev_plus = ref false +let line_start = ref 0 (* offset of the beginning of the line *) +let get_current_line_type lexbuf = + let (c,l,ll) = !current_line_type in + let lex_start = Lexing.lexeme_start lexbuf in + let preceeding_spaces = + if !line_start < 0 then 0 else lex_start - !line_start in + line_start := -1; + prev_plus := (c = D.PLUS); + (c,l,ll,lex_start,preceeding_spaces,[],[],Ast0.NoMetaPos) +let current_line_started = ref false +let col_zero = ref true + +let reset_line lexbuf = + line := !line + 1; + current_line_type := (D.CONTEXT,!line,!logical_line); + current_line_started := false; + col_zero := true; + line_start := Lexing.lexeme_start lexbuf + 1 + +let started_line = ref (-1) + +let start_line seen_char = + current_line_started := true; + col_zero := false; + (if seen_char && not(!line = !started_line) + then + begin + started_line := !line; + logical_line := !logical_line + 1 + end) + +let pass_zero _ = col_zero := false + +let lexerr s1 s2 = raise (Lexical (Printf.sprintf "%s%s" s1 s2)) + +let add_current_line_type x = + match (x,!current_line_type) with + (D.MINUS,(D.CONTEXT,ln,lln)) -> + current_line_type := (D.MINUS,ln,lln) + | (D.MINUS,(D.UNIQUE,ln,lln)) -> + current_line_type := (D.UNIQUEMINUS,ln,lln) + | (D.MINUS,(D.OPT,ln,lln)) -> + current_line_type := (D.OPTMINUS,ln,lln) + | (D.PLUS,(D.CONTEXT,ln,lln)) -> + current_line_type := (D.PLUS,ln,lln) + | (D.UNIQUE,(D.CONTEXT,ln,lln)) -> + current_line_type := (D.UNIQUE,ln,lln) + | (D.OPT,(D.CONTEXT,ln,lln)) -> + current_line_type := (D.OPT,ln,lln) + | _ -> lexerr "invalid control character combination" "" + +let check_minus_context_linetype s = + match !current_line_type with + (D.PLUS,_,_) -> lexerr "invalid in a + context: " s + | _ -> () + +let check_context_linetype s = + match !current_line_type with + (D.CONTEXT,_,_) -> () + | _ -> lexerr "invalid in a nonempty context: " s + +let check_plus_linetype s = + match !current_line_type with + (D.PLUS,_,_) -> () + | _ -> lexerr "invalid in a non + context: " s + +let check_arity_context_linetype s = + match !current_line_type with + (D.CONTEXT,_,_) | (D.PLUS,_,_) | (D.UNIQUE,_,_) | (D.OPT,_,_) -> () + | _ -> lexerr "invalid in a nonempty context: " s + +let process_include start finish str = + (match !current_line_type with + (D.PLUS,_,_) -> + (try + let _ = Str.search_forward (Str.regexp "\\.\\.\\.") str start in + lexerr "... not allowed in + include" "" + with Not_found -> ()) + | _ -> ()); + String.sub str (start + 1) (finish - start - 1) + +(* ---------------------------------------------------------------------- *) +type pm = PATCH | MATCH | UNKNOWN + +let pm = ref UNKNOWN + +let patch_or_match = function + PATCH -> + (match !pm with + MATCH -> lexerr "- or + not allowed in the first column for a match" "" + | PATCH -> () + | UNKNOWN -> Flag.sgrep_mode2 := false; pm := PATCH) + | MATCH -> + (match !pm with + PATCH -> lexerr "* not allowed in the first column for a patch" "" + | MATCH -> () + | UNKNOWN -> Flag.sgrep_mode2 := true; pm := MATCH) + | _ -> failwith "unexpected argument" + +(* ---------------------------------------------------------------------- *) +(* identifiers, including metavariables *) + +let metavariables = (Hashtbl.create(100) : (string, D.clt -> token) Hashtbl.t) + +let all_metavariables = + (Hashtbl.create(100) : (string,(string * (D.clt -> token)) list) Hashtbl.t) + +let type_names = (Hashtbl.create(100) : (string, D.clt -> token) Hashtbl.t) + +let declarer_names = (Hashtbl.create(100) : (string, D.clt -> token) Hashtbl.t) + +let iterator_names = (Hashtbl.create(100) : (string, D.clt -> token) Hashtbl.t) + +let rule_names = (Hashtbl.create(100) : (string, unit) Hashtbl.t) + +let check_var s linetype = + let fail _ = + if (!Data.in_prolog || !Data.in_rule_name) && + Str.string_match (Str.regexp "<.*>") s 0 + then TPathIsoFile s + else + try (Hashtbl.find metavariables s) linetype + with Not_found -> + (try (Hashtbl.find type_names s) linetype + with Not_found -> + (try (Hashtbl.find declarer_names s) linetype + with Not_found -> + (try (Hashtbl.find iterator_names s) linetype + with Not_found -> TIdent (s,linetype)))) in + if !Data.in_meta or !Data.in_rule_name + then (try Hashtbl.find rule_names s; TRuleName s with Not_found -> fail()) + else fail() + +let id_tokens lexbuf = + let s = tok lexbuf in + let linetype = get_current_line_type lexbuf in + let in_rule_name = !Data.in_rule_name in + let in_meta = !Data.in_meta in + let in_iso = !Data.in_iso in + let in_prolog = !Data.in_prolog in + match s with + "identifier" when in_meta -> check_arity_context_linetype s; TIdentifier + | "type" when in_meta -> check_arity_context_linetype s; TType + | "parameter" when in_meta -> check_arity_context_linetype s; TParameter + | "constant" when in_meta -> check_arity_context_linetype s; TConstant + | "expression" when in_meta || in_rule_name -> + check_arity_context_linetype s; TExpression + | "idexpression" when in_meta -> + check_arity_context_linetype s; TIdExpression + | "statement" when in_meta -> check_arity_context_linetype s; TStatement + | "function" when in_meta -> check_arity_context_linetype s; TFunction + | "local" when in_meta -> check_arity_context_linetype s; TLocal + | "list" when in_meta -> check_arity_context_linetype s; Tlist + | "fresh" when in_meta -> check_arity_context_linetype s; TFresh + | "typedef" when in_meta -> check_arity_context_linetype s; TTypedef + | "declarer" when in_meta -> check_arity_context_linetype s; TDeclarer + | "iterator" when in_meta -> check_arity_context_linetype s; TIterator + | "name" when in_meta -> check_arity_context_linetype s; TName + | "position" when in_meta -> check_arity_context_linetype s; TPosition + | "any" when in_meta -> check_arity_context_linetype s; TPosAny + | "pure" when in_meta && in_iso -> + check_arity_context_linetype s; TPure + | "context" when in_meta && in_iso -> + check_arity_context_linetype s; TContext + | "error" when in_meta -> check_arity_context_linetype s; TError + | "words" when in_meta -> check_context_linetype s; TWords + + | "using" when in_rule_name || in_prolog -> check_context_linetype s; TUsing + | "disable" when in_rule_name -> check_context_linetype s; TDisable + | "extends" when in_rule_name -> check_context_linetype s; TExtends + | "depends" when in_rule_name -> check_context_linetype s; TDepends + | "on" when in_rule_name -> check_context_linetype s; TOn + | "ever" when in_rule_name -> check_context_linetype s; TEver + | "never" when in_rule_name -> check_context_linetype s; TNever + | "exists" when in_rule_name -> check_context_linetype s; TExists + | "forall" when in_rule_name -> check_context_linetype s; TForall + | "reverse" when in_rule_name -> check_context_linetype s; TReverse + + | "char" -> Tchar linetype + | "short" -> Tshort linetype + | "int" -> Tint linetype + | "double" -> Tdouble linetype + | "float" -> Tfloat linetype + | "long" -> Tlong linetype + | "void" -> Tvoid linetype + | "struct" -> Tstruct linetype + | "union" -> Tunion linetype + | "unsigned" -> Tunsigned linetype + | "signed" -> Tsigned linetype + + | "auto" -> Tauto linetype + | "register" -> Tregister linetype + | "extern" -> Textern linetype + | "static" -> Tstatic linetype + | "inline" -> Tinline linetype + | "typedef" -> Ttypedef linetype + + | "const" -> Tconst linetype + | "volatile" -> Tvolatile linetype + + | "if" -> TIf linetype + | "else" -> TElse linetype + | "while" -> TWhile linetype + | "do" -> TDo linetype + | "for" -> TFor linetype + | "switch" -> TSwitch linetype + | "case" -> TCase linetype + | "default" -> TDefault linetype + | "return" -> TReturn linetype + | "break" -> TBreak linetype + | "continue" -> TContinue linetype + | "goto" -> TGoto linetype + + | "sizeof" -> TSizeof linetype + + | "Expression" -> TIsoExpression + | "ArgExpression" -> TIsoArgExpression + | "TestExpression" -> TIsoTestExpression + | "Statement" -> TIsoStatement + | "Declaration" -> TIsoDeclaration + | "Type" -> TIsoType + | "TopLevel" -> TIsoTopLevel + + | s -> check_var s linetype + +let mkassign op lexbuf = + TAssign (Ast.OpAssign op, (get_current_line_type lexbuf)) + +let init _ = + line := 1; + logical_line := 0; + prev_plus := false; + line_start := 0; + current_line_started := false; + col_zero := true; + pm := UNKNOWN; + Data.in_rule_name := false; + Data.in_meta := false; + Data.in_prolog := false; + Data.inheritable_positions := []; + Hashtbl.clear all_metavariables; + Hashtbl.clear Data.all_metadecls; + Hashtbl.clear metavariables; + Hashtbl.clear type_names; + Hashtbl.clear rule_names; + let get_name (_,x) = x in + Data.add_id_meta := + (fun name constraints pure -> + let fn clt = TMetaId(name,constraints,pure,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_type_meta := + (fun name pure -> + let fn clt = TMetaType(name,pure,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_param_meta := + (function name -> function pure -> + let fn clt = TMetaParam(name,pure,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_paramlist_meta := + (function name -> function lenname -> function pure -> + let fn clt = TMetaParamList(name,lenname,pure,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_const_meta := + (fun tyopt name constraints pure -> + let fn clt = TMetaConst(name,constraints,pure,tyopt,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_err_meta := + (fun name constraints pure -> + let fn clt = TMetaErr(name,constraints,pure,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_exp_meta := + (fun tyopt name constraints pure -> + let fn clt = TMetaExp(name,constraints,pure,tyopt,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_idexp_meta := + (fun tyopt name constraints pure -> + let fn clt = TMetaIdExp(name,constraints,pure,tyopt,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_local_idexp_meta := + (fun tyopt name constraints pure -> + let fn clt = TMetaLocalIdExp(name,constraints,pure,tyopt,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_explist_meta := + (function name -> function lenname -> function pure -> + let fn clt = TMetaExpList(name,lenname,pure,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_stm_meta := + (function name -> function pure -> + let fn clt = TMetaStm(name,pure,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_stmlist_meta := + (function name -> function pure -> + let fn clt = TMetaStmList(name,pure,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_func_meta := + (fun name constraints pure -> + let fn clt = TMetaFunc(name,constraints,pure,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_local_func_meta := + (fun name constraints pure -> + let fn clt = TMetaLocalFunc(name,constraints,pure,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_iterator_meta := + (fun name constraints pure -> + let fn clt = TMetaIterator(name,constraints,pure,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_declarer_meta := + (fun name constraints pure -> + let fn clt = TMetaDeclarer(name,constraints,pure,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_pos_meta := + (fun name constraints any -> + let fn ((d,ln,_,_,_,_,_,_) as clt) = + (if d = Data.PLUS + then + failwith + (Printf.sprintf "%d: positions only allowed in minus code" ln)); + TMetaPos(name,constraints,any,clt) in + Hashtbl.replace metavariables (get_name name) fn); + Data.add_type_name := + (function name -> + let fn clt = TTypeId(name,clt) in + Hashtbl.replace type_names name fn); + Data.add_declarer_name := + (function name -> + let fn clt = TDeclarerId(name,clt) in + Hashtbl.replace declarer_names name fn); + Data.add_iterator_name := + (function name -> + let fn clt = TIteratorId(name,clt) in + Hashtbl.replace iterator_names name fn); + Data.init_rule := (function _ -> Hashtbl.clear metavariables); + Data.install_bindings := + (function parent -> + List.iter (function (name,fn) -> Hashtbl.add metavariables name fn) + (Hashtbl.find all_metavariables parent)) + +let drop_spaces s = + let len = String.length s in + let rec loop n = + if n = len + then n + else + if List.mem (String.get s n) [' ';'\t'] + then loop (n+1) + else n in + let start = loop 0 in + String.sub s start (len - start) +} + +(* ---------------------------------------------------------------------- *) +(* tokens *) + +let letter = ['A'-'Z' 'a'-'z' '_'] +let digit = ['0'-'9'] + +let dec = ['0'-'9'] +let oct = ['0'-'7'] +let hex = ['0'-'9' 'a'-'f' 'A'-'F'] + +let decimal = ('0' | (['1'-'9'] dec*)) +let octal = ['0'] oct+ +let hexa = ("0x" |"0X") hex+ + +let pent = dec+ +let pfract = dec+ +let sign = ['-' '+'] +let exp = ['e''E'] sign? dec+ +let real = pent exp | ((pent? '.' pfract | pent '.' pfract? ) exp?) + + +rule token = parse + | [' ' '\t' ]+ { start_line false; token lexbuf } + | ['\n' '\r' '\011' '\012'] { reset_line lexbuf; token lexbuf } + + | "//" [^ '\n']* { start_line false; token lexbuf } + + | "@@" { start_line true; TArobArob } + | "@" { pass_zero(); + if !Data.in_rule_name or not !current_line_started + then (start_line true; TArob) + else (check_minus_context_linetype "@"; TPArob) } + + | "WHEN" | "when" + { start_line true; check_minus_context_linetype (tok lexbuf); + TWhen (get_current_line_type lexbuf) } + + | "..." + { start_line true; check_minus_context_linetype (tok lexbuf); + TEllipsis (get_current_line_type lexbuf) } +(* + | "ooo" + { start_line true; check_minus_context_linetype (tok lexbuf); + TCircles (get_current_line_type lexbuf) } + + | "***" + { start_line true; check_minus_context_linetype (tok lexbuf); + TStars (get_current_line_type lexbuf) } +*) + | "<..." { start_line true; check_context_linetype (tok lexbuf); + TOEllipsis (get_current_line_type lexbuf) } + | "...>" { start_line true; check_context_linetype (tok lexbuf); + TCEllipsis (get_current_line_type lexbuf) } + | "<+..." { start_line true; check_context_linetype (tok lexbuf); + TPOEllipsis (get_current_line_type lexbuf) } + | "...+>" { start_line true; check_context_linetype (tok lexbuf); + TPCEllipsis (get_current_line_type lexbuf) } +(* + | "" { start_line true; check_context_linetype (tok lexbuf); + TCCircles (get_current_line_type lexbuf) } + + | "<***" { start_line true; check_context_linetype (tok lexbuf); + TOStars (get_current_line_type lexbuf) } + | "***>" { start_line true; check_context_linetype (tok lexbuf); + TCStars (get_current_line_type lexbuf) } +*) + | "-" { pass_zero(); + if !current_line_started + then (start_line true; TMinus (get_current_line_type lexbuf)) + else (patch_or_match PATCH; + add_current_line_type D.MINUS; token lexbuf) } + | "+" { pass_zero(); + if !current_line_started + then (start_line true; TPlus (get_current_line_type lexbuf)) + else if !Data.in_meta + then TPlus0 + else (patch_or_match PATCH; + add_current_line_type D.PLUS; token lexbuf) } + | "?" { pass_zero(); + if !current_line_started + then (start_line true; TWhy (get_current_line_type lexbuf)) + else if !Data.in_meta + then TWhy0 + else (add_current_line_type D.OPT; token lexbuf) } + | "!" { pass_zero(); + if !current_line_started + then (start_line true; TBang (get_current_line_type lexbuf)) + else if !Data.in_meta + then TBang0 + else (add_current_line_type D.UNIQUE; token lexbuf) } + | "(" { if not !col_zero + then (start_line true; TOPar (get_current_line_type lexbuf)) + else + (start_line true; check_context_linetype (tok lexbuf); + TOPar0 (get_current_line_type lexbuf))} + | "\\(" { start_line true; TOPar0 (get_current_line_type lexbuf) } + | "|" { if not (!col_zero) + then (start_line true; TOr(get_current_line_type lexbuf)) + else (start_line true; + check_context_linetype (tok lexbuf); + TMid0 (get_current_line_type lexbuf))} + | "\\|" { start_line true; TMid0 (get_current_line_type lexbuf) } + | ")" { if not !col_zero + then (start_line true; TCPar (get_current_line_type lexbuf)) + else + (start_line true; check_context_linetype (tok lexbuf); + TCPar0 (get_current_line_type lexbuf))} + | "\\)" { start_line true; TCPar0 (get_current_line_type lexbuf) } + + | '[' { start_line true; TOCro (get_current_line_type lexbuf) } + | ']' { start_line true; TCCro (get_current_line_type lexbuf) } + | '{' { start_line true; TOBrace (get_current_line_type lexbuf) } + | '}' { start_line true; TCBrace (get_current_line_type lexbuf) } + + | "->" { start_line true; TPtrOp (get_current_line_type lexbuf) } + | '.' { start_line true; TDot (get_current_line_type lexbuf) } + | ',' { start_line true; TComma (get_current_line_type lexbuf) } + | ";" { start_line true; + if !Data.in_meta + then TMPtVirg (* works better with tokens_all *) + else TPtVirg (get_current_line_type lexbuf) } + + + | '*' { pass_zero(); + if !current_line_started + then + (start_line true; TMul (get_current_line_type lexbuf)) + else + (patch_or_match MATCH; + add_current_line_type D.MINUS; token lexbuf) } + | '/' { start_line true; + TDmOp (Ast.Div,get_current_line_type lexbuf) } + | '%' { start_line true; + TDmOp (Ast.Mod,get_current_line_type lexbuf) } + | '~' { start_line true; TTilde (get_current_line_type lexbuf) } + + | "++" { start_line true; TInc (get_current_line_type lexbuf) } + | "--" { start_line true; TDec (get_current_line_type lexbuf) } + + | "=" { start_line true; TEq (get_current_line_type lexbuf) } + + | "-=" { start_line true; mkassign Ast.Minus lexbuf } + | "+=" { start_line true; mkassign Ast.Plus lexbuf } + + | "*=" { start_line true; mkassign Ast.Mul lexbuf } + | "/=" { start_line true; mkassign Ast.Div lexbuf } + | "%=" { start_line true; mkassign Ast.Mod lexbuf } + + | "&=" { start_line true; mkassign Ast.And lexbuf } + | "|=" { start_line true; mkassign Ast.Or lexbuf } + | "^=" { start_line true; mkassign Ast.Xor lexbuf } + + | "<<=" { start_line true; mkassign Ast.DecLeft lexbuf } + | ">>=" { start_line true; mkassign Ast.DecRight lexbuf } + + | ":" { start_line true; TDotDot (get_current_line_type lexbuf) } + + | "==" { start_line true; TEqEq (get_current_line_type lexbuf) } + | "!=" { start_line true; TNotEq (get_current_line_type lexbuf) } + | ">=" { start_line true; + TLogOp(Ast.SupEq,get_current_line_type lexbuf) } + | "<=" { start_line true; + TLogOp(Ast.InfEq,get_current_line_type lexbuf) } + | "<" { start_line true; + TLogOp(Ast.Inf,get_current_line_type lexbuf) } + | ">" { start_line true; + TLogOp(Ast.Sup,get_current_line_type lexbuf) } + + | "&&" { start_line true; TAndLog (get_current_line_type lexbuf) } + | "||" { start_line true; TOrLog (get_current_line_type lexbuf) } + + | ">>" { start_line true; + TShOp(Ast.DecRight,get_current_line_type lexbuf) } + | "<<" { start_line true; + TShOp(Ast.DecLeft,get_current_line_type lexbuf) } + + | "&" { start_line true; TAnd (get_current_line_type lexbuf) } + | "^" { start_line true; TXor(get_current_line_type lexbuf) } + + | ( ("#" [' ' '\t']* "define" [' ' '\t']+)) + ( (letter (letter |digit)*) as ident) + { start_line true; + let (arity,line,lline,offset,col,strbef,straft,pos) as lt = + get_current_line_type lexbuf in + let off = String.length "#define " in + (* -1 in the code below because the ident is not at the line start *) + TDefine + (lt, + check_var ident + (arity,line,lline,offset+off,(-1),[],[],Ast0.NoMetaPos)) } + | ( ("#" [' ' '\t']* "define" [' ' '\t']+)) + ( (letter (letter | digit)*) as ident) + '(' + { start_line true; + let (arity,line,lline,offset,col,strbef,straft,pos) as lt = + get_current_line_type lexbuf in + let off = String.length "#define " in + TDefineParam + (lt, + check_var ident + (* why pos here but not above? *) + (arity,line,lline,offset+off,(-1),strbef,straft,pos), + offset + off + (String.length ident)) } + | "#" [' ' '\t']* "include" [' ' '\t']* '"' [^ '"']+ '"' + { TIncludeL + (let str = tok lexbuf in + let start = String.index str '"' in + let finish = String.rindex str '"' in + start_line true; + (process_include start finish str,get_current_line_type lexbuf)) } + | "#" [' ' '\t']* "include" [' ' '\t']* '<' [^ '>']+ '>' + { TIncludeNL + (let str = tok lexbuf in + let start = String.index str '<' in + let finish = String.rindex str '>' in + start_line true; + (process_include start finish str,get_current_line_type lexbuf)) } + | "#" [' ' '\t']* "if" [^'\n']* + | "#" [' ' '\t']* "ifdef" [^'\n']* + | "#" [' ' '\t']* "ifndef" [^'\n']* + | "#" [' ' '\t']* "else" [^'\n']* + | "#" [' ' '\t']* "elif" [^'\n']* + | "#" [' ' '\t']* "endif" [^'\n']* + | "#" [' ' '\t']* "error" [^'\n']* + { start_line true; check_plus_linetype (tok lexbuf); + TPragma (tok lexbuf) } + | "---" [^'\n']* + { (if !current_line_started + then lexerr "--- must be at the beginning of the line" ""); + start_line true; + TMinusFile + (let str = tok lexbuf in + (drop_spaces(String.sub str 3 (String.length str - 3)), + (get_current_line_type lexbuf))) } + | "+++" [^'\n']* + { (if !current_line_started + then lexerr "+++ must be at the beginning of the line" ""); + start_line true; + TPlusFile + (let str = tok lexbuf in + (drop_spaces(String.sub str 3 (String.length str - 3)), + (get_current_line_type lexbuf))) } + + | letter (letter | digit)* + { start_line true; id_tokens lexbuf } + + | "'" { start_line true; + TChar(char lexbuf,get_current_line_type lexbuf) } + | '"' { start_line true; + TString(string lexbuf,(get_current_line_type lexbuf)) } + | (real as x) { start_line true; + TFloat(x,(get_current_line_type lexbuf)) } + | ((( decimal | hexa | octal) + ( ['u' 'U'] + | ['l' 'L'] + | (['l' 'L'] ['u' 'U']) + | (['u' 'U'] ['l' 'L']) + | (['u' 'U'] ['l' 'L'] ['l' 'L']) + | (['l' 'L'] ['l' 'L']) + )? + ) as x) { start_line true; TInt(x,(get_current_line_type lexbuf)) } + + | "<=>" { TIso } + | "=>" { TRightIso } + + | eof { EOF } + + | _ { lexerr "unrecognised symbol, in token rule: " (tok lexbuf) } + + +and char = parse + | (_ as x) "'" { String.make 1 x } + | (("\\" (oct | oct oct | oct oct oct)) as x "'") { x } + | (("\\x" (hex | hex hex)) as x "'") { x } + | (("\\" (_ as v)) as x "'") + { (match v with + | 'n' -> () | 't' -> () | 'v' -> () | 'b' -> () + | 'r' -> () | 'f' -> () | 'a' -> () + | '\\' -> () | '?' -> () | '\'' -> () | '"' -> () + | 'e' -> () + | _ -> lexerr "unrecognised symbol: " (tok lexbuf) + ); + x + } + | _ { lexerr "unrecognised symbol: " (tok lexbuf) } + +and string = parse + | '"' { "" } + | (_ as x) { Common.string_of_char x ^ string lexbuf } + | ("\\" (oct | oct oct | oct oct oct)) as x { x ^ string lexbuf } + | ("\\x" (hex | hex hex)) as x { x ^ string lexbuf } + | ("\\" (_ as v)) as x + { + (match v with + | 'n' -> () | 't' -> () | 'v' -> () | 'b' -> () | 'r' -> () + | 'f' -> () | 'a' -> () + | '\\' -> () | '?' -> () | '\'' -> () | '"' -> () + | 'e' -> () + | '\n' -> () + | _ -> lexerr "unrecognised symbol:" (tok lexbuf) + ); + x ^ string lexbuf + } + | _ { lexerr "unrecognised symbol: " (tok lexbuf) } diff --git a/parsing_cocci/lexer_script.mll b/parsing_cocci/lexer_script.mll new file mode 100644 index 0000000..7e051db --- /dev/null +++ b/parsing_cocci/lexer_script.mll @@ -0,0 +1,42 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +{ +open Parser_cocci_menhir +module D = Data +module Ast = Ast_cocci +exception Lexical of string +let tok = Lexing.lexeme +} +(* ---------------------------------------------------------------------- *) +(* tokens *) + +let myrule = [^'@']+ + +rule token = parse + | myrule { TScriptData (tok lexbuf) } + | "@@" { TArobArob } + | "@" { TArob } + | eof { EOF } + | _ { raise (Lexical ("unrecognised symbol, in token rule:"^tok lexbuf)) } + + diff --git a/parsing_cocci/main.ml b/parsing_cocci/main.ml new file mode 100644 index 0000000..58a59b5 --- /dev/null +++ b/parsing_cocci/main.ml @@ -0,0 +1,46 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* ----------------------------------------------------------------------- *) +(* Entry point *) + +let file = ref "" +let isofile = ref None +let verbose = ref true + +let anonymous s = if !file = "" then file := s else isofile := Some s + +let speclist = [("-v", Arg.Set verbose, "print parse result")] + +let usage = + Printf.sprintf "Usage: %s [options] \nOptions are:" + (Filename.basename Sys.argv.(0)) + +let main _ = + begin + Arg.parse speclist anonymous usage; + (* Parse_cocci.parse_and_merge !file; *) + if !file = "" then failwith "filename required"; + Parse_cocci.process !file !isofile !verbose + end + +let _ = main () diff --git a/parsing_cocci/merge.ml b/parsing_cocci/merge.ml new file mode 100644 index 0000000..58a081d --- /dev/null +++ b/parsing_cocci/merge.ml @@ -0,0 +1,212 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* given parsed minus code and a stream of + code, figure out where to put +the + code in the mcode of the minus code *) + +(* Need to be able to find the nearest inhabited line rather than just +adding 1 or subtracting 1 to the actual line number. This is an issue for +plus.ml as well. This problem is dealt with by the logical line field, +which is not incremented for blank lines. *) + +module Ast = Ast_cocci +module Ast0 = Ast0_cocci +module V0 = Visitor_ast0 + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Step 1: convert minus/context code to an ordered stream of tokens *) + +type position = + Minus of Ast.info * Ast.anything list list ref + | Context of Ast.info * Ast.anything Ast.befaft ref + | Bad of Ast.info + +let mcode = function + (_,_,Ast.MINUS(info,plus_stream)) -> [Minus (info,plus_stream)] + | (_,_,Ast.CONTEXT(info,plus_stream)) -> [Context (info,plus_stream)] + | _ -> failwith "not possible 1" + +let bad_mcode = function + (_,_,Ast.MINUS(info,plus_stream)) -> Bad(info) + | (_,_,Ast.CONTEXT(info,plus_stream)) -> Bad(info) + | _ -> failwith "not possible 2" + +let make_bad l = + List.map + (function + Minus(info,plus_stream) -> Bad(info) + | Context(info,plus_stream) -> Bad(info) + | x -> x) + l + +(* --------------------------------------------------------------------- *) +(* combiner info *) + +let bind x y = x @ y +let option_default = [] + +(* --------------------------------------------------------------------- *) + +let get_option f = function + Some x -> f x + | None -> option_default + +let ident recursor k i = k i (* nothing special to do *) + +let expression recursor k e = + match Ast0.unwrap e with + Ast0.Edots(dots,whencode) | Ast0.Ecircles(dots,whencode) + | Ast0.Estars(dots,whencode) -> + (bad_mcode dots) :: + (get_option (function x -> make_bad(recursor.V0.combiner_expression x)) + whencode) + | _ -> k e + +let donothing recursor k ft = k ft + +(* needs a case for things to which new code cannot be attached *) +let parameterTypeDef recursor k p = + match Ast0.unwrap p with + Ast0.Pdots(dots) -> [bad_mcode dots] + | Ast0.Pcircles(dots) -> [bad_mcode dots] + | _ -> k p + +let statement recursor k s = + match Ast0.unwrap s with + Ast0.Dots(d,whencode) | Ast0.Circles(d,whencode) + | Ast0.Stars(d,whencode) -> + (bad_mcode d) :: + (get_option + (function x -> + make_bad(recursor.V0.combiner_statement_dots x)) + whencode) + | _ -> k s + +let top_level recursor k t = + match Ast0.unwrap t with + Ast0.FILEINFO(old_file,new_file) -> + [bad_mcode old_file;bad_mcode new_file] + | Ast0.ERRORWORDS(exps) -> + make_bad (List.concat (List.map recursor.V0.combiner_expression exps)) + | _ -> k t + +let recursor = + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + donothing donothing donothing + ident expression donothing donothing parameterTypeDef donothing + statement top_level + +let rule code = List.concat (List.map recursor.V0.combiner_top_level code) + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Step 2: merge the plus stream with the minus/context tokens *) + +(* Mcode *) + +let get_start l = + let (_,_,_,start,_) = List.hd (List.hd l) in + start + +let get_finish l = + let (_,_,_,_,finish) = List.hd (List.rev (List.hd (List.rev l))) in + finish + +let get_real_start l = + let (_,start,_,_,_) = List.hd (List.hd l) in + start + +let get_real_finish l = + let (_,_,finish,_,_) = List.hd (List.rev (List.hd (List.rev l))) in + finish + +let get_minus_next_line mline = function + [] -> mline + 1 + | Bad(info)::xs -> info.Ast.logical_line + | Minus(info,_)::xs -> info.Ast.logical_line + | Context(info,_)::xs -> info.Ast.logical_line + +let drop_lines l = List.map (List.map (function (x,_,_,_,_) -> x)) l + +let rec merge minus_stream plus_stream = + match (minus_stream,plus_stream) with + (_,[]) -> () + | ([],plus::plus_stream) -> + failwith + (Printf.sprintf + "minus stream ran out before plus stream\n(plus code begins on line %d)\n" + (get_real_start plus)) + | (Bad(info)::minus_stream,plus::plus_stream) -> + let pfinish = get_finish plus in + if info.Ast.logical_line > pfinish + then + failwith + (Printf.sprintf + "plus code starting on line %d has no minus or context code to attach to\n" + (get_real_start plus)) + else merge minus_stream (plus::plus_stream) + | (((Minus(info,cell)::minus_stream) as all_minus),plus::plus_stream) -> + let mline = info.Ast.logical_line in + let mnext_line = get_minus_next_line mline minus_stream in + let pstart = get_start plus in + let pfinish = get_finish plus in + if pstart < mline && pfinish > mline + then (cell := (drop_lines plus) @ !cell; merge minus_stream plus_stream) + else if pfinish + 1 = mline + then (cell := (drop_lines plus) @ !cell; merge all_minus plus_stream) + else if not(mline = mnext_line) && (pstart - 1 = mline) + then (cell := !cell @ (drop_lines plus); merge minus_stream plus_stream) + else if pfinish < mline + then + Printf.printf "failed to merge + code between lines %d and %d" + (get_real_start plus) (get_real_finish plus) + else merge minus_stream (plus::plus_stream) + | (((Context(info,cell)::minus_stream) as all_minus),plus::plus_stream) -> + let mline = info.Ast.logical_line in + let mnext_line = get_minus_next_line mline minus_stream in + let pstart = get_start plus in + let pfinish = get_finish plus in + if pfinish + 1 = mline + then (cell := Ast.BEFORE (drop_lines plus); merge all_minus plus_stream) + else if not(mline = mnext_line) && (pstart - 1 = mline) + then + begin + (match !cell with + Ast.BEFORE x -> cell := Ast.BEFOREAFTER (x,drop_lines plus) + | _ -> cell := Ast.AFTER (drop_lines plus)); + merge minus_stream plus_stream + end + else if pfinish < mline + then + Printf.printf "failed to merge + code between lines %d and %d" + (get_real_start plus) (get_real_finish plus) + else merge minus_stream (plus::plus_stream) + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Entry point *) + +let do_merge minus plus_stream = + let minus_tokens = rule minus in + merge minus_tokens plus_stream diff --git a/parsing_cocci/merge.mli b/parsing_cocci/merge.mli new file mode 100644 index 0000000..edff023 --- /dev/null +++ b/parsing_cocci/merge.mli @@ -0,0 +1,4 @@ +val do_merge : + Ast0_cocci.rule -> + (Ast_cocci.anything * int * int * int * int) list list list -> + unit (* updates Ast0_cocci.rule argument *) diff --git a/parsing_cocci/parse_aux.ml b/parsing_cocci/parse_aux.ml new file mode 100644 index 0000000..fb1ff7d --- /dev/null +++ b/parsing_cocci/parse_aux.ml @@ -0,0 +1,467 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* exports everything, used only by parser_cocci_menhir.mly *) +module Ast0 = Ast0_cocci +module Ast = Ast_cocci + +(* types for metavariable tokens *) +type info = Ast.meta_name * Ast0.pure * Data.clt +type idinfo = Ast.meta_name * Data.iconstraints * Ast0.pure * Data.clt +type expinfo = Ast.meta_name * Data.econstraints * Ast0.pure * Data.clt +type tyinfo = Ast.meta_name * Ast0.typeC list * Ast0.pure * Data.clt +type list_info = Ast.meta_name * Ast.meta_name option * Ast0.pure * Data.clt +type typed_info = + Ast.meta_name * Data.econstraints * Ast0.pure * + Type_cocci.typeC list option * Data.clt +type pos_info = Ast.meta_name * Data.pconstraints * Ast.meta_collect * Data.clt + + +let get_option fn = function + None -> None + | Some x -> Some (fn x) + +let make_info line logical_line offset col strbef straft = + { Ast0.line_start = line; Ast0.line_end = line; + Ast0.logical_start = logical_line; Ast0.logical_end = logical_line; + Ast0.attachable_start = true; Ast0.attachable_end = true; + Ast0.mcode_start = []; Ast0.mcode_end = []; + Ast0.column = col; Ast0.offset = offset; + Ast0.strings_before = strbef; Ast0.strings_after = straft; } + +let clt2info (_,line,logical_line,offset,col,strbef,straft,pos) = + make_info line logical_line offset col strbef straft + +let drop_bef (arity,line,lline,offset,col,strbef,straft,pos) = + (arity,line,lline,offset,col,[],straft,pos) + +let drop_aft (arity,line,lline,offset,col,strbef,straft,pos) = + (arity,line,lline,offset,col,strbef,[],pos) + +let clt2mcode str = function + (Data.MINUS,line,lline,offset,col,strbef,straft,pos) -> + (str,Ast0.NONE,make_info line lline offset col strbef straft, + Ast0.MINUS(ref([],Ast0.default_token_info)),ref pos) + | (Data.OPTMINUS,line,lline,offset,col,strbef,straft,pos) -> + (str,Ast0.OPT,make_info line lline offset col strbef straft, + Ast0.MINUS(ref([],Ast0.default_token_info)),ref pos) + | (Data.UNIQUEMINUS,line,lline,offset,col,strbef,straft,pos) -> + (str,Ast0.UNIQUE,make_info line lline offset col strbef straft, + Ast0.MINUS(ref([],Ast0.default_token_info)),ref pos) + | (Data.PLUS,line,lline,offset,col,strbef,straft,pos) -> + (str,Ast0.NONE,make_info line lline offset col strbef straft,Ast0.PLUS, + ref pos) + | (Data.CONTEXT,line,lline,offset,col,strbef,straft,pos) -> + (str,Ast0.NONE,make_info line lline offset col strbef straft, + Ast0.CONTEXT(ref(Ast.NOTHING, + Ast0.default_token_info,Ast0.default_token_info)), + ref pos) + | (Data.OPT,line,lline,offset,col,strbef,straft,pos) -> + (str,Ast0.OPT,make_info line lline offset col strbef straft, + Ast0.CONTEXT(ref(Ast.NOTHING, + Ast0.default_token_info,Ast0.default_token_info)), + ref pos) + | (Data.UNIQUE,line,lline,offset,col,strbef,straft,pos) -> + (str,Ast0.UNIQUE,make_info line lline offset col strbef straft, + Ast0.CONTEXT(ref(Ast.NOTHING, + Ast0.default_token_info,Ast0.default_token_info)), + ref pos) + +let id2name (name, clt) = name +let id2clt (name, clt) = clt +let id2mcode (name, clt) = clt2mcode name clt + +let mkdots str (dot,whencode) = + match str with + "..." -> Ast0.wrap(Ast0.Dots(clt2mcode str dot, whencode)) + | "ooo" -> Ast0.wrap(Ast0.Circles(clt2mcode str dot, whencode)) + | "***" -> Ast0.wrap(Ast0.Stars(clt2mcode str dot, whencode)) + | _ -> failwith "cannot happen" + +let mkedots str (dot,whencode) = + match str with + "..." -> Ast0.wrap(Ast0.Edots(clt2mcode str dot, whencode)) + | "ooo" -> Ast0.wrap(Ast0.Ecircles(clt2mcode str dot, whencode)) + | "***" -> Ast0.wrap(Ast0.Estars(clt2mcode str dot, whencode)) + | _ -> failwith "cannot happen" + +let mkdpdots str dot = + match str with + "..." -> Ast0.wrap(Ast0.DPdots(clt2mcode str dot)) + | "ooo" -> Ast0.wrap(Ast0.DPcircles(clt2mcode str dot)) + | _ -> failwith "cannot happen" + +let mkidots str (dot,whencode) = + match str with + "..." -> Ast0.wrap(Ast0.Idots(clt2mcode str dot, whencode)) + | _ -> failwith "cannot happen" + +let mkddots str (dot,whencode) = + match (str,whencode) with + ("...",None) -> Ast0.wrap(Ast0.Ddots(clt2mcode str dot, None)) + | ("...",Some [w]) -> Ast0.wrap(Ast0.Ddots(clt2mcode str dot, Some w)) + | _ -> failwith "cannot happen" + +let mkpdots str dot = + match str with + "..." -> Ast0.wrap(Ast0.Pdots(clt2mcode str dot)) + | "ooo" -> Ast0.wrap(Ast0.Pcircles(clt2mcode str dot)) + | _ -> failwith "cannot happen" + +let arith_op ast_op left op right = + Ast0.wrap + (Ast0.Binary(left, clt2mcode (Ast.Arith ast_op) op, right)) + +let logic_op ast_op left op right = + Ast0.wrap + (Ast0.Binary(left, clt2mcode (Ast.Logical ast_op) op, right)) + +let make_cv cv ty = + match cv with None -> ty | Some x -> Ast0.wrap (Ast0.ConstVol(x,ty)) + +let top_dots l = + let circle x = + match Ast0.unwrap x with Ast0.Circles(_) -> true | _ -> false in + let star x = + match Ast0.unwrap x with Ast0.Stars(_) -> true | _ -> false in + if List.exists circle l + then Ast0.wrap(Ast0.CIRCLES(l)) + else + if List.exists star l + then Ast0.wrap(Ast0.STARS(l)) + else Ast0.wrap(Ast0.DOTS(l)) + +(* here the offset is that of the first in the sequence of *s, not that of +each * individually *) +let pointerify ty m = + List.fold_left + (function inner -> + function cur -> + Ast0.wrap(Ast0.Pointer(inner,clt2mcode "*" cur))) + ty m + +let ty_pointerify ty m = + List.fold_left + (function inner -> function cur -> Type_cocci.Pointer(inner)) + ty m + +(* Left is <=>, Right is =>. Collect <=>s. *) +(* The parser should have done this, with precedences. But whatever... *) +let iso_adjust fn first rest = + let rec loop = function + [] -> [[]] + | (Common.Left x)::rest -> + (match loop rest with + front::after -> (fn x::front)::after + | _ -> failwith "not possible") + | (Common.Right x)::rest -> + (match loop rest with + front::after -> []::(fn x::front)::after + | _ -> failwith "not possible") in + match loop rest with + front::after -> (fn first::front)::after + | _ -> failwith "not possible" + +let check_meta tok = + let lookup rule name = + try + let info = Hashtbl.find Data.all_metadecls rule in + List.find (function mv -> Ast.get_meta_name mv = (rule,name)) info + with + Not_found -> + raise + (Semantic_cocci.Semantic + ("bad rule "^rule^" or bad variable "^name)) in + match tok with + Ast.MetaIdDecl(Ast.NONE,(rule,name)) -> + (match lookup rule name with + Ast.MetaIdDecl(_,_) | Ast.MetaFreshIdDecl(_,_) -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaFreshIdDecl(Ast.NONE,(rule,name)) -> + raise + (Semantic_cocci.Semantic + "can't inherit the freshness of an identifier") + | Ast.MetaListlenDecl((rule,name)) -> + (match lookup rule name with + Ast.MetaListlenDecl(_) -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaTypeDecl(Ast.NONE,(rule,name)) -> + (match lookup rule name with + Ast.MetaTypeDecl(_,_) -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaParamDecl(Ast.NONE,(rule,name)) -> + (match lookup rule name with + Ast.MetaParamDecl(_,_) -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaParamListDecl(Ast.NONE,(rule,name),len_name) -> + (match lookup rule name with + Ast.MetaParamListDecl(_,_,_) -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaErrDecl(Ast.NONE,(rule,name)) -> + (match lookup rule name with + Ast.MetaErrDecl(_,_) -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaExpDecl(Ast.NONE,(rule,name),ty) -> + (match lookup rule name with + Ast.MetaExpDecl(_,_,ty1) when ty = ty1 -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaIdExpDecl(Ast.NONE,(rule,name),ty) -> + (match lookup rule name with + Ast.MetaIdExpDecl(_,_,ty1) when ty = ty1 -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaLocalIdExpDecl(Ast.NONE,(rule,name),ty) -> + (match lookup rule name with + Ast.MetaLocalIdExpDecl(_,_,ty1) when ty = ty1 -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaExpListDecl(Ast.NONE,(rule,name),len_name) -> + (match lookup rule name with + Ast.MetaExpListDecl(_,_,_) -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaStmDecl(Ast.NONE,(rule,name)) -> + (match lookup rule name with + Ast.MetaStmDecl(_,_) -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaStmListDecl(Ast.NONE,(rule,name)) -> + (match lookup rule name with + Ast.MetaStmListDecl(_,_) -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaFuncDecl(Ast.NONE,(rule,name)) -> + (match lookup rule name with + Ast.MetaFuncDecl(_,_) -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaLocalFuncDecl(Ast.NONE,(rule,name)) -> + (match lookup rule name with + Ast.MetaLocalFuncDecl(_,_) -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaConstDecl(Ast.NONE,(rule,name),ty) -> + (match lookup rule name with + Ast.MetaConstDecl(_,_,ty1) when ty = ty1 -> () + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | Ast.MetaPosDecl(Ast.NONE,(rule,name)) -> + (match lookup rule name with + Ast.MetaPosDecl(_,_) -> + if not (List.mem rule !Data.inheritable_positions) + then + raise + (Semantic_cocci.Semantic + ("position cannot be inherited over modifications: "^name)) + | _ -> + raise + (Semantic_cocci.Semantic + ("incompatible inheritance declaration "^name))) + | _ -> + raise + (Semantic_cocci.Semantic ("arity not allowed on imported declaration")) + +let create_metadec ar ispure kindfn ids current_rule = + List.concat + (List.map + (function (rule,nm) -> + let (rule,checker) = + match rule with + None -> ((current_rule,nm),function x -> [Common.Left x]) + | Some rule -> + ((rule,nm), + function x -> check_meta x; [Common.Right x]) in + kindfn ar rule ispure checker) + ids) + +let create_metadec_ne ar ispure kindfn ids current_rule = + List.concat + (List.map + (function ((rule,nm),constraints) -> + let (rule,checker) = + match rule with + None -> ((current_rule,nm),function x -> [Common.Left x]) + | Some rule -> + ((rule,nm), + function x -> check_meta x; [Common.Right x]) in + kindfn ar rule ispure checker constraints) + ids) + +let create_metadec_ty ar ispure kindfn ids current_rule = + List.concat + (List.map + (function ((rule,nm),constraints) -> + let (rule,checker) = + match rule with + None -> ((current_rule,nm),function x -> [Common.Left x]) + | Some rule -> + ((rule,nm), + function x -> check_meta x; [Common.Right x]) in + kindfn ar rule ispure checker constraints) + ids) + +let create_len_metadec ar ispure kindfn lenid ids current_rule = + let lendec = + create_metadec Ast.NONE Ast0.Impure + (fun _ name _ check_meta -> check_meta(Ast.MetaListlenDecl(name))) + [lenid] current_rule in + let lenname = + match lendec with + [Common.Left (Ast.MetaListlenDecl(x))] -> x + | [Common.Right (Ast.MetaListlenDecl(x))] -> x + | _ -> failwith "unexpected length declaration" in + lendec@(create_metadec ar ispure (kindfn lenname) ids current_rule) + +(* ---------------------------------------------------------------------- *) + +let str2inc s = + let elements = Str.split (Str.regexp "/") s in + List.map (function "..." -> Ast.IncDots | s -> Ast.IncPath s) elements + +(* ---------------------------------------------------------------------- *) +(* statements *) + +let meta_stm name = + let (nm,pure,clt) = name in + Ast0.wrap(Ast0.MetaStmt(clt2mcode nm clt,pure)) + +let exp_stm exp pv = + Ast0.wrap(Ast0.ExprStatement (exp, clt2mcode ";" pv)) + +let ifthen iff lp tst rp thn = + Ast0.wrap(Ast0.IfThen(clt2mcode "if" iff, + clt2mcode "(" lp,tst,clt2mcode ")" rp,thn, + (Ast0.default_info(),Ast0.context_befaft()))) + +let ifthenelse iff lp tst rp thn e els = + Ast0.wrap(Ast0.IfThenElse(clt2mcode "if" iff, + clt2mcode "(" lp,tst,clt2mcode ")" rp,thn, + clt2mcode "else" e,els, + (Ast0.default_info(),Ast0.context_befaft()))) + +let forloop fr lp e1 sc1 e2 sc2 e3 rp s = + Ast0.wrap(Ast0.For(clt2mcode "for" fr,clt2mcode "(" lp,e1, + clt2mcode ";" sc1,e2, + clt2mcode ";" sc2,e3,clt2mcode ")" rp,s, + (Ast0.default_info(),Ast0.context_befaft()))) + +let whileloop w lp e rp s = + Ast0.wrap(Ast0.While(clt2mcode "while" w,clt2mcode "(" lp, + e,clt2mcode ")" rp,s, + (Ast0.default_info(),Ast0.context_befaft()))) + +let doloop d s w lp e rp pv = + Ast0.wrap(Ast0.Do(clt2mcode "do" d,s,clt2mcode "while" w, + clt2mcode "(" lp,e,clt2mcode ")" rp, + clt2mcode ";" pv)) + +let iterator i lp e rp s = + Ast0.wrap(Ast0.Iterator(i,clt2mcode "(" lp,e,clt2mcode ")" rp,s, + (Ast0.default_info(),Ast0.context_befaft()))) + +let switch s lp e rp lb c rb = + Ast0.wrap(Ast0.Switch(clt2mcode "switch" s,clt2mcode "(" lp,e, + clt2mcode ")" rp,clt2mcode "{" lb, + Ast0.wrap(Ast0.DOTS(c)),clt2mcode "}" rb)) + +let ret_exp r e pv = + Ast0.wrap(Ast0.ReturnExpr(clt2mcode "return" r,e,clt2mcode ";" pv)) + +let ret r pv = + Ast0.wrap(Ast0.Return(clt2mcode "return" r,clt2mcode ";" pv)) + +let break b pv = + Ast0.wrap(Ast0.Break(clt2mcode "break" b,clt2mcode ";" pv)) + +let cont c pv = + Ast0.wrap(Ast0.Continue(clt2mcode "continue" c,clt2mcode ";" pv)) + +let label i dd = + Ast0.wrap(Ast0.Label(i,clt2mcode ":" dd)) + +let goto g i pv = + Ast0.wrap(Ast0.Goto(clt2mcode "goto" g,i,clt2mcode ";" pv)) + +let seq lb s rb = + Ast0.wrap(Ast0.Seq(clt2mcode "{" lb,s,clt2mcode "}" rb)) + +(* ---------------------------------------------------------------------- *) + +let make_iso_rule_name_result n = + (try let _ = Hashtbl.find Data.all_metadecls n in + raise (Semantic_cocci.Semantic ("repeated rule name")) + with Not_found -> ()); + Ast.CocciRulename (Some n,Ast.NoDep,[],[],Ast.Undetermined,false (*discarded*)) + +let make_cocci_rule_name_result nm d i a e ee = + match nm with + Some nm -> + let n = id2name nm in + (try let _ = Hashtbl.find Data.all_metadecls n in + raise (Semantic_cocci.Semantic ("repeated rule name")) + with Not_found -> ()); + Ast.CocciRulename (Some n,d,i,a,e,ee) + | None -> Ast.CocciRulename (None,d,i,a,e,ee) + +let make_script_rule_name_result scr lang deps = + let s = id2name scr in + let l = id2name lang in + if s <> "script" then + raise (Semantic_cocci.Semantic ("malformed script rule")); + Ast.ScriptRulename (l,deps) diff --git a/parsing_cocci/parse_cocci.ml b/parsing_cocci/parse_cocci.ml new file mode 100644 index 0000000..45938ff --- /dev/null +++ b/parsing_cocci/parse_cocci.ml @@ -0,0 +1,1512 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* splits the entire file into minus and plus fragments, and parses each +separately (thus duplicating work for the parsing of the context elements) *) + +module D = Data +module PC = Parser_cocci_menhir +module V0 = Visitor_ast0 +module Ast = Ast_cocci +module Ast0 = Ast0_cocci +let pr = Printf.sprintf +(*let pr2 s = prerr_string s; prerr_string "\n"; flush stderr*) +let pr2 s = Printf.printf "%s\n" s + +(* for isomorphisms. all should be at the front!!! *) +let reserved_names = + ["all";"optional_storage";"optional_qualifier";"value_format";"comm_assoc"] + +(* ----------------------------------------------------------------------- *) +(* Debugging... *) + +let line_type (d,_,_,_,_,_,_,_) = d + +let line_type2c tok = + match line_type tok with + D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> ":-" + | D.PLUS -> ":+" + | D.CONTEXT | D.UNIQUE | D.OPT -> "" + +let token2c (tok,_) = + match tok with + PC.TIdentifier -> "identifier" + | PC.TType -> "type" + | PC.TParameter -> "parameter" + | PC.TConstant -> "constant" + | PC.TExpression -> "expression" + | PC.TIdExpression -> "idexpression" + | PC.TStatement -> "statement" + | PC.TPosition -> "position" + | PC.TPosAny -> "any" + | PC.TFunction -> "function" + | PC.TLocal -> "local" + | PC.Tlist -> "list" + | PC.TFresh -> "fresh" + | PC.TPure -> "pure" + | PC.TContext -> "context" + | PC.TTypedef -> "typedef" + | PC.TDeclarer -> "declarer" + | PC.TIterator -> "iterator" + | PC.TName -> "name" + | PC.TRuleName str -> "rule_name-"^str + | PC.TUsing -> "using" + | PC.TPathIsoFile str -> "path_iso_file-"^str + | PC.TDisable -> "disable" + | PC.TExtends -> "extends" + | PC.TDepends -> "depends" + | PC.TOn -> "on" + | PC.TEver -> "ever" + | PC.TNever -> "never" + | PC.TExists -> "exists" + | PC.TForall -> "forall" + | PC.TReverse -> "reverse" + | PC.TError -> "error" + | PC.TWords -> "words" + + | PC.TNothing -> "nothing" + + | PC.Tchar(clt) -> "char"^(line_type2c clt) + | PC.Tshort(clt) -> "short"^(line_type2c clt) + | PC.Tint(clt) -> "int"^(line_type2c clt) + | PC.Tdouble(clt) -> "double"^(line_type2c clt) + | PC.Tfloat(clt) -> "float"^(line_type2c clt) + | PC.Tlong(clt) -> "long"^(line_type2c clt) + | PC.Tvoid(clt) -> "void"^(line_type2c clt) + | PC.Tstruct(clt) -> "struct"^(line_type2c clt) + | PC.Tunion(clt) -> "union"^(line_type2c clt) + | PC.Tunsigned(clt) -> "unsigned"^(line_type2c clt) + | PC.Tsigned(clt) -> "signed"^(line_type2c clt) + | PC.Tstatic(clt) -> "static"^(line_type2c clt) + | PC.Tinline(clt) -> "inline"^(line_type2c clt) + | PC.Ttypedef(clt) -> "typedef"^(line_type2c clt) + | PC.Tattr(s,clt) -> s^(line_type2c clt) + | PC.Tauto(clt) -> "auto"^(line_type2c clt) + | PC.Tregister(clt) -> "register"^(line_type2c clt) + | PC.Textern(clt) -> "extern"^(line_type2c clt) + | PC.Tconst(clt) -> "const"^(line_type2c clt) + | PC.Tvolatile(clt) -> "volatile"^(line_type2c clt) + + | PC.TPragma(s) -> s + | PC.TIncludeL(s,clt) -> (pr "#include \"%s\"" s)^(line_type2c clt) + | PC.TIncludeNL(s,clt) -> (pr "#include <%s>" s)^(line_type2c clt) + | PC.TDefine(clt,_) -> "#define"^(line_type2c clt) + | PC.TDefineParam(clt,_,_) -> "#define_param"^(line_type2c clt) + | PC.TMinusFile(s,clt) -> (pr "--- %s" s)^(line_type2c clt) + | PC.TPlusFile(s,clt) -> (pr "+++ %s" s)^(line_type2c clt) + + | PC.TInc(clt) -> "++"^(line_type2c clt) + | PC.TDec(clt) -> "--"^(line_type2c clt) + + | PC.TIf(clt) -> "if"^(line_type2c clt) + | PC.TElse(clt) -> "else"^(line_type2c clt) + | PC.TWhile(clt) -> "while"^(line_type2c clt) + | PC.TFor(clt) -> "for"^(line_type2c clt) + | PC.TDo(clt) -> "do"^(line_type2c clt) + | PC.TSwitch(clt) -> "switch"^(line_type2c clt) + | PC.TCase(clt) -> "case"^(line_type2c clt) + | PC.TDefault(clt) -> "default"^(line_type2c clt) + | PC.TReturn(clt) -> "return"^(line_type2c clt) + | PC.TBreak(clt) -> "break"^(line_type2c clt) + | PC.TContinue(clt) -> "continue"^(line_type2c clt) + | PC.TGoto(clt) -> "goto"^(line_type2c clt) + | PC.TIdent(s,clt) -> (pr "ident-%s" s)^(line_type2c clt) + | PC.TTypeId(s,clt) -> (pr "typename-%s" s)^(line_type2c clt) + | PC.TDeclarerId(s,clt) -> (pr "declarername-%s" s)^(line_type2c clt) + | PC.TIteratorId(s,clt) -> (pr "iteratorname-%s" s)^(line_type2c clt) + | PC.TMetaDeclarer(_,_,_,clt) -> "declmeta"^(line_type2c clt) + | PC.TMetaIterator(_,_,_,clt) -> "itermeta"^(line_type2c clt) + + | PC.TSizeof(clt) -> "sizeof"^(line_type2c clt) + + | PC.TString(x,clt) -> x^(line_type2c clt) + | PC.TChar(x,clt) -> x^(line_type2c clt) + | PC.TFloat(x,clt) -> x^(line_type2c clt) + | PC.TInt(x,clt) -> x^(line_type2c clt) + + | PC.TOrLog(clt) -> "||"^(line_type2c clt) + | PC.TAndLog(clt) -> "&&"^(line_type2c clt) + | PC.TOr(clt) -> "|"^(line_type2c clt) + | PC.TXor(clt) -> "^"^(line_type2c clt) + | PC.TAnd (clt) -> "&"^(line_type2c clt) + | PC.TEqEq(clt) -> "=="^(line_type2c clt) + | PC.TNotEq(clt) -> "!="^(line_type2c clt) + | PC.TLogOp(op,clt) -> + (match op with + Ast.Inf -> "<" + | Ast.InfEq -> "<=" + | Ast.Sup -> ">" + | Ast.SupEq -> ">=" + | _ -> failwith "not possible") + ^(line_type2c clt) + | PC.TShOp(op,clt) -> + (match op with + Ast.DecLeft -> "<<" + | Ast.DecRight -> ">>" + | _ -> failwith "not possible") + ^(line_type2c clt) + | PC.TPlus(clt) -> "+"^(line_type2c clt) + | PC.TMinus(clt) -> "-"^(line_type2c clt) + | PC.TMul(clt) -> "*"^(line_type2c clt) + | PC.TDmOp(op,clt) -> + (match op with + Ast.Div -> "/" + | Ast.Mod -> "%" + | _ -> failwith "not possible") + ^(line_type2c clt) + | PC.TTilde (clt) -> "~"^(line_type2c clt) + + | PC.TMetaParam(_,_,clt) -> "parammeta"^(line_type2c clt) + | PC.TMetaParamList(_,_,_,clt) -> "paramlistmeta"^(line_type2c clt) + | PC.TMetaConst(_,_,_,_,clt) -> "constmeta"^(line_type2c clt) + | PC.TMetaErr(_,_,_,clt) -> "errmeta"^(line_type2c clt) + | PC.TMetaExp(_,_,_,_,clt) -> "expmeta"^(line_type2c clt) + | PC.TMetaIdExp(_,_,_,_,clt) -> "idexpmeta"^(line_type2c clt) + | PC.TMetaLocalIdExp(_,_,_,_,clt) -> "localidexpmeta"^(line_type2c clt) + | PC.TMetaExpList(_,_,_,clt) -> "explistmeta"^(line_type2c clt) + | PC.TMetaId(_,_,_,clt) -> "idmeta"^(line_type2c clt) + | PC.TMetaType(_,_,clt) -> "typemeta"^(line_type2c clt) + | PC.TMetaStm(_,_,clt) -> "stmmeta"^(line_type2c clt) + | PC.TMetaStmList(_,_,clt) -> "stmlistmeta"^(line_type2c clt) + | PC.TMetaFunc(_,_,_,clt) -> "funcmeta"^(line_type2c clt) + | PC.TMetaLocalFunc(_,_,_,clt) -> "funcmeta"^(line_type2c clt) + | PC.TMetaPos(_,_,_,clt) -> "posmeta" + | PC.TMPtVirg -> ";" + | PC.TArobArob -> "@@" + | PC.TArob -> "@" + | PC.TPArob -> "P@" + + | PC.TWhen(clt) -> "WHEN"^(line_type2c clt) + | PC.TAny(clt) -> "ANY"^(line_type2c clt) + | PC.TStrict(clt) -> "STRICT"^(line_type2c clt) + | PC.TEllipsis(clt) -> "..."^(line_type2c clt) +(* + | PC.TCircles(clt) -> "ooo"^(line_type2c clt) + | PC.TStars(clt) -> "***"^(line_type2c clt) +*) + + | PC.TOEllipsis(clt) -> "<..."^(line_type2c clt) + | PC.TCEllipsis(clt) -> "...>"^(line_type2c clt) + | PC.TPOEllipsis(clt) -> "<+..."^(line_type2c clt) + | PC.TPCEllipsis(clt) -> "...+>"^(line_type2c clt) +(* + | PC.TOCircles(clt) -> " "ooo>"^(line_type2c clt) + | PC.TOStars(clt) -> "<***"^(line_type2c clt) + | PC.TCStars(clt) -> "***>"^(line_type2c clt) +*) + | PC.TBang0 -> "!" + | PC.TPlus0 -> "+" + | PC.TWhy0 -> "?" + + | PC.TWhy(clt) -> "?"^(line_type2c clt) + | PC.TDotDot(clt) -> ":"^(line_type2c clt) + | PC.TBang(clt) -> "!"^(line_type2c clt) + | PC.TOPar(clt) -> "("^(line_type2c clt) + | PC.TOPar0(clt) -> "("^(line_type2c clt) + | PC.TMid0(clt) -> "|"^(line_type2c clt) + | PC.TCPar(clt) -> ")"^(line_type2c clt) + | PC.TCPar0(clt) -> ")"^(line_type2c clt) + + | PC.TOBrace(clt) -> "{"^(line_type2c clt) + | PC.TCBrace(clt) -> "}"^(line_type2c clt) + | PC.TOCro(clt) -> "["^(line_type2c clt) + | PC.TCCro(clt) -> "]"^(line_type2c clt) + + | PC.TPtrOp(clt) -> "->"^(line_type2c clt) + + | PC.TEq(clt) -> "="^(line_type2c clt) + | PC.TAssign(_,clt) -> "=op"^(line_type2c clt) + | PC.TDot(clt) -> "."^(line_type2c clt) + | PC.TComma(clt) -> ","^(line_type2c clt) + | PC.TPtVirg(clt) -> ";"^(line_type2c clt) + + | PC.EOF -> "eof" + | PC.TLineEnd(clt) -> "line end" + | PC.TInvalid -> "invalid" + | PC.TFunDecl(clt) -> "fundecl" + + | PC.TIso -> "<=>" + | PC.TRightIso -> "=>" + | PC.TIsoTopLevel -> "TopLevel" + | PC.TIsoExpression -> "Expression" + | PC.TIsoArgExpression -> "ArgExpression" + | PC.TIsoTestExpression -> "TestExpression" + | PC.TIsoStatement -> "Statement" + | PC.TIsoDeclaration -> "Declaration" + | PC.TIsoType -> "Type" + | PC.TScriptData s -> s + +let print_tokens s tokens = + Printf.printf "%s\n" s; + List.iter (function x -> Printf.printf "%s " (token2c x)) tokens; + Printf.printf "\n\n"; + flush stdout + +type plus = PLUS | NOTPLUS | SKIP + +let plus_attachable (tok,_) = + match tok with + PC.Tchar(clt) | PC.Tshort(clt) | PC.Tint(clt) | PC.Tdouble(clt) + | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt) | PC.Tstruct(clt) + | PC.Tunion(clt) | PC.Tunsigned(clt) | PC.Tsigned(clt) | PC.Tstatic(clt) + | PC.Tinline(clt) | PC.Ttypedef(clt) | PC.Tattr(_,clt) + | PC.Tauto(clt) | PC.Tregister(clt) + | PC.Textern(clt) | PC.Tconst(clt) | PC.Tvolatile(clt) + + | PC.TIncludeL(_,clt) | PC.TIncludeNL(_,clt) | PC.TDefine(clt,_) + | PC.TDefineParam(clt,_,_) | PC.TMinusFile(_,clt) | PC.TPlusFile(_,clt) + + | PC.TInc(clt) | PC.TDec(clt) + + | PC.TIf(clt) | PC.TElse(clt) | PC.TWhile(clt) | PC.TFor(clt) | PC.TDo(clt) + | PC.TSwitch(clt) | PC.TCase(clt) | PC.TDefault(clt) | PC.TReturn(clt) + | PC.TBreak(clt) | PC.TContinue(clt) | PC.TGoto(clt) | PC.TIdent(_,clt) + | PC.TTypeId(_,clt) | PC.TDeclarerId(_,clt) | PC.TIteratorId(_,clt) + + | PC.TSizeof(clt) + + | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt) + + | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt) + | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt) + | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt) + | PC.TDmOp(_,clt) | PC.TTilde (clt) + + | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt) + | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaErr(_,_,_,clt) + | PC.TMetaExp(_,_,_,_,clt) | PC.TMetaIdExp(_,_,_,_,clt) + | PC.TMetaLocalIdExp(_,_,_,_,clt) + | PC.TMetaExpList(_,_,_,clt) + | PC.TMetaId(_,_,_,clt) + | PC.TMetaType(_,_,clt) | PC.TMetaStm(_,_,clt) + | PC.TMetaStmList(_,_,clt) | PC.TMetaFunc(_,_,_,clt) + | PC.TMetaLocalFunc(_,_,_,clt) + + | PC.TWhen(clt) | PC.TAny(clt) | PC.TStrict(clt) | PC.TEllipsis(clt) + (* | PC.TCircles(clt) | PC.TStars(clt) *) + + | PC.TWhy(clt) | PC.TDotDot(clt) | PC.TBang(clt) | PC.TOPar(clt) + | PC.TCPar(clt) + + | PC.TOBrace(clt) | PC.TCBrace(clt) | PC.TOCro(clt) | PC.TCCro(clt) + + | PC.TPtrOp(clt) + + | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt) + | PC.TPtVirg(clt) -> + if line_type clt = D.PLUS then PLUS else NOTPLUS + + | PC.TOPar0(clt) | PC.TMid0(clt) | PC.TCPar0(clt) + | PC.TOEllipsis(clt) | PC.TCEllipsis(clt) + | PC.TPOEllipsis(clt) | PC.TPCEllipsis(clt) (* | PC.TOCircles(clt) + | PC.TCCircles(clt) | PC.TOStars(clt) | PC.TCStars(clt) *) -> NOTPLUS + | PC.TMetaPos(nm,_,_,_) -> NOTPLUS + + | _ -> SKIP + +let get_clt (tok,_) = + match tok with + PC.Tchar(clt) | PC.Tshort(clt) | PC.Tint(clt) | PC.Tdouble(clt) + | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt) | PC.Tstruct(clt) + | PC.Tunion(clt) | PC.Tunsigned(clt) | PC.Tsigned(clt) | PC.Tstatic(clt) + | PC.Tinline(clt) | PC.Tattr(_,clt) | PC.Tauto(clt) | PC.Tregister(clt) + | PC.Textern(clt) | PC.Tconst(clt) | PC.Tvolatile(clt) + + | PC.TIncludeL(_,clt) | PC.TIncludeNL(_,clt) | PC.TDefine(clt,_) + | PC.TDefineParam(clt,_,_) | PC.TMinusFile(_,clt) | PC.TPlusFile(_,clt) + + | PC.TInc(clt) | PC.TDec(clt) + + | PC.TIf(clt) | PC.TElse(clt) | PC.TWhile(clt) | PC.TFor(clt) | PC.TDo(clt) + | PC.TSwitch(clt) | PC.TCase(clt) | PC.TDefault(clt) | PC.TReturn(clt) + | PC.TBreak(clt) | PC.TContinue(clt) | PC.TGoto(clt) | PC.TIdent(_,clt) + | PC.TTypeId(_,clt) | PC.TDeclarerId(_,clt) | PC.TIteratorId(_,clt) + + | PC.TSizeof(clt) + + | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt) + + | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt) + | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt) + | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt) + | PC.TDmOp(_,clt) | PC.TTilde (clt) + + | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt) + | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaErr(_,_,_,clt) + | PC.TMetaExp(_,_,_,_,clt) | PC.TMetaIdExp(_,_,_,_,clt) + | PC.TMetaLocalIdExp(_,_,_,_,clt) + | PC.TMetaExpList(_,_,_,clt) + | PC.TMetaId(_,_,_,clt) + | PC.TMetaType(_,_,clt) | PC.TMetaStm(_,_,clt) + | PC.TMetaStmList(_,_,clt) | PC.TMetaFunc(_,_,_,clt) + | PC.TMetaLocalFunc(_,_,_,clt) | PC.TMetaPos(_,_,_,clt) + + | PC.TWhen(clt) | PC.TAny(clt) | PC.TStrict(clt) | PC.TEllipsis(clt) + (* | PC.TCircles(clt) | PC.TStars(clt) *) + + | PC.TWhy(clt) | PC.TDotDot(clt) | PC.TBang(clt) | PC.TOPar(clt) + | PC.TCPar(clt) + + | PC.TOBrace(clt) | PC.TCBrace(clt) | PC.TOCro(clt) | PC.TCCro(clt) + + | PC.TPtrOp(clt) + + | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt) + | PC.TPtVirg(clt) + + | PC.TOPar0(clt) | PC.TMid0(clt) | PC.TCPar0(clt) + | PC.TOEllipsis(clt) | PC.TCEllipsis(clt) + | PC.TPOEllipsis(clt) | PC.TPCEllipsis(clt) (* | PC.TOCircles(clt) + | PC.TCCircles(clt) | PC.TOStars(clt) | PC.TCStars(clt) *) -> clt + + | _ -> failwith "no clt" + +let update_clt (tok,x) clt = + match tok with + PC.Tchar(_) -> (PC.Tchar(clt),x) + | PC.Tshort(_) -> (PC.Tshort(clt),x) + | PC.Tint(_) -> (PC.Tint(clt),x) + | PC.Tdouble(_) -> (PC.Tdouble(clt),x) + | PC.Tfloat(_) -> (PC.Tfloat(clt),x) + | PC.Tlong(_) -> (PC.Tlong(clt),x) + | PC.Tvoid(_) -> (PC.Tvoid(clt),x) + | PC.Tstruct(_) -> (PC.Tstruct(clt),x) + | PC.Tunion(_) -> (PC.Tunion(clt),x) + | PC.Tunsigned(_) -> (PC.Tunsigned(clt),x) + | PC.Tsigned(_) -> (PC.Tsigned(clt),x) + | PC.Tstatic(_) -> (PC.Tstatic(clt),x) + | PC.Tinline(_) -> (PC.Tinline(clt),x) + | PC.Ttypedef(_) -> (PC.Ttypedef(clt),x) + | PC.Tattr(s,_) -> (PC.Tattr(s,clt),x) + | PC.Tauto(_) -> (PC.Tauto(clt),x) + | PC.Tregister(_) -> (PC.Tregister(clt),x) + | PC.Textern(_) -> (PC.Textern(clt),x) + | PC.Tconst(_) -> (PC.Tconst(clt),x) + | PC.Tvolatile(_) -> (PC.Tvolatile(clt),x) + + | PC.TIncludeL(s,_) -> (PC.TIncludeL(s,clt),x) + | PC.TIncludeNL(s,_) -> (PC.TIncludeNL(s,clt),x) + | PC.TDefine(_,a) -> (PC.TDefine(clt,a),x) + | PC.TDefineParam(_,a,b) -> (PC.TDefineParam(clt,a,b),x) + | PC.TMinusFile(s,_) -> (PC.TMinusFile(s,clt),x) + | PC.TPlusFile(s,_) -> (PC.TPlusFile(s,clt),x) + + | PC.TInc(_) -> (PC.TInc(clt),x) + | PC.TDec(_) -> (PC.TDec(clt),x) + + | PC.TIf(_) -> (PC.TIf(clt),x) + | PC.TElse(_) -> (PC.TElse(clt),x) + | PC.TWhile(_) -> (PC.TWhile(clt),x) + | PC.TFor(_) -> (PC.TFor(clt),x) + | PC.TDo(_) -> (PC.TDo(clt),x) + | PC.TSwitch(_) -> (PC.TSwitch(clt),x) + | PC.TCase(_) -> (PC.TCase(clt),x) + | PC.TDefault(_) -> (PC.TDefault(clt),x) + | PC.TReturn(_) -> (PC.TReturn(clt),x) + | PC.TBreak(_) -> (PC.TBreak(clt),x) + | PC.TContinue(_) -> (PC.TContinue(clt),x) + | PC.TGoto(_) -> (PC.TGoto(clt),x) + | PC.TIdent(s,_) -> (PC.TIdent(s,clt),x) + | PC.TTypeId(s,_) -> (PC.TTypeId(s,clt),x) + | PC.TDeclarerId(s,_) -> (PC.TDeclarerId(s,clt),x) + | PC.TIteratorId(s,_) -> (PC.TIteratorId(s,clt),x) + + | PC.TSizeof(_) -> (PC.TSizeof(clt),x) + + | PC.TString(s,_) -> (PC.TString(s,clt),x) + | PC.TChar(s,_) -> (PC.TChar(s,clt),x) + | PC.TFloat(s,_) -> (PC.TFloat(s,clt),x) + | PC.TInt(s,_) -> (PC.TInt(s,clt),x) + + | PC.TOrLog(_) -> (PC.TOrLog(clt),x) + | PC.TAndLog(_) -> (PC.TAndLog(clt),x) + | PC.TOr(_) -> (PC.TOr(clt),x) + | PC.TXor(_) -> (PC.TXor(clt),x) + | PC.TAnd (_) -> (PC.TAnd (clt),x) + | PC.TEqEq(_) -> (PC.TEqEq(clt),x) + | PC.TNotEq(_) -> (PC.TNotEq(clt),x) + | PC.TLogOp(op,_) -> (PC.TLogOp(op,clt),x) + | PC.TShOp(op,_) -> (PC.TShOp(op,clt),x) + | PC.TPlus(_) -> (PC.TPlus(clt),x) + | PC.TMinus(_) -> (PC.TMinus(clt),x) + | PC.TMul(_) -> (PC.TMul(clt),x) + | PC.TDmOp(op,_) -> (PC.TDmOp(op,clt),x) + | PC.TTilde (_) -> (PC.TTilde (clt),x) + + | PC.TMetaParam(a,b,_) -> (PC.TMetaParam(a,b,clt),x) + | PC.TMetaParamList(a,b,c,_) -> (PC.TMetaParamList(a,b,c,clt),x) + | PC.TMetaConst(a,b,c,d,_) -> (PC.TMetaConst(a,b,c,d,clt),x) + | PC.TMetaErr(a,b,c,_) -> (PC.TMetaErr(a,b,c,clt),x) + | PC.TMetaExp(a,b,c,d,_) -> (PC.TMetaExp(a,b,c,d,clt),x) + | PC.TMetaIdExp(a,b,c,d,_) -> (PC.TMetaIdExp(a,b,c,d,clt),x) + | PC.TMetaLocalIdExp(a,b,c,d,_) -> (PC.TMetaLocalIdExp(a,b,c,d,clt),x) + | PC.TMetaExpList(a,b,c,_) -> (PC.TMetaExpList(a,b,c,clt),x) + | PC.TMetaId(a,b,c,_) -> (PC.TMetaId(a,b,c,clt),x) + | PC.TMetaType(a,b,_) -> (PC.TMetaType(a,b,clt),x) + | PC.TMetaStm(a,b,_) -> (PC.TMetaStm(a,b,clt),x) + | PC.TMetaStmList(a,b,_) -> (PC.TMetaStmList(a,b,clt),x) + | PC.TMetaFunc(a,b,c,_) -> (PC.TMetaFunc(a,b,c,clt),x) + | PC.TMetaLocalFunc(a,b,c,_) -> (PC.TMetaLocalFunc(a,b,c,clt),x) + + | PC.TWhen(_) -> (PC.TWhen(clt),x) + | PC.TAny(_) -> (PC.TAny(clt),x) + | PC.TStrict(_) -> (PC.TStrict(clt),x) + | PC.TEllipsis(_) -> (PC.TEllipsis(clt),x) +(* + | PC.TCircles(_) -> (PC.TCircles(clt),x) + | PC.TStars(_) -> (PC.TStars(clt),x) +*) + + | PC.TOEllipsis(_) -> (PC.TOEllipsis(clt),x) + | PC.TCEllipsis(_) -> (PC.TCEllipsis(clt),x) + | PC.TPOEllipsis(_) -> (PC.TPOEllipsis(clt),x) + | PC.TPCEllipsis(_) -> (PC.TPCEllipsis(clt),x) +(* + | PC.TOCircles(_) -> (PC.TOCircles(clt),x) + | PC.TCCircles(_) -> (PC.TCCircles(clt),x) + | PC.TOStars(_) -> (PC.TOStars(clt),x) + | PC.TCStars(_) -> (PC.TCStars(clt),x) +*) + + | PC.TWhy(_) -> (PC.TWhy(clt),x) + | PC.TDotDot(_) -> (PC.TDotDot(clt),x) + | PC.TBang(_) -> (PC.TBang(clt),x) + | PC.TOPar(_) -> (PC.TOPar(clt),x) + | PC.TOPar0(_) -> (PC.TOPar0(clt),x) + | PC.TMid0(_) -> (PC.TMid0(clt),x) + | PC.TCPar(_) -> (PC.TCPar(clt),x) + | PC.TCPar0(_) -> (PC.TCPar0(clt),x) + + | PC.TOBrace(_) -> (PC.TOBrace(clt),x) + | PC.TCBrace(_) -> (PC.TCBrace(clt),x) + | PC.TOCro(_) -> (PC.TOCro(clt),x) + | PC.TCCro(_) -> (PC.TCCro(clt),x) + + | PC.TPtrOp(_) -> (PC.TPtrOp(clt),x) + + | PC.TEq(_) -> (PC.TEq(clt),x) + | PC.TAssign(s,_) -> (PC.TAssign(s,clt),x) + | PC.TDot(_) -> (PC.TDot(clt),x) + | PC.TComma(_) -> (PC.TComma(clt),x) + | PC.TPtVirg(_) -> (PC.TPtVirg(clt),x) + + | PC.TLineEnd(_) -> (PC.TLineEnd(clt),x) + | PC.TFunDecl(_) -> (PC.TFunDecl(clt),x) + + | _ -> failwith "no clt" + + +(* ----------------------------------------------------------------------- *) + +let make_name prefix ln = Printf.sprintf "%s starting on line %d" prefix ln + +(* ----------------------------------------------------------------------- *) +(* Read tokens *) + +let wrap_lexbuf_info lexbuf = + (Lexing.lexeme lexbuf, Lexing.lexeme_start lexbuf) + +let tokens_all_full token table file get_ats lexbuf end_markers : + (bool * ((PC.token * (string * (int * int) * (int * int))) list)) = + try + let rec aux () = + let result = token lexbuf in + let info = (Lexing.lexeme lexbuf, + (table.(Lexing.lexeme_start lexbuf)), + (Lexing.lexeme_start lexbuf, Lexing.lexeme_end lexbuf)) in + if result = PC.EOF + then + if get_ats + then failwith "unexpected end of file in a metavariable declaration" + else (false,[(result,info)]) + else if List.mem result end_markers + then (true,[(result,info)]) + else + let (more,rest) = aux() in + (more,(result, info)::rest) + in aux () + with + e -> pr2 (Common.error_message file (wrap_lexbuf_info lexbuf) ); raise e + +let tokens_all table file get_ats lexbuf end_markers : + (bool * ((PC.token * (string * (int * int) * (int * int))) list)) = + tokens_all_full Lexer_cocci.token table file get_ats lexbuf end_markers + +let tokens_script_all table file get_ats lexbuf end_markers : + (bool * ((PC.token * (string * (int * int) * (int * int))) list)) = + tokens_all_full Lexer_script.token table file get_ats lexbuf end_markers + +(* ----------------------------------------------------------------------- *) +(* Split tokens into minus and plus fragments *) + +let split t clt = + let (d,_,_,_,_,_,_,_) = clt in + match d with + D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> ([t],[]) + | D.PLUS -> ([],[t]) + | D.CONTEXT | D.UNIQUE | D.OPT -> ([t],[t]) + +let split_token ((tok,_) as t) = + match tok with + PC.TIdentifier | PC.TConstant | PC.TExpression | PC.TIdExpression + | PC.TStatement | PC.TPosition | PC.TPosAny + | PC.TFunction | PC.TTypedef | PC.TDeclarer | PC.TIterator | PC.TName + | PC.TType | PC.TParameter | PC.TLocal | PC.Tlist | PC.TFresh | PC.TPure + | PC.TContext | PC.TRuleName(_) | PC.TUsing | PC.TDisable | PC.TExtends + | PC.TPathIsoFile(_) + | PC.TDepends | PC.TOn | PC.TEver | PC.TNever | PC.TExists | PC.TForall + | PC.TReverse + | PC.TError | PC.TWords | PC.TNothing -> ([t],[t]) + + | PC.Tchar(clt) | PC.Tshort(clt) | PC.Tint(clt) | PC.Tdouble(clt) + | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt) | PC.Tstruct(clt) + | PC.Tunion(clt) | PC.Tunsigned(clt) | PC.Tsigned(clt) + | PC.Tstatic(clt) | PC.Tauto(clt) | PC.Tregister(clt) | PC.Textern(clt) + | PC.Tinline(clt) | PC.Ttypedef(clt) | PC.Tattr(_,clt) + | PC.Tconst(clt) | PC.Tvolatile(clt) -> split t clt + + | PC.TPragma(s) -> ([],[t]) (* only allowed in + *) + | PC.TPlusFile(s,clt) | PC.TMinusFile(s,clt) + | PC.TIncludeL(s,clt) | PC.TIncludeNL(s,clt) -> + split t clt + | PC.TDefine(clt,_) | PC.TDefineParam(clt,_,_) -> split t clt + + | PC.TIf(clt) | PC.TElse(clt) | PC.TWhile(clt) | PC.TFor(clt) | PC.TDo(clt) + | PC.TSwitch(clt) | PC.TCase(clt) | PC.TDefault(clt) + | PC.TSizeof(clt) + | PC.TReturn(clt) | PC.TBreak(clt) | PC.TContinue(clt) | PC.TGoto(clt) + | PC.TIdent(_,clt) + | PC.TTypeId(_,clt) | PC.TDeclarerId(_,clt) | PC.TIteratorId(_,clt) + | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaExp(_,_,_,_,clt) + | PC.TMetaIdExp(_,_,_,_,clt) | PC.TMetaLocalIdExp(_,_,_,_,clt) + | PC.TMetaExpList(_,_,_,clt) + | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt) + | PC.TMetaId(_,_,_,clt) | PC.TMetaType(_,_,clt) + | PC.TMetaStm(_,_,clt) | PC.TMetaStmList(_,_,clt) | PC.TMetaErr(_,_,_,clt) + | PC.TMetaFunc(_,_,_,clt) | PC.TMetaLocalFunc(_,_,_,clt) + | PC.TMetaDeclarer(_,_,_,clt) | PC.TMetaIterator(_,_,_,clt) -> split t clt + | PC.TMPtVirg | PC.TArob | PC.TArobArob -> ([t],[t]) + | PC.TPArob | PC.TMetaPos(_,_,_,_) -> ([t],[]) + + | PC.TFunDecl(clt) + | PC.TWhen(clt) | PC.TAny(clt) | PC.TStrict(clt) | PC.TLineEnd(clt) + | PC.TEllipsis(clt) (* | PC.TCircles(clt) | PC.TStars(clt) *) -> split t clt + + | PC.TOEllipsis(_) | PC.TCEllipsis(_) (* clt must be context *) + | PC.TPOEllipsis(_) | PC.TPCEllipsis(_) (* clt must be context *) +(* + | PC.TOCircles(_) | PC.TCCircles(_) (* clt must be context *) + | PC.TOStars(_) | PC.TCStars(_) (* clt must be context *) +*) + | PC.TBang0 | PC.TPlus0 | PC.TWhy0 -> + ([t],[t]) + + | PC.TWhy(clt) | PC.TDotDot(clt) + | PC.TBang(clt) | PC.TOPar(clt) | PC.TOPar0(clt) + | PC.TMid0(clt) | PC.TCPar(clt) | PC.TCPar0(clt) -> split t clt + + | PC.TInc(clt) | PC.TDec(clt) -> split t clt + + | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt) -> + split t clt + + | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt) + | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt) + | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt) + | PC.TDmOp(_,clt) | PC.TTilde (clt) -> split t clt + + | PC.TOBrace(clt) | PC.TCBrace(clt) -> split t clt + | PC.TOCro(clt) | PC.TCCro(clt) -> split t clt + + | PC.TPtrOp(clt) -> split t clt + + | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt) + | PC.TPtVirg(clt) -> split t clt + + | PC.EOF | PC.TInvalid -> ([t],[t]) + + | PC.TIso | PC.TRightIso + | PC.TIsoExpression | PC.TIsoStatement | PC.TIsoDeclaration | PC.TIsoType + | PC.TIsoTopLevel | PC.TIsoArgExpression | PC.TIsoTestExpression -> + failwith "unexpected tokens" + | PC.TScriptData s -> ([t],[t]) + +let split_token_stream tokens = + let rec loop = function + [] -> ([],[]) + | token::tokens -> + let (minus,plus) = split_token token in + let (minus_stream,plus_stream) = loop tokens in + (minus@minus_stream,plus@plus_stream) in + loop tokens + +(* ----------------------------------------------------------------------- *) +(* Find function names *) +(* This addresses a shift-reduce problem in the parser, allowing us to +distinguish a function declaration from a function call even if the latter +has no return type. Undoubtedly, this is not very nice, but it doesn't +seem very convenient to refactor the grammar to get around the problem. *) + +let rec find_function_names = function + [] -> [] + | ((PC.TIdent(_,clt),info) as t1) :: ((PC.TOPar(_),_) as t2) :: rest + | ((PC.TMetaId(_,_,_,clt),info) as t1) :: ((PC.TOPar(_),_) as t2) :: rest + | ((PC.TMetaFunc(_,_,_,clt),info) as t1) :: ((PC.TOPar(_),_) as t2) :: rest + | ((PC.TMetaLocalFunc(_,_,_,clt),info) as t1)::((PC.TOPar(_),_) as t2)::rest + -> + let rec skip level = function + [] -> ([],false,[]) + | ((PC.TCPar(_),_) as t)::rest -> + let level = level - 1 in + if level = 0 + then ([t],true,rest) + else let (pre,found,post) = skip level rest in (t::pre,found,post) + | ((PC.TOPar(_),_) as t)::rest -> + let level = level + 1 in + let (pre,found,post) = skip level rest in (t::pre,found,post) + | ((PC.TArobArob,_) as t)::rest + | ((PC.TArob,_) as t)::rest + | ((PC.EOF,_) as t)::rest -> ([t],false,rest) + | t::rest -> + let (pre,found,post) = skip level rest in (t::pre,found,post) in + let (pre,found,post) = skip 1 rest in + (match (found,post) with + (true,((PC.TOBrace(_),_) as t3)::rest) -> + (PC.TFunDecl(clt),info) :: t1 :: t2 :: pre @ + t3 :: (find_function_names rest) + | _ -> t1 :: t2 :: pre @ find_function_names post) + | t :: rest -> t :: find_function_names rest + +(* ----------------------------------------------------------------------- *) +(* an attribute is an identifier that preceeds another identifier and + begins with __ *) + +let rec detect_attr l = + let is_id = function + (PC.TIdent(_,_),_) | (PC.TMetaId(_,_,_,_),_) | (PC.TMetaFunc(_,_,_,_),_) + | (PC.TMetaLocalFunc(_,_,_,_),_) -> true + | _ -> false in + let rec loop = function + [] -> [] + | [x] -> [x] + | ((PC.TIdent(nm,clt),info) as t1)::id::rest when is_id id -> + if String.length nm > 2 && String.sub nm 0 2 = "__" + then (PC.Tattr(nm,clt),info)::(loop (id::rest)) + else t1::(loop (id::rest)) + | x::xs -> x::(loop xs) in + loop l + +(* ----------------------------------------------------------------------- *) +(* Look for variable declarations where the name is a typedef name. +We assume that C code does not contain a multiplication as a top-level +statement. *) + +(* bug: once a type, always a type, even if the same name is later intended + to be used as a real identifier *) +let detect_types in_meta_decls l = + let is_delim infn = function + (PC.TOEllipsis(_),_) (* | (PC.TOCircles(_),_) | (PC.TOStars(_),_) *) + | (PC.TPOEllipsis(_),_) (* | (PC.TOCircles(_),_) | (PC.TOStars(_),_) *) + | (PC.TEllipsis(_),_) (* | (PC.TCircles(_),_) | (PC.TStars(_),_) *) + | (PC.TPtVirg(_),_) | (PC.TOBrace(_),_) | (PC.TCBrace(_),_) + | (PC.TPure,_) | (PC.TContext,_) + | (PC.Tstatic(_),_) | (PC.Textern(_),_) + | (PC.Tinline(_),_) | (PC.Ttypedef(_),_) | (PC.Tattr(_),_) -> true + | (PC.TComma(_),_) when infn > 0 or in_meta_decls -> true + | (PC.TDotDot(_),_) when in_meta_decls -> true + | _ -> false in + let is_choices_delim = function + (PC.TOBrace(_),_) | (PC.TComma(_),_) -> true | _ -> false in + let is_id = function + (PC.TIdent(_,_),_) | (PC.TMetaId(_,_,_,_),_) | (PC.TMetaFunc(_,_,_,_),_) + | (PC.TMetaLocalFunc(_,_,_,_),_) -> true + | (PC.TMetaParam(_,_,_),_) + | (PC.TMetaParamList(_,_,_,_),_) + | (PC.TMetaConst(_,_,_,_,_),_) + | (PC.TMetaErr(_,_,_,_),_) + | (PC.TMetaExp(_,_,_,_,_),_) + | (PC.TMetaIdExp(_,_,_,_,_),_) + | (PC.TMetaLocalIdExp(_,_,_,_,_),_) + | (PC.TMetaExpList(_,_,_,_),_) + | (PC.TMetaType(_,_,_),_) + | (PC.TMetaStm(_,_,_),_) + | (PC.TMetaStmList(_,_,_),_) + | (PC.TMetaPos(_,_,_,_),_) -> in_meta_decls + | _ -> false in + let redo_id ident clt v = + !Data.add_type_name ident; + (PC.TTypeId(ident,clt),v) in + let rec loop start infn type_names = function + (* infn: 0 means not in a function header + > 0 means in a function header, after infn - 1 unmatched open parens*) + [] -> [] + | ((PC.TOBrace(clt),v)::_) as all when in_meta_decls -> + collect_choices type_names all (* never a function header *) + | delim::(PC.TIdent(ident,clt),v)::((PC.TMul(_),_) as x)::rest + when is_delim infn delim -> + let newid = redo_id ident clt v in + delim::newid::x::(loop false infn (ident::type_names) rest) + | delim::(PC.TIdent(ident,clt),v)::id::rest + when is_delim infn delim && is_id id -> + let newid = redo_id ident clt v in + delim::newid::id::(loop false infn (ident::type_names) rest) + | ((PC.TFunDecl(_),_) as fn)::rest -> + fn::(loop false 1 type_names rest) + | ((PC.TOPar(_),_) as lp)::rest when infn > 0 -> + lp::(loop false (infn + 1) type_names rest) + | ((PC.TCPar(_),_) as rp)::rest when infn > 0 -> + if infn - 1 = 1 + then rp::(loop false 0 type_names rest) (* 0 means not in fn header *) + else rp::(loop false (infn - 1) type_names rest) + | (PC.TIdent(ident,clt),v)::((PC.TMul(_),_) as x)::rest when start -> + let newid = redo_id ident clt v in + newid::x::(loop false infn (ident::type_names) rest) + | (PC.TIdent(ident,clt),v)::id::rest when start && is_id id -> + let newid = redo_id ident clt v in + newid::id::(loop false infn (ident::type_names) rest) + | (PC.TIdent(ident,clt),v)::rest when List.mem ident type_names -> + (PC.TTypeId(ident,clt),v)::(loop false infn type_names rest) + | ((PC.TIdent(ident,clt),v) as x)::rest -> + x::(loop false infn type_names rest) + | x::rest -> x::(loop false infn type_names rest) + and collect_choices type_names = function + [] -> [] (* should happen, but let the parser detect that *) + | (PC.TCBrace(clt),v)::rest -> + (PC.TCBrace(clt),v)::(loop false 0 type_names rest) + | delim::(PC.TIdent(ident,clt),v)::rest + when is_choices_delim delim -> + let newid = redo_id ident clt v in + delim::newid::(collect_choices (ident::type_names) rest) + | x::rest -> x::(collect_choices type_names rest) in + loop true 0 [] l + + +(* ----------------------------------------------------------------------- *) +(* Insert TLineEnd tokens at the end of a line that contains a WHEN. + WHEN is restricted to a single line, to avoid ambiguity in eg: + ... WHEN != x + +3 *) + +let token2line (tok,_) = + match tok with + PC.Tchar(clt) | PC.Tshort(clt) | PC.Tint(clt) | PC.Tdouble(clt) + | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt) | PC.Tstruct(clt) + | PC.Tunion(clt) | PC.Tunsigned(clt) | PC.Tsigned(clt) + | PC.Tstatic(clt) | PC.Tauto(clt) | PC.Tregister(clt) | PC.Textern(clt) + | PC.Tinline(clt) | PC.Ttypedef(clt) | PC.Tattr(_,clt) | PC.Tconst(clt) + | PC.Tvolatile(clt) + + | PC.TInc(clt) | PC.TDec(clt) + + | PC.TIf(clt) | PC.TElse(clt) | PC.TWhile(clt) | PC.TFor(clt) | PC.TDo(clt) + | PC.TSwitch (clt) | PC.TCase (clt) | PC.TDefault (clt) | PC.TSizeof (clt) + | PC.TReturn(clt) | PC.TBreak(clt) | PC.TContinue(clt) | PC.TGoto(clt) + | PC.TIdent(_,clt) + | PC.TTypeId(_,clt) | PC.TDeclarerId(_,clt) | PC.TIteratorId(_,clt) + | PC.TMetaDeclarer(_,_,_,clt) | PC.TMetaIterator(_,_,_,clt) + + | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt) + + | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt) + | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt) + | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt) + | PC.TDmOp(_,clt) | PC.TTilde (clt) + + | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt) + | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaExp(_,_,_,_,clt) + | PC.TMetaIdExp(_,_,_,_,clt) | PC.TMetaLocalIdExp(_,_,_,_,clt) + | PC.TMetaExpList(_,_,_,clt) + | PC.TMetaId(_,_,_,clt) | PC.TMetaType(_,_,clt) + | PC.TMetaStm(_,_,clt) | PC.TMetaStmList(_,_,clt) | PC.TMetaFunc(_,_,_,clt) + | PC.TMetaLocalFunc(_,_,_,clt) | PC.TMetaPos(_,_,_,clt) + + | PC.TFunDecl(clt) + | PC.TWhen(clt) | PC.TAny(clt) | PC.TStrict(clt) | PC.TEllipsis(clt) + (* | PC.TCircles(clt) | PC.TStars(clt) *) + + | PC.TOEllipsis(clt) | PC.TCEllipsis(clt) + | PC.TPOEllipsis(clt) | PC.TPCEllipsis(clt) (*| PC.TOCircles(clt) + | PC.TCCircles(clt) | PC.TOStars(clt) | PC.TCStars(clt) *) + + | PC.TWhy(clt) | PC.TDotDot(clt) | PC.TBang(clt) | PC.TOPar(clt) + | PC.TOPar0(clt) | PC.TMid0(clt) | PC.TCPar(clt) + | PC.TCPar0(clt) + + | PC.TOBrace(clt) | PC.TCBrace(clt) | PC.TOCro(clt) | PC.TCCro(clt) + + | PC.TPtrOp(clt) + + | PC.TDefine(clt,_) | PC.TDefineParam(clt,_,_) + | PC.TIncludeL(_,clt) | PC.TIncludeNL(_,clt) + + | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt) + | PC.TPtVirg(clt) -> + let (_,line,_,_,_,_,_,_) = clt in Some line + + | _ -> None + +let rec insert_line_end = function + [] -> [] + | (((PC.TWhen(clt),q) as x)::xs) -> + x::(find_line_end true (token2line x) clt q xs) + | (((PC.TDefine(clt,_),q) as x)::xs) + | (((PC.TDefineParam(clt,_,_),q) as x)::xs) -> + x::(find_line_end false (token2line x) clt q xs) + | x::xs -> x::(insert_line_end xs) + +and find_line_end inwhen line clt q = function + (* don't know what 2nd component should be so just use the info of + the When. Also inherit - of when, if any *) + [] -> [(PC.TLineEnd(clt),q)] + | ((PC.TIdent("strict",clt),a) as x)::xs when token2line x = line -> + (PC.TStrict(clt),a) :: (find_line_end inwhen line clt q xs) + | ((PC.TIdent("STRICT",clt),a) as x)::xs when token2line x = line -> + (PC.TStrict(clt),a) :: (find_line_end inwhen line clt q xs) + | ((PC.TIdent("any",clt),a) as x)::xs when token2line x = line -> + (PC.TAny(clt),a) :: (find_line_end inwhen line clt q xs) + | ((PC.TIdent("ANY",clt),a) as x)::xs when token2line x = line -> + (PC.TAny(clt),a) :: (find_line_end inwhen line clt q xs) + | ((PC.TIdent("forall",clt),a) as x)::xs when token2line x = line -> + (PC.TForall,a) :: (find_line_end inwhen line clt q xs) + | ((PC.TIdent("exists",clt),a) as x)::xs when token2line x = line -> + (PC.TExists,a) :: (find_line_end inwhen line clt q xs) + | ((PC.TComma(clt),a) as x)::xs when token2line x = line -> + (PC.TComma(clt),a) :: (find_line_end inwhen line clt q xs) + | ((PC.TPArob,a) as x)::xs -> (* no line #, just assume on the same line *) + x :: (find_line_end inwhen line clt q xs) + | x::xs when token2line x = line -> x :: (find_line_end inwhen line clt q xs) + | xs -> (PC.TLineEnd(clt),q)::(insert_line_end xs) + +(* ----------------------------------------------------------------------- *) +(* process pragmas: they can only be used in + code, and adjacent to +another + token. They are concatenated to the string representation of +that other token. *) + +let rec collect_all_pragmas collected = function + (PC.TPragma(s),_)::rest -> collect_all_pragmas (s::collected) rest + | l -> (List.rev collected,l) + +let rec collect_up_to_pragmas skipped = function + [] -> None (* didn't reach a pragma, so nothing to do *) + | ((PC.TPragma(s),_) as t)::rest -> + let (pragmas,rest) = collect_all_pragmas [] (t::rest) in + Some (List.rev skipped,pragmas,rest) + | x::xs -> + match plus_attachable x with + PLUS -> None + | NOTPLUS -> None + | SKIP -> collect_up_to_pragmas (x::skipped) xs + +let rec collect_up_to_plus skipped = function + [] -> failwith "nothing to attach a pragma to" + | x::xs -> + match plus_attachable x with + PLUS -> (List.rev skipped,x,xs) + | NOTPLUS -> failwith "nothing to attach a pragma to" + | SKIP -> collect_up_to_plus (x::skipped) xs + +let rec process_pragmas = function + [] -> [] + | ((PC.TPragma(s),_)::_) as l -> + let (pragmas,rest) = collect_all_pragmas [] l in + let (skipped,aft,rest) = collect_up_to_plus [] rest in + let (a,b,c,d,e,strbef,straft,pos) = get_clt aft in + skipped@ + (process_pragmas ((update_clt aft (a,b,c,d,e,pragmas,straft,pos))::rest)) + | bef::xs -> + (match plus_attachable bef with + PLUS -> + (match collect_up_to_pragmas [] xs with + Some(skipped,pragmas,rest) -> + let (a,b,c,d,e,strbef,straft,pos) = get_clt bef in + (update_clt bef (a,b,c,d,e,strbef,pragmas,pos)):: + skipped@(process_pragmas rest) + | None -> bef::(process_pragmas xs)) + | _ -> bef::(process_pragmas xs)) + +(* ----------------------------------------------------------------------- *) +(* Drop ... ... . This is only allowed in + code, and arises when there is +some - code between the ... *) +(* drop whens as well - they serve no purpose in + code and they cause +problems for drop_double_dots *) + +let rec drop_when = function + [] -> [] + | (PC.TWhen(clt),info)::xs -> + let rec loop = function + [] -> [] + | (PC.TLineEnd(_),info)::xs -> drop_when xs + | x::xs -> loop xs in + loop xs + | x::xs -> x::drop_when xs + +(* instead of dropping the double dots, we put TNothing in between them. +these vanish after the parser, but keeping all the ...s in the + code makes +it easier to align the + and - code in context_neg and in preparation for the +isomorphisms. This shouldn't matter because the context code of the + +slice is mostly ignored anyway *) +let rec drop_double_dots l = + let start = function + (PC.TOEllipsis(_),_) | (PC.TPOEllipsis(_),_) + (* | (PC.TOCircles(_),_) | (PC.TOStars(_),_) *) -> + true + | _ -> false in + let middle = function + (PC.TEllipsis(_),_) (* | (PC.TCircles(_),_) | (PC.TStars(_),_) *) -> true + | _ -> false in + let final = function + (PC.TCEllipsis(_),_) | (PC.TPCEllipsis(_),_) + (* | (PC.TCCircles(_),_) | (PC.TCStars(_),_) *) -> + true + | _ -> false in + let rec loop ((_,i) as prev) = function + [] -> [] + | x::rest when middle prev && middle x -> (PC.TNothing,i)::x::(loop x rest) + | x::rest when start prev && middle x -> (PC.TNothing,i)::x::(loop x rest) + | x::rest when start prev && final x -> (PC.TNothing,i)::x::(loop x rest) + | x::rest when middle prev && final x -> (PC.TNothing,i)::x::(loop x rest) + | x::rest -> x :: (loop x rest) in + match l with + [] -> [] + | (x::xs) -> x :: loop x xs + +let rec fix f l = + let cur = f l in + if l = cur then l else fix f cur + +(* ( | ... | ) also causes parsing problems *) + +exception Not_empty + +let rec drop_empty_thing starter middle ender = function + [] -> [] + | hd::rest when starter hd -> + let rec loop = function + x::rest when middle x -> loop rest + | x::rest when ender x -> rest + | _ -> raise Not_empty in + (match try Some(loop rest) with Not_empty -> None with + Some x -> drop_empty_thing starter middle ender x + | None -> hd :: drop_empty_thing starter middle ender rest) + | x::rest -> x :: drop_empty_thing starter middle ender rest + +let drop_empty_or = + drop_empty_thing + (function (PC.TOPar0(_),_) -> true | _ -> false) + (function (PC.TMid0(_),_) -> true | _ -> false) + (function (PC.TCPar0(_),_) -> true | _ -> false) + +let drop_empty_nest = drop_empty_thing + +(* ----------------------------------------------------------------------- *) +(* Read tokens *) + +let get_s_starts (_, (s,_,(starts, ends))) = + Printf.printf "%d %d\n" starts ends; (s, starts) + +let pop2 l = + let v = List.hd !l in + l := List.tl !l; + v + +let reinit _ = + PC.reinit (function _ -> PC.TArobArob (* a handy token *)) + (Lexing.from_function + (function buf -> function n -> raise Common.Impossible)) + +let parse_one str parsefn file toks = + let all_tokens = ref toks in + let cur_tok = ref (List.hd !all_tokens) in + + let lexer_function _ = + let (v, info) = pop2 all_tokens in + cur_tok := (v, info); + v in + + let lexbuf_fake = + Lexing.from_function + (function buf -> function n -> raise Common.Impossible) + in + + reinit(); + + try parsefn lexer_function lexbuf_fake + with + Lexer_cocci.Lexical s -> + failwith + (Printf.sprintf "%s: lexical error: %s\n =%s\n" str s + (Common.error_message file (get_s_starts !cur_tok) )) + | Parser_cocci_menhir.Error -> + failwith + (Printf.sprintf "%s: parse error: \n = %s\n" str + (Common.error_message file (get_s_starts !cur_tok) )) + | Semantic_cocci.Semantic s -> + failwith + (Printf.sprintf "%s: semantic error: %s\n =%s\n" str s + (Common.error_message file (get_s_starts !cur_tok) )) + + | e -> raise e + +let prepare_tokens tokens = + insert_line_end + (detect_types false (find_function_names (detect_attr tokens))) + +let rec consume_minus_positions = function + [] -> [] + | x::(PC.TPArob,_)::(PC.TMetaPos(name,constraints,per,clt),_)::xs -> + let (arity,ln,lln,offset,col,strbef,straft,_) = get_clt x in + let name = Parse_aux.clt2mcode name clt in + let x = + update_clt x + (arity,ln,lln,offset,col,strbef,straft, + Ast0.MetaPos(name,constraints,per)) in + x::(consume_minus_positions xs) + | x::xs -> x::consume_minus_positions xs + +let any_modif rule = + let mcode x = + match Ast0.get_mcode_mcodekind x with + Ast0.MINUS _ | Ast0.PLUS -> true + | _ -> false in + let donothing r k e = k e in + let bind x y = x or y in + let option_default = false in + let fn = + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing donothing + donothing donothing in + List.exists fn.V0.combiner_top_level rule + +let drop_last extra l = List.rev(extra@(List.tl(List.rev l))) + +let partition_either l = + let rec part_either left right = function + | [] -> (List.rev left, List.rev right) + | x :: l -> + (match x with + | Common.Left e -> part_either (e :: left) right l + | Common.Right e -> part_either left (e :: right) l) in + part_either [] [] l + +let get_metavars parse_fn table file lexbuf = + let rec meta_loop acc (* read one decl at a time *) = + let (_,tokens) = + tokens_all table file true lexbuf [PC.TArobArob;PC.TMPtVirg] in + let tokens = prepare_tokens tokens in + match tokens with + [(PC.TArobArob,_)] -> List.rev acc + | _ -> + let metavars = parse_one "meta" parse_fn file tokens in + meta_loop (metavars@acc) in + partition_either (meta_loop []) + +let get_script_metavars parse_fn table file lexbuf = + let rec meta_loop acc = + let (_, tokens) = + tokens_all table file true lexbuf [PC.TArobArob; PC.TMPtVirg] in + let tokens = prepare_tokens tokens in + match tokens with + [(PC.TArobArob, _)] -> List.rev acc + | _ -> + let metavar = parse_one "scriptmeta" parse_fn file tokens in + meta_loop (metavar :: acc) + in + meta_loop [] + +let get_rule_name parse_fn starts_with_name get_tokens file prefix = + Data.in_rule_name := true; + let mknm _ = make_name prefix (!Lexer_cocci.line) in + let name_res = + if starts_with_name + then + let (_,tokens) = get_tokens [PC.TArob] in + match parse_one "rule name" parse_fn file tokens with + Ast.CocciRulename (None,a,b,c,d,e) -> + Ast.CocciRulename (Some (mknm()),a,b,c,d,e) + | Ast.CocciRulename (Some nm,a,b,c,d,e) -> + (if List.mem nm reserved_names + then failwith (Printf.sprintf "invalid name %s\n" nm)); + Ast.CocciRulename (Some nm,a,b,c,d,e) + | Ast.ScriptRulename(s,deps) -> Ast.ScriptRulename(s,deps) + else + Ast.CocciRulename(Some(mknm()),Ast.NoDep,[],[],Ast.Undetermined,false) in + Data.in_rule_name := false; + name_res + +let parse_iso file = + let table = Common.full_charpos_to_pos file in + Common.with_open_infile file (fun channel -> + let lexbuf = Lexing.from_channel channel in + let get_tokens = tokens_all table file false lexbuf in + let res = + match get_tokens [PC.TArobArob;PC.TArob] with + (true,start) -> + let parse_start start = + let rev = List.rev start in + let (arob,_) = List.hd rev in + (arob = PC.TArob,List.rev(List.tl rev)) in + let (starts_with_name,start) = parse_start start in + let rec loop starts_with_name start = + (!Data.init_rule)(); + (* get metavariable declarations - have to be read before the + rest *) + let (rule_name,_,_,_,_,_) = + match get_rule_name PC.iso_rule_name starts_with_name get_tokens + file ("iso file "^file) with + Ast.CocciRulename (Some n,a,b,c,d,e) -> (n,a,b,c,d,e) + | _ -> failwith "Script rules cannot appear in isomorphism rules" + in + Ast0.rule_name := rule_name; + Data.in_meta := true; + let iso_metavars = + match get_metavars PC.iso_meta_main table file lexbuf with + (iso_metavars,[]) -> iso_metavars + | _ -> failwith "unexpected inheritance in iso" in + Data.in_meta := false; + (* get the rule *) + let (more,tokens) = + get_tokens + [PC.TIsoStatement;PC.TIsoExpression;PC.TIsoArgExpression; + PC.TIsoTestExpression; + PC.TIsoDeclaration;PC.TIsoType;PC.TIsoTopLevel] in + let next_start = List.hd(List.rev tokens) in + let dummy_info = ("",(-1,-1),(-1,-1)) in + let tokens = drop_last [(PC.EOF,dummy_info)] tokens in + let tokens = prepare_tokens (start@tokens) in + (* + print_tokens "iso tokens" tokens; + *) + let entry = parse_one "iso main" PC.iso_main file tokens in + let entry = List.map (List.map Test_exps.process_anything) entry in + if more + then (* The code below allows a header like Statement list, + which is more than one word. We don't have that any more, + but the code is left here in case it is put back. *) + match get_tokens [PC.TArobArob;PC.TArob] with + (true,start) -> + let (starts_with_name,start) = parse_start start in + (iso_metavars,entry,rule_name) :: + (loop starts_with_name (next_start::start)) + | _ -> failwith "isomorphism ends early" + else [(iso_metavars,entry,rule_name)] in + loop starts_with_name start + | (false,_) -> [] in + res) + +let parse_iso_files existing_isos iso_files extra_path = + let get_names = List.map (function (_,_,nm) -> nm) in + let old_names = get_names existing_isos in + Data.in_iso := true; + let (res,_) = + List.fold_left + (function (prev,names) -> + function file -> + Lexer_cocci.init (); + let file = + match file with + Common.Left(fl) -> Filename.concat extra_path fl + | Common.Right(fl) -> Filename.concat Config.path fl in + let current = parse_iso file in + let new_names = get_names current in + if List.exists (function x -> List.mem x names) new_names + then failwith (Printf.sprintf "repeated iso name found in %s" file); + (current::prev,new_names @ names)) + ([],old_names) iso_files in + Data.in_iso := false; + existing_isos@(List.concat (List.rev res)) + +let parse file = + let table = Common.full_charpos_to_pos file in + Common.with_open_infile file (fun channel -> + let lexbuf = Lexing.from_channel channel in + let get_tokens = tokens_all table file false lexbuf in + Data.in_prolog := true; + let initial_tokens = get_tokens [PC.TArobArob;PC.TArob] in + Data.in_prolog := false; + let res = + match initial_tokens with + (true,data) -> + (match List.rev data with + ((PC.TArobArob as x),_)::_ | ((PC.TArob as x),_)::_ -> + let iso_files = + parse_one "iso file names" PC.include_main file data in + + let parse_cocci_rule old_metas + (rule_name, dependencies, iso, dropiso, exists, is_expression) = + Ast0.rule_name := rule_name; + Data.inheritable_positions := + rule_name :: !Data.inheritable_positions; + + (* get metavariable declarations *) + Data.in_meta := true; + let (metavars, inherited_metavars) = + get_metavars PC.meta_main table file lexbuf in + Data.in_meta := false; + Hashtbl.add Data.all_metadecls rule_name metavars; + Hashtbl.add Lexer_cocci.rule_names rule_name (); + Hashtbl.add Lexer_cocci.all_metavariables rule_name + (Hashtbl.fold + (fun key v rest -> (key,v)::rest) + Lexer_cocci.metavariables []); + + (* get transformation rules *) + let (more, tokens) = get_tokens [PC.TArobArob; PC.TArob] in + let (minus_tokens, plus_tokens) = split_token_stream tokens in + + let minus_tokens = consume_minus_positions minus_tokens in + let minus_tokens = prepare_tokens minus_tokens in + let plus_tokens = prepare_tokens plus_tokens in + + (* + print_tokens "minus tokens" minus_tokens; + print_tokens "plus tokens" plus_tokens; + *) + + let plus_tokens = + process_pragmas + (fix (function x -> drop_double_dots (drop_empty_or x)) + (drop_when plus_tokens)) in + (* + print_tokens "plus tokens" plus_tokens; + Printf.printf "before minus parse\n"; + *) + let minus_res = + if is_expression + then parse_one "minus" PC.minus_exp_main file minus_tokens + else parse_one "minus" PC.minus_main file minus_tokens in + (* + Unparse_ast0.unparse minus_res; + Printf.printf "before plus parse\n"; + *) + let plus_res = + if !Flag.sgrep_mode2 + then (* not actually used for anything, except context_neg *) + List.map + (Iso_pattern.rebuild_mcode None).V0.rebuilder_top_level + minus_res + else + if is_expression + then parse_one "plus" PC.plus_exp_main file plus_tokens + else parse_one "plus" PC.plus_main file plus_tokens in + (* + Printf.printf "after plus parse\n"; + *) + + (if not !Flag.sgrep_mode2 && + (any_modif minus_res or any_modif plus_res) + then Data.inheritable_positions := []); + + Check_meta.check_meta rule_name old_metas inherited_metavars + metavars minus_res plus_res; + + (more, Ast0.CocciRule ((minus_res, metavars, + (iso, dropiso, dependencies, rule_name, exists)), + (plus_res, metavars)), metavars, tokens) in + + let parse_script_rule language old_metas deps = + let get_tokens = tokens_script_all table file false lexbuf in + + (* meta-variables *) + Data.in_meta := true; + let metavars = + get_script_metavars PC.script_meta_main table file lexbuf in + Data.in_meta := false; + + let exists_in old_metas (py,(r,m)) = + let test (rr,mr) x = + let (ro,vo) = Ast.get_meta_name x in + ro = rr && vo = mr in + List.exists (test (r,m)) old_metas in + + List.iter + (function x -> + let meta2c (r,n) = Printf.sprintf "%s.%s" r n in + if not (exists_in old_metas x) then + failwith + (Printf.sprintf + "Script references unknown meta-variable: %s" + (meta2c(snd x)))) + metavars; + + (* script code *) + let (more, tokens) = get_tokens [PC.TArobArob; PC.TArob] in + let data = + match List.hd tokens with + (PC.TScriptData(s),_) -> s + | (PC.TArobArob,_) | (PC.TArob,_) -> "" + | _ -> failwith "Malformed script rule" in + (more,Ast0.ScriptRule(language, deps, metavars, data),[],tokens) in + + let parse_rule old_metas starts_with_name = + let rulename = + get_rule_name PC.rule_name starts_with_name get_tokens file + "rule" in + match rulename with + Ast.CocciRulename (Some s, a, b, c, d, e) -> + parse_cocci_rule old_metas (s, a, b, c, d, e) + | Ast.ScriptRulename (l,deps) -> parse_script_rule l old_metas deps + | _ -> failwith "Malformed rule name" + in + + let rec loop old_metas starts_with_name = + (!Data.init_rule)(); + + let gen_starts_with_name more tokens = + more && + (match List.hd (List.rev tokens) with + (PC.TArobArob,_) -> false + | (PC.TArob,_) -> true + | _ -> failwith "unexpected token") + in + + let (more, rule, metavars, tokens) = + parse_rule old_metas starts_with_name in + if more then + rule:: + (loop (metavars @ old_metas) (gen_starts_with_name more tokens)) + else [rule]; + + in + + (iso_files, loop [] (x = PC.TArob)) + | _ -> failwith "unexpected code before the first rule\n") + | (false,[(PC.TArobArob,_)]) | (false,[(PC.TArob,_)]) -> + ([],([] : Ast0.parsed_rule list)) + | _ -> failwith "unexpected code before the first rule\n" in + res) + +(* parse to ast0 and then convert to ast *) +let process file isofile verbose = + let extra_path = Filename.dirname file in + Lexer_cocci.init(); + let (iso_files, rules) = parse file in + let std_isos = + match isofile with + None -> [] + | Some iso_file -> parse_iso_files [] [Common.Left iso_file] "" in + let global_isos = parse_iso_files std_isos iso_files extra_path in + let rules = Unitary_ast0.do_unitary rules in + let parsed = + List.map + (function + Ast0.ScriptRule (a,b,c,d) -> [([],Ast.ScriptRule (a,b,c,d))] + | Ast0.CocciRule + ((minus, metavarsm, + (iso, dropiso, dependencies, rule_name, exists)), + (plus, metavars)) -> + let chosen_isos = + parse_iso_files global_isos + (List.map (function x -> Common.Left x) iso) + extra_path in + let chosen_isos = + (* check that dropped isos are actually available *) + (try + let iso_names = + List.map (function (_,_,nm) -> nm) chosen_isos in + let local_iso_names = reserved_names @ iso_names in + let bad_dropped = + List.find + (function dropped -> + not (List.mem dropped local_iso_names)) + dropiso in + failwith + ("invalid iso name " ^ bad_dropped ^ " in " ^ rule_name) + with Not_found -> ()); + if List.mem "all" dropiso + then + if List.length dropiso = 1 + then [] + else failwith "disable all should only be by itself" + else (* drop those isos *) + List.filter + (function (_,_,nm) -> not (List.mem nm dropiso)) + chosen_isos in + List.iter Iso_compile.process chosen_isos; + let dropped_isos = + match reserved_names with + "all"::others -> + (match dropiso with + ["all"] -> others + | _ -> + List.filter (function x -> List.mem x dropiso) others) + | _ -> + failwith + "bad list of reserved names - all must be at start" in + let minus = Test_exps.process minus in + let minus = Compute_lines.compute_lines minus in + let plus = Compute_lines.compute_lines plus in + let is_exp = + (* only relevant to Flag.make_hrule *) + (* doesn't handle multiple minirules properly, but since + we don't really handle them in lots of other ways, it + doesn't seem very important *) + match plus with + [] -> [false] + | p::_ -> + [match Ast0.unwrap p with + Ast0.CODE c -> + (match List.map Ast0.unwrap (Ast0.undots c) with + [Ast0.Exp e] -> true | _ -> false) + | _ -> false] in + let minus = Arity.minus_arity minus in + let ((metavars,minus),function_prototypes) = + Function_prototypes.process + rule_name metavars dropped_isos minus plus in + (* warning! context_neg side-effects its arguments *) + let (m,p) = List.split (Context_neg.context_neg minus plus) in + Type_infer.type_infer p; + (if not !Flag.sgrep_mode2 then Insert_plus.insert_plus m p); + Type_infer.type_infer minus; + let (extra_meta, minus) = + Iso_pattern.apply_isos chosen_isos minus rule_name in + let minus = Comm_assoc.comm_assoc minus rule_name dropiso in + let minus = + if !Flag.sgrep_mode2 then minus + else Single_statement.single_statement minus in + let minus = Simple_assignments.simple_assignments minus in + let minus_ast = + Ast0toast.ast0toast rule_name dependencies dropped_isos + exists minus is_exp in + match function_prototypes with + None -> [(extra_meta @ metavars, minus_ast)] + | Some mv_fp -> + [(extra_meta @ metavars, minus_ast); mv_fp]) +(* Ast0.CocciRule ((minus, metavarsm, (iso, dropiso, dependencies, rule_name, exists)), (plus, metavars))*) + rules in + let parsed = List.concat parsed in + let disjd = Disjdistr.disj parsed in + + let (code,fvs,neg_pos,ua,pos) = Free_vars.free_vars disjd in + if !Flag_parsing_cocci.show_SP + then List.iter Pretty_print_cocci.unparse code; + + let grep_tokens = + Common.profile_code "get_constants" + (fun () -> Get_constants.get_constants code) in (* for grep *) + let glimpse_tokens2 = + Common.profile_code "get_glimpse_constants" + (fun () -> Get_constants2.get_constants code neg_pos) in(* for glimpse *) + (code,fvs,neg_pos,ua,pos,grep_tokens,glimpse_tokens2) diff --git a/parsing_cocci/parse_cocci.mli b/parsing_cocci/parse_cocci.mli new file mode 100644 index 0000000..9ef89f6 --- /dev/null +++ b/parsing_cocci/parse_cocci.mli @@ -0,0 +1,10 @@ +val process : + string (* filename *) -> string option (* iso filename *) -> + bool (* verbose? *) -> + (Ast_cocci.rule list) * + (((Ast_cocci.meta_name list) list) list) (*fvs of the rule*) * + (((Ast_cocci.meta_name list) list) list) (*negated pos vars*) * + (((Ast_cocci.meta_name list) list) list) (*used after list*) * + (((Ast_cocci.meta_name list) list) list) (*positions list*) * + string list list (* non metavars in - code, for grep *) * + string option (* non metavars in - code, for glimpse *) diff --git a/parsing_cocci/parser_cocci.mly b/parsing_cocci/parser_cocci.mly new file mode 100644 index 0000000..b34a116 --- /dev/null +++ b/parsing_cocci/parser_cocci.mly @@ -0,0 +1,1361 @@ +/* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*/ + + +%{ + +(* Not clear how to allow function declarations to specify a return type +and how to allow both to be specified as static, because they are in +different rules. The rules seem to have to be combined, which would allow +functions to be declared as local variables *) + +(* Not clear how to let a function have a parameter of type void. At the +moment, void is allowed to be the type of a variable, which is wrong, and a +parameter needs both a type and an identifier *) + +module Ast0 = Ast0_cocci +module Ast = Ast_cocci + +(*let warning s v = + if !Flag.verbose_parsing + then Common.warning s v + else v*) + +let make_info line logical_line = + { Ast.line = line; Ast.logical_line = logical_line } + +let clt2info (_,line,logical_line) = make_info line logical_line + +let clt2mcode str = function + (Data.MINUS,line,lline) -> + (str,Ast0.NONE, + (Ast.MINUS({Ast.line=line;Ast.logical_line=lline},ref[]))) + | (Data.OPTMINUS,line,lline) -> + (str,Ast0.OPT, + (Ast.MINUS({Ast.line=line;Ast.logical_line=lline},ref[]))) + | (Data.UNIQUEMINUS,line,lline) -> + (str,Ast0.UNIQUE, + (Ast.MINUS({Ast.line=line;Ast.logical_line=lline},ref[]))) + | (Data.MULTIMINUS,line,lline) -> + (str,Ast0.MULTI, + (Ast.MINUS({Ast.line=line;Ast.logical_line=lline},ref[]))) + | (Data.PLUS,line,lline) -> + (str,Ast0.NONE,Ast.PLUS({Ast.line=line;Ast.logical_line=lline})) + | (Data.CONTEXT,line,lline) -> + (str,Ast0.NONE, + Ast.CONTEXT({Ast.line=line;Ast.logical_line=lline},ref Ast.NOTHING)) + | (Data.OPT,line,lline) -> + (str,Ast0.OPT, + Ast.CONTEXT({Ast.line=line;Ast.logical_line=lline},ref Ast.NOTHING)) + | (Data.UNIQUE,line,lline) -> + (str,Ast0.UNIQUE, + Ast.CONTEXT({Ast.line=line;Ast.logical_line=lline},ref Ast.NOTHING)) + | (Data.MULTI,line,lline) -> + (str,Ast0.MULTI, + Ast.CONTEXT({Ast.line=line;Ast.logical_line=lline},ref Ast.NOTHING)) + +let id2name (name, clt) = name +let id2clt (name, clt) = clt +let id2info (name, clt) = clt2info clt +let id2mcode (name, clt) = clt2mcode name clt + +let arith_op ast_op left op right = + Ast0.Binary(left, clt2mcode (Ast.Arith ast_op) op, right) + +let logic_op ast_op left op right = + Ast0.Binary(left, clt2mcode (Ast.Logical ast_op) op, right) + +let top_dots l = + if List.exists (function Ast0.Circles(_) -> true | _ -> false) l + then Ast0.CIRCLES(l) + else if List.exists (function Ast0.Stars(_) -> true | _ -> false) l + then Ast0.STARS(l) + else Ast0.DOTS(l) + +%} + + +%token EOF + +%token TIdentifier TExpression TStatement TFunction TLocal TType TParameter +%token TWhy0 TPlus0 TBang0 Tlist TFresh TConstant TError TWords + +%token Tchar Tshort Tint Tdouble Tfloat Tlong Tvoid +%token Tstruct Tunion +%token Tunsigned Tsigned + +%token Tstatic Tconst Tvolatile + +%token TIf TElse TWhile TFor TDo TReturn +%token TIdent TFunName TMetaFunName +%token TMetaId TMetaType TMetaErr +%token TMetaParam TMetaParamList +%token TMetaStm TMetaStmList TMetaFunc +%token TMetaLocalFunc TMetaExpList +%token +TMetaExp TMetaConst +%token TArobArob + +%token TEllipsis TOEllipsis TCEllipsis +%token TWhen +%token TLineEnd +%token TCircles TOCircles TCCircles +%token TStars TOStars TCStars + +%token TWhy TDotDot TBang TOPar TOPar0 TMid +%token TMid0 TCPar TCPar0 + +%token TInclude TMinusFile TPlusFile + +%token TInc TDec + +%token TString TChar TFloat TInt + +%token TOrLog +%token TAndLog +%token TOr +%token TXor +%token TAnd +%token TEqEq TNotEq +%token TInf TSup TInfEq TSupEq +%token TShl TShr +%token TPlus TMinus +%token TMul TDiv TMod + +%token TOBrace TCBrace +%token TOCro TCCro + +%token TPtrOp + +%token TEq TDot TComma TPtVirg +%token TAssign + +/* operator precedence */ +%nonassoc TIf +%nonassoc TElse + +%left TOrLog +%left TAndLog +%left TOr +%left TXor +%left TAnd +%left TEqEq TNotEq +%left TInf TSup TInfEq TSupEq +%left TShl TShr +%left TPlus TMinus +%left TMul TDiv TMod + +%start main +%type main + +%start meta_main +%type meta_main + + + +%% + +main: body EOF { $1 } | body TArobArob { $1 } +meta_main: meta_var_list_opt TArobArob { $1 } + +/***************************************************************************** +* +* +*****************************************************************************/ + +meta_var: + arity TIdentifier pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_id_meta name; + Ast.MetaIdDecl($1,name)) + $3 } +| arity TFresh TIdentifier pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_id_meta name; + Ast.MetaFreshIdDecl($1,name)) + $4 } +| arity TType pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_type_meta name; + Ast.MetaTypeDecl($1,name)) + $3 } +| arity TParameter pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_param_meta name; + Ast.MetaParamDecl($1,name)) + $3 } +| arity TParameter Tlist pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_paramlist_meta name; + Ast.MetaParamListDecl($1,name)) + $4 } +| arity TError pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_err_meta name; + Ast.MetaErrDecl($1,name)) + $3 } +| arity TExpression pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_exp_meta None name; + Ast.MetaExpDecl($1,name)) + $3 } +| arity TExpression Tlist pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_explist_meta name; + Ast.MetaExpListDecl($1,name)) + $4 } +| arity TStatement pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_stm_meta name; + Ast.MetaStmDecl($1,name)) + $3 } +| arity TStatement Tlist pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_stmlist_meta name; + Ast.MetaStmListDecl($1,name)) + $4 } +| arity TFunction pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_func_meta name; + Ast.MetaFuncDecl($1,name)) + $3 } +| arity TLocal TFunction pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_local_func_meta name; + Ast.MetaLocalFuncDecl($1,name)) + $4 } +| arity meta_exp_type pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_exp_meta (Some $2) name; + Ast.MetaExpDecl($1,name)) + $3 } +| arity TConstant meta_exp_type pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_const_meta (Some $3) name; + Ast.MetaConstDecl($1,name)) + $4 } +| arity TConstant pure_ident_or_meta_ident_list TPtVirg + { List.map + (function name -> + !Data.add_const_meta None name; + Ast.MetaConstDecl($1,name)) + $3 } + +meta_exp_type: + ctype { [$1] } +| TOBrace ctype_list TCBrace { $2 } + +arity: TBang0 { Ast.UNIQUE } + | TWhy0 { Ast.OPT } + | TPlus0 { Ast.MULTI } + | /* empty */ { Ast.NONE } + +ctype: Tvoid + { Ast0.BaseType(clt2mcode Ast.VoidType $1, None) } + | ctype_qualif Tchar + { Ast0.BaseType(clt2mcode Ast.CharType $2, $1) } + | ctype_qualif Tshort + { Ast0.BaseType(clt2mcode Ast.ShortType $2, $1) } + | ctype_qualif Tint + { Ast0.BaseType(clt2mcode Ast.IntType $2, $1) } + | Tdouble + { Ast0.BaseType(clt2mcode Ast.DoubleType $1, None) } + | Tfloat + { Ast0.BaseType(clt2mcode Ast.FloatType $1, None) } + | ctype_qualif Tlong + { Ast0.BaseType(clt2mcode Ast.LongType $2, $1) } + | Tstruct pure_ident + { Ast0.StructUnionName(id2mcode $2,clt2mcode Ast.Struct $1) } + | Tunion pure_ident + { Ast0.StructUnionName(id2mcode $2,clt2mcode Ast.Union $1) } + | ctype TMul + { Ast0.Pointer($1,clt2mcode "*" $2) } + | TMetaType + { let (nm,clt) = $1 in Ast0.MetaType(clt2mcode nm clt) } + +ctype_qualif: + Tunsigned + { Some (clt2mcode Ast.Unsigned $1) } + | Tsigned + { Some (clt2mcode Ast.Signed $1) } + | /* empty */ { None } + +param_ctype: + Tvoid + { Ast0.BaseType(clt2mcode Ast.VoidType $1, None) } + | ctype_qualif Tchar + { Ast0.BaseType(clt2mcode Ast.CharType $2, $1) } + | ctype_qualif Tshort + { Ast0.BaseType(clt2mcode Ast.ShortType $2, $1) } + | ctype_qualif Tint + { Ast0.BaseType(clt2mcode Ast.IntType $2, $1) } + | Tdouble + { Ast0.BaseType(clt2mcode Ast.DoubleType $1, None) } + | Tfloat + { Ast0.BaseType(clt2mcode Ast.FloatType $1, None) } + | ctype_qualif Tlong + { Ast0.BaseType(clt2mcode Ast.LongType $2, $1) } + | Tstruct pure_ident + { Ast0.StructUnionName(id2mcode $2,clt2mcode Ast.Struct $1) } + | Tunion pure_ident + { Ast0.StructUnionName(id2mcode $2,clt2mcode Ast.Union $1) } + | pure_ident { Ast0.TypeName(id2mcode $1) } + | param_ctype TMul { Ast0.Pointer($1,clt2mcode "*" $2) } + | TMetaType + { let (nm,clt) = $1 in Ast0.MetaType(clt2mcode nm clt) } + +/*****************************************************************************/ + +/* have to inline everything to avoid conflicts? switch to proper +declarations, statements, and expressions for the subterms */ + +body: function_decl_statement_or_expression { Top_level.top_level $1 } + | /* empty */ { [] } + +/*****************************************************************************/ + +fundecl: + storage TFunName TOPar decl_list TCPar + TOBrace pre_post_decl_statement_and_expression_opt TCBrace + { Ast0.FunDecl($1, Ast0.Id(id2mcode $2), clt2mcode "(" $3, $4, + clt2mcode ")" $5, clt2mcode "{" $6, $7, + clt2mcode "}" $8) } +| storage TMetaFunName TOPar decl_list TCPar + TOBrace pre_post_decl_statement_and_expression_opt TCBrace + { Ast0.FunDecl($1, Ast0.MetaFunc(id2mcode $2), clt2mcode "(" $3, $4, + clt2mcode ")" $5, clt2mcode "{" $6, $7, + clt2mcode "}" $8) } + +storage: Tstatic { Some (clt2mcode Ast.Static $1) } + | /* empty */ { None } + +decl: decl_qualif param_ctype ident + { Ast0.Param($3, $1, $2) } + | TMetaParam + { let (nm,clt) = $1 in Ast0.MetaParam(clt2mcode nm clt) } + +decl_qualif: + Tconst { Some (clt2mcode Ast.Const $1) } + | Tvolatile { Some (clt2mcode Ast.Volatile $1) } + | /* empty */ { None } + +/*****************************************************************************/ + +statement: + TMetaStm + { let (nm,clt) = $1 in Ast0.MetaStmt(clt2mcode nm clt) } +| expr TPtVirg + { Ast0.ExprStatement ($1, clt2mcode ";" $2) } +| TIf TOPar eexpr TCPar single_statement %prec TIf + { Ast0.IfThen(clt2mcode "if" $1, + clt2mcode "(" $2,$3,clt2mcode ")" $4,$5) } +| TIf TOPar eexpr TCPar single_statement TElse single_statement + { Ast0.IfThenElse(clt2mcode "if" $1, + clt2mcode "(" $2,$3,clt2mcode ")" $4,$5, + clt2mcode "else" $6,$7) } +| TFor TOPar eexpr_opt TPtVirg eexpr_opt TPtVirg eexpr_opt TCPar + single_statement + { Ast0.For(clt2mcode "for" $1,clt2mcode "(" $2,$3, + clt2mcode ";" $4,$5,clt2mcode ";" $6,$7,clt2mcode ")" $8,$9) } +| TWhile TOPar eexpr TCPar single_statement + { Ast0.While(clt2mcode "while" $1, + clt2mcode "(" $2,$3,clt2mcode ")" $4,$5) } +| TDo single_statement TWhile TOPar eexpr TCPar TPtVirg + { Ast0.Do(clt2mcode "do" $1,$2,clt2mcode "while" $3, + clt2mcode "(" $4,$5,clt2mcode ")" $6, clt2mcode ";" $7) } +| TReturn eexpr TPtVirg + { Ast0.ReturnExpr(clt2mcode "return" $1,$2,clt2mcode ";" $3) } +| TReturn TPtVirg + { Ast0.Return(clt2mcode "return" $1,clt2mcode ";" $2) } +| TOBrace pre_post_decl_statement_and_expression_opt TCBrace + { Ast0.Seq(clt2mcode "{" $1,$2,clt2mcode "}" $3) } +| TOEllipsis decl_statement_or_expression_dots TCEllipsis + { Ast0.Nest(Ast0.DOTS($2)) } +| TOCircles decl_statement_or_expression_circles TCCircles + { Ast0.Nest(Ast0.CIRCLES($2)) } +| TOStars decl_statement_or_expression_stars TCStars + { Ast0.Nest(Ast0.STARS($2)) } + +/* In the following, an identifier as a type is not fully supported. Indeed, +the language is ambiguous: what is foo * bar; */ +decl_var: ctype d_ident_list TPtVirg + { (List.map + (function (id,fn) -> Ast0.UnInit(fn $1,id,clt2mcode ";" $3)) + $2) } + | ctype d_ident TEq eexpr TPtVirg + { let (id,fn) = $2 in + [Ast0.Init(fn $1,id,clt2mcode "=" $3,$4,clt2mcode ";" $5)] } + | pure_ident d_ident TPtVirg + { let (id,fn) = $2 in + [Ast0.UnInit(fn (Ast0.TypeName(id2mcode $1)),id,clt2mcode ";" $3)] } + | pure_ident d_ident TEq eexpr TPtVirg + { let (id,fn) = $2 in + [Ast0.Init(fn(Ast0.TypeName(id2mcode $1)),id, + clt2mcode "=" $3,$4,clt2mcode ";" $5)] } + +d_ident: + ident + { ($1,function x -> x) } + | ident TOCro eexpr_opt TCCro + { ($1,function x -> Ast0.Array(x,clt2mcode "[" $2,$3,clt2mcode "]" $4)) } + +/* a statement on its own */ +single_statement: + statement { $1 } + | TOPar0 statement_mid TCPar0 + { Ast0.Disj($2) } + +/* a statement that is part of a list */ +decl_statement: + TMetaStmList + { let (nm,clt) = $1 in [Ast0.MetaStmt(clt2mcode nm clt)] } + | decl_var + { List.map (function x -> Ast0.Decl(x)) $1 } + | statement { [$1] } + | TOPar0 pre_post_decl_statement_and_expression_opt_mid TCPar0 + { if List.for_all (function Ast0.DOTS([]) -> true | _ -> false) $2 + then [] + else [Ast0.Disj($2)] } + +/*****************************************************************************/ + + +/*****************************************************************************/ +/* The following cannot contain <... ...> at the top level. This can only +be allowed as an expression when the expression is delimited on both sides +by expression-specific markers. In that case, the rule eexpr is used, which +allows <... ...> anywhere. Hopefully, this will not be too much of a problem +in practice. */ + +expr: assign_expr { $1 } + +assign_expr: + cond_expr { $1 } + | unary_expr TAssign assign_expr + { let (op,clt) = $2 in Ast0.Assignment($1,clt2mcode op clt,$3) } + | unary_expr TEq assign_expr + { Ast0.Assignment($1,clt2mcode Ast.SimpleAssign $2,$3) } + +cond_expr: arith_expr { $1 } + | arith_expr TWhy eexpr_opt TDotDot cond_expr + { Ast0.CondExpr ($1, clt2mcode "?" $2, $3, clt2mcode "?" $4, $5) } + +arith_expr: cast_expr { $1 } + | arith_expr TMul arith_expr { arith_op Ast.Mul $1 $2 $3 } + | arith_expr TDiv arith_expr { arith_op Ast.Div $1 $2 $3 } + | arith_expr TMod arith_expr { arith_op Ast.Mod $1 $2 $3 } + | arith_expr TPlus arith_expr { arith_op Ast.Plus $1 $2 $3 } + | arith_expr TMinus arith_expr { arith_op Ast.Minus $1 $2 $3 } + | arith_expr TShl arith_expr { arith_op Ast.DecLeft $1 $2 $3 } + | arith_expr TShr arith_expr { arith_op Ast.DecRight $1 $2 $3 } + | arith_expr TInf arith_expr { logic_op Ast.Inf $1 $2 $3 } + | arith_expr TSup arith_expr { logic_op Ast.Sup $1 $2 $3 } + | arith_expr TInfEq arith_expr { logic_op Ast.InfEq $1 $2 $3 } + | arith_expr TSupEq arith_expr { logic_op Ast.SupEq $1 $2 $3 } + | arith_expr TEqEq arith_expr { logic_op Ast.Eq $1 $2 $3 } + | arith_expr TNotEq arith_expr { logic_op Ast.NotEq $1 $2 $3 } + | arith_expr TAnd arith_expr { arith_op Ast.And $1 $2 $3 } + | arith_expr TOr arith_expr { arith_op Ast.Or $1 $2 $3 } + | arith_expr TXor arith_expr { arith_op Ast.Xor $1 $2 $3 } + | arith_expr TAndLog arith_expr { logic_op Ast.AndLog $1 $2 $3 } + | arith_expr TOrLog arith_expr { logic_op Ast.OrLog $1 $2 $3 } + +cast_expr: unary_expr { $1 } + | TOPar ctype TCPar cast_expr + { Ast0.Cast (clt2mcode "(" $1, $2, clt2mcode ")" $3, $4) } + +unary_expr: postfix_expr { $1 } + | TInc unary_expr + { Ast0.Infix ($2, clt2mcode Ast.Inc $1) } + | TDec unary_expr + { Ast0.Infix ($2, clt2mcode Ast.Dec $1) } + | unary_op unary_expr + { let mcode = $1 in Ast0.Unary($2, mcode) } + +unary_op: TAnd { clt2mcode Ast.GetRef $1 } + | TMul { clt2mcode Ast.DeRef $1 } + | TPlus { clt2mcode Ast.UnPlus $1 } + | TMinus { clt2mcode Ast.UnMinus $1 } + | TBang { clt2mcode Ast.Not $1 } + +postfix_expr: primary_expr { $1 } + | postfix_expr TOCro eexpr TCCro + { Ast0.ArrayAccess ($1,clt2mcode "[" $2,$3,clt2mcode "]" $4) } + | postfix_expr TDot ident + { Ast0.RecordAccess($1, clt2mcode "." $2, $3) } + | postfix_expr TPtrOp ident + { Ast0.RecordPtAccess($1, clt2mcode "->" $2, $3) } + | postfix_expr TInc + { Ast0.Postfix ($1, clt2mcode Ast.Inc $2) } + | postfix_expr TDec + { Ast0.Postfix ($1, clt2mcode Ast.Dec $2) } + | postfix_expr TOPar eexpr_list_opt TCPar + { Ast0.FunCall($1,clt2mcode "(" $2,$3,clt2mcode ")" $4) } + +primary_expr: ident { Ast0.Ident($1) } + | TInt + { let (x,clt) = $1 in + Ast0.Constant (clt2mcode (Ast.Int x) clt) } + | TFloat + { let (x,clt) = $1 in + Ast0.Constant (clt2mcode (Ast.Float x) clt) } + | TString + { let (x,clt) = $1 in + Ast0.Constant (clt2mcode (Ast.String x) clt) } + | TChar + { let (x,clt) = $1 in + Ast0.Constant (clt2mcode (Ast.Char x) clt) } + | TMetaConst + { let (nm,ty,clt) = $1 in Ast0.MetaConst(clt2mcode nm clt,ty) } + | TMetaErr + { let (nm,clt) = $1 in Ast0.MetaErr(clt2mcode nm clt) } + | TMetaExp + { let (nm,ty,clt) = $1 in Ast0.MetaExpr(clt2mcode nm clt,ty) } + | TOPar eexpr TCPar + { Ast0.Paren(clt2mcode "(" $1,$2,clt2mcode ")" $3) } + | TOPar0 expr_mid TCPar0 { Ast0.DisjExpr($2) } + +/*****************************************************************************/ + +eexpr: eassign_expr { $1 } + +eassign_expr: econd_expr { $1 } + | eunary_expr TAssign eassign_expr + { let (op,clt) = $2 in + Ast0.Assignment($1,clt2mcode op clt,$3) } + | eunary_expr TEq eassign_expr + { Ast0.Assignment($1,clt2mcode Ast.SimpleAssign $2,$3) } + +econd_expr: earith_expr { $1 } + | earith_expr TWhy eexpr_opt TDotDot econd_expr + { Ast0.CondExpr ($1, clt2mcode "?" $2, $3, clt2mcode "?" $4, $5) } + +earith_expr: ecast_expr { $1 } + | earith_expr TMul earith_expr { arith_op Ast.Mul $1 $2 $3 } + | earith_expr TDiv earith_expr { arith_op Ast.Div $1 $2 $3 } + | earith_expr TMod earith_expr { arith_op Ast.Mod $1 $2 $3 } + | earith_expr TPlus earith_expr { arith_op Ast.Plus $1 $2 $3 } + | earith_expr TMinus earith_expr { arith_op Ast.Minus $1 $2 $3 } + | earith_expr TShl earith_expr { arith_op Ast.DecLeft $1 $2 $3 } + | earith_expr TShr earith_expr { arith_op Ast.DecRight $1 $2 $3 } + | earith_expr TInf earith_expr { logic_op Ast.Inf $1 $2 $3 } + | earith_expr TSup earith_expr { logic_op Ast.Sup $1 $2 $3 } + | earith_expr TInfEq earith_expr { logic_op Ast.InfEq $1 $2 $3 } + | earith_expr TSupEq earith_expr { logic_op Ast.SupEq $1 $2 $3 } + | earith_expr TEqEq earith_expr { logic_op Ast.Eq $1 $2 $3 } + | earith_expr TNotEq earith_expr { logic_op Ast.NotEq $1 $2 $3 } + | earith_expr TAnd earith_expr { arith_op Ast.And $1 $2 $3 } + | earith_expr TOr earith_expr { arith_op Ast.Or $1 $2 $3 } + | earith_expr TXor earith_expr { arith_op Ast.Xor $1 $2 $3 } + | earith_expr TAndLog earith_expr { logic_op Ast.AndLog $1 $2 $3 } + | earith_expr TOrLog earith_expr { logic_op Ast.OrLog $1 $2 $3 } + +ecast_expr: eunary_expr { $1 } + | TOPar ctype TCPar ecast_expr + { Ast0.Cast (clt2mcode "(" $1, $2, clt2mcode ")" $3, $4) } + +eunary_expr: epostfix_expr { $1 } + | TInc eunary_expr + { Ast0.Infix ($2, clt2mcode Ast.Inc $1) } + | TDec eunary_expr + { Ast0.Infix ($2, clt2mcode Ast.Dec $1) } + | unary_op eunary_expr + { let mcode = $1 in Ast0.Unary($2, mcode) } + +epostfix_expr: eprimary_expr { $1 } + | epostfix_expr TOCro eexpr TCCro + { Ast0.ArrayAccess ($1,clt2mcode "[" $2,$3,clt2mcode "]" $4) } + | epostfix_expr TDot ident + { Ast0.RecordAccess($1, clt2mcode "." $2, $3) } + | epostfix_expr TPtrOp ident + { Ast0.RecordPtAccess($1, clt2mcode "->" $2, $3) } + | epostfix_expr TInc + { Ast0.Postfix ($1, clt2mcode Ast.Inc $2) } + | epostfix_expr TDec + { Ast0.Postfix ($1, clt2mcode Ast.Dec $2) } + | epostfix_expr TOPar eexpr_list_opt TCPar + { Ast0.FunCall($1,clt2mcode "(" $2,$3,clt2mcode ")" $4) } + +eprimary_expr: ident { Ast0.Ident($1) } + | TEllipsis { Ast0.Edots(clt2mcode "..." $1,None) } + | TInt + { let (x,clt) = $1 in + Ast0.Constant (clt2mcode (Ast.Int x) clt) } + | TFloat + { let (x,clt) = $1 in + Ast0.Constant (clt2mcode (Ast.Float x) clt) } + | TString + { let (x,clt) = $1 in + Ast0.Constant (clt2mcode (Ast.String x) clt) } + | TChar + { let (x,clt) = $1 in + Ast0.Constant (clt2mcode (Ast.Char x) clt) } + | TMetaConst + { let (nm,ty,clt) = $1 in Ast0.MetaConst(clt2mcode nm clt,ty) } + | TMetaErr + { let (nm,clt) = $1 in Ast0.MetaErr(clt2mcode nm clt) } + | TMetaExp + { let (nm,ty,clt) = $1 in Ast0.MetaExpr(clt2mcode nm clt,ty) } + | TOPar eexpr TCPar + { Ast0.Paren(clt2mcode "(" $1,$2,clt2mcode ")" $3) } + | TOPar0 eexpr_mid TCPar0 + { Ast0.DisjExpr($2) } + | TOEllipsis expr_dots TCEllipsis + { Ast0.NestExpr(Ast0.DOTS($2)) } + | TOCircles expr_circles TCCircles + { Ast0.NestExpr(Ast0.CIRCLES($2)) } + | TOStars expr_stars TCStars + { Ast0.NestExpr(Ast0.STARS($2)) } + +/*****************************************************************************/ + +dexpr: dassign_expr { $1 } + +dassign_expr: dcond_expr { $1 } + | dunary_expr TAssign dassign_expr + { let (op,clt) = $2 in + Ast0.Assignment($1,clt2mcode op clt,$3) } + | dunary_expr TEq dassign_expr + { Ast0.Assignment($1,clt2mcode Ast.SimpleAssign $2,$3) } + +dcond_expr: darith_expr { $1 } + | darith_expr TWhy eexpr_opt TDotDot dcond_expr + { Ast0.CondExpr ($1, clt2mcode "?" $2, $3, clt2mcode "?" $4, $5) } + +darith_expr: dcast_expr { $1 } + | darith_expr TMul darith_expr { arith_op Ast.Mul $1 $2 $3 } + | darith_expr TDiv darith_expr { arith_op Ast.Div $1 $2 $3 } + | darith_expr TMod darith_expr { arith_op Ast.Mod $1 $2 $3 } + | darith_expr TPlus darith_expr { arith_op Ast.Plus $1 $2 $3 } + | darith_expr TMinus darith_expr { arith_op Ast.Minus $1 $2 $3 } + | darith_expr TShl darith_expr { arith_op Ast.DecLeft $1 $2 $3 } + | darith_expr TShr darith_expr { arith_op Ast.DecRight $1 $2 $3 } + | darith_expr TInf darith_expr { logic_op Ast.Inf $1 $2 $3 } + | darith_expr TSup darith_expr { logic_op Ast.Sup $1 $2 $3 } + | darith_expr TInfEq darith_expr { logic_op Ast.InfEq $1 $2 $3 } + | darith_expr TSupEq darith_expr { logic_op Ast.SupEq $1 $2 $3 } + | darith_expr TEqEq darith_expr { logic_op Ast.Eq $1 $2 $3 } + | darith_expr TNotEq darith_expr { logic_op Ast.NotEq $1 $2 $3 } + | darith_expr TAnd darith_expr { arith_op Ast.And $1 $2 $3 } + | darith_expr TOr darith_expr { arith_op Ast.Or $1 $2 $3 } + | darith_expr TXor darith_expr { arith_op Ast.Xor $1 $2 $3 } + | darith_expr TAndLog darith_expr { logic_op Ast.AndLog $1 $2 $3 } + | darith_expr TOrLog darith_expr { logic_op Ast.OrLog $1 $2 $3 } + +dcast_expr: dunary_expr { $1 } + | TOPar ctype TCPar dcast_expr + { Ast0.Cast (clt2mcode "(" $1, $2, clt2mcode ")" $3, $4) } + +dunary_expr: dpostfix_expr { $1 } + | TInc dunary_expr + { Ast0.Infix ($2, clt2mcode Ast.Inc $1) } + | TDec dunary_expr + { Ast0.Infix ($2, clt2mcode Ast.Dec $1) } + | unary_op dunary_expr + { let mcode = $1 in Ast0.Unary($2, mcode) } + +dpostfix_expr: dprimary_expr { $1 } + | dpostfix_expr TOCro eexpr TCCro + { Ast0.ArrayAccess ($1,clt2mcode "[" $2,$3,clt2mcode "]" $4) } + | dpostfix_expr TDot ident + { Ast0.RecordAccess($1, clt2mcode "." $2, $3) } + | dpostfix_expr TPtrOp ident + { Ast0.RecordPtAccess($1, clt2mcode "->" $2, $3) } + | dpostfix_expr TInc + { Ast0.Postfix ($1, clt2mcode Ast.Inc $2) } + | dpostfix_expr TDec + { Ast0.Postfix ($1, clt2mcode Ast.Dec $2) } + | dpostfix_expr TOPar eexpr_list_opt TCPar + { Ast0.FunCall($1,clt2mcode "(" $2,$3,clt2mcode ")" $4) } + +dprimary_expr: ident { Ast0.Ident($1) } + | TInt + { let (x,clt) = $1 in + Ast0.Constant (clt2mcode (Ast.Int x) clt) } + | TFloat + { let (x,clt) = $1 in + Ast0.Constant (clt2mcode (Ast.Float x) clt) } + | TString + { let (x,clt) = $1 in + Ast0.Constant (clt2mcode (Ast.String x) clt) } + | TChar + { let (x,clt) = $1 in + Ast0.Constant (clt2mcode (Ast.Char x) clt) } + | TMetaConst + { let (nm,ty,clt) = $1 in Ast0.MetaConst(clt2mcode nm clt,ty) } + | TMetaErr + { let (nm,clt) = $1 in Ast0.MetaErr(clt2mcode nm clt) } + | TMetaExp + { let (nm,ty,clt) = $1 in Ast0.MetaExpr(clt2mcode nm clt,ty) } + | TOPar eexpr TCPar + { Ast0.Paren(clt2mcode "(" $1,$2,clt2mcode ")" $3) } + | TOPar0 eexpr_mid TCPar0 + { Ast0.DisjExpr($2) } + | TOEllipsis expr_dots TCEllipsis + { Ast0.NestExpr(Ast0.DOTS($2)) } + | TOCircles expr_circles TCCircles + { Ast0.NestExpr(Ast0.CIRCLES($2)) } + | TOStars expr_stars TCStars + { Ast0.NestExpr(Ast0.STARS($2)) } + +expr_dots: + dexpr { [$1] } + | dexpr TEllipsis expr_dots + { $1 :: Ast0.Edots(clt2mcode "..." $2,None) :: $3 } + | dexpr TEllipsis TWhen TNotEq eexpr TLineEnd expr_dots + { $1 :: Ast0.Edots(clt2mcode "..." $2,Some $5) :: $7 } + +expr_circles: + dexpr { [$1] } + | dexpr TCircles expr_circles + { $1 :: Ast0.Ecircles(clt2mcode "ooo" $2,None) :: $3 } + | dexpr TCircles TWhen TNotEq eexpr TLineEnd expr_dots + { $1 :: Ast0.Ecircles(clt2mcode "ooo" $2,Some $5) :: $7 } + +expr_stars: + dexpr { [$1] } + | dexpr TStars expr_stars + { $1 :: Ast0.Estars(clt2mcode "***" $2,None) :: $3 } + | dexpr TStars TWhen TNotEq eexpr TLineEnd expr_dots + { $1 :: Ast0.Estars(clt2mcode "***" $2,Some $5) :: $7 } + +/*****************************************************************************/ + +pure_ident: TIdent { $1 } + +/* allows redeclaring metavariables. used in @@ @@ */ +pure_ident_or_meta_ident: + TIdent { $1 } + | TMetaId { $1 } + | TMetaType { $1 } + | TMetaParam { $1 } + | TMetaParamList { $1 } + | TMetaStm { $1 } + | TMetaStmList { $1 } + | TMetaFunc { $1 } + | TMetaLocalFunc { $1 } + | TMetaExpList { $1 } + | TMetaConst { let (name,_,info) = $1 in (name,info) } + | TMetaExp { let (name,_,info) = $1 in (name,info) } + | TMetaErr { $1 } + +ident: TIdent { Ast0.Id(id2mcode $1) } + | TMetaId { Ast0.MetaId(id2mcode $1) } + | TMetaFunc { Ast0.MetaFunc(id2mcode $1) } + | TMetaLocalFunc { Ast0.MetaLocalFunc(id2mcode $1) } + +/*****************************************************************************/ + +meta_var_list: meta_var { $1 } + | meta_var meta_var_list { $1@$2 } + +meta_var_list_opt: meta_var_list { $1 } + | /* empty */ { [] } + +d_ident_list: d_ident { [$1] } + | d_ident TComma d_ident_list { $1::$3 } + +ctype_list: ctype { [$1] } + | ctype TComma ctype_list { $1::$3 } + +pure_ident_or_meta_ident_list: + pure_ident_or_meta_ident + { [id2name $1] } + | pure_ident_or_meta_ident TComma pure_ident_or_meta_ident_list + { (id2name $1)::$3 } + +decl_list: + decl_list_start + { if List.exists (function Ast0.Pcircles(_) -> true | _ -> false) $1 + then Ast0.CIRCLES($1) + else Ast0.DOTS($1) } + +decl_list_start: + decl { [$1] } + | TMetaParamList + { let (nm,clt) = $1 in [Ast0.MetaParamList(clt2mcode nm clt)] } + | TEllipsis + { [Ast0.Pdots(clt2mcode "..." $1)] } + | TCircles + { [Ast0.Pcircles(clt2mcode "ooo" $1)] } + | decl TComma decl_list_start + { $1::Ast0.PComma(clt2mcode "," $2)::$3 } + | TMetaParamList TComma decl_list_start + { let (nm,clt) = $1 in + Ast0.MetaParamList(clt2mcode nm clt):: + Ast0.PComma(clt2mcode "," $2)::$3 } + | TEllipsis TComma decl_list_dots + { Ast0.Pdots(clt2mcode "..." $1):: + Ast0.PComma(clt2mcode "," $2):: + $3 } + | TCircles TComma decl_list_circles + { Ast0.Pcircles(clt2mcode "ooo" $1):: + Ast0.PComma(clt2mcode "," $2):: + $3 } + +decl_list_dots: + decl { [$1] } + | TMetaParamList + { let (nm,clt) = $1 in [Ast0.MetaParamList(clt2mcode nm clt)] } + | TEllipsis + { [Ast0.Pdots(clt2mcode "..." $1)] } + | decl TComma decl_list_dots + { $1::Ast0.PComma(clt2mcode "," $2)::$3 } + | TMetaParamList TComma decl_list_dots + { let (nm,clt) = $1 in + Ast0.MetaParamList(clt2mcode nm clt):: + Ast0.PComma(clt2mcode "," $2)::$3 } + | TEllipsis TComma decl_list_dots + { Ast0.Pdots(clt2mcode "..." $1)::Ast0.PComma(clt2mcode "," $2):: + $3 } + +decl_list_circles: + decl { [$1] } + | TMetaParamList + { let (nm,clt) = $1 in [Ast0.MetaParamList(clt2mcode nm clt)] } + | TCircles + { [Ast0.Pcircles(clt2mcode "ooo" $1)] } + | decl TComma decl_list_circles + { $1::Ast0.PComma(clt2mcode "," $2)::$3 } + | TMetaParamList TComma decl_list_circles + { let (nm,clt) = $1 in + Ast0.MetaParamList(clt2mcode nm clt):: + Ast0.PComma(clt2mcode "," $2)::$3 } + | TCircles TComma decl_list_circles + { Ast0.Pcircles(clt2mcode "ooo" $1):: + Ast0.PComma(clt2mcode "," $2):: + $3 } + +/* must be a single statement */ +statement_mid: + statement { [Ast0.DOTS([$1])] } + | statement TMid0 statement_mid { Ast0.DOTS([$1])::$3 } + +/* must be a list of declarations or statements, with no ... or expressions +for "and" case */ +pure_decl_statement_list: + decl_statement { $1 } + | decl_statement pure_decl_statement_list { $1@$2 } + +/* as above, but allows a single expression - for "or" case */ +exp_decl_statement_list: + expr { [Ast0.Exp($1)] } + | decl_statement { $1 } + | decl_statement pure_decl_statement_list { $1@$2 } + +fun_exp_decl_statement_list: + expr + { [Ast0.OTHER(Ast0.Exp($1))] } + | decl_statement + { List.map (function x -> Ast0.OTHER x) $1 } + | fundecl + { [Ast0.FUNCTION($1)] } + | TInclude + { [Ast0.INCLUDE(clt2mcode "#include" (id2clt $1),id2mcode $1)] } + | TMinusFile TPlusFile + { [Ast0.FILEINFO(id2mcode $1,id2mcode $2)] } + | decl_statement fun_exp_decl_statement_list + { (List.map (function x -> Ast0.OTHER x) $1)@$2 } + | fundecl fun_exp_decl_statement_list + { Ast0.FUNCTION($1)::$2 } + | TInclude fun_exp_decl_statement_list + { Ast0.INCLUDE(clt2mcode "#include" (id2clt $1),id2mcode $1)::$2 } + | TMinusFile TPlusFile fun_exp_decl_statement_list + { Ast0.FILEINFO(id2mcode $1,id2mcode $2)::$3 } + +/* ---------------------------------------------------------------------- */ + +error_words: + TError TWords TEq TOCro dotless_eexpr_list TCCro + { Ast0.ERRORWORDS($5) } + +/* ---------------------------------------------------------------------- */ +/* sequences of statements and expressions */ + +/* a mix of declarations, statements and expressions. an expression may +appear by itself. always nonempty and cannot just be dots. */ + +function_decl_statement_or_expression: + error_words /* only at the end */ + { [$1] } + | fun_exp_decl_statement_list + { $1 } + | fun_exp_decl_statement_list TEllipsis + function_decl_statement_or_expression_dots + { $1@Ast0.OTHER(Ast0.Dots(clt2mcode "..." $2,None))::$3 } + | TEllipsis function_decl_statement_or_expression_dots + { Ast0.OTHER(Ast0.Dots(clt2mcode "..." $1,None))::$2 } + | fun_exp_decl_statement_list TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + function_decl_statement_or_expression_dots + { $1@Ast0.OTHER(Ast0.Dots(clt2mcode "..." $2,Some $5))::$7 } + | TEllipsis TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + function_decl_statement_or_expression_dots + { Ast0.OTHER(Ast0.Dots(clt2mcode "..." $2,Some $4))::$6 } + | fun_exp_decl_statement_list TCircles + function_decl_statement_or_expression_circles + { $1@Ast0.OTHER(Ast0.Circles(clt2mcode "ooo" $2,None))::$3 } + | TCircles function_decl_statement_or_expression_circles + { Ast0.OTHER(Ast0.Circles(clt2mcode "ooo" $1,None))::$2 } + | fun_exp_decl_statement_list TCircles + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + function_decl_statement_or_expression_circles + { $1@Ast0.OTHER(Ast0.Circles(clt2mcode "ooo" $2,Some $5))::$7 } + | TCircles TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + function_decl_statement_or_expression_circles + { Ast0.OTHER(Ast0.Circles(clt2mcode "ooo" $1,Some $4))::$6 } + | fun_exp_decl_statement_list TStars + function_decl_statement_or_expression_stars + { $1@Ast0.OTHER(Ast0.Stars(clt2mcode "***" $2,None))::$3 } + | TStars function_decl_statement_or_expression_stars + { Ast0.OTHER(Ast0.Stars(clt2mcode "***" $1,None))::$2 } + | fun_exp_decl_statement_list TStars + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + function_decl_statement_or_expression_stars + { $1@Ast0.OTHER(Ast0.Stars(clt2mcode "***" $2,Some $5))::$7 } + | TStars TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + function_decl_statement_or_expression_stars + { Ast0.OTHER(Ast0.Stars(clt2mcode "***" $1,Some $4))::$6 } + +function_decl_statement_or_expression_dots: + /* empty */ { [] } + | fun_exp_decl_statement_list + { $1 } + | fun_exp_decl_statement_list TEllipsis + function_decl_statement_or_expression_dots + { $1@Ast0.OTHER(Ast0.Dots(clt2mcode "..." $2,None))::$3 } + | fun_exp_decl_statement_list TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + function_decl_statement_or_expression_dots + { $1@Ast0.OTHER(Ast0.Dots(clt2mcode "..." $2,Some $5))::$7 } + +function_decl_statement_or_expression_circles: + /* empty */ { [] } + | fun_exp_decl_statement_list + { $1 } + | fun_exp_decl_statement_list TCircles + function_decl_statement_or_expression_circles + { $1@Ast0.OTHER(Ast0.Circles(clt2mcode "ooo" $2,None))::$3 } + | fun_exp_decl_statement_list TCircles + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + function_decl_statement_or_expression_circles + { $1@Ast0.OTHER(Ast0.Circles(clt2mcode "ooo" $2,Some $5))::$7 } + +function_decl_statement_or_expression_stars: + /* empty */ { [] } + | fun_exp_decl_statement_list + { $1 } + | fun_exp_decl_statement_list TStars + function_decl_statement_or_expression_stars + { $1@Ast0.OTHER(Ast0.Stars(clt2mcode "***" $2,None))::$3 } + | fun_exp_decl_statement_list TStars + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + function_decl_statement_or_expression_stars + { $1@Ast0.OTHER(Ast0.Stars(clt2mcode "***" $2,Some $5))::$7 } + +decl_statement_or_expression_dots: + exp_decl_statement_list + { $1 } + | exp_decl_statement_list TEllipsis decl_statement_or_expression_dots + { $1@Ast0.Dots(clt2mcode "..." $2,None)::$3 } + | exp_decl_statement_list TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + decl_statement_or_expression_dots + { $1@Ast0.Dots(clt2mcode "..." $2,Some $5)::$7 } + +decl_statement_or_expression_circles: + exp_decl_statement_list + { $1 } + | exp_decl_statement_list TCircles decl_statement_or_expression_circles + { $1@Ast0.Dots(clt2mcode "..." $2,None)::$3 } + | exp_decl_statement_list TCircles + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + decl_statement_or_expression_circles + { $1@Ast0.Dots(clt2mcode "..." $2,Some $5)::$7 } + +decl_statement_or_expression_stars: + exp_decl_statement_list + { $1 } + | exp_decl_statement_list TStars decl_statement_or_expression_stars + { $1@Ast0.Stars(clt2mcode "***" $2,None)::$3 } + | exp_decl_statement_list TStars + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + decl_statement_or_expression_stars + { $1@Ast0.Stars(clt2mcode "***" $2,Some $5)::$7 } + +post_decl_statement_or_expression: + exp_decl_statement_list + { $1 } + | exp_decl_statement_list TEllipsis + { $1@[Ast0.Dots(clt2mcode "..." $2,None)] } + | exp_decl_statement_list TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + { $1@[Ast0.Dots(clt2mcode "..." $2,Some $5)] } + | exp_decl_statement_list TCircles + { $1@[Ast0.Circles(clt2mcode "ooo" $2,None)] } + | exp_decl_statement_list TCircles + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + { $1@[Ast0.Circles(clt2mcode "ooo" $2,Some $5)] } + | exp_decl_statement_list TStars + { $1@[Ast0.Stars(clt2mcode "***" $2,None)] } + | exp_decl_statement_list TStars + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + { $1@[Ast0.Stars(clt2mcode "***" $2,Some $5)] } + | exp_decl_statement_list TEllipsis post_decl_statement_or_expression_dots + { $1@Ast0.Dots(clt2mcode "..." $2,None)::$3 } + | exp_decl_statement_list TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_or_expression_dots + { $1@Ast0.Dots(clt2mcode "..." $2,Some $5)::$7 } + | exp_decl_statement_list TCircles post_decl_statement_or_expression_dots + { $1@Ast0.Circles(clt2mcode "ooo" $2,None)::$3 } + | exp_decl_statement_list TCircles + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_or_expression_dots + { $1@Ast0.Circles(clt2mcode "ooo" $2,Some $5)::$7 } + | exp_decl_statement_list TStars post_decl_statement_or_expression_dots + { $1@Ast0.Stars(clt2mcode "***" $2,None)::$3 } + | exp_decl_statement_list TStars + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_or_expression_dots + { $1@Ast0.Stars(clt2mcode "***" $2,Some $5)::$7 } + +post_decl_statement_or_expression_dots: + exp_decl_statement_list + { $1 } + | exp_decl_statement_list TEllipsis + { $1@[Ast0.Dots(clt2mcode "..." $2,None)] } + | exp_decl_statement_list TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + { $1@[Ast0.Dots(clt2mcode "..." $2,Some $5)] } + | exp_decl_statement_list TEllipsis post_decl_statement_or_expression_dots + { $1@Ast0.Dots(clt2mcode "..." $2,None)::$3 } + | exp_decl_statement_list TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_or_expression_dots + { $1@Ast0.Dots(clt2mcode "..." $2,Some $5)::$7 } + +post_decl_statement_or_expression_circles: + exp_decl_statement_list + { $1 } + | exp_decl_statement_list TCircles + { $1@[Ast0.Circles(clt2mcode "ooo" $2,None)] } + | exp_decl_statement_list TCircles + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + { $1@[Ast0.Circles(clt2mcode "ooo" $2,Some $5)] } + | exp_decl_statement_list TCircles post_decl_statement_or_expression_circles + { $1@Ast0.Circles(clt2mcode "ooo" $2,None)::$3 } + | exp_decl_statement_list TCircles + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_or_expression_circles + { $1@Ast0.Circles(clt2mcode "ooo" $2,Some $5)::$7 } + +post_decl_statement_or_expression_stars: + exp_decl_statement_list + { $1 } + | exp_decl_statement_list TEllipsis + { $1@[Ast0.Stars(clt2mcode "***" $2,None)] } + | exp_decl_statement_list TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + { $1@[Ast0.Stars(clt2mcode "***" $2,Some $5)] } + | exp_decl_statement_list TEllipsis post_decl_statement_or_expression_stars + { $1@Ast0.Stars(clt2mcode "***" $2,None)::$3 } + | exp_decl_statement_list TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_or_expression_stars + { $1@Ast0.Stars(clt2mcode "***" $2,Some $5)::$7 } + +pre_post_decl_statement_or_expression: + post_decl_statement_or_expression + { if List.exists (function Ast0.Circles(_) -> true | _ -> false) $1 + then Ast0.CIRCLES($1) + else if List.exists (function Ast0.Stars(_) -> true | _ -> false) $1 + then Ast0.STARS($1) + else Ast0.DOTS($1) } + | TEllipsis post_decl_statement_or_expression_dots + { Ast0.DOTS(Ast0.Dots(clt2mcode "..." $1,None)::$2) } + | TEllipsis TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_or_expression_dots + { Ast0.DOTS(Ast0.Dots(clt2mcode "..." $1,Some $4)::$6) } + | TCircles post_decl_statement_or_expression_circles + { Ast0.CIRCLES(Ast0.Circles(clt2mcode "ooo" $1,None)::$2) } + | TCircles TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_or_expression_circles + { Ast0.CIRCLES(Ast0.Circles(clt2mcode "ooo" $1,Some $4)::$6) } + | TStars post_decl_statement_or_expression_stars + { Ast0.STARS(Ast0.Stars(clt2mcode "***" $1,None)::$2) } + | TStars TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_or_expression_stars + { Ast0.STARS(Ast0.Stars(clt2mcode "***" $1,Some $4)::$6) } + +/* a mix of declarations, statements and expressions. an expression must +be surrounded by ... */ + +post_decl_statement_and_expression_dots: + /* empty */ { [] } + | pure_decl_statement_list { $1 } + | expr TEllipsis post_decl_statement_and_expression_dots + { Ast0.Exp($1)::Ast0.Dots(clt2mcode "..." $2,None)::$3 } + | expr TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_and_expression_dots + { Ast0.Exp($1)::Ast0.Dots(clt2mcode "..." $2,Some $5)::$7 } + | pure_decl_statement_list TEllipsis post_decl_statement_and_expression_dots + { $1@Ast0.Dots(clt2mcode "..." $2,None)::$3 } + | pure_decl_statement_list TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_and_expression_dots + { $1@Ast0.Dots(clt2mcode "..." $2,Some $5)::$7 } + +post_decl_statement_and_expression_circles: + /* empty */ { [] } + | pure_decl_statement_list { $1 } + | expr TCircles post_decl_statement_and_expression_circles + { Ast0.Exp($1)::Ast0.Circles(clt2mcode "ooo" $2,None)::$3 } + | expr TCircles + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_and_expression_circles + { Ast0.Exp($1)::Ast0.Circles(clt2mcode "ooo" $2,Some $5)::$7 } + | pure_decl_statement_list TCircles + post_decl_statement_and_expression_circles + { $1@Ast0.Circles(clt2mcode "ooo" $2,None)::$3 } + | pure_decl_statement_list TCircles + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_and_expression_circles + { $1@Ast0.Circles(clt2mcode "ooo" $2,Some $5)::$7 } + +post_decl_statement_and_expression_stars: + /* empty */ { [] } + | pure_decl_statement_list { $1 } + | expr TStars post_decl_statement_and_expression_stars + { Ast0.Exp($1)::Ast0.Stars(clt2mcode "***" $2,None)::$3 } + | expr TStars + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_and_expression_stars + { Ast0.Exp($1)::Ast0.Stars(clt2mcode "***" $2,Some $5)::$7 } + | pure_decl_statement_list TStars post_decl_statement_and_expression_stars + { $1@Ast0.Stars(clt2mcode "***" $2,None)::$3 } + | pure_decl_statement_list TStars + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_and_expression_stars + { $1@Ast0.Stars(clt2mcode "***" $2,Some $5)::$7 } + +pre_post_decl_statement_and_expression: + pure_decl_statement_list + { top_dots $1 } + | pure_decl_statement_list TEllipsis post_decl_statement_and_expression_dots + { Ast0.DOTS($1@Ast0.Dots(clt2mcode "..." $2,None)::$3) } + | pure_decl_statement_list TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_and_expression_dots + { Ast0.DOTS($1@Ast0.Dots(clt2mcode "..." $2,Some $5)::$7) } + | pure_decl_statement_list TCircles + post_decl_statement_and_expression_circles + { Ast0.CIRCLES($1@Ast0.Circles(clt2mcode "ooo" $2,None)::$3) } + | pure_decl_statement_list TCircles + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_and_expression_circles + { Ast0.CIRCLES($1@Ast0.Circles(clt2mcode "ooo" $2,Some $5)::$7) } + | pure_decl_statement_list TStars post_decl_statement_and_expression_stars + { Ast0.STARS($1@Ast0.Stars(clt2mcode "***" $2,None)::$3) } + | pure_decl_statement_list TStars + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_and_expression_stars + { Ast0.STARS($1@Ast0.Stars(clt2mcode "***" $2,Some $5)::$7) } + | TEllipsis post_decl_statement_and_expression_dots + { Ast0.DOTS(Ast0.Dots(clt2mcode "..." $1,None)::$2) } + | TEllipsis + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_and_expression_dots + { Ast0.DOTS(Ast0.Dots(clt2mcode "..." $1,Some $4)::$6) } + | TCircles post_decl_statement_and_expression_circles + { Ast0.CIRCLES(Ast0.Circles(clt2mcode "ooo" $1,None)::$2) } + | TCircles + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_and_expression_circles + { Ast0.CIRCLES(Ast0.Circles(clt2mcode "ooo" $1,Some $4)::$6) } + | TStars post_decl_statement_and_expression_stars + { Ast0.STARS(Ast0.Stars(clt2mcode "***" $1,None)::$2) } + | TStars + TWhen TNotEq pre_post_decl_statement_or_expression TLineEnd + post_decl_statement_and_expression_stars + { Ast0.STARS(Ast0.Stars(clt2mcode "***" $1,Some $4)::$6) } + +pre_post_decl_statement_and_expression_opt: + /* empty */ { Ast0.DOTS([]) } + | pre_post_decl_statement_and_expression { $1 } + +pre_post_decl_statement_and_expression_opt_mid: + pre_post_decl_statement_and_expression { [$1] } + | /* empty */ { [Ast0.DOTS([])] } + | pre_post_decl_statement_and_expression TMid0 + pre_post_decl_statement_and_expression_opt_mid { $1::$3 } + | TMid0 + pre_post_decl_statement_and_expression_opt_mid { Ast0.DOTS([])::$2 } + +/* ---------------------------------------------------------------------- */ + +dotless_eexpr_list: + dexpr + { [$1] } + | dexpr TComma dotless_eexpr_list + { $1::Ast0.EComma(clt2mcode "," $2)::$3 } + +eexpr_list: + eexpr_list_start + { if List.exists (function Ast0.Ecircles(_) -> true | _ -> false) $1 + then Ast0.CIRCLES($1) + else if List.exists (function Ast0.Estars(_) -> true | _ -> false) $1 + then Ast0.STARS($1) + else Ast0.DOTS($1) } + +eexpr_list_start: + dexpr + { [$1] } + | TMetaExpList + { let (nm,clt) = $1 in [Ast0.MetaExprList(clt2mcode nm clt)] } + | TEllipsis + { [Ast0.Edots(clt2mcode "..." $1,None)] } + | TEllipsis TWhen TNotEq eexpr TLineEnd + { [Ast0.Edots(clt2mcode "..." $1,Some $4)] } + | TCircles + { [Ast0.Ecircles(clt2mcode "ooo" $1,None)] } + | TCircles TWhen TNotEq eexpr TLineEnd + { [Ast0.Ecircles(clt2mcode "ooo" $1,Some $4)] } + | TStars + { [Ast0.Estars(clt2mcode "***" $1,None)] } + | TStars TWhen TNotEq eexpr TLineEnd + { [Ast0.Estars(clt2mcode "***" $1,Some $4)] } + | dexpr TComma eexpr_list_start + { $1::Ast0.EComma(clt2mcode "," $2)::$3 } + | TMetaExpList TComma eexpr_list_start + { let (nm,clt) = $1 in + Ast0.MetaExprList(clt2mcode nm clt)::Ast0.EComma(clt2mcode "," $2)::$3 } + | TEllipsis TComma eexpr_list_dots + { Ast0.Edots(clt2mcode "..." $1,None):: + Ast0.EComma(clt2mcode "," $2)::$3 } + | TEllipsis TWhen TNotEq eexpr TLineEnd TComma eexpr_list_dots + { Ast0.Edots(clt2mcode "..." $1,Some $4):: + Ast0.EComma(clt2mcode "," $6)::$7 } + | TCircles TComma eexpr_list_circles + { Ast0.Ecircles(clt2mcode "ooo" $1,None):: + Ast0.EComma(clt2mcode "," $2)::$3 } + | TCircles TWhen TNotEq eexpr TLineEnd TComma eexpr_list_circles + { Ast0.Ecircles(clt2mcode "ooo" $1,Some $4):: + Ast0.EComma(clt2mcode "," $6)::$7 } + | TStars TComma eexpr_list_stars + { Ast0.Estars(clt2mcode "***" $1,None):: + Ast0.EComma(clt2mcode "," $2)::$3 } + | TStars TWhen TNotEq eexpr TLineEnd TComma eexpr_list_stars + { Ast0.Estars(clt2mcode "***" $1,Some $4):: + Ast0.EComma(clt2mcode "," $6)::$7 } + +eexpr_list_dots: + dexpr + { [$1] } + | TMetaExpList + { let (nm,clt) = $1 in [Ast0.MetaExprList(clt2mcode nm clt)] } + | TEllipsis + { [Ast0.Edots(clt2mcode "..." $1,None)] } + | TEllipsis TWhen TNotEq eexpr TLineEnd + { [Ast0.Edots(clt2mcode "..." $1,Some $4)] } + | dexpr TComma eexpr_list_dots + { $1::Ast0.EComma(clt2mcode "," $2)::$3 } + | TMetaExpList TComma eexpr_list_dots + { let (nm,clt) = $1 in + Ast0.MetaExprList(clt2mcode nm clt)::Ast0.EComma(clt2mcode "," $2)::$3 } + | TEllipsis TComma eexpr_list_dots + { Ast0.Edots(clt2mcode "..." $1,None):: + Ast0.EComma(clt2mcode "," $2)::$3 } + | TEllipsis TWhen TNotEq eexpr TLineEnd TComma eexpr_list_dots + { Ast0.Edots(clt2mcode "..." $1,Some $4):: + Ast0.EComma(clt2mcode "," $6)::$7 } + +eexpr_list_circles: + dexpr + { [$1] } + | TMetaExpList + { let (nm,clt) = $1 in [Ast0.MetaExprList(clt2mcode nm clt)] } + | TCircles + { [Ast0.Ecircles(clt2mcode "ooo" $1,None)] } + | TCircles TWhen TNotEq eexpr TLineEnd + { [Ast0.Ecircles(clt2mcode "ooo" $1,Some $4)] } + | dexpr TComma eexpr_list_circles + { $1::Ast0.EComma(clt2mcode "," $2)::$3 } + | TMetaExpList TComma eexpr_list_circles + { let (nm,clt) = $1 in + Ast0.MetaExprList(clt2mcode nm clt)::Ast0.EComma(clt2mcode "," $2)::$3 } + | TCircles TComma eexpr_list_circles + { Ast0.Ecircles(clt2mcode "ooo" $1,None):: + Ast0.EComma(clt2mcode "," $2)::$3 } + | TCircles TWhen TNotEq eexpr TLineEnd TComma eexpr_list_circles + { Ast0.Ecircles(clt2mcode "ooo" $1,Some $4):: + Ast0.EComma(clt2mcode "," $6)::$7 } + +eexpr_list_stars: + dexpr + { [$1] } + | TMetaExpList + { let (nm,clt) = $1 in [Ast0.MetaExprList(clt2mcode nm clt)] } + | TStars + { [Ast0.Estars(clt2mcode "***" $1,None)] } + | TStars TWhen TNotEq eexpr TLineEnd + { [Ast0.Estars(clt2mcode "***" $1,Some $4)] } + | dexpr TComma eexpr_list_stars + { $1::Ast0.EComma(clt2mcode "," $2)::$3 } + | TMetaExpList TComma eexpr_list_stars + { let (nm,clt) = $1 in + Ast0.MetaExprList(clt2mcode nm clt)::Ast0.EComma(clt2mcode "," $2)::$3 } + | TStars TComma eexpr_list_stars + { Ast0.Estars(clt2mcode "***" $1,None):: + Ast0.EComma(clt2mcode "," $2)::$3 } + | TStars TWhen TNotEq eexpr TLineEnd TComma eexpr_list_stars + { Ast0.Estars(clt2mcode "***" $1,Some $4):: + Ast0.EComma(clt2mcode "," $6)::$7 } + +eexpr_list_opt: eexpr_list { $1 } + | /* empty */ { Ast0.DOTS([]) } + +expr_mid: + expr { [$1] } + | expr TMid0 expr_mid { $1::$3 } + +eexpr_mid: + eexpr { [$1] } + | eexpr TMid0 eexpr_mid { $1::$3 } + +eexpr_opt: eexpr { Some ($1) } + | /* empty */ { None } + diff --git a/parsing_cocci/parser_cocci_menhir.ml b/parsing_cocci/parser_cocci_menhir.ml new file mode 100644 index 0000000..58c840f --- /dev/null +++ b/parsing_cocci/parser_cocci_menhir.ml @@ -0,0 +1,28763 @@ + +# 23 "parser_cocci_menhir.mly" + + +(* Not clear how to allow function declarations to specify a return type +and how to allow both to be specified as static, because they are in +different rules. The rules seem to have to be combined, which would allow +functions to be declared as local variables *) + +(* Not clear how to let a function have a parameter of type void. At the +moment, void is allowed to be the type of a variable, which is wrong, and a +parameter needs both a type and an identifier *) +module Ast0 = Ast0_cocci +module Ast = Ast_cocci +module P = Parse_aux + +# 18 "parser_cocci_menhir.ml" +exception Error + +type token = + | Tvolatile of ( +# 54 "parser_cocci_menhir.mly" + (Data.clt) +# 25 "parser_cocci_menhir.ml" +) + | Tvoid of ( +# 50 "parser_cocci_menhir.mly" + (Data.clt) +# 30 "parser_cocci_menhir.ml" +) + | Tunsigned of ( +# 51 "parser_cocci_menhir.mly" + (Data.clt) +# 35 "parser_cocci_menhir.ml" +) + | Tunion of ( +# 50 "parser_cocci_menhir.mly" + (Data.clt) +# 40 "parser_cocci_menhir.ml" +) + | Ttypedef of ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 45 "parser_cocci_menhir.ml" +) + | Tstruct of ( +# 50 "parser_cocci_menhir.mly" + (Data.clt) +# 50 "parser_cocci_menhir.ml" +) + | Tstatic of ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 55 "parser_cocci_menhir.ml" +) + | Tsigned of ( +# 51 "parser_cocci_menhir.mly" + (Data.clt) +# 60 "parser_cocci_menhir.ml" +) + | Tshort of ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 65 "parser_cocci_menhir.ml" +) + | Tregister of ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 70 "parser_cocci_menhir.ml" +) + | Tlong of ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 75 "parser_cocci_menhir.ml" +) + | Tlist + | Tint of ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 81 "parser_cocci_menhir.ml" +) + | Tinline of ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 86 "parser_cocci_menhir.ml" +) + | Tfloat of ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 91 "parser_cocci_menhir.ml" +) + | Textern of ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 96 "parser_cocci_menhir.ml" +) + | Tdouble of ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 101 "parser_cocci_menhir.ml" +) + | Tconst of ( +# 54 "parser_cocci_menhir.mly" + (Data.clt) +# 106 "parser_cocci_menhir.ml" +) + | Tchar of ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 111 "parser_cocci_menhir.ml" +) + | Tauto of ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 116 "parser_cocci_menhir.ml" +) + | Tattr of ( +# 55 "parser_cocci_menhir.mly" + (string * Data.clt) +# 121 "parser_cocci_menhir.ml" +) + | TXor of ( +# 91 "parser_cocci_menhir.mly" + (Data.clt) +# 126 "parser_cocci_menhir.ml" +) + | TWords + | TWhy0 + | TWhy of ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 133 "parser_cocci_menhir.ml" +) + | TWhile of ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 138 "parser_cocci_menhir.ml" +) + | TWhen of ( +# 73 "parser_cocci_menhir.mly" + (Data.clt) +# 143 "parser_cocci_menhir.ml" +) + | TUsing + | TTypedef + | TTypeId of ( +# 59 "parser_cocci_menhir.mly" + (string * Data.clt) +# 150 "parser_cocci_menhir.ml" +) + | TType + | TTilde of ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 156 "parser_cocci_menhir.ml" +) + | TSwitch of ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 161 "parser_cocci_menhir.ml" +) + | TString of ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 166 "parser_cocci_menhir.ml" +) + | TStrict of ( +# 73 "parser_cocci_menhir.mly" + (Data.clt) +# 171 "parser_cocci_menhir.ml" +) + | TStatement + | TSizeof of ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 177 "parser_cocci_menhir.ml" +) + | TShOp of ( +# 95 "parser_cocci_menhir.mly" + (Ast_cocci.arithOp * Data.clt) +# 182 "parser_cocci_menhir.ml" +) + | TScriptData of ( +# 70 "parser_cocci_menhir.mly" + (string) +# 187 "parser_cocci_menhir.ml" +) + | TRuleName of ( +# 47 "parser_cocci_menhir.mly" + (string) +# 192 "parser_cocci_menhir.ml" +) + | TRightIso + | TReverse + | TReturn of ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 199 "parser_cocci_menhir.ml" +) + | TPure + | TPtrOp of ( +# 103 "parser_cocci_menhir.mly" + (Data.clt) +# 205 "parser_cocci_menhir.ml" +) + | TPtVirg of ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 210 "parser_cocci_menhir.ml" +) + | TPragma of ( +# 78 "parser_cocci_menhir.mly" + (string) +# 215 "parser_cocci_menhir.ml" +) + | TPosition + | TPosAny + | TPlusFile of ( +# 82 "parser_cocci_menhir.mly" + (string * Data.clt) +# 222 "parser_cocci_menhir.ml" +) + | TPlus0 + | TPlus of ( +# 97 "parser_cocci_menhir.mly" + (Data.clt) +# 228 "parser_cocci_menhir.ml" +) + | TPathIsoFile of ( +# 78 "parser_cocci_menhir.mly" + (string) +# 233 "parser_cocci_menhir.ml" +) + | TParameter + | TPOEllipsis of ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 239 "parser_cocci_menhir.ml" +) + | TPCEllipsis of ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 244 "parser_cocci_menhir.ml" +) + | TPArob + | TOrLog of ( +# 88 "parser_cocci_menhir.mly" + (Data.clt) +# 250 "parser_cocci_menhir.ml" +) + | TOr of ( +# 90 "parser_cocci_menhir.mly" + (Data.clt) +# 255 "parser_cocci_menhir.ml" +) + | TOn + | TOPar0 of ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 261 "parser_cocci_menhir.ml" +) + | TOPar of ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 266 "parser_cocci_menhir.ml" +) + | TOEllipsis of ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 271 "parser_cocci_menhir.ml" +) + | TOCro of ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 276 "parser_cocci_menhir.ml" +) + | TOBrace of ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 281 "parser_cocci_menhir.ml" +) + | TNothing + | TNotEq of ( +# 93 "parser_cocci_menhir.mly" + (Data.clt) +# 287 "parser_cocci_menhir.ml" +) + | TNever + | TName + | TMul of ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 294 "parser_cocci_menhir.ml" +) + | TMinusFile of ( +# 82 "parser_cocci_menhir.mly" + (string * Data.clt) +# 299 "parser_cocci_menhir.ml" +) + | TMinus of ( +# 97 "parser_cocci_menhir.mly" + (Data.clt) +# 304 "parser_cocci_menhir.ml" +) + | TMid0 of ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 309 "parser_cocci_menhir.ml" +) + | TMetaType of ( +# 64 "parser_cocci_menhir.mly" + (Parse_aux.info) +# 314 "parser_cocci_menhir.ml" +) + | TMetaStmList of ( +# 64 "parser_cocci_menhir.mly" + (Parse_aux.info) +# 319 "parser_cocci_menhir.ml" +) + | TMetaStm of ( +# 64 "parser_cocci_menhir.mly" + (Parse_aux.info) +# 324 "parser_cocci_menhir.ml" +) + | TMetaPos of ( +# 67 "parser_cocci_menhir.mly" + (Parse_aux.pos_info) +# 329 "parser_cocci_menhir.ml" +) + | TMetaParamList of ( +# 65 "parser_cocci_menhir.mly" + (Parse_aux.list_info) +# 334 "parser_cocci_menhir.ml" +) + | TMetaParam of ( +# 64 "parser_cocci_menhir.mly" + (Parse_aux.info) +# 339 "parser_cocci_menhir.ml" +) + | TMetaLocalIdExp of ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 344 "parser_cocci_menhir.ml" +) + | TMetaLocalFunc of ( +# 61 "parser_cocci_menhir.mly" + (Parse_aux.idinfo) +# 349 "parser_cocci_menhir.ml" +) + | TMetaIterator of ( +# 62 "parser_cocci_menhir.mly" + (Parse_aux.idinfo) +# 354 "parser_cocci_menhir.ml" +) + | TMetaIdExp of ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 359 "parser_cocci_menhir.ml" +) + | TMetaId of ( +# 61 "parser_cocci_menhir.mly" + (Parse_aux.idinfo) +# 364 "parser_cocci_menhir.ml" +) + | TMetaFunc of ( +# 61 "parser_cocci_menhir.mly" + (Parse_aux.idinfo) +# 369 "parser_cocci_menhir.ml" +) + | TMetaExpList of ( +# 65 "parser_cocci_menhir.mly" + (Parse_aux.list_info) +# 374 "parser_cocci_menhir.ml" +) + | TMetaExp of ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 379 "parser_cocci_menhir.ml" +) + | TMetaErr of ( +# 63 "parser_cocci_menhir.mly" + (Parse_aux.expinfo) +# 384 "parser_cocci_menhir.ml" +) + | TMetaDeclarer of ( +# 62 "parser_cocci_menhir.mly" + (Parse_aux.idinfo) +# 389 "parser_cocci_menhir.ml" +) + | TMetaConst of ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 394 "parser_cocci_menhir.ml" +) + | TMPtVirg + | TLogOp of ( +# 94 "parser_cocci_menhir.mly" + (Ast_cocci.logicalOp * Data.clt) +# 400 "parser_cocci_menhir.ml" +) + | TLocal + | TLineEnd of ( +# 73 "parser_cocci_menhir.mly" + (Data.clt) +# 406 "parser_cocci_menhir.ml" +) + | TIteratorId of ( +# 59 "parser_cocci_menhir.mly" + (string * Data.clt) +# 411 "parser_cocci_menhir.ml" +) + | TIterator + | TIsoType + | TIsoTopLevel + | TIsoTestExpression + | TIsoStatement + | TIsoExpression + | TIsoDeclaration + | TIsoArgExpression + | TIso + | TInvalid + | TInt of ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 426 "parser_cocci_menhir.ml" +) + | TIncludeNL of ( +# 79 "parser_cocci_menhir.mly" + (string * Data.clt) +# 431 "parser_cocci_menhir.ml" +) + | TIncludeL of ( +# 79 "parser_cocci_menhir.mly" + (string * Data.clt) +# 436 "parser_cocci_menhir.ml" +) + | TInc of ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 441 "parser_cocci_menhir.ml" +) + | TIf of ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 446 "parser_cocci_menhir.ml" +) + | TIdentifier + | TIdent of ( +# 59 "parser_cocci_menhir.mly" + (string * Data.clt) +# 452 "parser_cocci_menhir.ml" +) + | TIdExpression + | TGoto of ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 458 "parser_cocci_menhir.ml" +) + | TFunction + | TFunDecl of ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 464 "parser_cocci_menhir.ml" +) + | TFresh + | TForall + | TFor of ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 471 "parser_cocci_menhir.ml" +) + | TFloat of ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 476 "parser_cocci_menhir.ml" +) + | TExtends + | TExpression + | TExists + | TEver + | TError + | TEqEq of ( +# 93 "parser_cocci_menhir.mly" + (Data.clt) +# 486 "parser_cocci_menhir.ml" +) + | TEq of ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 491 "parser_cocci_menhir.ml" +) + | TElse of ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 496 "parser_cocci_menhir.ml" +) + | TEllipsis of ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 501 "parser_cocci_menhir.ml" +) + | TDotDot of ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 506 "parser_cocci_menhir.ml" +) + | TDot of ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 511 "parser_cocci_menhir.ml" +) + | TDo of ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 516 "parser_cocci_menhir.ml" +) + | TDmOp of ( +# 96 "parser_cocci_menhir.mly" + (Ast_cocci.arithOp * Data.clt) +# 521 "parser_cocci_menhir.ml" +) + | TDisable + | TDepends + | TDefineParam of ( +# 81 "parser_cocci_menhir.mly" + (Data.clt * token * int) +# 528 "parser_cocci_menhir.ml" +) + | TDefine of ( +# 80 "parser_cocci_menhir.mly" + (Data.clt * token) +# 533 "parser_cocci_menhir.ml" +) + | TDefault of ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 538 "parser_cocci_menhir.ml" +) + | TDeclarerId of ( +# 59 "parser_cocci_menhir.mly" + (string * Data.clt) +# 543 "parser_cocci_menhir.ml" +) + | TDeclarer + | TDec of ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 549 "parser_cocci_menhir.ml" +) + | TContinue of ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 554 "parser_cocci_menhir.ml" +) + | TContext + | TConstant + | TComma of ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 561 "parser_cocci_menhir.ml" +) + | TChar of ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 566 "parser_cocci_menhir.ml" +) + | TCase of ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 571 "parser_cocci_menhir.ml" +) + | TCPar0 of ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 576 "parser_cocci_menhir.ml" +) + | TCPar of ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 581 "parser_cocci_menhir.ml" +) + | TCEllipsis of ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 586 "parser_cocci_menhir.ml" +) + | TCCro of ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 591 "parser_cocci_menhir.ml" +) + | TCBrace of ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 596 "parser_cocci_menhir.ml" +) + | TBreak of ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 601 "parser_cocci_menhir.ml" +) + | TBang0 + | TBang of ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 607 "parser_cocci_menhir.ml" +) + | TAssign of ( +# 107 "parser_cocci_menhir.mly" + (Ast_cocci.assignOp * Data.clt) +# 612 "parser_cocci_menhir.ml" +) + | TArobArob + | TArob + | TAny of ( +# 73 "parser_cocci_menhir.mly" + (Data.clt) +# 619 "parser_cocci_menhir.ml" +) + | TAndLog of ( +# 89 "parser_cocci_menhir.mly" + (Data.clt) +# 624 "parser_cocci_menhir.ml" +) + | TAnd of ( +# 92 "parser_cocci_menhir.mly" + (Data.clt) +# 629 "parser_cocci_menhir.ml" +) + | EOF + +and _menhir_jeton = token + +let _eRR = + Error + +module MenhirInterpreter = MenhirLib.TableInterpreter.Make (struct + + exception Error = Error + + type token = _menhir_jeton + + let token2terminal : token -> int = + fun _tok -> + match _tok with + | EOF -> + 162 + | TAnd _ -> + 161 + | TAndLog _ -> + 160 + | TAny _ -> + 159 + | TArob -> + 158 + | TArobArob -> + 157 + | TAssign _ -> + 156 + | TBang _ -> + 155 + | TBang0 -> + 154 + | TBreak _ -> + 153 + | TCBrace _ -> + 152 + | TCCro _ -> + 151 + | TCEllipsis _ -> + 150 + | TCPar _ -> + 149 + | TCPar0 _ -> + 148 + | TCase _ -> + 147 + | TChar _ -> + 146 + | TComma _ -> + 145 + | TConstant -> + 144 + | TContext -> + 143 + | TContinue _ -> + 142 + | TDec _ -> + 141 + | TDeclarer -> + 140 + | TDeclarerId _ -> + 139 + | TDefault _ -> + 138 + | TDefine _ -> + 137 + | TDefineParam _ -> + 136 + | TDepends -> + 135 + | TDisable -> + 134 + | TDmOp _ -> + 133 + | TDo _ -> + 132 + | TDot _ -> + 131 + | TDotDot _ -> + 130 + | TEllipsis _ -> + 129 + | TElse _ -> + 128 + | TEq _ -> + 127 + | TEqEq _ -> + 126 + | TError -> + 125 + | TEver -> + 124 + | TExists -> + 123 + | TExpression -> + 122 + | TExtends -> + 121 + | TFloat _ -> + 120 + | TFor _ -> + 119 + | TForall -> + 118 + | TFresh -> + 117 + | TFunDecl _ -> + 116 + | TFunction -> + 115 + | TGoto _ -> + 114 + | TIdExpression -> + 113 + | TIdent _ -> + 112 + | TIdentifier -> + 111 + | TIf _ -> + 110 + | TInc _ -> + 109 + | TIncludeL _ -> + 108 + | TIncludeNL _ -> + 107 + | TInt _ -> + 106 + | TInvalid -> + 105 + | TIso -> + 104 + | TIsoArgExpression -> + 103 + | TIsoDeclaration -> + 102 + | TIsoExpression -> + 101 + | TIsoStatement -> + 100 + | TIsoTestExpression -> + 99 + | TIsoTopLevel -> + 98 + | TIsoType -> + 97 + | TIterator -> + 96 + | TIteratorId _ -> + 95 + | TLineEnd _ -> + 94 + | TLocal -> + 93 + | TLogOp _ -> + 92 + | TMPtVirg -> + 91 + | TMetaConst _ -> + 90 + | TMetaDeclarer _ -> + 89 + | TMetaErr _ -> + 88 + | TMetaExp _ -> + 87 + | TMetaExpList _ -> + 86 + | TMetaFunc _ -> + 85 + | TMetaId _ -> + 84 + | TMetaIdExp _ -> + 83 + | TMetaIterator _ -> + 82 + | TMetaLocalFunc _ -> + 81 + | TMetaLocalIdExp _ -> + 80 + | TMetaParam _ -> + 79 + | TMetaParamList _ -> + 78 + | TMetaPos _ -> + 77 + | TMetaStm _ -> + 76 + | TMetaStmList _ -> + 75 + | TMetaType _ -> + 74 + | TMid0 _ -> + 73 + | TMinus _ -> + 72 + | TMinusFile _ -> + 71 + | TMul _ -> + 70 + | TName -> + 69 + | TNever -> + 68 + | TNotEq _ -> + 67 + | TNothing -> + 66 + | TOBrace _ -> + 65 + | TOCro _ -> + 64 + | TOEllipsis _ -> + 63 + | TOPar _ -> + 62 + | TOPar0 _ -> + 61 + | TOn -> + 60 + | TOr _ -> + 59 + | TOrLog _ -> + 58 + | TPArob -> + 57 + | TPCEllipsis _ -> + 56 + | TPOEllipsis _ -> + 55 + | TParameter -> + 54 + | TPathIsoFile _ -> + 53 + | TPlus _ -> + 52 + | TPlus0 -> + 51 + | TPlusFile _ -> + 50 + | TPosAny -> + 49 + | TPosition -> + 48 + | TPragma _ -> + 47 + | TPtVirg _ -> + 46 + | TPtrOp _ -> + 45 + | TPure -> + 44 + | TReturn _ -> + 43 + | TReverse -> + 42 + | TRightIso -> + 41 + | TRuleName _ -> + 40 + | TScriptData _ -> + 39 + | TShOp _ -> + 38 + | TSizeof _ -> + 37 + | TStatement -> + 36 + | TStrict _ -> + 35 + | TString _ -> + 34 + | TSwitch _ -> + 33 + | TTilde _ -> + 32 + | TType -> + 31 + | TTypeId _ -> + 30 + | TTypedef -> + 29 + | TUsing -> + 28 + | TWhen _ -> + 27 + | TWhile _ -> + 26 + | TWhy _ -> + 25 + | TWhy0 -> + 24 + | TWords -> + 23 + | TXor _ -> + 22 + | Tattr _ -> + 21 + | Tauto _ -> + 20 + | Tchar _ -> + 19 + | Tconst _ -> + 18 + | Tdouble _ -> + 17 + | Textern _ -> + 16 + | Tfloat _ -> + 15 + | Tinline _ -> + 14 + | Tint _ -> + 13 + | Tlist -> + 12 + | Tlong _ -> + 11 + | Tregister _ -> + 10 + | Tshort _ -> + 9 + | Tsigned _ -> + 8 + | Tstatic _ -> + 7 + | Tstruct _ -> + 6 + | Ttypedef _ -> + 5 + | Tunion _ -> + 4 + | Tunsigned _ -> + 3 + | Tvoid _ -> + 2 + | Tvolatile _ -> + 1 + + let error_terminal = + 0 + + let token2value : token -> Obj.t = + fun _tok -> + match _tok with + | EOF -> + Obj.repr () + | TAnd _v -> + Obj.repr _v + | TAndLog _v -> + Obj.repr _v + | TAny _v -> + Obj.repr _v + | TArob -> + Obj.repr () + | TArobArob -> + Obj.repr () + | TAssign _v -> + Obj.repr _v + | TBang _v -> + Obj.repr _v + | TBang0 -> + Obj.repr () + | TBreak _v -> + Obj.repr _v + | TCBrace _v -> + Obj.repr _v + | TCCro _v -> + Obj.repr _v + | TCEllipsis _v -> + Obj.repr _v + | TCPar _v -> + Obj.repr _v + | TCPar0 _v -> + Obj.repr _v + | TCase _v -> + Obj.repr _v + | TChar _v -> + Obj.repr _v + | TComma _v -> + Obj.repr _v + | TConstant -> + Obj.repr () + | TContext -> + Obj.repr () + | TContinue _v -> + Obj.repr _v + | TDec _v -> + Obj.repr _v + | TDeclarer -> + Obj.repr () + | TDeclarerId _v -> + Obj.repr _v + | TDefault _v -> + Obj.repr _v + | TDefine _v -> + Obj.repr _v + | TDefineParam _v -> + Obj.repr _v + | TDepends -> + Obj.repr () + | TDisable -> + Obj.repr () + | TDmOp _v -> + Obj.repr _v + | TDo _v -> + Obj.repr _v + | TDot _v -> + Obj.repr _v + | TDotDot _v -> + Obj.repr _v + | TEllipsis _v -> + Obj.repr _v + | TElse _v -> + Obj.repr _v + | TEq _v -> + Obj.repr _v + | TEqEq _v -> + Obj.repr _v + | TError -> + Obj.repr () + | TEver -> + Obj.repr () + | TExists -> + Obj.repr () + | TExpression -> + Obj.repr () + | TExtends -> + Obj.repr () + | TFloat _v -> + Obj.repr _v + | TFor _v -> + Obj.repr _v + | TForall -> + Obj.repr () + | TFresh -> + Obj.repr () + | TFunDecl _v -> + Obj.repr _v + | TFunction -> + Obj.repr () + | TGoto _v -> + Obj.repr _v + | TIdExpression -> + Obj.repr () + | TIdent _v -> + Obj.repr _v + | TIdentifier -> + Obj.repr () + | TIf _v -> + Obj.repr _v + | TInc _v -> + Obj.repr _v + | TIncludeL _v -> + Obj.repr _v + | TIncludeNL _v -> + Obj.repr _v + | TInt _v -> + Obj.repr _v + | TInvalid -> + Obj.repr () + | TIso -> + Obj.repr () + | TIsoArgExpression -> + Obj.repr () + | TIsoDeclaration -> + Obj.repr () + | TIsoExpression -> + Obj.repr () + | TIsoStatement -> + Obj.repr () + | TIsoTestExpression -> + Obj.repr () + | TIsoTopLevel -> + Obj.repr () + | TIsoType -> + Obj.repr () + | TIterator -> + Obj.repr () + | TIteratorId _v -> + Obj.repr _v + | TLineEnd _v -> + Obj.repr _v + | TLocal -> + Obj.repr () + | TLogOp _v -> + Obj.repr _v + | TMPtVirg -> + Obj.repr () + | TMetaConst _v -> + Obj.repr _v + | TMetaDeclarer _v -> + Obj.repr _v + | TMetaErr _v -> + Obj.repr _v + | TMetaExp _v -> + Obj.repr _v + | TMetaExpList _v -> + Obj.repr _v + | TMetaFunc _v -> + Obj.repr _v + | TMetaId _v -> + Obj.repr _v + | TMetaIdExp _v -> + Obj.repr _v + | TMetaIterator _v -> + Obj.repr _v + | TMetaLocalFunc _v -> + Obj.repr _v + | TMetaLocalIdExp _v -> + Obj.repr _v + | TMetaParam _v -> + Obj.repr _v + | TMetaParamList _v -> + Obj.repr _v + | TMetaPos _v -> + Obj.repr _v + | TMetaStm _v -> + Obj.repr _v + | TMetaStmList _v -> + Obj.repr _v + | TMetaType _v -> + Obj.repr _v + | TMid0 _v -> + Obj.repr _v + | TMinus _v -> + Obj.repr _v + | TMinusFile _v -> + Obj.repr _v + | TMul _v -> + Obj.repr _v + | TName -> + Obj.repr () + | TNever -> + Obj.repr () + | TNotEq _v -> + Obj.repr _v + | TNothing -> + Obj.repr () + | TOBrace _v -> + Obj.repr _v + | TOCro _v -> + Obj.repr _v + | TOEllipsis _v -> + Obj.repr _v + | TOPar _v -> + Obj.repr _v + | TOPar0 _v -> + Obj.repr _v + | TOn -> + Obj.repr () + | TOr _v -> + Obj.repr _v + | TOrLog _v -> + Obj.repr _v + | TPArob -> + Obj.repr () + | TPCEllipsis _v -> + Obj.repr _v + | TPOEllipsis _v -> + Obj.repr _v + | TParameter -> + Obj.repr () + | TPathIsoFile _v -> + Obj.repr _v + | TPlus _v -> + Obj.repr _v + | TPlus0 -> + Obj.repr () + | TPlusFile _v -> + Obj.repr _v + | TPosAny -> + Obj.repr () + | TPosition -> + Obj.repr () + | TPragma _v -> + Obj.repr _v + | TPtVirg _v -> + Obj.repr _v + | TPtrOp _v -> + Obj.repr _v + | TPure -> + Obj.repr () + | TReturn _v -> + Obj.repr _v + | TReverse -> + Obj.repr () + | TRightIso -> + Obj.repr () + | TRuleName _v -> + Obj.repr _v + | TScriptData _v -> + Obj.repr _v + | TShOp _v -> + Obj.repr _v + | TSizeof _v -> + Obj.repr _v + | TStatement -> + Obj.repr () + | TStrict _v -> + Obj.repr _v + | TString _v -> + Obj.repr _v + | TSwitch _v -> + Obj.repr _v + | TTilde _v -> + Obj.repr _v + | TType -> + Obj.repr () + | TTypeId _v -> + Obj.repr _v + | TTypedef -> + Obj.repr () + | TUsing -> + Obj.repr () + | TWhen _v -> + Obj.repr _v + | TWhile _v -> + Obj.repr _v + | TWhy _v -> + Obj.repr _v + | TWhy0 -> + Obj.repr () + | TWords -> + Obj.repr () + | TXor _v -> + Obj.repr _v + | Tattr _v -> + Obj.repr _v + | Tauto _v -> + Obj.repr _v + | Tchar _v -> + Obj.repr _v + | Tconst _v -> + Obj.repr _v + | Tdouble _v -> + Obj.repr _v + | Textern _v -> + Obj.repr _v + | Tfloat _v -> + Obj.repr _v + | Tinline _v -> + Obj.repr _v + | Tint _v -> + Obj.repr _v + | Tlist -> + Obj.repr () + | Tlong _v -> + Obj.repr _v + | Tregister _v -> + Obj.repr _v + | Tshort _v -> + Obj.repr _v + | Tsigned _v -> + Obj.repr _v + | Tstatic _v -> + Obj.repr _v + | Tstruct _v -> + Obj.repr _v + | Ttypedef _v -> + Obj.repr _v + | Tunion _v -> + Obj.repr _v + | Tunsigned _v -> + Obj.repr _v + | Tvoid _v -> + Obj.repr _v + | Tvolatile _v -> + Obj.repr _v + + let default_reduction = + (16, "\000\000\000\000\001 \001!\000\000\001#\001\"\000\001\000\000\001[\000\000\000\000\000\136\000\000\000\000\001\213\000\142\000\145\002\195\002\194\000\146\001\013\001\019\001\015\001\018\001\017\000\135\001\011\001\026\000\000\000\000\001\025\000\000\000\000\000\000\000\000\000\000\001O\000\232\002\185\002o\000\000\000\000\000\000\000\000\000\000\002\190\000\000\001\022\000\000\002\192\000\000\001\029\001\028\000\000\000\000\002\249\0029\000\000\002\247\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\252\000\000\002S\000\000\000\000\002\246\002\248\002?\001\004\002>\001\002\001\003\002=\002<\002;\0027\000\000\000\000\0028\000\205\000\000\002:\000\000\002\245\000\000\002\220\001\001\002\026\000\000\000\000\002\029\000\000\000\015\000\000\000\000\000\000\000\000\000\206\0026\002B\000[\000\021\000]\000\000\000\000\000c\000\000\000\000\000\000\000\000\000\000\000\000\000\022\000\000\000\023\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\130\001\250\000R\000\215\000^\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\\\000T\000\000\000S\000\000\000\000\000\140\000\216\000\000\002 \000\217\000\014\000\000\001\014\001\020\001\016\001\012\000\016\000\000\000\000\000\143\000\000\000\141\000\000\000\000\000\220\000\000\000\000\002\027\002\030\000\000\002\028\002\031\002\221\002\219\000\000\002@\002\218\000\000\002[\000\000\000\000\001\189\000\000\001i\001\171\000\000\000\000\002Z\000\000\002\237\002Y\002X\002W\002V\002U\002Q\000\000\000\000\002R\000\000\002T\000\000\000\000\002\234\002(\000\000\000\000\002+\000\000\000\000\002.\000\000\000\000\002)\002,\000\000\002*\002-\002\\\002P\002\235\002\233\002\232\002\236\000\000\000\000\000\000\000g\000h\000\000\000\000\000W\000\000\000V\000\227\000\000\001\205\000\000\000\000\000\000\000\000\000\000\000\210\001\211\000\000\000\000\001s\000U\0001\000\203\000_\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0002\000\000\0003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\132\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002A\000\000\000\144\000\000\000\000\001\188\000\000\001g\001\170\000\000\000\000\000d\000\000\002\252\000\000\000\000\001\206\000\000\000\000\002\223\002\222\000\000\000Q\000\147\000\000\001Q\000\000\002\188\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\225\000\151\000\000\000\000\000n\000o\001\224\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\160\001\194\000\000\000\148\000\155\000\000\001\196\000\000\000\000\000\000\000\000\000\149\000\161\000\000\001W\000\000\000\000\002\187\000\000\000\000\000\138\000\000\000\000\002\186\000\000\000\000\000\000\002\189\002\193\000\000\000\000\000\000\001\023\000\000\000\214\000\000\001\024\000\000\000\000\001:\000\000\0019\000\000\001G\000\000\001]\000\000\000\000\000\000\000\000\000\000\000\000\001\008\000\000\000\000\002\216\000\000\000\189\002\215\002\181\002\183\002\184\002\182\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002`\000\000\000\000\000\000\000\000\002g\000\000\000\000\002f\002e\002d\002c\002b\0016\002^\000\000\000\000\002_\000\000\002a\000\000\000\000\002\241\002/\000\000\000\000\0022\000\000\000\000\0025\000\000\000\000\0020\0023\000\000\0021\0024\002i\002]\002\242\002\240\002\239\000i\000j\000\000\000\000\000Z\000\000\000Y\000\000\002h\000\000\001\172\000X\000?\000\226\000`\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\134\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\244\002\243\000\000\002\172\000\000\002\171\000\000\000\000\000\018\000\000\000\000\000\000\002\253\000\000\001u\000\000\000\000\000\000\000\162\002\162\001M\000\000\000\153\001L\001%\001$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\176\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\207\000\208\000\195\000\000\001Y\000\000\000\000\000\194\000\190\000\000\000\197\000\191\000\196\000\000\002\174\000\000\002\173\002\159\000\000\000\000\000\000\000\000\000\000\002\168\000\000\000\000\000\000\000\000\000\000\002\169\002\161\000\000\002\175\000\000\002\163\000\000\000\166\000\000\002\178\000\152\000\000\001'\000\000\000\000\000\000\000\000\000\000\000\000\001\t\000\000\000w\000\000\000\000\000\000\002F\000\000\000\000\000\000\002N\000\000\000\000\002M\000\000\002\230\002L\002K\002J\002I\002H\002D\000\000\000\000\002E\000\000\002G\000\000\000\000\002\227\002!\000\000\000\000\002$\000\000\000\000\002'\000\000\000\000\002\"\002%\000\000\002#\002&\002O\002C\002\228\002\226\002\225\002\229\000\000\000\000\000\000\000e\000f\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\212\001(\000\000\000\000\000\000\001.\000\000\000\000\001/\000#\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000%\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001-\0012\000\000\001,\000\000\000\000\0014\000\000\000\000\000\000\000\000\000\000\000\000\000t\000q\000r\0015\0011\000\000\000\000\0010\001*\000\000\001)\000\000\000\182\000\000\002\140\000\000\000\000\000\178\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\185\000\000\000\000\000\188\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\007\000\000\000\000\000\000\000\175\000\000\000\172\000\000\000\000\000\000\000\000\000\000\000\183\000\000\000\179\000\000\000\000\002\198\000\000\002\205\000\168\000\000\000\000\000\000\000\000\000\180\000\000\000\176\000\173\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\184\000\000\000\000\000\187\000\000\002\199\000\167\000\000\002\200\000\000\002\207\000\000\000\000\000\000\000\000\000\186\000\000\000\170\000\000\000\000\000\000\000\000\001\006\000\000\000\000\000\000\000\174\000\000\000\171\000\000\000\000\000\000\000\000\000\000\000\181\000\000\000\177\000\164\000\163\000\000\002\208\002\209\000\000\002\210\000\000\002\211\000\000\001&\002\166\000\000\000\000\001\193\000\000\001q\001\176\000\000\002\160\000\000\000\000\000\000\002\165\000\000\000\000\000\000\000\250\000\000\000\244\000\000\000\245\000\000\000\255\000\243\000\254\000\000\002\177\001\000\000\000\000\169\000\000\000\000\000\000\000\000\000\252\000\247\001\190\000\000\000\248\000\000\000\249\000\000\001k\001\173\000\000\000\000\000\000\001\201\000\000\001\199\000\000\000\000\001\203\001\197\000\000\001\204\001\198\000\000\002\179\001\207\000\000\000\165\000\000\000\000\001\191\000\000\001m\001\174\000\000\002\254\000\000\002\250\000\000\002\251\000\019\000\020\000\000\000\000\002}\000\000\002|\000\000\000\000\002\127\000\000\002~\000\000\000\000\000\000\001\234\000\000\000\000\001\238\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\241\000\000\000\000\001\244\000\000\000\000\001\228\000\000\000\000\001\231\000\000\000\000\000\000\001\235\000\000\000\000\001\239\000\000\000\000\001\192\000\000\000\000\001\232\000\000\000\000\001\236\002z\001\229\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\240\000\000\000\000\001\243\000\000\002{\000\000\000\000\000\000\000\000\001\242\000\000\001\226\000\000\001\227\000\000\000\000\001\230\000\000\000\000\000\000\001\233\000\000\000\000\001\237\000\000\001o\001\175\000\000\002\128\000\000\000\000\000\000\002\255\000\017\000u\000\000\003\000\000\000\000\000\002\136\000\000\000\000\002\180\000a\000\000\000\000\000\000\000b\000\000\002\170\000\000\001S\002\167\000\000\000\000\001@\000\000\001?\000\000\001H\000\000\001c\000\000\000\000\000\000\001>\000\000\001=\000\000\001E\000\000\001a\000\000\000\000\000\000\001B\000\000\001A\000\000\001F\000\000\001e\000\000\000\000\000\000\001C\000\000\000\000\000\000\000\000\001<\000\000\001;\000\000\001I\000\000\001_\000\000\000\000\000\000\001D\000\002\000\000\000N\000O\000M\001J\000\003\000\000\000\000\002l\000\000\001\248\000\000\002r\002t\000\000\000\000\001\140\002s\000\128\000\000\000\000\002\158\000\000\000\000\000\000\000z\000\000\000\000\002\146\000\000\001\221\001\220\001\135\002x\002p\002q\000\000\001\167\000\000\002m\000\000\000\000\000|\000\000\000\000\002\150\000\000\001\149\000\000\000\000\001\146\000\000\000\000\000\000\001\148\000\000\001\147\000\000\000\000\000\000\000\000\000\000\000\000\001\168\000\000\001\144\000\000\001\143\000\000\000v\000\000\000\000\002\138\000\000\000\000\001\139\000\000\000\000\000~\000\000\000\000\002\154\000\000\000\000\000\000\000{\000\000\000\000\002\148\000\000\001\217\001\216\001\131\002v\000\000\001\154\000\000\000\000\000\000\001\151\000\000\001\156\000\000\000\000\001\152\000\000\000\000\001\153\000\000\000\000\000\000\001\142\000\000\000\000\000\000\000\000\000\000\000\000\001\169\000\000\001\145\000}\000\000\000\000\002\152\000\000\000\000\000\000\001\031\000y\001\030\000\000\000\000\002\144\000\000\001\215\001\214\001\129\002u\000\000\000\127\000\000\000\000\002\156\000\000\000\000\000\000\000\000\001\219\001\218\001\133\002w\000\000\001\161\000\000\001\165\000\000\000\000\001\157\000\000\000\000\000\000\001\150\000\000\001\155\000\000\000\000\000\000\000\000\000\000\000\000\001\164\001\138\000\000\001\163\000\000\000\000\000\000\000\000\001\160\000\000\000\000\001\159\000\000\001\158\000\000\000\000\000\000\000\000\001\162\000\000\001\166\000\000\000\000\001K\000\004\000\000\001\141\000\005\000\000\000\000\000\230\000\006\000\000\001\180\001\181\001\179\000\000\000\000\000\000\000\000\000\000\000\000\000x\000\000\000\000\002\142\000\000\000\221\001\178\001{\002\196\001}\000\000\000\007\000\000\001\183\001\184\001\182\000\000\000\000\000\000\000\000\000\000\000\000\000\231\000\234\000\000\000\000\000\000\000\000\000\239\000\241\000\240\000\235\000\237\000\236\001\187\000\000\000\000\000\000\000\000\002\201\002\212\000\000\002\202\000\000\002\203\001\127\000\000\001\177\001\185\000\000\000\000\000\000\000\000\001\223\000\000\000\000\000l\000m\000\000\000\000\000\000\001\222\000\000\000\158\000\000\001U\000\000\000\000\000\157\000\154\000\000\000\000\000\000\000\000\001\005\000\000\000\000\002\213\000\000\002\214\000\000\000\000\001\210\001\208\000\000\001\209\000\008\000\000\000\t\000\000\002\011\002\012\002\n\000\000\000\000\002\t\000\000\000\n\000\000\002\014\002\015\002\013\000\000\000\000\000\000\000\000\002\003\000\000\000\000\002\005\000\000\001\255\000\000\002\001\000\000\002\006\000\000\002\007\002\000\001\254\002\017\001\137\000\000\002\008\000\000\002\019\000\000\002\018\000\000\002\020\000\000\002y\000\011\000\000\000\000\000\229\000\012\000\000\000\000\000\000\000\000\000\000\002\021\000\000\000\000\002\024\000\000\002\023\000\000\002\022\000\198\000\000\000\000\000\000\000\000\000\199\002\025\000\000\000\000\002\131\000\000\000\000\000\000\000\000\000\000\002\134\000k\000\000\000\000\000\204\000\000\000\000\000\224\000\223\000\222\000\000\0018\000\000\002\130\001y\001w\000\000\000\000\000\000\000\000\000\000\000\000\002\129\000\000\000\013\000\000\000\000\000\000\000\000\000\000\002\132") + + let error = + (163, "\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\000\000\000\000\004\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000`\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\252\000\000\000\000\000\000\000=j\184\001\000@\000\002\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000@0\128\000 \152\019\000\128 \001\000\000\019!\136\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000z\213p\002\000\128\000\004\000 \000\000\000\000\000\000\000\000\000\000\000%Q\128 \024@\000XL\t\128@\016\017\000\128\000\t\144\197\235U\192\008\002\000\000\016\128\128\000\000\000\002\000\001\000\000\000\000\000\000\000\000\000\000\000\001\001\000\000\000\000\000\000\000\000\000\000\000\000\018(\192\000\000 \000 $\004\192 \000\008\128@\000\004\192b\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\015Z\174\002@\016\000\000\132\004\000\000\000\000\016\000\000\000\000\016\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000=j\184\001\000@\000\002\016\016\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\128\000\000\008\000\000\000\000\000\000\245\170\224\004\001\000\000\008@@\000\000\000\001\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\015Z\174\000@\016\000\000\132\004\000\000\000\000\016\000\008\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000 \000\000\000\000\000\000\000@\000\017\000\000\000\000\000\005 \000H8\020\006\237\000\001$\004\002\000!\008\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\144\000$\028\n\003v\128\000\146\002\001\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\n@\000\144p(\013\218\000\002H\008\000\000B\001\004\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000)\000\002A\192\1607h\000\t \016\001\008\004\016\000\000\000\005 \000H8\020\006\237\000\001$\004\002\000!\000\130z\213p\002\164\128\t\007\002\160\221\160\000$\128\128@\004 \016OZ\174\000T\144\001 \224T\027\180\000\004\144\016\008\000\132\002\008\000\000\000B\144\000$\028\n\003v\128\000\146\002\000\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\n@\000\144p(\013\218\000\002H\008\000\000B\001\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000)\000\002A\192\1607h\000\t \000\001\008\004\016\000\000\000\005 \000H8\020\006\237\000\001$\004\002\000!\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000R\000\004\131\129@n\208\000\018@@ \002\016\008 \000\000\000\n@\000\144p(\013\218\000\002H\008\004\000B\001\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005 \000H8\020\006\237\000\001$\004\002\000!\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\128\001 \224P\027\180\000\004\144\016\008\000\132\002\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000R\000\004\131\129@n\208\000\018@@ \002\016\008 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\018\000\0180M\156\150\000\000P\004 \000;\160\"xw\000\000\000\000\000\000\000\000\000\000\008\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\235U\192\n\146\000$\028\n\131~\128\000\146\002\001\000\016\144A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000 \131\001,\000\000\160\000\000\000v@\004\208\238\000\000\000\001H\000\018\014\005\001\187@\000I\001\000\128\008@ \128\000\000\144\000\144\130lD\176\000\002\128 \000\001\217\000\019\195\184\000\000\000\005 \000H8\020\006\237\000\001$\004\002\000!\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\144\000\144\130lD\176\000\002\128 \000\001\153\000\019\193\184\000\000\000\005 \000H8\020\006\237\000\001$\004\002\000!\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000H\000HA6\"X\000\001@\016\000\000\204\128\t\224\220\000\000\000\002\144\000$\028\n\003v\128\000\146\002\001\000\016\128A\000\000\001 \001!\004\216\137`\000\005\000@\000\0032\000'\131p\000\000\000\n@\000\144p(\013\218\000\002H\008\004\000B\001\004\000\000\004\128\004\132\019b%\128\000\020\001\000\000\012\200\000\158\013\192\000\000\000)\000\002A\192\1607h\000\t \016\001\008\004\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128@\004 \016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\144\000$\028\n\003v\128\000\146\002\001\000\016\128A\000\000\001 \001!\004\216\137`\000\005\000@\000\0032\000'\131p\000\000\000\n@\000\144p(\013\218\000\002H\008\004\000B\001\004\000\000\004\128\004\132\019b%\128\000\020\001\000\000\012\200\000\158\013\192\000\000\000)\000\002A\192\1607h\000\t \016\001\008\004\016\000\000\018\000\018\016M\136\150\000\000P\004\000\0003 \002x7\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128@\004 \016@\000\000H\000HA6\"X\000\001@\016\000\000\204\128\t\224\220\000\000\000\002\144\000$\028\n\003v\128\000\146\002\001\000\016\128A\000\000\001 \001!\004\216\137`\000\005\000@\000\0032\000'\131p\000\000\000\n@\000\144p(\013\218\000\002H\008\006\000B\001\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000)\000\002A\192\1607h\000\t \016\001\008\004\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\n@\000\144p(\013\218\000\002H\008\004\000B\001\004\000\000\004\128\004\132\019b%\128\000\020\001\000\000\012\200\000\158\013\192\000\000\000)\000\002A\192\1607h\000\t \016\001\008\004\016\000\000\018\000\018\016M\136\150\000\000P\004\000\0003 \002x7\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128@\004 \016@\000\000H\000HA6\"X\000\001@\016\000\000\204\128\t\224\220\000\000\000\002\144\000$\028\n\003v\128\000\146\002\001\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001H\000\018\014\005\001\187@\000I\001\000\128\008@ \128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\008\006\000\000\004\019\000\000\000\004\004\000 \000\002d\001\001*\140\001\000\194\000\002\130`L\002\000\128\136\004\000\000L\134 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\011\244\224\008\006\016\000\020\019\002`\016\004\004@ \000\002d1\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000u\170\160\004\001\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\001\000\194\000\000\130`L\002\000\128\128\004\000\000L\134 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\016\000=j\184\001R@\004\131\129Po\208\000\018@@ \002\016\008 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001H\000\018\014\005\001\187@\000I\001\000\128\008@ \128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\004\000\000\000\000\000\n@\000\144p(\013\218\000\002H\008\004\000B\001\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\015Z\174\000T\144\001 \224T\027\180\000\004\144\016\008\000\132\002\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\n@\000\144p(\013\218\000\002H\008\000\000B\001\004\000\000\000\001H\000\018\014\005\001\187@\000I\001\000\128\008@ \128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005 \000H8\020\006\237\000\001$\004\000\000!\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\128\001 \224P\027\180\000\004\144\016\000\000\132\002\008\000\000\000\002\144\000$\028\n\003v\128\000\146\002\000\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\128\004\136\017e%\000\000\016\001\008\000\006\168\008\134\017\192\000\000\000\000\000\000\000\000\000\002\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000z\213p\002\164\128\t\007\002\160\223\160\000$\128\128@\004$\016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000R\000\004\131\129@n\208\000\018@@ \002\016\008 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000z\213p\002\164\128\t\007\002\160\221\160\000$\128\128@\004 \016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\002\144\000$\028\n\003v\128\000\146\002\000\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\128\004\128\017`%\000\000\016\001\000\000\006\136\000\134\017\192\000\000\000)\000\002A\192\1607h\000\t \016\001\008\004\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128@\004 \016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\128\000\004\000\000\000\000\004)\000\002A\192\1607h\000\t \000\001\008\004\016\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128@\004 \016@\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\n@\000\144p(\013\218\000\002H\008\000\000B\001\004\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\128\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001 \001 \004X\t@\000\004\000@\000\001\"\000!\128p\000\000\000\n@\000\144p(\013\218\000\002H\008\000\000B\001\004\000\000\004\128\004\128\017`%\000\000\016\001\000\000\004\136\000\134\001\192\000\000\000)\000\002A\192\1607h\000\t \000\001\008\004\016\000\000\018\000\018\000E\128\148\000\000@\004\000\000\018 \002\024\007\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128\000\004 \016@\000\000H\000H\001\022\002P\000\001\000\016\000\000H\128\008`\028\000\000\000\002\144\000$\028\n\003v\128\000\146\002\000\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\n@\000\144p(\013\218\000\002H\008\000\000B\001\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000)\000\002A\192\1607h\000\t \000\001\008\004\016\000\000\018\000\018\000E\128\148\000\000@\004\000\000\018 \002\024\007\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128\000\004 \016@\000\000H\000H\001\022\002P\000\001\000\016\000\000H\128\008`\028\000\000\000\002\144\000$\028\n\003v\128\000\146\002\000\000\016\128A\000\000\001 \001 \004X\t@\000\004\000@\000\001\"\000!\128p\000\000\000\n@\000\144p(\013\218\000\002H\008\000\000B\001\004\000\000\004\128\004\128\017`%\000\000\016\001\000\000\004\136\000\134\001\192\000\000\000)\000\002A\192\1607h\000\t \000\001\008\004\016\000\000\018\000\018\000E\128\148\000\000@\004\000\000\018 \002\024\007\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128`\004 \016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\002\144\000$\028\n\003v\128\000\146\002\000\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\n@\000\144p(\013\218\000\002H\008\000\000B\001\004\000\000\004\128\004\128\017`%\000\000\016\001\000\000\004\136\000\134\001\192\000\000\000)\000\002A\192\1607h\000\t \000\001\008\004\016\000\000\018\000\018\000E\128\148\000\000@\004\000\000\018 \002\024\007\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128\000\004 \016@\000\000H\000H\001\022\002P\000\001\000\016\000\000H\128\008`\028\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\002\000\003\214\171\128\016\004\000\000 \001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\001H\000\018\014\005\001\187@\000I\001\000\128\008@ \128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\128\001 \224P\027\180\000\004\144\016\000\000\132\002\008\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007\173W\000*H\000\144p*\013\218\000\002H\008\004\000B\001\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000@\000\000\000\000\000\000\000\128\000\"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\t\020`\000\000\016\000\016\018\002`\016\000\004@ \000\002`1\001\"\140\000\000\002\000\002\000@L\002\000\000\136\004\000\000L\006 \000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\030\181\\\000\128 \000\001\000\008\192\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\016\016\000\000\000\000\000\000\000\000\002 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\016\000=j\184\001\000@\000\002\000\017\128\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\016\000\000\000\000\128\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000=j\184\001\000@\000\002\000\017\128\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004@\000\245\170\224\004\001\000\000\008\000F\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\128\000\000\000D\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\003\214\171\128\016\004\000\000 \001\024\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000z\213p\002\000\128\000\004 \000\000\000\000\128\000\000\000\000\128\015Z\174\000@\016\000\000\132\004\000\000\000\000\016\000\008\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000@\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\014\181T\000\128 \000\000\000\008\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\004\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\149F\000\128a\000\001a0&\001\000@D\002\000\000&C\023\173W\000 \008\000\000B\002\000\000\000\000\008\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000@\000\000\000\000\000\000\023\173W\000 \008\000\000@\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\030\181\\\000\128 \000\001\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007\255_\130.I\000\128f+\143\222\016\007\234\024\000\141b\005\004\002E\024\000\000\000\000\004\004\000\152\000\000\001\016\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\003\214\171\128\016\004\000\000 \001\024\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000=j\184\001\000@\000\002\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000)\000\002A\192\1607h\000\t \016\001\008\004\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000 \228\016\008\006B\136\253\161\000~\161\128\008\198 P@\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\144\000$\028\n\003v\128\000\146\002\001\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@!\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\003\255\175\193\023$\128H:\021\199\239\008\003\245\012\002G\177\134\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\128\001\000\192P\027\180\000\012\144\016\000\000\132\002\008\000\000\000\002\144\000 \024\n\003v\128\001\146\002\000\000\016\128A=j\184\001R@\004\131\129Pn\208\000\018@@ \002\016\008 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\005 \000@0\020\006\237\000\003$\004\000\000!\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005 \000@0\020\006\237\000\003$\004\000\000!\000\130\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128@\004 \016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\144\000 \024\n\003v\128\001\146\002\000\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\n@\000\128`(\013\218\000\006H\008\000\000B\001\004\000\000\000\001H\000\016\012\005\001\187@\000\201\001\000\000\008@ \128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002@\002F\t\179\146\192\000\n\000\132\000\007T\004\n\014\224\000\000\000\000\000\000\000\000\000\001\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000=j\184\001R@\004\131\129Po\208\000\018@@ \002\018\008 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000)\000\002A\192\1607h\000\t \016\001\008\004\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000$ \155\017,\000\000\160\008\000\000t@\000\160\238\000\000\000\001H\000\018\014\005\001\187@\000I\001\000\128\008@ \128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005 \000H8\020\006\237\000\001$\004\002\000!\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000H\000HA6\"X\000\001@\016\000\000\200\128\001@\220\000\000\000\002\144\000 \024\n\003v\128\001\146\002\000\000\016\128A\000\000\001 \001!\004\216\137`\000\005\000@\000\003\"\000\005\003p\000\000\000\n@\000\128`(\013\218\000\006H\008\000\000B\001\004\000\000\004\128\004\132\019b%\128\000\020\001\000\000\012\136\000\020\013\192\000\000\000)\000\002\001\128\1607h\000\025 \000\001\008\004\016\000\000\018\000\018\016M\136\150\000\000P\004\000\0002 \000P7\000\000\000\000\164\000\008\006\002\128\221\160\000d\128\128\000\004 \016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\144\000 \024\n\003v\128\001\146\002\000\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\n@\000\128`(\013\218\000\006H\008\000\000B\001\004\000\000\004\128\004\132\019b%\128\000\020\001\000\000\012\136\000\020\013\192\000\000\000)\000\002\001\128\1607h\000\025 \000\001\008\004\016\000\000\018\000\018\016M\136\150\000\000P\004\000\0002 \000P7\000\000\000\000\164\000\008\006\002\128\221\160\000d\128\128\000\004 \016@\000\000H\000HA6\"X\000\001@\016\000\000\200\128\001@\220\000\000\000\002\144\000 \024\n\003v\128\001\146\002\000\000\016\128A\000\000\001 \001!\004\216\137`\000\005\000@\000\003\"\000\005\003p\000\000\000\n@\000\128`(\013\218\000\006H\008\000\000B\001\004\000\000\004\128\004\132\019b%\128\000\020\001\000\000\012\136\000\020\013\192\000\000\000)\000\002A\192\1607h\000\t \024\001\008\004\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\164\000\008\006\002\128\221\160\000d\128\128\000\004 \016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\144\000 \024\n\003v\128\001\146\002\000\000\016\128A\000\000\001 \001!\004\216\137`\000\005\000@\000\003\"\000\005\003p\000\000\000\n@\000\128`(\013\218\000\006H\008\000\000B\001\004\000\000\004\128\004\132\019b%\128\000\020\001\000\000\012\136\000\020\013\192\000\000\000)\000\002\001\128\1607h\000\025 \000\001\008\004\016\000\000\018\000\018\016M\136\150\000\000P\004\000\0002 \000P7z\213p\002\164\128\t\007\002\160\221\160\000$\128\128@\004 \016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\n@ \144p(\013\218\000\002H\008\004\000B\001\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\127\245\2482\228\144\008\006b\184\253\225\000~\161\128\008\214 P@\000\000\000\002\000\000\000\002\000\000\000\000\000\000B \000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000?\250\252\017rH\004\003!\\~\240\128?P\192\004k\016('\255_\130.I\000\144t/\143\222\016\007\234\024\004\141b\133\004\255\235\240e\201 \016\012\197q\251\194\000\253C\000\017\172@\160\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\255\191\225\151$\128@3\023\199\239\024\003\245L G\177\198\179\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\015\254\191\004\\\146\001\000\204W\031\188 \015\2120\001\026\196\n\t\255\215\224\139\146@$\029\011\227\247\132\001\250\134\001#X\161A?\250\252\017rH\004\131\161\\~\240\128?P\192$k\016h \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\018\000\0180M\156\150\000\000P\004 \000;\160\"Pw\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001H\000\018\014\005\001\187@\000I\001\000\128\008@ \128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\001\007 \128@2\020G\237\008\003\245\012\000F1\002\130\000\000\000 \228\016\008\006B\136\253\161\000~\161\128\008\198 P@\000\000\000\000\000\000\000\000\000\001\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001H\004\018\014\005\001\187@\000I\001\000\128\008@ \128\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005 \016H8\020\006\237\000\001$\004\002\000!\000\130\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\128\001 \224P\027\180\000\004\144\016\008\000\132\130\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\016r\008\004\003!D~\208\128?P\192\004c\016( \000\000\002\014A\000\128d(\143\218\016\007\234\024\000\140b\005\004\000\000\000\000\000\000\000\000\000\000\016\000\000\001\000\000\128\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\017\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\004\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\136\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000 \000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\n@\000\144p(\013\218\000\002H\008\004\000B\001\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002@\002\006\0082\146\192\000\008\000\004\000\0034\004H\008\192\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\001\235U\192\n\146\000$\028\n\131~\128\000\146\002\001\000\016\144A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\002\014A\000\128d(\143\218\016\007\234\024\000\140b\005\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000?\250\252\017rH\004\131\161\\~\240\128?P\192$k\016( \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\255\239\248e\201 \016\012\197\241\251\198\000\253S\008\017\236q\172\192\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\235U\192\008\002\000\000\016\000\128\000\000\000\002\000\000\000\000\000\000\000\145F\000\000\000\000\001\001\000&\000\000\000D\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\245\170\224\004\001\000\000\008\000F\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\128\000 \000\000\000\000\000\n@\000\144t(\013\218\000\002H\008\004\000B\001\004\000\000\000\001H\000\016\013\133\001\187@\000\201\001\000\160\008A \128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005 \000@0\020\006\237\000\003$\004\000\000!\000\130\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128@\004 \016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000=j\184\001R@\004\131\129Pn\208\000\018@@ \002\016\008 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000)\000\002\001\128\1607h\000\025 \000\001\008\004\016\000\000\000\005 \000H8\020\006\237\000\001$\004\002\000!\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\128\001\000\192P\027\180\000\012\144\016\000\000\132\002\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000R\000\004\003\001@n\208\0002@@\000\002\016\008 \000\000\000\n@\000\128`(\013\218\000\006H\008\000\000B\001\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\016 A\148\148\000\000@\000 \000\016\160\"\000\006\000\000\000\000\000\000\000\000\000\000\008\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\235U\192\n\146\000$\028\n\131~\128\000\146\002\001\000\016\144A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001H\000\018\014\005\001\187@\000I\001\000\128\008@ \128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\235U\192\n\146\000$\028\n\131v\128\000\146\002\001\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\n@\000\128`(\013\218\000\006H\008\000\000B\001\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005 \000H8\020\006\237\000\001$\004\002\000!\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\001\000\000\000\000\000\020\128\001 \224P\027\180\000\004\144\016\008\000\132\002\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\n@\000\128l(\013\218\000\006H\008\001\000B\001\004\000\000\000\001H\000\016\013\133\001\187@\000\201\001\000\160\008A \128\000\000\004)\000\002\001\176\1607h\000\025 \020\001\008$\016\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\164\000\t\007B\128\221\160\000$\128\128@\004 \016@\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000)\000\002\001\176\1607h\000\025 \004\001\008\004\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\020\128\001\000\216P\027\180\000\012\144\016\002\000\132\002\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000 \000\131\001(\000\000\128\000\000\000 @\004\000\012\000\000\000\001H\000\016\012\005\001\187@\000\201\001\000\000\008@ \128\000\000\128\000\128\002\012\004\160\000\002\000\000\000\000\129\000\016\0000\000\000\000\005 \000@0\020\006\237\000\003$\004\000\000!\000\130\000\000\002\000\002\000\0080\018\128\000\008\000\000\000\002\004\000@\000\192\000\000\000\020\128\001\000\192P\027\180\000\012\144\016\000\000\132\002\008\000\000\008\000\008\000 \192J\000\000 \000\000\000\008\016\001\000\003\000\000\000\000R\000\004\003\001@n\208\0002@@\000\002\016\008 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001H\000\016\012\005\001\187@\000\201\001\000\000\008@ \128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005 \000@0\020\006\237\000\003$\004\000\000!\000\130\000\000\002\000\002\000\0080\018\128\000\008\000\000\000\002\004\000@\000\192\000\000\000\020\128\001\000\192P\027\180\000\012\144\016\000\000\132\002\008\000\000\008\000\008\000 \192J\000\000 \000\000\000\008\016\001\000\003\000\000\000\000R\000\004\003\001@n\208\0002@@\000\002\016\008 \000\000 \000 \000\131\001(\000\000\128\000\000\000 @\004\000\012\000\000\000\001H\000\016\012\005\001\187@\000\201\001\000\000\008@ \128\000\000\128\000\128\002\012\004\160\000\002\000\000\000\000\129\000\016\0000\000\000\000\005 \000@0\020\006\237\000\003$\004\000\000!\000\130\000\000\002\000\002\000\0080\018\128\000\008\000\000\000\002\004\000@\000\192\000\000\000\020\128\001\000\192P\027\180\000\012\144\016\000\000\132\002\008\000\000\008\000\008\000 \192J\000\000 \000\000\000\008\016\001\000\003\000\000\000\000R\000\004\003\001@n\208\0002@@\000\002\016\008 \000\000 \000 \000\131\001(\000\000\128\000\000\000 @\004\000\012\000\000\000\001H\000\016\012\005\001\187@\000\201\001\000\000\008@ \128\000\000\128\000\128\002\012\004\160\000\002\000\000\000\000\129\000\016\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\n@\000\128l(\013\218\000\006H\008\005\000B\t\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000)\000\002\001\176\1607h\000\025 \020\001\008$\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\164\000\008\006\194\128\221\160\000d\128\128P\004 \144@\000\000\000\020\128\001\000\216P\027\180\000\012\144\016\002\000\132\018\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000R\000\004\003a@n\208\0002@@(\002\016H \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\002\144\000 \027\n\003v\128\001\146\002\000@\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000=j\184\001\000@\000\002\000\017\128\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005 \000H:\020\006\237\000\001$\004\002\000!\000\130\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0010\000\000\002\000\000\000\000\000\000\000\000\000\000\000\001\000\001@\000\000\000\000\000\000\000\128\000 \000\000\000\000\000\000\000 \000(\000\000\000\000\000\000\000\016\000\004\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\030\181\\\000\128 \000\001\000\008\192\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\004\000\001\000\000\000\000\000\000R\000\004\131\161@n\208\000\018@@ \002\016\008 \000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000:\213P\002\000\128\000\000\000 \000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\004\000\001\000\000\000\000\000\000R\000\004\131\161@n\208\000\018@@ \002\016\008 \000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\127\245\248\"\228\144\008\006b\184\253\227\000~\161\128\008\214 P@\000\000\000\000\000\000 \000\000\000@\000\000\000\136\000\000\000\196\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000?\250\252\017rH\004\0031\\~\241\128?P\194\004k\016+0\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\144\000\145\130l\228\176\002\002\128! \001\221\001\002\131\184\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\008\000\002\000\000\000\000\000\000\164\000\t\007B\128\221\160\000$\128\128@\004 \016@\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000=j\184\001\000@\000\002\000\017\128\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005 \000H:\020\006\237\000\001$\004\002\000!\000\130\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\004\004\000\000\000\008\000\000\000\017\000\000\000\024\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\255\235\240E\201 \018\014\133q\251\198\000\253C\008\145\172@\172\192\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\255\175\193\023$\128@3\021\199\239\024\003\245\012 F\177\002\179\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\001\235U\192\n\146\000$\028\n\131~\128\000\146\002\001\000\016\144A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\019\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\015Z\174\000@\016\000\000\128\004`\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\002\000\000\128\000\000\000\000\000)\000\002A\208\1607h\000\t \016\001\008\004\016\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\029j\168\001\000@\000\000\000\016\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\008\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\002\000\000\128\000\000\000\000\000)\000\002A\208\1607h\000\t \016\001\008\004\016\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\255\235\240E\201 \018\014\133q\251\198\000\253C\008\145\172@\172\192\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\001\001\000\000\000\002\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\255\215\224\139\146@$\029\n\227\247\140\001\250\134\001#X\129A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\004\192 \000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000@\000\000\000\000 \228\016\008\006B\136\253\161\000~\161\128\008\198 P@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\002\000\000\000\000\000\000\000\000\000@\000\127\247\252\"\228\208\t\135B\248\253\227\000\254\169\132\200\246:\214`\000\000\004\028\130\001\000\200Q\031\180 \015\2120\001\024\196\n\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000?\250\252\017rH\004\0031|~\240\128?P\192\004{\028h \000\000\000\000\000\000\016\016\000\000\000\000\000\000\000\004\000\000\000\000\255\235\240E\201 \016\012\197\241\251\194\000\253C\000\017\236q\160\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\008\008\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\015\254\191\004\\\146\001 \232_\031\188 \015\2120\t\030\199\026\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000?\250\252\017rH\004\131\161|~\240\128?P\192${\028h \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\128\000\255\235\240E\201 \016\012\197\241\251\194\000\253C\000\017\172P\160\128\000\000\000\000\000\000@@\016\000\000\000\000\000\000\016\000\002\000\003\255\175\193\023$\128@3\023\199\239\008\003\245\012\000F\177B\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\128\128 \000\000\000\000\000\000 \000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\255\235\240E\201 \018\014\133\241\251\194\000\253C\000\145\172P\160\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\001\0010\000\000\002\000\000\000\000 \000\000\000\000\000\000 \000\192\128\000\000\000\000@\000\000 \000\001\000\023\255_\130.I\000\128f+\143\222\016\007\234\024\000\141b\005\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\128`@\000\000\000\000 \000\000\016\000\000\128\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\127\245\248\"\228\208\t\135B\184\253\225\000\254\161\128H\214\"Po\254\191\004\\\146\001\000\204W\031\188 \015\2120\001\026\196\n\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007\255_\130.M\000\152t+\143\222\016\015\234\024\004\141b%\006\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\128\000\255\235\240E\201 \018\014\133\241\251\194\000\253C\000\145\172P\160\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \016\016\000\000\000 \000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\031\253~\008\185$\002A\208\174?x\192\031\168`\0185\136\020\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\239\215\224\n\146@ \024\n\131w\128\001\146\002\000\000X\129A\000\000\000\000R\001\004\131\129@n\208\000\018@@ \002\016\008 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\223\175\192\021$\128@0\021\006\239\000\003$\004\000\000\177\002\130\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007\173W\000 \008\000\000@\002\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\164\000\t\007B\128\221\160\000$\128\128@\004 \016@\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000z\213p\002\000\128\000\004\000#\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\n@\000\144t(\013\218\000\002H\008\004\000B\001\004\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002`\000\000\004\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\144\000$\029\n\003v\128\000\146\002\001\000\016\128A\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000u\170\160\004\001\000\000\000\000@\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\128\001 \232P\027\180\000\004\144\016\008\000\132\002\008\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\128\000\247\235\240\005I \016\012\005A\187\192\000\201\001\000\000,@\160\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\018\000\0160A\148\150\000@@\000$\000\024\160 @F\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\144\000$\029\n\003v\128\000\146\002\001\000\016\128A\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\007\173W\000 \008\000\000@\0020\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\164\000\t\007B\128\221\160\000$\128\128@\004 \016@\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\030\181\\\000\169 \002A\192\1687\232\000\t \016\001\t\004\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\0010\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000)\000\002A\208\1607h\000\t \016\001\008\004\016\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007Z\170\000@\016\000\000\000\004\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\002\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001H\000\018\014\133\001\187@\000I\001\000\128\008@ \128\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\128\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\128\000\000\016\019\000\000\000 \000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\128\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\132\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\127\245\248\"\228\144\008\006b\184\253\225\000~\161\128\008\214 P@\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\n@\000\144p(\013\218\000\002H\008\004\000B\001\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\031\253~\008\185$\002A\208\174?x@\031\168`\018=\1404\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128B\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\001\000\000\000\000\000\000\000_\253~\008\185$\002\001\152\174?x@\031\168`\0025\136\020\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\127\245\248\"\228\144\008\006b\184\253\225\000~\161\128\008\214 P@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\008\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000)\000\002A\192\1607h\000\t \000\001\008\004\016\000\000\000\000\002\000\000\000\000\000\000\000\004\000\000\000\000\000\000\001\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128\000\004 \016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\144\000$\028\n\003v\128\000\146\002\000\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000 \000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \228\016\008\006B\136\253\161\000~\161\128\008\198 P@\000\000\000\000\008\000\000\000\000\000\000\000\016\000\000\000\000\000\000\004\000\000\000\131\144@ \025\n#\246\132\001\250\134\000#\024\129A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\014A\000\128d(\143\218\016\007\234\024\000\140b\005\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\128\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\144\000$\028\n\003v\128\000\146\002\000\000\016\128A\000\000\000\000\000 \000\000\000\000\000\000\000@\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\031\253~\000\128 \000\001\000\008\000\016\000\000 \000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\004\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\128\000\000\000\000\000\000/\254\191\000@\016\000\000\128\004\000\008\000\000\016\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000?\250\252\001\000@\000\002\000\016\000 \000\000@\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\004\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\128\001 \224P\027\180\000\004\144\016\000\000\132\002\008\000\000\000\000\001\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\030\181\\!\194\"$\129\016\008\000\001 \000U\t\000\002`\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007\173W\000p\136\136 D\002\000\000H\000\021B@\000\152\000\000\245\170\224\014\017\000\004\008\128@\000\t\000\002\168H\000\019\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\008\004\002\000\000\000\000\000\000\000\004\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000 \016\000\000\000\000\000\000\000\000\016\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\008\000\000\000 \000\004\002\000\000\000\000\000\000\000\000\002\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\001\000\000\000\000\000\000\004\000\000\000\000\000\000\001\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\128\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007\173W\000p\136\128 D\002\000\000H\000\021B@\000\136\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\030\181\\\001\194 \000\129\016\008\000\001 \000U\t\000\002 \000\000\000@\000\008\004\000\000\000\000\000\000\000\000\004\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\008\000\000\000 \000\004\002\000\000\000\000\000\000\000\000\002\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000@ \000\000\000\000\000\000\000\000 \001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000 \016\000\000\000\000\000\000\000\000\016\000\128\000\000\000\000\000 \000\004\002\000\000\000\000\000\000@\000\002\000\016\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\008\004\000\000\000\000\000\000\000\000\004\000 \000\000\000\000\000\008\000\001\000\128\000\000\128\000\000\016\000\000\128\004\000\000@\000\000\001\000\000 \016\000\000\000\000\000\000\000\000\016\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\004\000\000\128@\000\000\000\000\000\000\000\000@\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\235U\192\008\002\000\000\016\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\008\000\245\170\224\004\001\000\000\008\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\008\000\001\000\128\000\000\130\000\000\000\000\000\128\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001@\000\000\000\000\000\000\004\000\000\128@\000\000\000\000\000\000\000\000@\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\128\000\000\002\000\000@ \000\000\000\000\000\000\000\000 \001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\016\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000#\000\000\004\008 \000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000@ \000\000\001\000\000\000\000\000 \001\000\000\000\000\000\000@\000\008\004\000\000\000\000\000\000\000\000\004\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\016\008\000\000\000\000\000\000\000\000\008\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\008\004\000\000\000\000\000\000\000\000\004\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\004\000\000\128@\000\000\000\000\000\000\000\000@\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000@ \000\000\000\128\000\000\000\000 \001\000\000\000\000\000\000@\000\008\004\000\000\004\128\000\000\128\000\004\000 \000\002\000\000\000\008\000\001\000\128\000\000\000\000\000\000\000\000\128\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000 \000\004\002\000\000\000\000\000\000\000\000\002\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000@\000\000\001\000\000 \016\000\000\000\000\000\000\000\000\016\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\008\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\004\000\000\000\000\002\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000 \016\000\000\000\000\000\000\000\000\016\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000 \000\000\000\128\000\016\008\000\000\000\000\000\000\000\000\008\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\004\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\004\002\000\000\000\000\000\000\000\000\002\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\002\001\000\000\000\008\000\000\000\000\001\000\008\000\000\000\000\000\002\000\000@ \000\000\000\000\000\000\000\000 \001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000=n\184\001\128@\000\002 \016\000\000\000\000@\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\002\000\000@ \000\000\004\128\000\004\000\000 \001\000\000\016\000\000\000@\000\008\004\000\000\000\000\000\000\000\000\004\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\030\183\\\000\192 \000\001\016\136\000\000\000\000 \001\000\000\000\000\000\000@\000\008\004\000\000\000\000\000\000\000\000\004\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\004\002\000\000\000\000\000\000\000\000\002\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\008\004\000\000\004\000\000\000\000\000\004\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\001\000\000 \016\000\000\000\000\000\000\000\000\016\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\235U\194\028\"\"H\017\000\128\000\018\000\005P\144\000&\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001H\000\018\014\007\001\187@\000I\001\000\128\008@ \128\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\196\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001H\000\018\014\005\001\187@\000I\001\000\128\008@ \128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\001\136\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\144\000$\028\n\003v\128\000\146\002\000\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\016\000\000\000\000\001H\000\018\014\005\001\187@\000I\001\000\000\008@ \128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\255\239\248E\201 \018\014\135q\251\194\000\253S\008\145\172@\172\192\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000?\251\254\017rH\004\131\161\\~\240\128?T\194$k\016+3\191}\192 \008\000\000\000\002\000\000\000\000\000\128\000\000\000\000\000\002E\024\000\000\000\000\000\004\000\000\000\000\000\016\000\000\000\000\000\014\253\247\000\128 \000\000\000\008\000\000\000\000\002\000\000\000\000\000\001\223\190\224\016\004\000\000\000\001\000\000\000\000\000@\000\000\000\000\000\001\"\140\000\000\000\000\000\002\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\145F\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\018(\192\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\002E\024\000\000\000\000\000\000\000\000\000\000\000\016\000\000\000\000\000\000H\163\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\030\253\255\000\128 \000\001\000\008\000\000\000\000\"\000\000\000\000\000\000\t\020`\000\000\000\000\016\000\000\000\000\000\000@\000\000\000\000\000\127\245\248\"\228\144\008\006b\184\253\225\000~\161\128\008\214 P@\000\000\000\000\000\000 \000\000\000\000\000\000\000\136\000\000\000\196\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \016\016\000\000\000\000\000\000\000D\000\000\000b\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\031\253~\008\185$\002A\208\174?x@\031\168a\0185\136\021\152\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\196\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\152\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\003\214\171\128\016\004\000\000 \001\024\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\128\001\235U\192\008\002\000\000\016\000\140\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\136\000\030\181\\\000\128 \000\001\000\008\192\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000?\250\252\017rH\004\131\161\\~\240\128?P\192$k\016h \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000H\163\000\000\000\000\000\128\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\016\008\008\000\000\000\000\000\000\000\"\000\000\0001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\015\254\191\004\\\146\001 \232W\031\188 \015\2120\137\026\196\n\204\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000&\000\000\000@\002\000\000\000\003\016\000\000\000\000\016\016\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\144\000$\028\014\003v\128\000\146\002\001\000\016\128A\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000b\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\164\000\t\007\002\128\221\160\000$\128\128@\004 \016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\196\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000?\251\254\017rH\004\131\161\220~\240\128?T\194$k\016+0\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\012@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\015\254\255\132\\\146\001 \232W\031\188 \015\2130\137\026\196\n\205\255\223\240\139\146@ \025\138\227\247\132\001\250\166\016#X\129Y\128\000\000\000\000\000\000\128\128\000\000\000\000\000\000\002 \000\000\003\023\255\127\194.I\000\128f+\143\222\016\007\234\152@\141b\005f\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\031\253\255\008\185$\002A\208\174?x@\031\170a\0185\136\021\155\255\191\225\023$\128@3\021\199\239\008\003\245L F\177\002\179\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@ \000\000\000\000\000\000\000\136\000\000\000\196\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000?\251\254\017rH\004\131\161\\~\240\128?T\194$k\016+0\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\255\239\248E\201 \018\014\133q\251\194\000\253S\008\145\172@\172\192\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\255\191\225\023$\128H:\021\199\239\008\003\245L\"F\177\002\179\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\012@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\255\191\225\023$\128H:\021\199\239\008\003\245L\"F\177\002\179\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@ \000\000\000\000\000\000\000\136\000\000\000\196\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000?\251\254\017rH\004\131\161\\~\240\128?T\194$k\016+0\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\152\000\000\001\000\008\000\000\000\012@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000 \000\000\000\000\000\000\000\000\130p\003\000\000\002\000\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\002\000\000\000\000\000\000\000\000\000'\0020\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\128\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\002\008\000\000\000\000\000\000\008\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\008 \000\000\000\000\000\000 \000\000\000@\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\016\002\000\000\000\000\000@\000\001\004\000\000\000\000\000\000\004\000\000\000\008\000\000\000\000\128\002\000\002\000\000\000\000\000\000\000#\000 \000@(\000\000\000\000\001\000\000\004\016\000\000\000\000\000\000\016\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000 \000 \000\000\000\000\000\000\0020\002\000\000\002\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\016\000\000\000\000\000\000\000\000\001\024\001\128\000\001\000\000\000\000\128\002\000\000\000\000\000\000\000\000\000#\000 \000\000 \000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\140\000\128\016\000\128\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\008\192\008\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\004`\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\128\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000 \000\000\000\000\000\000\000\000\0020\003\000\000\002\000\000\000\001\000\004\000\000\000\000\000\000\000\000\000F\000@\000\000@\000\000\000\000\000\128\000\000\000\000\000\000\000\000\008\192\008\000\000\008\000\000\000\000\000\016\000\000\000\000\000\000\000\000\001\024\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000") + + let action = + ((16, "\000r\000r\000\000\000\000\000\211\000\000\000\000\000\000\000r\000\000\000m$\152\000\000\000<=,\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\031\000\018\000\000$\152\"\212\024z\000\016%\018\000\000\000\000\000\000\000\000\021>\000\130\024z\000m\024z\000\000\000`\000\000\024z\000\000\000m\000\000\000\000\001\0203,\000\000\000\0004\208\000\0005~\001.3,3,\016X\016X5~\000\0007,\000\0007\1723,\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0005\2543,\000\000\000\0005\254\000\0005\254\000\0005\254\000\000\000\000\000\000\018\160\000m\000\000\016X\000\000*\2083,\022\2263,\000\000\000\000\000\000\000\000\000\000\000\000\025\1763,\000\000\026\1563,\026\2423,\027\2223,\000\0003,\000\0003,\02843,\029 3,\029v3,\030b3,\030\1843,\000\1783,\000\000\000\000\000\000\000\000\000\0003,\031\1643,\031\2503, \2303,\000\000\000\0003,\000\000\"\168$\222\000\000\000\000\000\182\000\000\000\000\000\000\024\026\000\000\000\000\000\000\000\000\000\000\025r\000<\000\000$\222\000\000\000\166\016X\000\0003,\000\222\000\000\000\000\000m\000\000\000\000\000\000\000\000\001\030\000\000\000\000\002.\000\000\000\0113,\000\000\000\011\000\000\000\000\016X\002f\000\000\002\204\000\000\000\000\000\000\000\000\000\000\000\000\000\0008,3,\000\0008,\000\0008,8,\000\000\000\000'\"\000m\000\000\016X\003\020\000\0003,\003\018\000\000\000\000\000m\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016X\003>7,\000\000\000\000<\1523,\000\0003,\000\000\000\000\003\132\000\000\000p6\172\004B3,\004\018\000\000\000\0007,\000p\000\000\000\000\000\000\000\000\000\000'\1647,>B7,>\1427,>\2187,\000\0007,\000\0007,?&7,?r7,?\1907,@\n7,@V3,\003\2287,\000\0007,@\1627,@\2387,A:\003\208\000\000\004 \000\000\000\138$\152\000\000\000\138\000\000\000\000\00423,\000\000\004\166\000\0007,\004\246\000\000\016X\004T\000\000\000\000\004T\000\000\000\000\001\020\000\000\005(\000\000$\222A\204\005N\005L\000m\004\194\005tC\018\001\148\000\000\000\000\002\028C:\000\000\000\000\000\000\005x\005l\001$\005~C\018\002\\C\018\000\000\000\000\001\"\000\000\000\000\004\238\000\000\005\018\005\198C\018\005@\000\000\000\000\002\028\000\000\005X\006,\000\000C\218\026P\000\000\000m\006.\000\000(\250\000m\006B\000\000\000\000#\158\024z\005p\000\000\005\234\000\000\005z\000\000\001*$\152\000\000$\152\000\000\005h\000\000\001*\000\000\012\166\016\n\0064C\018\005\136\006X\000\000$\152\000\004\000\000\006\\\000\000\000\000\000\000\000\000\000\000\000\000\006@3,\005\148\016\252\006F3,\005\154\006D\002\012\005\212\006R\000\0008\1729,\016X\005\178\000\000\005\1829,\000\000\000\000\000\000\000\000\000\000\000\000\000\0009\1723,\000\0009\172\000\0009\1729\172\000\000\000\000\022\140\000m\000\000\016X\005\198\000\0003,\005\208\000\000\000\000\000m\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000%\1843,\000\0003,\000\000\005\224\000\000\000\011\000\000\000\000\000\000\000\000\000\000+&9,,\0089,,^9,-@9,\000\0009,\000\0009,-\1509,.x9,.\2069,/\1769,0\0063,\006\0149,\000\0009,0\2329,1>9,2 \016X\005\236\000\000\000\0003,\000\000\006\188\000\000\001B\002\134\000\000\006R\006R\001B\000\000\001B\000\000\012\166\006R\006R\000\000\000\000\000\000\020\162\000\000\000\000\000\000\000\000\006\1583,\005\242\016\252\017\190\000m\006\194\000\000\006\1663\208\006\2123\208\006\2163,\006\014\016\252\016\252\003\170\002\244\001\"\000\000\000\000\000\000\002\244\000\000\003\146\001\128\000\000\000\000\006\020\000\000\000\000\000\000\006\234\000\000\006\236\000\000\000\000\007\028\006\2383,\006F\007\022\000\000\018\246\007\000\016X\006T\016\252\000\000\000\000\006|\000\000\000\011\000\000\003\202\000\000\001B\000\000\000\000\006\206\000\000&X\016\n\007\020C\018\006h\007R\000\000\000m\000\000\001\2083\208'\238\000\000:,3,\006\154\000\000\016X\006\156\000\000\006\158\000\000\000\000\000\000\000\000\000\000\000\000\000\000:\1723,\000\000:\172\000\000:\172:\172\000\000\000\000C\184\000m\000\000\016X\006\162\000\0003,\006\160\000\000\000\000\000m\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016X\006\166;,\000\000\000\0003,\000i3,\006\188\006\240'\238(\178&\134\007j3\208\0076\000\000\000\000\000m\006\248'\238\000\000\006\244'\238\000\000\000\000\015x;,\019\250;,#\012;,)H;,\000\000;,\000\000;,*\012;,5P;,6~;,8\254;,9~;,9\254;,:~;,<\214\000\000\000\000\006\202\000\000\006\218)v\000\000*:\006\222*:2~\006\224*:\000\000\000\000\000\000\000\000\000\000\007\008'\238\000\000\000\000\006\218\000\000\007\176\000\000\000m\000\000\000\186\007\178\000\000\006p\007\144\000m\006\246\007\182C\018\007\n\000p\000\0003\208\007\230\000\000\000_\005\166\007h\007\208C\018\007$\007\244\000\000\002\1403\208\007\250\000\000\007\252\000\000(\250\000m\00363\208\007\254\000\000\008\000\000\000\011b\0009\000\000\011b\000\000\000\000\019\164\004z3\208\008\002\000\000\008\004\000\000\000\000\0076\007\214\000m\007J\007\252C\018\007R\002\016\000\0003\208\008\"\000\000\003H\000\000\000\000\007\150\000\000\011b\000\000\008\006\016X\007^\0080\000\000\000\022\000\000\008\018C\018\007h\0088\000\000\004\1523\208\008>\000\000\008@\000\000(\250\000m\004\1723\208\008D\000\000\008F\000\000\000\000\000\000\007\150\000\000\000\000\000\008\000\000\006R\000\000\000\254\000\000\000\000\001\030\017\190\000\000\001\030\000\000\000\000\007|\000\000\000\011\000\003\016\252\000\000\003\202\0009\003\202\000\000\000\008\000\000\006R\000\000\006R\000\000\000\000\000\000\007~\000\000\000\000\007\140\000\000\002\146\005\014\001\012\003\202\000\000\000\000\000\000\001\210\000\000\006R\000\000\002\146\000\000\000\000\014n\005\002\012\166\000\000\012\212\000\000\008\218\012\166\000\000\000\000\008\218\000\000\000\000\007\138\000\000\000\000\007\144\000\000\003j\006R\000\000\003j\000\000\000\000\008\002\000\000\000\008\000\000\006R\000\000\000\000\000\000\015 4P\000\000\008d\000\000\015 \008f\000\000\008j\000\000&X\000m\003>\000\0003\208\008n\000\000\008X\008J\000m\007\200\008zC\018\007\220\003\248\000\0003\208\008\172\000\000\000_\004\202\000\0003\208\008\180\000\000(\250\000m\005\012\000\0003\208\008\184\000\000\004$\015 \000\000\019\164\005\176\000\0003\208\008\202\000\000\000\000\000\000\008\172\008\170\000m\008\018\008\194C\018\008\022\005\184\000\0003\208\008\240\000\000\000X\000\000\008\210\016X\008&\008\246\000\000\000\148\000\000\005\216\000\0003\208\008\254\000\000(\250\000m\005\240\000\0003\208\t\004\000\000\004$\000\000\000\000\008<\000\000\000X\015\016\008\176\000\000\000\000\000\000\008\186\000\000\001N\002\134\000\000\012\166\t\022\000\000\000\0003,\008\140\006R\000\000\008b\000\000\002\012\000\000\000\000\003V\012\166\000\000\012\166\000\000\008P\000\000\003V\000\0007,\003\1667,\000\0007,\000\000\008R\000\000\003\166\000\000\016\252\003\190\016\252\000\000\016\252\000\000\008V\000\000\003\190\000\0007,\003\166\008X\000\000<\028\000m\004\018<\028\000\000<\028\000\000\008Z\000\000\004\018\000\0007,\003\166\008^\000\000\000\000\021\230\000\000\000\000\000\000\000\000\000\000\025\020!\130\000\000\003<\000\000\004\128\000\000\000\000\008\158\000m\000\000\000\000\000\000\002\138\004\128\000\000\002\146\003\184\003\184\000\000\000\179\003\184\000\000\008v\000\000\000\000\000\000\000\000\000\000\000\000\008\242\000\000\"L\000\000$\152\004\128\000\000\003n\004\128\000\000\t\002\000\000\004\128\t\006\000\000\007\202\012\192\t\n\000\000\t\012\000\000\t\190\012\192\004\128\008\164\004\128\t\"\000\000\t$\000\000\t*\000\000$\152\000\000\003d$\152\000\000\008\180\0032\000\000\000F\004\128\000\000\004\138\004\128\000\000\002\222\001\216\000m\000\000\000\204\000m\000\000\008\194\000\000\000\000\000\000\000\000\tB\000\000\004\128\004\128\tJ\000\000\tR\000\000\004\128\tT\000\000\004\128\t\\\000\000\t6\004\128\tb\000\000\004\174\021:\004\128\t\008\004\128\t\150\000\000\t\152\000\000\000\000\004\164\004\128\000\000\003t\002n\002n\000\000\000\000\000\000\004d\002n\000\000\t \000\000\000\000\000\000\000\000\004\128\000\000\004\184\004\128\000\000\004\"\002\208\000m\t$\000\000\000\000\000\000\000\000\t\160\000\000\t\162\000\000\004\128\t\180\000\000\0076\004\128\t\182\000\000\t\186\000\000>\028\tl\t\150\008~\004\128\t\194\000\000\000\000\t\196\000\000\t\156>\028\004\128\t\202\000\000\004\128\t\204\000\000\t\206\000\000\008\244\tZ\004\128\t\212\000\000\t\214\000\000\000m\tR\000\000\000\000\021\230\000\000\000\000\0026\n,\000\000\000\000\001\017\000\000\000\000\000\0003,\001\194\nf\t\152\n\0287,\000\000\004\1627,\000\000\tx\000\000\000\000\000\000\000\000\000\000\002\134\000\000\001\013\000\000\000\000\000\000\003\202B~\001zB~B~\001z\000\000\000\000\005\242\005\242\005\242\005\242\000\000\000\000\000\000\000\000\000\000\000\000\000\000<\152\006p\013\232\0009\000\000\000\000\003H\000\000\007\150\000\000\000\000\001\194\000\000\000\000\t\192\000R\n4Dz\000\000\004\178E\024\000\000\000\000\n>\n0\000m\000\000\000m\000\000\004\178\000\000\004\180Dz\000\000\000\000\t\160\nR\006R\t\166\000\000\0076\003H\000\000\007\150\000\000\000\254\002\132\000\000\000\000\n>\000\000\000\000\0026\000\000\004\002\000\000\000\000\000\0003,\001\194\000\000\002\134\000\000\0040\000\000\000\000\000\000\005\014\n\030\005\208\n\030\000\000\006R\n\030\000\000\005\208\000\000\006R\000\000\006R\000\000\006R\000\000\000\000\000\000\000\000\000\000\001\194\000\000\006R\000\000\005\208\000\000\006R\000\000\003\134\000\000\000\000\008\218\n\138\000\000\000\000\008\218\000m\003\020\nf\002p\000\000\002p\n\144\000\000\n\146\000\000\n\148\000\000\000\000\002\216\002p\012\164\002p\000\000\000\000\006\232\t\170\000\000\008,\t\014\n\164\tp\n\164\000\000\000\000\nP\000m\000\000\005D\t\254\000\000\000\000\000\000\001\230\000\000\t\176\000\000\000\000\000\000\008,\t\014\nP\005D\001\230\t\178\000\000\000m\000\000\n\176\n\176\t\254\000m\nR\000\000"), (16, "\n\141\n\141\n\141\n\141\n\141\n\141\n\141\n\141\n\141\n\141\n\141\000\182\n\141\n\141\n\141\n\141\n\141\n\141\n\141\n\141\n\141\020\011\020\015\020c\020g\n\141\020\019\008\002\020k\n\141\000\210\n\141\n\141\n\141\001.\008\022\n\141\011\174\001:\n\141\n\141\t*\n\141\000.\006\018\016:\016b\016\138\016\154\016\198\t*\n\141\000\023\000\027\n\141\n\141\017F\012\158\000\162\008\002\n\141\n\141\n\141\nA\n\141\000\162\011-\008\022\002\242\n\141\0055\n\141\n\141\n\141\n\141\n\141\0066\nF\000\146\n\141\n\141\n\141\n\141\n\141\n\141\000\006\n\141\n\141\n\141\n\141\015R\000\n\001.\n\141\n\141\011\174\001:\011-\011-\011F\000:\t6\011\154\n\141\n\141\n\141\n\141\n\141\n\141\n\141\000\014\n\141\005\197\n\141\000\162\n\141\000z\002\242\n\141\n\141\015n\000~\001.\000\162\n\141\0016\001:\013F\n\141\011-\011-\n\141\000\174\t6\011-\n\141\n\141\n\141\n\141\n)\n\141\n\141\004\158\005\157\nI\n\141\n\141\n\141\007\213\n\141\018\014\n\141\n\141\000\162\n\141\001.\n\141\n\141\011\174\001:\n\141\n\141\005\205\005\205\005\205\005\205\005\205\005\205\005\205\005\205\005\205\005\205\005\205\012\158\005\205\005\205\005\205\005\205\005\205\005\205\005\205\005\205\005\205\011\158\005=\003\218\000\162\005\205\008\006\008\002\005\242\005\205\005\157\005\205\005\205\005\205\0055\008\022\005\205\0055\000\194\005\205\000\222\0055\005\205\0055\005\197\003\233\001.\0055\0055\011\174\001:\005\205\005e\005e\013\"\005\149\000\250\002\026\nI\013\022\005\205\005\205\nI\nI\005\205\005\205\002\174\000\210\000\210\005\205\003i\005\205\005\205\005\205\005\205\005\205\011f\000\162\002r\005\205\005\205\005\205\005\205\005\205\005\205\0186\005\205\005\205\005\205\005\205\006\229\005\250\nI\005\205\005\205\000\162\000\162\002b\nI\n\025\002\190\t6\0055\005=\005\205\005\205\005\205\005\205\005\205\005\205\000\146\005\205\008\162\005\205\000\210\005\205\n)\t*\005\205\005\205\003\233\005=\006\229\006\229\005\205\005=\008\002\006\229\007\t\005\189\002\222\005\205\007\t\005J\008\022\005\205\005\205\005\205\005\205\018*\005\205\005\205\000\162\0055\003\233\005\205\005\205\005\205\012Z\005m\015\218\005\205\005\205\005\237\005\205\005\237\005\205\005\205\005\237\008\154\005\205\005\205\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\005\237\002U\000\162\005\237\020\030\002U\022f\005\237\019\250\005\237\005\237\005\237\008\n\tr\005\237\021w\t6\005\237\005\237\022\238\005\237\005\237\005\237\021{\005\237\005\237\n)\005\237\022j\005\237\018\214\011f\005\237\021~\022n\003\233\005\229\005\229\005\237\005\237\005\237\005\229\005\237\005\237\008\014\012^\005\237\005\237\019\250\005\237\0176\005\237\005\237\005\237\006z\004\217\013\150\005\237\005\237\005\237\005\237\005\237\005\237\015\242\005\237\005\237\005\237\005\237\005E\005.\nq\018\218\005\237\005U\006\021\0055\022\142\000\162\005\237\019\"\007\217\002\234\005\237\005\237\005\237\005\237\005\237\005\237\018&\005\237\022v\005\237\005\237\005\237\0055\014B\005\237\005\237\005\237\007\217\014F\005V\005\237\0055\014J\002y\005\237\011\206\007\217\005\237\003\014\n)\006\005\005\237\005\237\014~\005\237\017\002\005\237\005\237\t*\022~\016\026\005\237\017*\011f\000\162\0055\006\021\008\002\005\237\005\165\005\237\002b\005\237\005\237\015\198\008\022\005\237\005\237\0002\006\022\000F\000J\006.\000N\006F\000R\000V\006J\000Z\012\158\000^\020r\000b\006N\000f\000j\000n\006R\020z\003\022\016B\018\210\014\022\006V\006\005\022\158\011-\000r\017\018\000\226\006f\006\130\016j\0055\006\134\008\158\022\150\000v\007\217\005]\007\242\022^\nQ\016\"\001.\005\253\0055\011\174\001:\000\238\011\238\007\217\008\002\017:\014\130\003j\003v\011-\008*\006\142\008\022\t6\008.\013R\003!\000\210\014\174\001\"\011f\001&\003\197\000\134\t2\0086\016\166\000\162\003\170\006\162\001.\008:\006\166\008>\001:\016J\006\170\006\174\008B\006\178\008=\011-\011-\017\246\008F\000\162\011-\016r\017\138\005\173\n!\005\253\017\n\005\133\006\182\006\186\008J\008N\006\190\008R\019\030\000\162\008\154\008f\003\210\003\161\008\186\014\246\008r\006\198\003\001\017\014\008=\008=\005\245\018\158\003\226\008=\t6\003\234\017\018\008\146\002\253\n)\006\013\008\150\008\210\003\197\t>\016\174\006\202\008\214\004j\005}\017\014\006\206\003\197\003\197\n)\014\178\004\142\003\197\008\222\017\018\006\210\005\141\005\245\005\245\n)\018^\001j\005\245\0002\006\022\000F\000J\006.\000N\006F\000R\000V\006J\000Z\014\198\000^\020r\000b\006N\000f\000j\000n\006R\020z\000:\021\151\021\155\na\006V\006\013\021\159\004\150\000r\005\181\000\226\006f\006\130\007\029\005u\006\134\nY\004\182\000v\000\162\004\194\007\242\004\206\014\226\021\187\021\191\ni\008\002\007\029\021\195\000\238\012\"\017\030\008\002\004\218\008\022\004\230\004\250\018\234\008*\006\142\008\022\000\162\008.\013\154\n9\012\186\022\218\001\"\011f\001&\003\213\000\134\t2\0086\017\030\012\218\018\026\006\162\001.\008:\006\166\008>\001:\011f\006\170\006\174\008B\006\178\0206\018\198\014\202\005\n\008F\011f\n1\007\029\021\n\021:\005\014\019\018\005M\002m\006\182\006\186\008J\008N\006\190\008R\005\022\000\162\005\026\008f\005B\003\161\005F\005N\008r\006\198\006F\004q\t6\006J\006\029\014\230\015\006\020\146\t6\006N\015>\008\146\005r\006R\020\150\008\150\008\210\004\005\t>\004q\006\202\008\214\t*\007\029\022\226\006\206\015v\003\213\003\129\022\230\005z\008\002\008\222\005~\006\210\007\029\006\029\006\029\015\146\008\022\001j\006\029\0002\006\022\000F\000J\006.\000N\006F\000R\000V\006J\000Z\005\134\000^\020r\000b\006N\000f\000j\000n\006R\020z\006F\003\129\005\154\006J\006V\005\158\005\182\020\146\000r\006N\000\226\006f\006\130\006R\020\150\006\134\005\198\005\218\000v\004q\005\226\007\242\005\234\006\007\015\n\006\030\006&\006*\015B\006>\000\238\006Z\006b\008\002\006j\006r\006v\004q\008\005\008\018\006\142\008\022\t6\008.\015z\006~\003\181\006\150\001\"\006\158\001&\003\241\000\134\0082\0086\011~\015\150\006\246\006\162\001.\008:\006\166\008>\001:\007\002\006\170\006\174\008B\006\178\007J\008\005\008\005\0115\008F\007\194\008\005\007\234\007\254\008V\008^\008n\003%\008v\006\182\006\186\008J\008N\006\190\008R\008~\000\162\008\134\008f\008\142\003\161\003%\008\202\008r\006\198\006F\008\218\008\226\006J\008\013\017\n\008\238\020\146\t6\006N\003\181\008\146\022\142\006R\020\150\008\150\008\210\003\241\t>\008\242\006\202\008\214\008\250\008\254\017\014\006\206\003\241\003\241\t\n\t\018\t\"\003\241\008\222\017\018\006\210\tF\008\013\008\013\tV\t^\001j\008\013\0002\006\022\000F\000J\006.\000N\006F\000R\000V\006J\000Z\tb\000^\012>\000b\006N\000f\000j\000n\006R\019Z\t\138\004m\t\150\t\158\006V\t\242\t\254\n2\000r\003%\000\226\006f\006\130\003%\003%\006\134\017\170\004\001\000v\004m\nN\007\242\nR\nb\nj\003%\nz\n\134\011\n\011\018\000\238\011\"\011.\008\002\011J\017\014\011Z\011b\011v\008\018\006\142\008\022\000\162\008.\017\018\011\130\003\181\011\138\001\"\003%\001&\022\150\000\134\0082\0086\017\030\011\142\011\150\006\162\001.\008:\006\166\008>\001:\011\166\006\170\006\174\008B\006\178\011\186\011\194\011\198\0115\008F\011\214\011\222\011\246\011\254\012*\0122\012B\003!\004m\006\182\006\186\008J\008N\006\190\008R\012J\000\162\012N\008f\012V\012f\003!\012\138\008r\006\198\012\146\004m\012\150\012\166\0115\012\174\012\178\004a\t6\012\194\012\202\008\146\012\226\012\234\013:\008\150\008\210\000\162\t>\013\130\006\202\008\214\013\142\014\002\014\014\006\206\004a\014.\014Z\014f\017\030\014n\008\222\014\138\006\210\004a\0115\0115\014\146\014\150\001j\0115\0002\006\022\000F\000J\006.\000N\006F\000R\000V\006J\000Z\014\158\000^\014\162\000b\006N\000f\000j\000n\006R\t\185\014\170\014\186\004a\017\n\006V\014\210\003\141\014\238\000r\003!\000\226\006f\006\130\003!\003!\006\134\015\018\015\"\000v\007%\003\141\007\242\017\014\t\185\015&\003!\022^\015.\0152\015:\000\238\017\018\022\182\008\002\007%\015J\015Z\015b\015f\008\018\006\142\008\022\015\130\008.\004a\015\158\005\213\015\178\001\"\003!\001&\015\194\000\134\0082\0086\019\194\015\210\004a\006\162\001.\008:\006\166\008>\001:\015\234\006\170\006\174\008B\006\178\015\250\016\006\016/\016W\008F\016\127\016\151\016\187\t\185\016\211\017\022\017R\017o\007%\006\182\006\186\008J\008N\006\190\008R\017\151\000\162\017\163\008f\017\179\017\187\n\017\003\141\008r\006\198\022F\003\141\003\141\017\206\000\162\017\194\017\215\017\223\t6\022V\017\231\008\146\018\002\003\141\003\141\008\150\008\210\017\030\t>\018B\006\202\008\214\018W\005\213\017\014\006\206\018g\005\213\005\213\007%\018o\018{\008\222\017\018\006\210\018\135\018\142\003\141\018\151\005\213\001j\007%\0002\006\022\000F\000J\006.\000N\006F\000R\000V\006J\000Z\018\170\000^\020r\000b\006N\000f\000j\000n\006R\020z\005\213\018\179\018\187\018\246\006V\019*\019?\019G\000r\n\017\000\226\006f\006\130\n\017\n\017\006\134\019S\019c\000v\019k\019v\007\242\019z\019\135\019\147\n\017\019\154\019\167\019\179\019\187\000\238\019\198\019\207\019\215\019\227\019\254\022\190\020\"\020&\008*\006\142\020*\000\162\008.\021\206\005\221\020B\020\246\001\"\n\017\001&\020\254\000\134\t2\0086\017\030\021\026\021\030\006\162\001.\008:\006\166\008>\001:\021J\006\170\006\174\008B\006\178\021N\021V\021\131\022J\008F\022b\022r\022z\022\130\022\171\022\186\022\222\022\247\023\027\006\182\006\186\008J\008N\006\190\008R\023*\000\162\023.\008f\0232\003\161\023;\000\000\008r\006\198\000\000\000\000\000\000\000\000\007\241\000\000\000\000\000\000\000\000\000\000\000\000\008\146\000\000\000\000\000\000\008\150\008\210\000\000\t>\000\000\006\202\008\214\005\221\000\000\000\000\006\206\005\221\005\221\000\000\000\000\000\000\000\000\008\222\000\000\006\210\000\000\007\241\007\241\022\206\000\000\001j\007\241\0002\006\022\000F\000J\006.\000N\006F\000R\000V\006J\000Z\000\000\000^\000\000\000b\006N\000f\000j\000n\006R\005\221\000\000\000\000\000\000\000\000\006V\000\000\000\000\000\000\000r\000\000\000\226\006f\006\130\000\000\000\000\006\134\000\000\000\000\000v\000\000\000\000\007\242\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\238\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008*\006\142\000\000\000\000\008.\012\006\000\000\000\000\000\000\001\"\000\000\001&\000\000\000\134\t2\0086\000\000\000\000\000\000\006\162\001.\008:\006\166\008>\001:\000\000\006\170\006\174\008B\006\178\000\000\000\000\000\000\011\017\008F\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\182\006\186\008J\008N\006\190\008R\000\000\000\162\000\000\008f\000\000\000\000\000\000\000\000\008r\006\198\000\000\000\000\000\000\000\000\011\017\000\000\000\000\000\000\000\000\000\000\000\000\008\146\000\000\000\000\000\000\008\150\008\210\000\000\t>\000\000\006\202\008\214\000\000\000\000\000\000\006\206\000\000\000\000\000\000\000\000\000\000\000\000\008\222\000\000\006\210\000\000\011\017\011\017\000\000\000\000\001j\011\017\0002\006\022\000F\000J\006.\000N\006F\000R\000V\006J\000Z\000\000\000^\000\000\000b\006N\000f\000j\000n\006R\000\000\000\000\000\000\000\000\017\n\006V\003\029\000\000\000\000\000r\000\000\000\226\006f\006\130\000\000\000\000\006\134\000\000\000\000\000v\003\029\000\000\007\242\017\014\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\238\017\018\000\000\000\000\000\000\003\029\000\000\000\000\000\000\008*\006\142\000\000\007\029\008.\013\206\000\000\000\000\t*\001\"\000\000\001&\000\000\000\134\t2\0086\017\198\008\002\007\029\006\162\001.\008:\006\166\008>\001:\008\022\006\170\006\174\008B\006\178\000\000\000\000\000\000\000\000\008F\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\t\197\006\182\006\186\008J\008N\006\190\008R\000\000\000\162\000\000\008f\000\000\000\000\003\029\000\000\008r\006\198\003\029\003\029\000\000\000\000\000\162\000\000\007\029\000\000\000\000\000\000\000\000\008\146\003\029\000\000\000\000\008\150\008\210\017\030\t>\000\000\006\202\008\214\000\000\000\000\000\000\006\206\000\000\003\029\000\000\000\000\000\000\t6\008\222\000\000\006\210\000\000\003\029\t\197\022\150\000\000\001j\0002\006\022\000F\000J\006.\000N\006F\000R\000V\006J\000Z\007\029\000^\000\000\000b\006N\000f\000j\000n\006R\000\000\000\000\000\000\007\029\000\000\006V\000\000\000\000\000\000\000r\000\000\000\226\006f\006\130\000\000\000\000\006\134\000\000\000\000\000v\000\000\000\000\007\242\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\238\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008*\006\142\000\000\000\000\008.\020\198\000\000\000\000\000\000\001\"\000\000\001&\000\000\000\134\t2\0086\000\000\000\000\000\000\006\162\001.\008:\006\166\008>\001:\000\000\006\170\006\174\008B\006\178\000\000\000\000\000\000\000\000\008F\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\182\006\186\008J\008N\006\190\008R\000\000\000\162\012\158\008f\000\000\000\000\000\000\000\000\008r\006\198\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\146\000\000\000\000\000\000\008\150\008\210\000\000\t>\004\158\006\202\008\214\000\000\000\000\000\000\006\206\000\000\001.\000\000\000\000\011\174\001:\008\222\000\000\006\210\000\000\0002\006\022\000F\000J\001j\000N\006F\000R\000V\006J\000Z\000\000\000^\000\000\000b\006N\000f\000j\000n\006R\000\000\000\000\000\162\000\000\000\000\000\000\000\000\000\000\000\000\000r\000\000\000\226\000\000\006\130\000\000\000\000\006\134\015n\000\000\000v\000\000\000\000\014N\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\238\000\000\000\000\000\000\000\000\000\000\000\000\005\149\000\000\014^\006\142\000\000\000\000\004\158\n\150\000\000\000\000\000\000\001\"\000\000\001&\001.\000\134\000\000\011\174\001:\000\000\000\000\006\162\001.\n\158\006\166\0016\001:\000\000\006\170\006\174\008B\006\178\000\000\000\000\000\000\000\000\000\000\n\166\000\000\000\000\000\000\000\000\000\000\n\230\n\238\000\162\006\182\006\186\000\000\000\000\006\190\000\000\n\198\000\162\000\000\n\174\000\000\n\190\000\000\000\000\000\000\006\198\000\000\000\000\000\000\0055\000\000\000\000\0055\000\000\000\000\000\000\0055\000\000\0055\000\000\000\000\n\206\0055\0055\t>\005\149\006\202\014b\000\000\000\000\000\000\006\206\000\000\000\000\000\000\000\000\000\000\000\000\014j\000\000\006\210\000\000\0002\0006\000F\000J\001j\000N\000\000\000R\000V\000\000\000Z\000\000\000^\n\214\000b\000\000\000f\000j\000n\000\000\n\182\000\000\0055\000\000\000\000\000\000\000\000\000\000\000\000\000r\000\146\000\226\004\169\000\230\000\000\000\000\000\234\000\000\000\000\000v\000\000\001.\000\000\000\000\0016\001:\000\000\n\246\n\222\000\000\000\000\000\238\000\000\000\000\000\242\000\000\000\000\000\000\000\000\000\000\001\006\001\002\001\n\000\000\000\000\000\000\000\000\000\000\000\000\001\"\000\000\001&\000\162\000\134\000\000\000\000\0055\000\000\000\000\001*\001.\000\000\0012\0016\001:\001\142\001>\001B\000\000\001F\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001J\000\000\006V\001N\000\000\000\000\000\162\000\000\000\226\006f\006\130\000\000\000\000\006\134\001V\000\000\000\000\000\000\000\000\007\242\000\000\000\000\000\000\001Z\000\000\000\000\000\000\000\000\000\238\000\000\000\000\000\000\000\000\000\000\000\000\001^\000\000\008b\006\142\000\000\001b\008.\000\000\003e\000\000\000\000\001\"\000\000\001&\001f\000\000\000\000\0086\000\000\000\000\001j\006\162\001.\008:\006\166\008>\001:\000\000\006\170\006\174\000\000\006\178\000\000\000\000\000\000\000\000\008F\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\182\006\186\008J\008N\006\190\008R\000\000\000\162\000\000\008f\000\000\000\000\000\000\000\000\008r\006\198\000\000\000\000\006V\000\000\000\000\000\000\000\000\000\000\000\226\006f\006\130\008\146\000\000\006\134\000\000\008\150\008\210\000\000\000\000\007\242\006\202\008\214\000\000\000\000\000\000\006\206\000\000\000\000\000\238\000\000\000\000\000\000\008\222\000\000\006\210\000\000\000\000\006\138\006\142\000\000\001j\008.\000\000\000\000\000\000\000\000\001\"\000\000\001&\000\000\000\000\000\000\0086\000\000\000\000\000\000\006\162\001.\008:\006\166\008>\001:\000\000\006\170\006\174\000\000\006\178\000\000\000\000\000\000\000\000\008F\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\182\006\186\008J\008N\006\190\008R\000\000\000\162\000\000\008f\000\000\000\000\000\000\000\000\008r\006\198\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\146\000\000\000\000\011a\008\150\008\210\011a\000\000\000\000\006\202\008\214\000\000\000\000\000\000\006\206\000\000\000\000\000\000\000\000\011a\000\000\008\222\011a\006\210\000\000\000\000\001\130\011a\000\000\001j\000\000\000\000\000\000\011a\000\000\000\000\011a\011a\000\000\011a\011a\000\000\000\000\001\138\011a\002\182\004\001\000\000\011a\004\001\000\000\011a\000\000\011a\011a\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\001\000\000\000\000\000\000\000\000\000\000\000\000\004\001\004\001\000\000\000\000\011a\000\000\011a\004\001\000\000\000\000\000\000\000\000\000\000\004\001\004\001\000\000\011a\004\001\000\000\004\001\000\000\002\194\004\001\000\000\000\000\004\001\000\000\004\001\004\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\011a\011a\011a\000\000\011a\011a\002\198\000\000\011a\000\000\004\001\000\000\000\000\000\000\000\000\000\000\002\206\000\000\000\000\000\000\011a\000\000\000\000\011a\011a\011a\011a\004\001\000\000\000\000\004\001\011a\011a\011a\000\000\011a\011a\011a\000\000\000\000\000\000\000\000\000\000\004\001\004\001\004\001\004\001\000\000\004m\004\001\004\001\004\001\000\000\000\000\000\000\000\000\000\000\004\001\000\000\004\001\004\001\004\001\000\000\004\001\004\001\000\000\004\001\004\001\004\001\004\001\000\181\000\000\004\001\000\000\004\001\004\001\000\000\004\001\004\001\004\001\000\000\000\000\000\000\000\000\000\000\000\000\n\158\000\000\000\000\000\210\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\001\000\000\004\001\n\166\000\000\000\000\000\000\000\000\000\000\000\181\000\181\000\000\004\001\000\000\000\000\000\000\000\000\004\001\n\198\000\000\000\162\n\174\000\000\n\190\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\001\004\001\004\001\000\000\004\001\004m\004\001\000\000\004\001\000\000\n\206\000\000\000\000\000\000\000\000\000\000\004\001\000\000\000\000\000\000\000\000\000\000\000\000\004\001\004\005\004\001\000\000\004\005\000\000\000\000\000\000\004\001\004\001\004\001\000\000\004\001\004\001\004\001\000\000\000\000\004\005\000\000\000\000\004\005\n\214\000\000\000\000\004\005\004\005\000\000\000\000\n\182\000\000\000\000\004\005\000\000\000\000\004\005\004\005\000\000\004\005\004\005\000\000\000\181\004\005\004\005\004\005\000\000\000\000\004\005\000\000\000\000\004\005\000\000\004\005\004\005\000\000\000\000\000\181\n\222\000\000\003Q\003Q\003Q\003Q\000\000\003Q\000\000\003Q\003Q\017\n\003Q\000\000\003Q\004\005\003Q\004\005\003Q\003Q\003Q\000\000\000\000\000\000\000\000\000\000\000\000\004\005\000\170\000\000\017\014\003Q\004\005\000\000\000\000\000\000\000\000\000\000\000\000\017\018\000\000\003Q\000\000\000\000\000\000\000\000\000\000\000\000\004\005\004\005\004\005\000\000\004\005\004q\004\005\000\000\004\005\000\000\000\000\000\000\000\000\000\000\003Q\018\162\004\005\000\000\t\197\003Q\004\005\000\000\000\000\004\005\000\000\004\005\000\000\003Q\000\000\000\000\000\000\004\005\004\005\004\005\000\000\004\005\004\005\004\005\001=\001=\001=\001=\t\197\001=\000\000\001=\001=\000\000\001=\000\000\001=\000\000\001=\000\000\001=\001=\001=\000\000\000\000\000\000\000\000\016\222\000\000\000\162\000\000\003Q\001=\001=\001=\000\000\000\000\000\000\000\000\001=\000\000\000\000\017\030\001=\000\000\000\000\000\000\001=\000\000\000\000\000\000\001=\000\000\000\000\016\226\000\000\000\000\001=\000\000\000\000\000\000\000\000\t\197\000\000\001=\000\000\000\000\000\000\001=\000\000\000\000\003Q\000\000\000\000\000\000\000\000\000\000\001=\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001=\000\000\000\000\001=\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\011\181\000\000\000\000\011\181\000\000\000\000\001=\000\000\001=\000\000\001=\000\000\001=\000\000\000\000\000\000\011\181\001=\000\000\011\181\001=\000\000\000\000\006\230\011\181\000\000\000\000\000\000\000\000\000\000\011\181\000\000\000\000\011\181\011\181\001=\011\181\011\181\001=\001=\006\238\011\181\006\250\001\137\000\000\011\181\001\137\000\000\011\181\016\230\011\181\011\181\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\137\000\000\000\000\001\137\000\000\000\000\000\000\000\000\001\137\000\000\000\000\011\181\000\000\011\181\001\137\000\000\000\000\001\137\001\137\000\000\001\137\001\137\000\000\011\181\000\000\001\137\000\000\000\000\007\006\001\137\000\000\000\000\001\137\000\000\001\137\001\137\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\011\181\011\181\011\181\000\000\011\181\000\000\007\n\000\000\011\181\000\000\001\137\000\000\001\137\000\000\000\000\000\000\007\018\000\000\000\000\000\000\000\000\000\000\001\137\011\181\000\000\011\181\000\000\000\000\000\000\000\000\000\000\011\181\011\181\011\181\000\000\011\181\011\181\011\181\000\000\000\000\000\000\000\000\000\000\001\137\001\137\001\158\000\000\001\137\001\137\000\000\000\000\001\137\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\137\000\000\000\000\001\137\001\137\001\137\001\137\000\000\000\000\000\000\000\000\002J\001\137\001\137\000\000\001\137\001\137\001\137\004%\000\000\002\130\004%\002\134\004%\002\138\004%\000\000\004%\000\000\000\000\002\142\004%\004%\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004%\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004%\004%\000\000\000\000\000\000\000\000\004%\000\000\000\000\0002\000\142\000F\000J\000\000\000N\000\000\000R\000V\000\000\000Z\000\000\000^\004%\000b\004%\000f\000j\000n\000\000\000\000\004%\000\000\000\000\004%\004%\000\000\000\000\000\000\000r\000\000\000\000\004%\000\000\000\000\004%\004%\000\000\000\000\000v\000\000\000\000\000\000\000\000\000\000\004%\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004%\000\000\000\000\000\000\000\000\000\130\000\000\000\000\004%\000\000\000\158\000\000\004%\000\000\000\000\000\000\000\000\000\000\000\134\000\000\000\000\004%\t\181\t\181\t\181\t\181\000\000\t\181\000\000\t\181\t\181\000\000\t\181\000\000\t\181\000\000\t\181\000\000\t\181\t\181\t\181\004%\000\000\000\000\004%\004%\000\000\000\000\004%\000\000\t\181\t\181\t\181\004%\004%\000\000\000\162\t\181\004%\000\000\000\000\t\181\000\000\000\000\000\000\016\246\000\000\000\000\000\000\016\254\002\154\000F\000J\000\166\000N\t\181\000R\000V\000\000\000Z\000\000\000^\t\181\000b\000\000\000f\t\181\000n\000\000\000\000\000\000\000\000\000\000\000\000\000\000\t\181\n\249\000\000\000r\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000v\000\000\000\000\000\000\000\000\000\000\t\181\000\000\000\000\t\181\000\000\000\000\000\000\001\190\000\000\000\000\002\018\000\000\000\000\000\000\000\000\000\000\000\000\000\000\t\181\000\000\t\181\000\000\t\181\001\202\t\181\000\000\002\001\000\000\000\134\t\181\000\000\002\001\t\181\000\000\000\000\000\000\000\000\001\210\000\000\000\000\002\001\002\001\000\000\0022\002:\000\000\000\000\t\181\002\001\000\000\017r\t\181\001\242\000\000\000\000\001\218\000\000\001\234\002\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0002\000\142\000F\000J\000\000\000N\000\000\000R\000V\000\000\000Z\001\250\000^\002\001\000b\000\000\000f\000j\000n\000\000\000\000\000\000\000\000\002\001\000\000\000\000\000\000\000\000\000\000\000r\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000v\000\000\000\000\000\000\000\000\002\001\002\002\000\000\000\000\002\001\002\001\000\000\000\000\001\226\000\000\000\000\000\000\000\000\000\000\000\000\000}\000\130\000\000\000}\000\000\002\001\000\158\000\000\002\001\002\001\002\001\002\001\000\000\000\000\000\134\000\000\001\202\002\001\002\001\000}\002B\002\n\002\001\000\000\000}\000\000\000\000\000\000\000\000\000\000\001\210\000\000\000\000\000}\000}\000\000\000}\000}\000\000\000\000\000\000\000}\000\000\000e\000\000\001\242\000e\000\000\001\218\000\000\001\234\000}\000\162\000\000\000\000\000\000\000\000\000\000\000\000\000e\000\000\000\000\000e\000\000\000\000\000\000\000\000\000e\000\000\000\166\001\250\000\000\000}\001\210\000\000\000\000\000e\000e\000\000\000e\000e\000\000\000}\000\000\000e\000\000\000\000\000\000\000e\000\000\000\000\001\218\002)\001\234\000e\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}\002\002\000\000\000\000\000}\000}\000\000\000\000\001\226\000\000\000e\000\000\000e\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}\000\000\000e\000}\000}\000}\000}\000\000\000\000\000\000\000\000\000\000\000}\000}\000\000\000}\002\n\000}\000\000\000\000\000\000\000\000\000\000\000e\000e\000\000\000\000\000e\000e\000\000\000\000\001\226\000\000\000\000\000\000\000\000\000\000\000\000\000]\000\000\000\000\000]\000\000\000e\000\000\000\000\000e\000e\000e\000e\000\000\000\000\000\000\000\000\000]\000e\000e\000]\000e\000e\000e\000\000\000]\000\000\000\000\000\000\000\000\000\000\000]\000\000\000\000\000]\000]\000\000\000]\000]\000\000\000\000\000\000\000]\000\000\000a\000\000\000]\000a\000\000\001\218\000\000\000]\000]\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000a\000\000\000\000\000a\000\000\000\000\000\000\000\000\000a\000\000\000\000\000]\000\000\000]\000a\000\000\000\000\000a\000a\000\000\000a\000a\000\000\000]\000\000\000a\000\000\000\000\000\000\000a\000\000\000\000\001\218\000\000\000a\000a\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000]\000]\000\000\000\000\000]\000]\000\000\000\000\001\226\000\000\000a\000\000\000a\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000]\000\000\000a\000]\000]\000]\000]\000\000\000\000\000\000\000\000\000\000\000]\000]\000\000\000]\000]\000]\000\000\000\000\000\000\000\000\000\000\000a\000a\000\000\000\000\000a\000a\000\000\000\000\001\226\000\000\000\000\000\000\000\000\000\000\000\000\000q\000\000\000\000\000q\000\000\000a\000\000\000\000\000a\000a\000a\000a\000\000\000\000\000\000\000\000\001\202\000a\000a\000q\000a\000a\000a\000\000\000q\000\000\000\000\000\000\000\000\000\000\001\210\000\000\000\000\000q\000q\000\000\000q\000q\000\000\000\000\000\000\000q\000\000\000i\000\000\000q\000i\000\000\001\218\000\000\001\234\000q\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\202\000\000\000\000\000i\000\000\000\000\000\000\000\000\000i\000\000\000\000\001\250\000\000\000q\001\210\000\000\000\000\000i\000i\000\000\000i\000i\000\000\000q\000\000\000i\000\000\000\000\000\000\000i\000\000\000\000\001\218\000\000\001\234\000i\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000q\000q\000\000\000\000\000q\000q\000\000\000\000\001\226\000\000\000i\000\000\000i\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000q\000\000\000i\000q\000q\000q\000q\000\000\000\000\000\000\000\000\000\000\000q\000q\000\000\000q\000q\000q\000\000\000\000\000\000\000\000\000\000\000i\000i\000\000\000\000\000i\000i\000\000\000\000\001\226\000\000\000\000\000\000\000\000\000\000\000\000\000m\000\000\000\000\000m\000\000\000i\000\000\000\000\000i\000i\000i\000i\000\000\000\000\000\000\000\000\001\202\000i\000i\000m\000i\000i\000i\000\000\000m\000\000\000\000\000\000\000\000\000\000\001\210\000\000\000\000\000m\000m\000\000\000m\000m\000\000\000\000\000\000\000m\000\000\000u\000\000\000m\000u\000\000\001\218\000\000\001\234\000m\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\202\000\000\000\000\000u\000\000\000\000\000\000\000\000\000u\000\000\000\000\001\250\000\000\000m\001\210\000\000\000\000\000u\000u\000\000\000u\000u\000\000\000m\000\000\000u\000\000\000\000\000\000\001\242\000\000\000\000\001\218\000\000\001\234\000u\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000m\000m\000\000\000\000\000m\000m\000\000\000\000\001\226\000\000\001\250\000\000\000u\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000m\000\000\000u\000m\000m\000m\000m\000\000\000\000\000\000\000\000\000\000\000m\000m\000\000\000m\000m\000m\000\000\000\000\000\000\000\000\000\000\000u\002\002\000\000\000\000\000u\000u\000\000\000\000\001\226\000\000\000\000\000\000\000\000\000\000\000\000\001\190\000\000\000\000\000\133\000\000\000u\000\000\000\000\000u\000u\000u\000u\000\000\000\000\000\000\000\000\001\202\000u\000u\000\133\000u\000u\000u\000\000\000\133\000\000\000\000\000\000\000\000\000\000\001\210\000\000\000\000\000\133\000\133\000\000\000\133\002:\000\000\000\000\000\000\000\133\000\000\001\190\000\000\001\242\000y\000\000\001\218\000\000\001\234\000\133\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\202\000\000\000\000\000y\000\000\000\000\000\000\000\000\000y\000\000\000\000\001\250\000\000\000\133\001\210\000\000\000\000\000y\000y\000\000\000y\000y\000\000\000\133\000\000\000y\000\000\000\000\000\000\001\242\000\000\000\000\001\218\000\000\001\234\000y\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\133\002\002\000\000\000\000\000\133\000\133\000\000\000\000\001\226\000\000\001\250\000\000\000y\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\133\000\000\000y\000\133\000\133\000\133\000\133\000\000\000\000\000\000\000\000\000\000\000\133\000\133\000\000\002B\002\n\000\133\000\000\000\000\000\000\000\000\000\000\000y\002\002\000\000\000\000\000y\000y\000\000\000\000\001\226\000\000\000\000\000\000\000\000\000\000\000\000\001\190\000\000\000\000\000\129\000\000\000y\000\000\000\000\000y\000y\000y\000y\000\000\000\000\000\000\000\000\001\202\000y\000y\000\129\000y\002\n\000y\000\000\000\129\000\000\000\000\000\000\000\000\000\000\001\210\000\000\000\000\000\129\000\129\000\000\000\129\002:\000\000\000\000\000\000\000\129\000\000\000\000\000\000\001\242\000\000\000\000\001\218\000\000\001\234\000\129\000\000\000\000\000\000\000\000\000\000\t\165\t\165\t\165\t\165\000\000\t\165\000\000\t\165\t\165\000\000\t\165\000\000\t\165\001\250\t\165\000\129\t\165\t\165\t\165\000\000\000\000\000\000\000\000\000\000\000\000\000\129\000\000\000\000\t\165\t\165\t\165\000\000\000\000\000\000\000\000\t\165\000\000\000\000\000\000\t\165\000\000\000\000\000\000\000\000\000\000\000\000\000\129\002\002\000\000\000\000\000\129\000\129\000\000\t\165\001\226\000\000\000\000\000\000\000\000\000\000\t\165\000\000\000\000\000\000\t\165\000\000\000\129\000\000\000\000\000\129\000\129\000\129\000\129\t\165\000\000\000\000\000\000\000\000\000\129\000\129\000\000\000\129\002\n\000\129\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\t\165\000\000\000\000\t\165\000\000\000\000\000\000\000\000\000\000\t\169\t\169\t\169\t\169\000\000\t\169\000\000\t\169\t\169\t\165\t\169\t\165\t\169\t\165\t\169\t\165\t\169\t\169\t\169\000\000\t\165\000\000\000\000\t\165\000\000\000\000\000\000\000\000\t\169\t\169\t\169\000\000\000\000\000\000\000\000\t\169\000\000\000\000\t\165\t\169\000\000\016\250\t\165\017v\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\t\169\000\000\000\000\000\000\0055\000\000\000\000\t\169\000\000\000\000\000\000\t\169\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\t\169\004i\000\000\0055\004i\000\000\004i\000\000\004i\000\000\004i\000\000\0055\0055\004i\004i\000\000\000\000\000\000\t\169\000\000\000\000\t\169\000\000\000\000\004i\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004i\004i\0055\t\169\000\000\t\169\004i\t\169\002b\t\169\000\157\0055\0055\000\000\t\169\000\000\000\000\t\169\000\000\000\000\000\000\000\000\004i\000\000\004i\000\138\000\157\000\000\000\000\000\000\004i\000\000\t\169\004i\004i\000\000\t\169\000\000\000\000\000\000\n\166\004i\0055\000\000\004i\004i\000\157\000\157\000\000\000\000\0055\000\000\000\000\000\000\004i\000\157\000\000\000\000\n\174\000\000\n\190\000\000\000\000\0055\004i\000\000\000\000\000\000\004Q\000\000\000\000\004Q\004i\004Q\000\000\004Q\004i\004Q\000\000\000\000\000\157\004Q\004Q\0055\000\000\004i\0055\0055\000\000\000\000\0055\000\000\004Q\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0055\004Q\004Q\000\000\000\000\004i\000\000\004Q\004i\004i\000\000\000\000\004i\000\000\000\157\000\000\000\000\004i\004i\000\000\000\000\n\182\004i\004Q\000\000\004Q\005\210\000\000\000\000\000\000\000\000\004Q\000\000\000\157\004Q\004Q\000\000\000\000\000\000\000\000\000\000\000\000\004Q\000\000\000\000\004Q\004Q\000\000\000\157\000\157\000\000\000\000\000\000\000\000\000\000\004Q\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004Q\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004Q\000\000\000\000\000\000\004Q\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004Q\0002\0006\000F\000J\000\000\000N\000\000\000R\000V\000\000\000Z\000\000\000^\000\000\000b\000\000\000f\000j\000n\004Q\000\000\000\000\004Q\004Q\000\000\000\000\004Q\000\000\017~\000r\017\154\004Q\004Q\000\000\000\000\017\166\004Q\000\000\000\000\000v\000\000\0055\000\000\000\000\0055\000\000\0055\000\000\0055\000\000\0055\000\000\000\000\017\190\0055\0055\000\000\000\000\000\000\000\000\000\130\000\000\000\000\000\000\017\234\0055\000\000\0055\000\000\000\000\0055\000\000\000\000\000\134\0055\0055\0055\000\000\000\000\000\000\0055\0055\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\018\n\000\000\000\000\018Z\0055\000\000\0055\000\000\000\000\000\000\000\000\000\000\002b\000\000\007M\0055\0055\000\000\018r\000\000\007\209\000\000\018~\0055\018\138\000\000\0055\0055\000\000\018\154\0055\000\000\019J\000\000\000\000\000\000\0055\000\000\000\146\000\000\000\000\007M\000\000\000\000\000\000\000\000\0055\019V\000\000\007M\000\000\019n\007M\007M\0055\000\000\000\000\000\000\0055\000\000\000\000\000\000\007M\000\000\000\000\000\000\000\000\0055\000\000\000\000\000\000\000\000\000\000\001\161\000\000\000\000\001\161\000\000\000\000\000\000\007M\000\000\000\000\000\000\0055\000\000\000\000\0055\000\000\001\161\0055\0055\001\161\007M\0055\000\000\000\000\001\161\000\000\0055\0055\000\000\000\000\001\161\0055\000\000\001\161\001\161\000\000\001\161\001\161\000\000\000\000\007M\001\161\000\000\007M\007M\001\161\000\000\000\000\001\161\000\000\001\161\001\161\007M\007M\000\000\000\000\000\000\007M\000\000\0002\tN\000F\000J\000\000\000N\000\000\000R\000V\000\000\000Z\001\161\000^\001\161\000b\000\000\000f\000j\000n\000\000\000\000\000\000\000\000\001\161\000\000\000\000\000\000\000\000\000\000\000r\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000v\000\000\000\000\000\000\000\000\001\161\001\161\0076\000\000\001\161\n^\000\000\000\000\001\161\000\000\003I\000\000\003I\000\000\000\000\003I\000\130\000\000\000\000\000\000\000\000\000\000\000\000\001\161\000\000\001\161\000\000\000\000\000\000\000\134\003I\007>\001\161\001\161\000\000\001\161\001\161\001\161\000\000\003I\003I\000\000\003I\003I\000\000\000\000\000\000\000\000\003I\000\000\003I\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003I\003I\000\000\003I\003I\003I\000\000\003I\003I\000\162\003I\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\011\153\000\000\000\000\011\153\000\000\003I\003I\000\000\000\000\003I\000\000\000\000\003I\000\000\000\000\000\000\011\153\000\000\000\000\011\153\003I\000\000\000\000\003Z\000\000\000\000\000\000\000\000\000\000\003I\011\153\003I\000\000\000\000\011\153\000\000\011\153\011\153\000\000\000\000\003b\003I\003n\000\000\000\000\011\153\003I\000\000\011\153\000\000\011\153\000\000\003I\000\000\000\000\003I\000\000\000\000\000\000\000\000\000\000\003I\000\000\000\000\000\000\004\018\000\000\000\000\004b\000\000\011\153\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\026\011\153\000\000\002\t\000\000\000\000\003z\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\"\000\000\000\000\000\000\002\t\000\000\004r\004z\000\000\011\153\011\153\000\000\011\153\000\000\003~\004B\011\153\000\226\004*\tz\004:\000\000\t~\000\000\003\134\000\000\000\000\000\000\011\153\000\000\000\000\000\000\000\000\011\153\011\153\000\000\000\000\000\238\000\000\011\153\004J\000\000\000\000\011\153\011\153\011\153\t\130\n*\000\000\n>\nV\000\000\002\t\000\000\000\000\001\"\000\000\001&\000\000\000\000\000\000\000\000\000\000\000\000\000\000\t\162\001.\000\000\t\166\008>\001:\000\000\t\170\t\174\004R\t\178\000\000\002\t\000\000\000\000\000\000\0042\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\182\t\182\000\000\002\t\t\186\000\000\000\000\000\162\002\t\002\t\000\000\000\000\000\000\000\000\000\000\t\194\000\000\000\000\004\130\004Z\002\t\000\000\000\000\000\000\nZ\000\226\nr\tz\000\000\000\000\t~\002\154\000F\000J\000\000\000N\t\198\000R\000V\000\000\000Z\t\202\000^\000\000\000b\000\238\000f\011R\000n\000\000\t\206\000\000\000\000\000\000\t\130\n*\001j\n>\nV\000r\000\000\000\000\000\000\001\"\000\000\001&\000\000\000\000\000\000\000v\000\000\000\000\000\000\t\162\001.\000\000\t\166\008>\001:\000\000\t\170\t\174\000\000\t\178\000\000\000\000\000\000\000\000\000\000\000\000\000\149\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\182\t\182\000\000\000\000\t\186\000\134\000\000\000\162\000\149\000\000\000\000\000\000\000\000\000\000\000\000\t\194\000\000\000\000\000\000\000\000\000\000\000\000\000\149\000\000\nZ\000\226\nr\tz\000\149\000\149\t~\000\000\000\000\000\000\000\000\000\000\t\198\000\149\000\000\000\000\n\174\t\202\000\149\000\162\000\000\000\238\000\000\n\254\000\000\000\000\t\206\000\000\000\000\000\000\t\130\n*\001j\n>\nV\000\000\000\000\000\000\000\149\001\"\000\000\001&\000\000\000\000\000\000\000\000\000\000\000\000\000\000\t\162\001.\000\000\t\166\008>\001:\000\000\t\170\t\174\000\000\t\178\000\000\000\000\000\000\000\000\000\000\000\000\000\153\000\000\000\000\000\000\000\000\000\000\000\149\000\000\006\182\t\182\000\000\000\000\t\186\n\182\000\000\000\162\000\153\000\000\000\000\000\000\000\000\000\000\000\000\t\194\000\000\000\149\000\000\000\000\000\000\000\000\000\153\000\000\nZ\000\226\nr\tz\000\153\000\153\t~\000\000\000\149\000\149\000\000\000\000\t\198\000\153\000\000\000\000\n\174\t\202\000\153\000\000\000\000\000\238\000\000\004\201\000\000\000\000\t\206\000\000\000\000\000\000\t\130\n*\001j\n>\nV\000\000\000\000\000\000\000\153\001\"\000\000\001&\000\000\000\000\000\000\000\000\000\000\000\000\000\000\t\162\001.\000\000\t\166\008>\001:\000\000\t\170\t\174\000\000\t\178\000\000\000\000\000\000\000\000\000\000\000\000\001\137\000\000\000\000\001\137\000\000\000\000\000\153\000\000\006\182\t\182\000\000\000\000\t\186\n\182\000\000\000\162\001\137\000\000\000\000\000\000\000\000\000\000\000\000\t\194\001\137\000\153\000\000\000\000\000\000\000\000\001\137\000\000\nZ\000\000\nr\000\000\001\137\001\137\000\000\000\000\000\153\000\153\000\000\007j\t\198\001\137\007\186\000\000\001\137\t\202\001\137\001\137\000\000\000\000\000\000\001\189\000\000\000\000\t\206\007r\000\000\000\000\002\017\000\000\001j\000\000\000\000\002\017\000\000\000\000\001\137\000\000\001\137\007z\000\000\000\000\002\017\002\017\000\000\007\202\007\210\000\000\000\000\000\000\002\017\000\000\000\000\000\000\007\154\000\000\000\000\007\130\000\000\007\146\002\017\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\137\001\137\001\150\000\000\001\137\001\137\000\000\000\000\001\137\000\000\007\162\000\000\002\017\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\137\000\000\002\017\001\137\001\137\000\000\001\137\000\000\000\000\000\000\000\000\002V\001\137\001\137\000\000\001\137\001\137\001\137\000\000\000\000\000\000\000\000\000\000\002\017\007\170\000\000\000\000\002\017\000\000\000\000\000\000\007\138\000\000\001%\000\000\000\000\001%\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\017\000\000\002\017\007r\000\000\000\000\001%\000\000\000\000\002\017\002\017\001%\007\218\007\178\002\017\000\000\000\000\007z\000\000\000\000\001%\001%\000\000\001%\001%\000\000\000\000\000\000\001%\000\000\001\013\000\000\007\154\001\013\000\000\007\130\000\000\007\146\001%\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\013\000\000\000\000\001\013\000\000\000\000\000\000\000\000\001\013\000\000\000\000\007\162\000\000\001%\007z\000\000\000\000\001\013\001\013\000\000\001\013\001\013\000\000\001%\000\000\001\013\000\000\000\000\000\000\001\013\000\000\000\000\007\130\000\000\007\146\001\013\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001%\007\170\000\000\000\000\001%\000\000\000\000\000\000\007\138\000\000\001\013\000\000\001\013\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\013\001%\000\000\001%\000\000\000\000\000\000\000\000\000\000\000\000\001%\001%\000\000\001%\007\178\001%\000\000\000\000\000\000\000\000\000\000\001\013\001\013\000\000\000\000\001\013\000\000\000\000\000\000\007\138\000\000\001\005\000\000\000\000\001\005\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\013\000\000\001\013\001\005\000\000\000\000\001\005\000\000\000\000\001\013\001\013\001\005\001\013\001\013\001\013\000\000\000\000\001\005\000\000\000\000\001\005\001\005\000\000\001\005\001\005\000\000\000\000\000\000\001\005\000\000\001\t\000\000\001\005\001\t\000\000\007\130\000\000\001\005\001\005\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\t\000\000\000\000\001\t\000\000\000\000\000\000\000\000\001\t\000\000\000\000\001\005\000\000\001\005\001\t\000\000\000\000\001\t\001\t\000\000\001\t\001\t\000\000\001\005\000\000\001\t\000\000\000\000\000\000\001\t\000\000\000\000\007\130\000\000\001\t\001\t\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\005\001\005\000\000\000\000\001\005\000\000\000\000\000\000\007\138\000\000\001\t\000\000\001\t\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\t\001\005\000\000\001\005\000\000\000\000\000\000\000\000\000\000\000\000\001\005\001\005\000\000\001\005\001\005\001\005\000\000\000\000\000\000\000\000\000\000\001\t\001\t\000\000\000\000\001\t\000\000\000\000\000\000\007\138\000\000\001\025\000\000\000\000\001\025\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\t\000\000\001\t\007r\000\000\000\000\001\025\000\000\000\000\001\t\001\t\001\025\001\t\001\t\001\t\000\000\000\000\007z\000\000\000\000\001\025\001\025\000\000\001\025\001\025\000\000\000\000\000\000\001\025\000\000\001\017\000\000\001\025\001\017\000\000\007\130\000\000\007\146\001\025\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007r\000\000\000\000\001\017\000\000\000\000\000\000\000\000\001\017\000\000\000\000\007\162\000\000\001\025\007z\000\000\000\000\001\017\001\017\000\000\001\017\001\017\000\000\001\025\000\000\001\017\000\000\000\000\000\000\001\017\000\000\000\000\007\130\000\000\007\146\001\017\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\025\001\025\000\000\000\000\001\025\000\000\000\000\000\000\007\138\000\000\001\017\000\000\001\017\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\017\001\025\000\000\001\025\000\000\000\000\000\000\000\000\000\000\000\000\001\025\001\025\000\000\001\025\001\025\001\025\000\000\000\000\000\000\000\000\000\000\001\017\001\017\000\000\000\000\001\017\000\000\000\000\000\000\007\138\000\000\001\021\000\000\000\000\001\021\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\017\000\000\001\017\007r\000\000\000\000\001\021\000\000\000\000\001\017\001\017\001\021\001\017\001\017\001\017\000\000\000\000\007z\000\000\000\000\001\021\001\021\000\000\001\021\001\021\000\000\000\000\000\000\001\021\000\000\001\029\000\000\001\021\001\029\000\000\007\130\000\000\007\146\001\021\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007r\000\000\000\000\001\029\000\000\000\000\000\000\000\000\001\029\000\000\000\000\007\162\000\000\001\021\007z\000\000\000\000\001\029\001\029\000\000\001\029\001\029\000\000\001\021\000\000\001\029\000\000\000\000\000\000\007\154\000\000\000\000\007\130\000\000\007\146\001\029\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\021\001\021\000\000\000\000\001\021\000\000\000\000\000\000\007\138\000\000\007\162\000\000\001\029\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\029\001\021\000\000\001\021\000\000\000\000\000\000\000\000\000\000\000\000\001\021\001\021\000\000\001\021\001\021\001\021\000\000\000\000\000\000\000\000\000\000\001\029\007\170\000\000\000\000\001\029\000\000\000\000\000\000\007\138\000\000\007j\000\000\000\000\001-\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\029\000\000\001\029\007r\000\000\000\000\001-\000\000\000\000\001\029\001\029\001-\001\029\001\029\001\029\000\000\000\000\007z\000\000\000\000\001-\001-\000\000\001-\007\210\000\000\000\000\000\000\001-\000\000\007j\000\000\007\154\001!\000\000\007\130\000\000\007\146\001-\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007r\000\000\000\000\001!\000\000\000\000\000\000\000\000\001!\000\000\000\000\007\162\000\000\001-\007z\000\000\000\000\001!\001!\000\000\001!\001!\000\000\001-\000\000\001!\000\000\000\000\000\000\007\154\000\000\000\000\007\130\000\000\007\146\001!\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001-\007\170\000\000\000\000\001-\000\000\000\000\000\000\007\138\000\000\007\162\000\000\001!\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001!\001-\000\000\001-\000\000\000\000\000\000\000\000\000\000\000\000\001-\001-\000\000\007\218\007\178\001-\000\000\000\000\000\000\000\000\000\000\001!\007\170\000\000\000\000\001!\000\000\000\000\000\000\007\138\000\000\007j\000\000\000\000\001)\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001!\000\000\001!\007r\000\000\000\000\001)\000\000\000\000\001!\001!\001)\001!\007\178\001!\000\000\000\000\007z\000\000\000\000\001)\001)\000\000\001)\007\210\000\000\000\000\000\000\001)\000\000\000\000\000\000\007\154\000\000\000\000\007\130\000\000\007\146\001)\000\000\000\000\000\000\000\000\000\000\000\226\000\000\tz\000\000\000\000\t~\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007\162\000\000\001)\000\000\000\000\000\000\000\000\000\238\000\000\000\000\000\000\000\000\001)\000\000\000\000\000\000\t\130\n*\000\000\n>\nV\000\000\000\000\000\000\000\000\001\"\000\000\001&\000\000\000\000\000\000\000\000\000\000\001)\007\170\t\162\001.\001)\t\166\008>\001:\007\138\t\170\t\174\000\000\t\178\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001)\000\000\001)\000\000\006\182\t\182\000\000\000\000\t\186\001)\001)\000\162\001)\007\178\001)\000\000\000\000\000\000\000\226\t\194\000\230\000\000\000\000\000\234\000\000\000\000\000\000\000\000\000\000\000\000\nr\000\000\007\246\000\000\000\000\000\000\000\000\000\000\000\238\000\000\t\198\000\242\000\000\000\000\000\000\t\202\000\000\000\254\001\002\001\n\000\000\001\201\000\000\000\000\t\206\000\000\001\"\000\000\001&\000\000\001j\000\000\000\000\000\000\000\000\000\000\001*\001.\000\000\0012\0016\001:\000\000\001>\001B\000\000\001F\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001J\000\000\000\000\001N\000\000\000\000\000\162\000\000\000\226\000\000\000\230\000\000\000\000\000\234\001V\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007\225\001Z\007\225\000\000\000\000\000\000\000\238\000\000\000\000\000\242\000\000\000\000\000\000\001^\000\000\000\254\001\002\001\n\001b\tv\000\000\007\225\000\000\007\225\001\"\000\000\001&\001f\000\000\000\000\000\000\000\000\000\000\001j\001*\001.\000\000\0012\0016\001:\000\000\001>\001B\000\000\001F\000\000\000\000\000\000\000\000\000\000\000\226\000\000\000\230\000\000\000\000\000\234\000\000\000\000\000\000\000\000\001J\000\000\000\000\001N\014R\000\000\000\162\000\000\000\000\000\000\000\238\000\000\000\000\000\242\001V\000\000\000\000\000\000\000\000\000\254\001\002\001\n\000\000\001Z\000\000\000\000\000\000\000\000\001\"\000\000\001&\000\000\000\000\000\000\000\000\001^\000\000\000\000\001*\001.\001b\0012\0016\001:\000\000\001>\001B\000\000\001F\001f\000\000\000\000\000\000\000\000\000\226\001j\000\230\000\000\000\000\000\234\000\000\000\000\000\000\000\000\001J\000\000\000\000\001N\000\000\000\000\000\162\000\000\000\000\000\000\000\238\000\000\000\000\000\242\001V\000\000\000\000\000\000\000\000\000\254\004\210\001\n\000\000\001Z\000\000\000\000\000\000\000\000\001\"\000\000\001&\000\000\000\000\000\000\000\000\001^\000\000\000\000\001*\001.\001b\0012\0016\001:\000\169\001>\001B\000\000\001F\001f\000\000\000\000\000\000\000\000\000\000\001j\000\000\000\000\000\000\000\000\n\158\000\000\000\000\000\000\001J\000\000\000\000\001N\000\000\000\000\000\162\000\000\000\246\000\000\n\166\000\000\000\000\007\233\001V\007\233\000\169\000\169\007\233\000\000\000\000\000\000\000\000\001Z\000\000\000\169\000\000\000\000\n\174\000\000\n\190\000\000\000\000\007\233\000\000\001^\007\233\000\000\000\000\000\000\001b\000\000\007\233\007\233\007\233\000\000\000\000\000\000\000\000\001f\n\206\007\233\000\000\007\233\000\000\001j\000\000\000\000\000\000\000\000\000\000\007\233\007\233\000\000\007\233\007\233\007\233\000\000\007\233\007\233\000\000\007\233\000\000\000\000\000\000\000\000\000\000\000\226\000\000\000\230\000\000\000\000\000\234\000\000\000\169\000\000\000\000\007\233\000\000\000\000\007\233\n\182\000\000\007\233\000\000\000\000\000\000\000\238\000\000\000\000\000\242\007\233\000\000\000\169\000\000\000\000\000\254\001R\001\n\000\000\000\000\000\000\000\000\000\000\000\000\001\"\000\000\001&\000\169\000\169\000\000\000\000\007\233\000\000\000\000\001*\001.\007\233\0012\0016\001:\000\161\001>\001B\000\000\001F\007\233\000\000\000\000\000\000\000\000\000\000\007\233\000\000\000\000\000\000\000\000\n\158\000\000\000\000\000\000\001J\000\000\000\000\001N\000\000\000\000\000\162\000\000\003\222\000\000\n\166\000\000\000\000\003A\001V\003A\000\161\000\161\003A\000\000\000\000\000\000\000\000\001Z\000\000\000\161\000\000\000\000\n\174\000\000\n\190\000\000\000\000\003A\000\000\001^\003A\000\000\000\000\000\000\001b\000\000\003A\003A\003A\000\000\000\000\000\000\000\000\001f\000\161\003A\000\000\003A\000\000\001j\000\000\000\000\000\000\000\000\000\000\003A\003A\000\000\003A\003A\003A\000\000\003A\003A\000\000\003A\000\000\000\000\000\000\000\000\000\000\000\226\000\000\001\022\000\000\000\000\001\026\000\000\000\161\000\000\000\000\003A\000\000\000\000\003A\n\182\000\000\003A\000\000\000\000\000\000\000\238\000\000\000\000\000\242\003A\000\000\000\161\000\000\000\000\001\030\003\162\001\n\000\000\000\000\000\000\000\000\000\000\000\000\001\"\000\000\001&\000\161\000\161\000\000\000\000\003A\000\000\000\000\003\026\001.\003A\003\030\0016\001:\000\000\003\"\003&\000\000\003*\003A\000\000\000\000\000\000\000\000\000\226\003A\001\022\000\000\000\000\001\026\000\000\000\000\000\000\000\000\003.\000\000\000\000\0032\000\000\000\000\000\162\000\000\000\000\000\000\000\238\000\000\000\000\000\242\003:\000\000\000\000\000\000\000\000\001\030\003\006\001\n\000\000\000\000\000\000\000\000\000\000\000\000\001\"\000\000\001&\000\000\000\000\000\000\000\000\003>\000\000\000\000\003\026\001.\003B\003\030\0016\001:\000\000\003\"\003&\000\000\003*\003F\000\000\000\000\000\000\000\000\000\226\001j\001\022\000\000\000\000\001\026\000\000\000\000\000\000\000\000\003.\000\000\000\000\0032\000\000\000\000\000\162\000\000\000\000\000\000\000\238\000\000\000\000\000\242\003:\000\000\000\000\000\000\000\000\001\030\0036\001\n\000\000\000\000\000\000\000\000\000\000\000\000\001\"\000\000\001&\000\000\000\000\000\000\000\000\003>\000\000\000\000\003\026\001.\003B\003\030\0016\001:\000\000\003\"\003&\000\000\003*\003F\000\000\000\000\000\000\000\000\000\226\001j\006\130\000\000\000\000\006\134\000\000\000\000\000\000\000\000\003.\000\000\000\000\0032\000\000\000\000\000\162\000\000\000\000\000\000\000\238\000\000\000\000\000\000\003:\000\000\000\000\000\000\000\000\006\138\007\226\000\165\000\000\000\000\000\000\000\000\000\000\000\000\001\"\000\000\001&\000\000\000\000\000\000\000\000\003>\000\000\n\158\006\162\001.\003B\006\166\0016\001:\000\000\006\170\006\174\000\000\006\178\003F\000\000\n\166\000\000\000\000\000\226\001j\006\130\000\165\000\165\006\134\000\000\000\000\000\000\006\182\006\186\000\000\000\165\006\190\000\000\n\174\000\162\n\190\000\000\000\000\000\238\000\000\000\000\000\000\006\198\000\000\000\000\000\000\000\000\006\138\006\142\000\173\000\000\000\000\000\000\000\000\000\000\n\206\001\"\000\000\001&\000\000\000\000\000\000\000\000\006\202\000\000\n\158\006\162\001.\006\206\006\166\0016\001:\000\000\006\170\006\174\000\000\006\178\006\210\000\000\n\166\000\000\000\000\000\226\001j\006\130\000\173\000\173\006\134\000\000\000\165\000\000\006\182\006\186\000\000\n\198\006\190\n\182\n\174\000\162\n\190\000\000\000\000\000\238\000\000\000\000\000\000\006\198\000\000\000\165\000\000\000\000\006\138\006\194\n\150\000\000\000\000\000\000\000\000\000\000\n\206\001\"\000\000\001&\000\165\000\165\000\000\000\000\006\202\000\000\n\158\006\162\001.\006\206\006\166\0016\001:\000\000\006\170\006\174\000\000\006\178\006\210\000\000\n\166\000\000\000\000\000\226\001j\tz\000\189\n\238\t~\000\000\n\214\000\000\006\182\006\186\000\000\n\198\006\190\n\182\n\174\000\162\n\190\000\000\000\000\000\238\000\000\000\000\000\000\006\198\000\000\000\173\000\000\000\000\t\130\t\142\n\150\000\000\000\000\000\000\000\000\000\000\n\206\001\"\000\000\001&\000\173\000\173\000\000\000\000\006\202\000\000\n\158\t\162\001.\006\206\t\166\0016\001:\000\000\t\170\t\174\000\000\t\178\006\210\000\000\n\166\000\000\000\000\000\226\001j\tz\000\177\000\177\t~\000\000\n\214\000\000\006\182\t\182\000\000\n\198\t\186\n\182\n\174\000\162\n\190\000\000\000\000\000\238\000\000\000\000\000\000\t\194\000\000\000\189\000\000\000\000\t\130\t\190\000\000\000\000\000\000\000\000\000\000\000\000\n\206\001\"\000\000\001&\n\246\n\222\000\000\000\000\t\198\000\000\000\000\t\162\001.\t\202\t\166\0016\001:\000\000\t\170\t\174\000\000\t\178\t\206\000\000\000\000\000\000\000\000\000\226\001j\tz\000\000\000\000\t~\000\000\n\214\000\000\006\182\t\182\000\000\000\000\t\186\n\182\000\000\000\162\000\000\000\000\000\000\000\238\000\000\000\000\000\000\t\194\000\000\000\177\000\000\000\000\t\130\n*\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\"\000\000\001&\000\177\n\222\000\000\000\000\t\198\000\000\000\000\t\162\001.\t\202\t\166\0016\001:\000\000\t\170\t\174\000\000\t\178\t\206\000\000\000\000\000\000\000\000\000\000\001j\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\182\t\182\000\000\000\000\t\186\000\000\000\000\000\162\000\000\000\000\000\000\000\000\000\000\000\000\000\000\t\194\0002\006\022\000F\000J\006.\000N\006F\000R\000V\006J\000Z\000\000\000^\000\000\000b\006N\000f\000j\000n\006R\t\198\000\000\000\000\000\000\000\000\t\202\000\000\000\000\000\000\000r\000\000\000\000\000\000\000\000\t\206\000\000\000\000\000\000\000\000\000v\001j\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\130\000\000\0002\tN\000F\000J\000\000\000N\006F\000R\000V\006J\000Z\000\134\000^\020r\000b\006N\000f\000j\000n\006R\020z\001\153\000\000\000\000\001\153\000\000\008B\000\000\000\000\000r\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\153\000\000\000v\001\153\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\162\000\000\001\153\n\150\000\000\000\000\001\153\000\000\001\153\001\153\000\000\000\130\000\000\000\000\000\000\000\000\000\000\001\153\000\000\n\158\001\153\000\000\001\153\000\000\000\134\000\000\000\000\t>\000\000\000\000\000\000\000\000\000\000\n\166\000\000\000\000\007M\000\000\000\000\000\185\n\238\000\000\001\153\000\000\000\000\000\000\000\000\000\000\n\198\000\000\000\000\n\174\000\000\n\190\001\153\007M\000\000\000\000\000\000\000\000\000\000\000\000\000\162\000\000\007M\007M\003\161\000\000\000\000\000\000\007M\000\000\000\000\n\206\000\000\000\000\001\153\003\186\000\000\001\153\000\000\000\000\000\000\001\153\000\000\000\000\000\000\000\000\007M\000\000\000\000\000\000\000\000\000\000\000:\001\153\000\000\007M\007M\000\000\001\153\001\153\000\000\000\000\000\000\007M\003\194\n\214\007M\007M\001\153\001\153\001\153\000\000\n\182\000\000\000\000\000\000\007M\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\185\000\000\007M\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007M\000\000\000\000\000\000\000\000\000\185\n\222\000\000\000\000\0002\0006\000F\000J\007M\000N\000\000\000R\000V\000\000\000Z\017\n\000^\000\000\000b\000\000\000f\000j\000n\000\000\000\000\000\000\000\000\000\000\007M\000\000\000\000\007M\007M\000r\017\014\007M\000\000\000\000\000\000\000\000\007M\007M\000\000\019r\000\237\007M\000\000\000\237\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\026\000\000\000\000\000\237\000\130\000\000\000\000\000\000\017\234\000\000\000\000\000\000\000\000\000:\004\"\000\000\000\000\000\134\000\237\000\000\000\237\000\237\000\213\000\000\000\000\000\213\000\000\000\000\000\000\004B\000\000\000\000\004*\000\000\004:\000\000\000\000\000\000\000\213\000\000\000\000\000\213\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\"\000\000\004J\000\162\000\213\000\000\000\213\000\213\000\205\000\000\000\000\000\205\000\000\000\000\000\237\000\213\017\030\000\000\004*\000\000\004:\000\000\000\000\000\000\000\205\000\000\000\000\000\205\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004R\000\000\000\205\000\237\000\213\000\000\000\205\0042\000\205\000\205\000\209\000\000\000\000\000\209\000\000\000\000\000\213\000\205\000\000\000\237\004*\000\000\000\205\000\000\000\237\000\237\000\209\000\000\000\000\000\209\000\000\000\000\000\000\000\000\000\237\004Z\000\237\000\000\000\213\000\000\000\209\000\213\000\205\000\000\000\209\0042\000\209\000\209\000\225\000\000\000\000\000\225\000\000\000\000\000\205\000\209\000\000\000\213\004*\000\000\000\209\000\000\000\213\000\213\004\026\000\000\000\000\000\225\000\000\000\000\000\000\000\000\000\213\000\213\000\213\000\000\000\205\000\000\004\"\000\205\000\209\000\000\000\225\0042\000\225\000\225\000\217\000\000\000\000\000\217\000\000\000\000\000\209\000\225\000\000\000\205\004*\000\000\004:\000\000\000\205\000\205\004\026\000\000\000\000\000\217\000\000\000\000\000\000\000\000\000\205\000\205\000\205\000\000\000\209\000\000\004\"\000\209\004J\000\000\000\217\0042\000\217\000\217\000\221\000\000\000\000\000\221\000\000\000\000\000\225\000\217\000\000\000\209\004*\000\000\004:\000\000\000\209\000\209\004\026\000\000\000\000\000\221\000\000\000\000\000\000\000\000\000\209\000\209\000\209\000\000\000\225\000\000\004\"\000\225\000\217\000\000\000\221\0042\000\221\000\221\000\229\000\000\000\000\000\229\000\000\000\000\000\217\000\221\000\000\000\225\004*\000\000\004:\000\000\000\225\000\225\004\026\000\000\000\000\000\229\000\000\000\000\000\000\000\000\000\225\000\225\000\225\000\000\000\217\000\000\004\"\000\217\004J\000\000\000\229\0042\000\229\000\229\004\018\000\000\000\000\000\245\000\000\000\000\000\221\004B\000\000\000\217\004*\000\000\004:\000\000\000\217\000\217\004\026\000\000\000\000\000\245\000\000\000\000\000\000\000\000\000\217\000\217\000\217\000\000\000\221\000\000\004\"\000\221\004J\000\000\000\245\0042\000\245\004z\004\018\000\000\000\000\000\233\000\000\000\000\000\229\004B\000\000\000\221\004*\000\000\004:\000\000\000\221\000\221\004\026\000\000\000\000\000\233\000\000\000\000\000\000\000\000\000\221\000\221\000\221\000\000\004R\000\000\004\"\000\229\004J\000\000\000\233\0042\000\233\000\233\004\018\000\000\000\000\000\241\000\000\000\000\000\245\004B\000\000\000\229\004*\000\000\004:\000\000\000\229\000\229\004\026\000\000\000\000\000\241\000\000\000\000\000\000\000\000\000\229\000\229\000\229\000\000\004R\000\000\004\"\000\245\004J\000\000\000\241\0042\000\241\004z\000\000\000\000\000\000\000\000\000\000\000\000\000\233\004B\000\000\000\245\004*\000\000\004:\000\000\000\245\000\245\000\000\000\000\000\000\000\000\003\153\000\000\000\000\003\153\004\130\004Z\000\245\003\153\004R\003\153\000\000\000\233\004J\003\153\003\153\0042\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\241\000\000\000\000\000\233\000\000\000\000\000\000\000\000\000\233\000\233\000\000\000\000\000\000\000\000\000\000\002-\000\000\000\000\000\233\004Z\000\233\000\000\004R\000\000\000\000\000\241\000\000\000\000\000\000\0042\000\000\003\153\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\241\002-\000\000\000\000\000\000\000\241\000\241\000\000\000\000\002-\000\000\000\000\002-\002-\000\000\000\241\004Z\000\241\000\000\020v\000F\000J\002-\000N\006F\000R\000V\006J\000Z\000\000\000^\020r\000b\006N\000f\000\000\000n\006R\020z\000\000\002-\000\000\000\000\000\000\003\153\000\000\000\000\000r\000\000\000\000\000\000\000\000\000\000\002-\000\000\000\000\000\000\000v\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002-\000\000\000\000\002-\002-\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002-\002-\000\000\000\000\000\000\002-\000\134\0002\005\030\000F\000J\000\000\000N\000\000\000R\000V\000\000\000Z\000\000\000^\000\000\000b\000\000\000f\000j\000n\000\000\0002\005\030\000F\000J\000\000\000N\000\000\000R\000V\000r\000Z\000\000\000^\000\000\000b\000\000\000f\000j\000n\000v\000\000\003\161\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000r\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000v\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\134\000\000\000\000\000\000\005\"\005&\000\000\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\134\000\000\000\000\000\000\005\"\005&\000\000\0002\000\142\000F\000J\011}\000N\000\000\000R\000V\000\000\000Z\000\000\000^\000\000\000b\000\000\000f\000j\000n\000\000\011}\000\000\000\000\000\000\000\000\000\000\000\000\t\226\005*\000r\000\000\000\000\000\000\000\000\011}\000\000\000\000\000\000\000\000\000v\011}\011}\000\000\000\000\t\234\000\000\t\246\000\000\0052\011}\000\000\000\000\011}\000\000\011}\000\000\000\000\000\000\000\000\000\000\000\130\000\000\000\000\000\000\000\000\000\158\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\134\011}\000\000\000\000\000\000\000\000\000\000\0002\005\030\000F\000J\000\000\000N\000\000\000R\000V\000\000\000Z\n\002\000^\000\000\000b\000\000\000f\000j\000n\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\011}\000r\000\000\000\162\000\000\n\006\000\000\011}\000\000\000\000\000\000\000v\000\000\000\000\000\000\n\014\000\000\000\000\000\000\011}\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\130\000\000\011}\011}\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002!\000\000\000\134\000\000\000\000\000\000\021\002\005&\0002\005\030\000F\000J\000\000\000N\000\000\000R\000V\000\000\000Z\000\000\000^\000\000\000b\000\000\000f\000j\000n\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000r\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000v\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\021\006\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\134\000\000\000\000\000\000\021\002\005&\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\021\014")) + + let lhs = + (16, "\000\012\000\011\000\n\000\t\000\008\000\007\000\006\000\005\000\004\000\003\000\002\000\001\000\000\001\004\001\004\001\004\001\003\001\003\001\003\001\003\001\002\001\002\001\002\001\002\001\002\001\002\001\002\001\002\001\002\001\002\001\002\001\002\001\002\001\002\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\000\001\000\001\000\001\000\001\000\001\000\001\000\001\000\001\000\001\000\001\000\001\000\001\000\001\000\000\255\000\255\000\255\000\255\000\255\000\255\000\255\000\255\000\255\000\255\000\255\000\255\000\255\000\255\000\254\000\254\000\254\000\254\000\253\000\252\000\252\000\252\000\251\000\251\000\251\000\250\000\250\000\250\000\249\000\249\000\249\000\248\000\247\000\246\000\245\000\245\000\244\000\244\000\243\000\243\000\242\000\242\000\241\000\241\000\240\000\239\000\239\000\238\000\238\000\237\000\237\000\237\000\236\000\236\000\235\000\234\000\233\000\232\000\231\000\230\000\229\000\228\000\227\000\226\000\225\000\224\000\223\000\223\000\222\000\222\000\221\000\221\000\220\000\220\000\219\000\219\000\219\000\218\000\218\000\218\000\218\000\218\000\217\000\217\000\216\000\215\000\215\000\215\000\215\000\214\000\214\000\213\000\212\000\211\000\211\000\211\000\210\000\210\000\210\000\209\000\209\000\209\000\209\000\208\000\208\000\208\000\208\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\207\000\206\000\205\000\205\000\204\000\204\000\204\000\203\000\203\000\202\000\202\000\202\000\201\000\201\000\200\000\199\000\198\000\198\000\197\000\197\000\196\000\196\000\195\000\195\000\194\000\194\000\193\000\192\000\191\000\191\000\190\000\190\000\189\000\188\000\188\000\188\000\188\000\187\000\186\000\185\000\185\000\184\000\183\000\183\000\182\000\182\000\182\000\182\000\182\000\181\000\181\000\181\000\181\000\180\000\180\000\180\000\180\000\179\000\179\000\179\000\179\000\178\000\177\000\177\000\176\000\176\000\176\000\175\000\174\000\174\000\174\000\174\000\173\000\172\000\172\000\172\000\172\000\171\000\171\000\171\000\171\000\171\000\171\000\171\000\171\000\171\000\171\000\171\000\171\000\171\000\171\000\171\000\171\000\171\000\171\000\170\000\170\000\169\000\169\000\168\000\168\000\167\000\167\000\166\000\166\000\166\000\166\000\165\000\165\000\165\000\164\000\164\000\164\000\164\000\164\000\164\000\164\000\163\000\162\000\162\000\162\000\161\000\160\000\160\000\159\000\159\000\158\000\158\000\157\000\157\000\156\000\156\000\155\000\155\000\154\000\154\000\154\000\154\000\154\000\154\000\154\000\153\000\152\000\151\000\151\000\150\000\150\000\149\000\149\000\148\000\148\000\147\000\147\000\146\000\146\000\145\000\145\000\144\000\144\000\143\000\143\000\142\000\142\000\141\000\141\000\140\000\140\000\139\000\139\000\138\000\138\000\137\000\137\000\136\000\136\000\135\000\135\000\134\000\134\000\133\000\133\000\132\000\132\000\131\000\131\000\130\000\130\000\129\000\129\000\128\000\128\000\127\000\127\000~\000~\000}\000}\000|\000|\000{\000{\000z\000z\000y\000y\000x\000x\000w\000v\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000u\000t\000s\000r\000q\000p\000o\000n\000m\000l\000k\000k\000k\000j\000j\000j\000i\000i\000i\000h\000g\000f\000e\000d\000c\000b\000b\000b\000a\000a\000a\000`\000`\000_\000_\000_\000^\000^\000]\000\\\000\\\000\\\000[\000Z\000Z\000Y\000Y\000X\000X\000W\000W\000V\000V\000U\000U\000T\000T\000S\000S\000S\000S\000S\000S\000S\000S\000S\000S\000S\000S\000S\000S\000S\000S\000S\000S\000S\000R\000R\000Q\000Q\000P\000P\000O\000O\000N\000N\000N\000N\000N\000M\000M\000L\000L\000L\000L\000K\000J\000I\000I\000I\000H\000H\000H\000G\000G\000G\000G\000G\000F\000F\000F\000F\000F\000E\000E\000E\000E\000E\000E\000E\000D\000D\000D\000D\000D\000D\000D\000C\000C\000C\000C\000C\000C\000C\000B\000B\000B\000B\000B\000B\000B\000A\000A\000A\000A\000A\000A\000A\000A\000A\000A\000A\000A\000A\000@\000@\000@\000@\000@\000@\000@\000@\000@\000@\000@\000@\000@\000?\000?\000?\000?\000?\000?\000?\000?\000?\000?\000?\000?\000?\000>\000>\000>\000>\000>\000>\000>\000>\000>\000>\000>\000>\000>\000=\000=\000=\000=\000=\000<\000;\000;\000;\000;\000;\000:\0009\0008\0007\0006\0005\0005\0005\0005\0005\0005\0005\0004\0004\0004\0003\0002\0002\0001\0001\0000\0000\000/\000/\000.\000.\000-\000-\000,\000,\000+\000+\000*\000*\000)\000)\000(\000(\000'\000'\000&\000&\000%\000%\000$\000$\000$\000$\000$\000$\000$\000$\000$\000$\000$\000$\000$\000$\000$\000$\000$\000#\000#\000#\000\"\000\"\000\"\000\"\000!\000!\000!\000!\000!\000 \000\031\000\031\000\031\000\030\000\030\000\029\000\028\000\028\000\028\000\028\000\027\000\027\000\027\000\026\000\026\000\025\000\025\000\025\000\024\000\024\000\024\000\023\000\023\000\023\000\022\000\022\000\021\000\021\000\021\000\021\000\021\000\021\000\021\000\020\000\020\000\020\000\020\000\020\000\020\000\020\000\019\000\019\000\019\000\019\000\019\000\019\000\019\000\018\000\018\000\018\000\018\000\018\000\018\000\018\000\017\000\017\000\017\000\017\000\017\000\016\000\016\000\015\000\014\000\013\000\013\000\013") + + let goto = + ((16, "\0009\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\025\000\000\0011\001\020\000\000\000\163\000U\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001n\000\000\008^\000Y\000U\000\000\000\000\000\000\000\000\000\000\000\000\008\200\000s\012t\000\000\000\000\000\000\021\224\000\000\000\132\000\000\000\000\001\015\000\019\000\000\000\000\000h\000\000\0002\000\0001\\\003\162%\230$@\000h\000\000\005\\\000\000\011\026\011\164\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\250%\230\000\000\000\000\004\008\000\000\006r\000\000\008\014\000\000\000\000\000\000\000\000\000\170\000\000 \240\000\000\000\000\003\030\000\000\018Z\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\224\000\000\000\000\0132\000\000\016r\000\000\"\164\000\000#\162\000\0007,\000\0007\218\000\0007\224\000\0007\244\000\0007\250\000\000\014\192\000\000\031\198\000\000\000\000\000\000\000\000\000\0008\000\000\0008\014\000\0008\"\000\000\022h\000\000\000\000 4\000\000\000`\000U\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000D\001\024\000\000\000\234\000\000\000\000$\248\000\0001\224\000\000\000\000\000\000\001J\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000g1\230\000\000\001\168\000\000\000\000&\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\012\212&\020\000\000\018\180\000\000\025\180\027x\000\000\000\000\000\000\002\164\000\000!~\000\000\000\0001\254\000\000\000\000\000\000\002\210\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000&\144\000\000\nb\000\000\000\000\000\000$\148\000\000'R\000\000\000\000\000\000\000\000\001\198\000\000\000\0002~\000\000\000\000\000\000\021\134\002\028\000\000\000\000\000\000\000\000\000\000\000\000\004\196\000\000\017`\000\000 \214\000\000!\030\000\000*d\000\000+\206\000\0000\200\000\0001\198\000\0003\156\000\0008N\000\000\019~\000\000\027n\000\0008|\000\0008\158\000\0008\180\000\000\000\000\000\000\000\000\000\000\002\132\t~\000\000\003P\000\000\000\000\000\000\000\021\000\000\000\000\000\000\007\242\000\000\000\000'\002\000\000\000\000\000\000\000\000\000\000\000\000\000.\000\000\000\000\000\000\002\n\000\000\000\000\000\000\000\174\000\000\000\000\028\220\000Y\000\000\000\000\001\194\002\168\000\000\000\000\000\000\000\000\000\000\004N\000\000\"\168\000\000\000\017\000\000\000\000\004v\000\000\000\000\000\000\000\000\000\000\000\000%\016\000\000\000\000\000\000\001\202\000\000\000\000\000\000\000\000\005\254\029R\000\000\002\144\000\000\000\000\004\150\002\234\000\000\000\000\000\000\000\000\012\254\000\000\000\000\000\000\000\000\000\000\000\000\000\165\0128\000\000\013\230\000\000\000\000\000\000\004 \000\000\013\"\000I\000\000%\174\000\000\000\000\000\000\014\016\002\176\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0002\132\000\000\021X\000\0002\156\000\000\000\000\001X\000\000\007d\000\000\015\196\003\190'\128\000\000\000\000\000\000\000\140\000\000\000\000\000\000\000\000\000\000\000\000\000\000\015\216'\128\000\000\019`\000\000\021\016\023\176\000\000\000\000\000\000\004z\000\000!\148\000\000\000\0003\014\000\000\000\000\000\000\004\144\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0005l\000\0005\134\000\000\000\000\000\000\004b\000\000\000\000\000\000\000\000\000\000\000\000\030P\000\000\031\128\000\000)Z\000\000*\202\000\0001\206\000\0008j\000\0008\198\000\0008\220\000\0008\254\000\0009$\000\000\024\142\000\000\024D\000\0009n\000\0009\156\000\0009\172\000\000'\244\000\000\000\000\000\0003\140\000\000\000\000\000\000\002x\000*\000\000\024\192\000#\003\150\000\000\005\224\000\000\013\210\000\214\007\222\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0004\008\000\000(t%\196\004\148\000\000\000\000\000\000\031B\000\000(\160\000\000)\198\000\000(\230)B\004\030\000\251\005<\000\000\000\000\000\000\000P\000\000\000\000\003\132\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0004*\000\000\000\000\000\000\000\000\000\000\":\000\000)z\000\000\000\000\000\000\000\000\000\000\000\000\014\194\000\000\007\136\000\000\000\000\000\000\000\000\024\156\002\188\000\000,\222\000\000\000\000\000\000\002\224\000\000\000\000+\246\001\232\000\000\008,,8\000\000\000\000)\244\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\013^)\244\000\000\028\140\000\000\028\204\029\140\000\000\000\000\000\000\005Z\000\000#V\000\000\000\0004z\000\000\000\000\000\000\005\210\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000*p\000\000\021J\000\000\000\0004\158\000\0004\194\000\000\000\000\004|\004(\000\000\000\000,\232\000\000\000\000\000\000\006\030\000\0004V\000\000\000\0005\244\000\000\000\000\000\000\006\252\000\000\007\238\000\000\"8\000\000-.\000\0004\200\000\0005J\000\0009\142\000\000:\012\000\000:\026\000\000:.\000\000::\000\000:\130\000\000:\166\000\000\000\000\000\000\000\000\000\000\000\000\nl\000\000\n\n\000\000\012\236\012\132\000\000\018H\000\000\000\000\000\000\000\000\000\000\000\0006\024\000\000\000\000\000\000\000\000\000\000\000\000\000\012\000\000\000\000\000\000\000\000\000\000\000\000\003*\000\000\000\0000\230\000\000\000\000\000\000-R\000\000\000\000\000\202\000\000\000\000\000\0006\012\000\000\000\000\000\000\000\000-h\000\000\000\000\000\000\000\000\004\180\003$\000\000-\156\000\000\000\000\000\000\000\000\025@\005\006\000\000\025\192\000\000\000\000\006&\000\000-\210\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\148\000\000\000\0006\020\000\000\000\000\000\000.&\000\000\000\000\005 \000\000\000\000\015r\000\000\026\132\000\000\000\000#\132\000\000\000\000\000\000\004H\000\000\000\0006*\000\000\000\000\000\000\000\000.Z\000\000\000\000\000\000\000\000\0068\008r\000\000.\218\000\000\000\000\000\000\000\000\000\000\000\000\015\238\000\000\000\000\005\"\000\000\016\186\000\000\004H\000\000\000\000\004\194\016j\000\000\005\180\000\000\000\000\000\000\000\000\004b\000\000*\232\000\000\027\004\000\t\027\132\000\000\000\188\000\000\0176\000\000\017\178\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005\216\028\004\000\242\028\132\000\000\000\000\000\000\005\128\000\000\018~\000\000\006\006\000\000\000\000\006\020\003:\029\132\000\000\004\134\000\000\018\250\0302\000\000\000\000\019v\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006P\008\170\000\000\006\174\000\000\000\000\000\000\000\000\005|\000\000\020B\000\000\000\000\000\000\031\1784\248\000\000\000\000\000\000\0312\000\000\000\000\000\000\000\000\0252\004\234\000\000\000\000.\240\000\000\000\000\000\000\000\000\006\016\000\000\000\0006<\000\000\000\000\000\000/$\000\000\000\000\005\170\000\000\000\000/D\000\000\000\000\006\178\006\026\000\000\000\000/p\000\000\000\000\006\240 v\000\000\007j\000\000\000\000/\174\000\000\000\000\000\000\000\000\000\000\000\000\007\148\000\000\000\0006\162\000\000\000\000\000\000/\206\000\000\000\000\000\000\000\000\000\000$\018\000\000\000\000\000\000\004\130\000\000\000\000\000\0000>\000\000\000\000\008\240\008:\000\000\000\0000\212\000\000\000\000\007\016\000\000\000\000\000\000\000\000\004b\004\130\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005,\000\000\020\190\000\000\000\000\000\00056\000\000\tb\000\000\000\000\000\000\005\208\000\000\000\000\004\168\021n\000\000\022Z\000\000\000\000\000\000\007P\000\000\022n\007h\023h\000\000\025n\000\000\000\000\000\000\007\186\000\000+Z\007\198+r\000\000+\238\000\000\000\000\000\000\007\242\000\000\025\170\008R\000\000\000\000\002\014\006&\008\178\008\004\000\000\028\234\000\000\000\000\000\000\008\200\000\000#\238\008\218\000\000\000\000\000\000\003D\000\000\000\000\000\000\000\000\000\000\003\174\000\000\000\000\004\020\000\000\000x\000\000\000\000\000\000\004\254\000\000\000\000\000\000\000\000\000/\000\000\006\186\004\140\000\178\000\000\000\000\003\134\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001J\000\136\000\000\000\000\002\150\000\000\000\000\000\000\008\008\000\000\000\000\011\006\012\224\000\000\000\000\000\000\000\000\0146\014\188\000\246\000\000\015\172\000\000\000\000\000\000\000\000\000\000\000\000\004\238\000\000\000\000\008\232\000\000\000\000\004\190\000\000\000\000\000V\000\000\000\000\000=\000\000\006\218\005\136\002\240\000\000\000\000\0026\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\162\016\n\000\000\000\000\000\000\000\000\006\208\000\000\000\000\tL\000\000\000\000\000\000\017\196\000\000\000\000\000B\021P\004\176\000\000\021\210\000\000\000\000\000\000\000\000\000\000\000\000\0003\000\000\007H\003\\\001\n\000\000\000\000\000\000\000\000\002X\000\000\000\000\000\000\000\000\000\000\000\000\005\190\000\000\000\000\000%\000\000\007|\005\230\0050\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007\188\000\000\000\000\012H\022\132\000\000\000\000\000\000\000\000\000\242\000\000\004\254\000\000\008h\000\000\000\000\000\000\000\000\000\000\000\000\019\148\nf\000\000\000\000\011\192\000\000\000\000\000\000\000\000\006b\000\000\012\024\000\000\000\000\000\000\000\000\003\240\000\000\000\000\000\000\000y\000\000\000\000\000\205\000\000\000\000\000\000\000\000\000\000\000\000\000\0000\236\005P\000\000\000\000\000\000\028\194\000\000\000\000\013\012\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000}\000\000\000\000\000\000\000\000\000\000\000Z\002\150\000Y\004\168\n\166\005\196\000\000\000\000\005\218\007\206\008\188\008\202\000\000\000\000\000\000\000\000\000\000\000\000\000\000\013\238\005\218\030\204\006\190\000\000\000\000\t\030\000\000\023<\000\000\000\000\006\166\000\000\000\000\000\000\004\208\000\000\001B\000\000\006\024\015\"\000\000\000\000\000\000\000\000\004N\000\000\004v\000\000\007d\000\000\000\000\001R\000\000\000\000\000\000\000\000\n.\000\000\000\000\005\218\t*\000\000\023\252\000\000\004H\006\216\000\000\000\000\000\000\000\000\000\000\003$\000\000\000\000\000\000\000\000\000\0001v\008\148\000\000\000c\000\000\000\000\000\000\000\000\000\000\002\030\n\170\001\164\011&\000\000\002\154\012\166\000\000\006\198\000\000\003\022\000\000\004\154\000\000\005\020\000\000\000\000\000\000\000\000\000\000\008\160\000\000\005\224\000\000\t^\000\000\006\152\000\000\004H\007*\000\000\003\166\000\000\000\000\000\000\006,\007P\006>\000\000\008\136\000\000\008\212\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008\234\000\000\tn\000\000\000\000\000\000\000\000\000\000\006\140\007\232\007\226\000\000\007\250\000\000\000\000\000\181\t\182\000\000\006\232\000\000\000\000\000\000\000\000\0074\000\000\000\000\000\000\000\000\000\000\0074\008t\002\134\007\128\007\210\000\000\000\000\t\202\000\000\000\000\000\000\000\000\t\002\000\000\000\000"), (16, "\001\182\001\205\0046\0006\000\n\005\001\005\002\000\\\000\\\000\017\004\136\000q\000e\000-\001;\004L\004\179\002S\003T\003<\002+\004\198\000-\005m\000^\005\006\005n\004\134\000\t\004\137\004Y\003V\004J\004\177\004\180\004Y\004M\004Y\004\196\005\182\000D\004\199\004Y\003\007\005\023\001\184\000\017\005\024\000\016\001\185\000^\000^\000\191\002\219\000\017\000_\000_\004\252\004\253\000`\000`\001\129\001\182\001\205\000-\005\028\0006\000D\005.\000\\\003\243\0019\002,\0018\004\176\000-\001U\001\131\005r\005/\0051\003\006\005\021\004\133\000i\000i\000\193\001\182\001\203\004Z\001O\004\177\004\180\004Y\004Z\003\131\004Z\001\210\004I\001%\004\134\004Z\004\137\004Y\0012\003\007\000'\001\184\000&\005\191\004a\001\185\000^\001t\000'\004J\000\005\000_\001<\004M\004Y\000`\005\021\004\194\001\182\001\205\0006\004b\004Y\003V\000^\000E\001\184\004P\002B\005\021\001\185\000-\001\135\000\008\000\t\002S\003T\003<\001\198\0006\000i\0006\002[\002G\0059\000-\004Z\002H\001@\003\014\003h\001\199\003\133\003b\004\195\002\237\004Z\001@\000j\000j\003\015\003\007\000-\001\184\003P\005:\001=\001\185\003^\001P\0007\004\196\004\184\004Z\004\199\004Y\004s\004Y\000\137\002-\002L\004Z\000k\000k\003=\000-\003\\\004\185\004=\000-\002B\003\"\000\154\000-\000\160\003s\001W\0034\001\214\000\169\001\198\001X\004Q\000\160\001Y\002G\000\166\000-\000\138\002H\001@\003\014\005<\001\199\003c\001\210\002\220\001%\001\215\0006\000j\005=\005W\001\216\000\168\001\198\005X\001\217\001/\000m\0007\002,\001\218\000\139\004Z\004\224\004Z\000\140\001\199\005u\005N\004\230\002L\000o\000k\000\160\003\029\005Z\005N\000b\003\244\0007\002B\003\"\004\209\002u\000\160\005\\\002\142\0034\001\214\000\170\001\198\004\149\000\\\0007\003Y\002G\000\185\002\238\001<\002H\001@\003\014\003\246\001\199\001>\003e\004[\004\240\001\215\005\131\001\182\001\205\003\015\001\216\000\152\000-\003P\001\217\004e\002S\003j\001%\001\218\000-\004\186\001E\002A\005/\005s\003\006\002w\000\152\002L\001\204\002x\000^\003=\000\191\003\\\002\243\000_\004T\004\001\003\"\000`\004(\000\160\003s\004\143\0034\001\214\002\007\002\008\003\007\001@\001\184\002\247\000\179\000\152\001\185\000\160\004\227\001@\000\166\005\133\004\141\005F\004\188\004\228\000i\001\215\000\192\001\182\001\205\005F\001\216\000\152\000\160\001|\001\217\000\166\000\252\004\185\000-\001\218\000-\004\189\005 \001\143\005/\005x\003<\000-\001c\005Q\004d\005R\001e\005I\004\133\000\160\005J\005P\000\166\000\160\004\227\005I\000\166\000\160\005J\0006\000\166\004b\004Y\005\134\003\007\004\134\001\184\004\137\004Y\0006\001\185\000\160\001'\000\255\000\166\001\145\002\133\002\193\002\214\002\196\005\130\000^\001A\001\182\001\205\002\161\002[\000\\\004\003\002\134\004\140\000g\0006\002B\000\253\001N\000-\001*\000j\0006\005/\005x\003<\001\198\0006\001@\003\014\004\141\002G\001O\002\199\000\017\002H\001@\003\014\005\136\001\199\003\015\003\249\003u\002[\004Z\000k\005\196\005=\005W\003\007\004Z\001\184\005\138\000^\001,\001\185\0006\001d\000_\0006\000\253\001d\000`\004\186\004)\005}\002\007\002\008\002L\005d\005e\003\"\003\029\005\140\000\160\003'\000\\\0034\002B\003\"\000e\002\164\000\160\005\142\004\185\0034\001\214\000i\001\198\004S\001\182\001\205\0007\002G\000'\002\165\005!\002H\001@\003\014\005~\001\199\000\216\003\127\0006\001@\001\215\005-\005$\005=\005W\001\216\0006\005\148\002J\001\217\005\191\001P\002U\000^\001\218\005\149\001*\005i\000_\000\225\004_\000\\\000`\004;\002L\000\182\0007\000^\003=\001\184\005\128\0007\001m\001\185\002B\003\"\000\160\002u\000\160\003'\002\142\0034\001\214\001X\001\198\000\160\001Y\000i\000\166\002G\001+\004\155\004\248\002H\001@\003\014\005~\001\199\004Q\004<\0007\000j\001\215\0007\000^\005=\005W\001\216\001#\000_\002J\001\217\002\\\000`\005\021\0006\001\218\001q\002\n\002u\002A\001\210\002\142\002[\002w\000k\002L\004\191\002x\002\221\003=\004B\005\128\004\144\001\182\001\205\002\237\003\"\000i\0006\000\160\003'\003u\0034\001\214\000-\002\251\000-\002.\002\226\000l\005/\005x\003<\000-\000\211\0007\000\236\005 \0006\000-\0006\002A\002\255\001\215\002\237\002w\000j\001\198\001\216\002x\000m\0006\001\217\0006\001p\000\149\003\007\001\218\001\184\005\193\001\199\0020\001\185\004\250\000o\000\188\004\170\004Y\000-\002\250\000k\000\191\005\127\001\212\001\182\001\205\003\003\000^\001\132\004=\000\213\003\018\003x\000^\000\214\003\004\004|\000-\001*\003\028\003B\005/\005x\003<\001\131\000\138\0006\000j\003\004\003\004\002\133\002\193\002\194\002\196\002.\001\213\004G\001\214\004V\002\161\000\211\000\227\000\238\002\134\004\140\003K\000m\003\007\003\248\001\184\000\139\000k\001,\001\185\000\140\0007\004Z\001\215\001^\003)\000o\004\141\001\216\005\129\002\199\003\142\001\217\0006\0021\0022\0024\001\218\002\133\004\011\003\004\002\209\003h\002B\001Z\003M\001\187\002\161\0006\000^\0007\002\134\000\213\001\198\003)\004\013\000\214\001\196\002G\002\027\004\130\000\169\002H\001@\003\014\005~\001\199\003.\002\007\002\008\005!\004\146\001\182\001\205\005=\005W\000\169\004\195\002\164\002J\000\243\005,\005$\000\227\0032\000-\005'\000\228\002\237\005/\005x\003<\002\165\005?\004\196\002L\003\221\004\199\004Y\003=\000-\005\128\0007\001j\002B\000\152\003\"\000\160\0006\000\160\003'\005\018\0034\001\214\001\198\003\007\000\160\001\184\004\204\002G\002\164\001\185\000\160\002H\001@\003\014\005~\001\199\002[\000-\0004\005\137\003K\001\215\002\165\005=\005W\002[\001\216\0006\002J\002\237\001\217\002*\0006\000\\\0006\001\218\003\159\000\181\0006\000\160\004}\003p\000\166\001\001\002L\004Z\002z\0035\003=\004\176\005\128\000\228\001\182\001\205\003L\003\"\004\128\001\006\000\160\003'\005\019\0034\001\214\000\244\003p\000-\004\177\004\180\004Y\005/\005x\003<\003m\001*\002\t\003r\000^\000\246\000-\005\"\0053\000_\001\215\004\004\004\202\000`\0007\001\216\000\\\003\004\002\238\001\217\000q\005u\002B\003\007\001\218\001\184\003q\001\000\003\136\001\185\002u\004\133\001\198\002\142\002\131\001,\003\183\002G\000i\005\141\003\246\002H\001@\003\014\005~\001\199\005K\001\001\004\134\005+\004\137\004Y\001\002\005=\005W\004Z\001\003\001@\002J\000^\003\177\001\004\003\138\005{\000_\0007\004W\0007\000`\001B\0007\003)\002\158\000^\002L\003\136\0007\002w\003=\004\207\005\128\002x\001\182\001\205\004\147\003\"\000\169\005b\000\160\003'\005\144\0034\001\214\000i\005\172\000-\002\007\002\008\005;\002S\003T\003<\004X\000\160\001l\001s\001o\003\233\004\003\003\137\004Z\003\167\001\215\003.\002B\005\151\003\184\001\216\000j\005\170\004\148\001\217\003\008\003\233\001\198\003\007\001\218\001\184\0006\002G\0032\001\185\000\160\002H\001@\003\014\005~\001\199\005L\003\012\004\192\003\235\000k\001\182\001\205\005=\005W\000\169\004\195\0006\002J\002u\005'\000\211\002\142\000\238\000-\003\234\005\173\005\019\002S\003T\003<\004\245\004\205\004\196\002L\000\\\004\199\004Y\003=\000]\005\128\000j\002\133\000-\004\193\003\"\005\178\002S\000\160\003'\002u\0034\001\214\002\138\003\007\002\134\001\184\004a\005\177\005\187\001\185\000\160\000^\004\014\000^\000k\002w\000\213\004\206\005\189\002x\000\214\001\215\004(\004b\004Y\004\021\001\216\000^\004\013\005M\001\217\002O\000_\002B\004\158\001\218\000`\000-\000/\001z\0002\004\023\000^\001\198\000\243\004Z\002w\000\227\002G\0006\002x\004\195\002H\001@\003\014\0007\001\199\003\252\003b\005\194\000m\000i\001\182\001\205\002[\003\015\004\024\0004\004\196\002J\004\031\004\199\004Y\002\164\000r\000-\0007\0006\005\179\002S\003T\003<\004\023\004Z\005\197\002L\004!\002\167\005'\003=\000-\003\\\004\"\001x\002B\005'\003\"\005\198\005\162\000\160\003'\003\193\0034\001\214\001\198\003\007\000-\001\184\004!\002G\000-\001\185\002\133\002H\001@\003\014\005*\001\199\003`\003b\0004\005L\003\203\001\215\004\127\002\134\003\015\000\228\001\216\0056\002J\004Z\001\217\001@\003\014\005Y\005\162\001\218\003\004\0013\003\227\000j\004%\002\133\003\004\003\015\002L\005\162\005\195\005\206\003=\004\212\003\\\000\246\001\182\001\205\002\134\003\"\004\023\0007\000\160\003'\005k\0034\001\214\000k\004\133\000-\005\135\004+\005u\002S\003T\003<\000\000\001\000\003\"\000\000\001@\000\160\003'\000-\0034\004\134\001\215\004\137\004Y\0007\005\192\001\216\001B\004.\004h\001\217\002\164\001\001\002B\003\007\001\218\001\184\001\002\001i\0041\001\185\001\003\003\228\001\198\0040\002\169\001\004\0044\002G\005\139\005\162\000\000\002H\001@\003\014\0040\001\199\003\135\003b\005\181\005\019\000\160\001l\004\023\001o\003\015\005\019\005\169\001@\002J\0036\000\000\005)\000\000\004\225\002u\004\141\005\201\002\142\005(\001B\000\000\004Z\000\000\000\152\002L\005\202\003:\000\169\003=\000\000\003\\\000\000\001\182\001\205\005\192\003\"\000\000\000\000\000\160\003'\000\000\0034\001\214\000\000\005\163\000-\000\000\000\000\000\000\002S\003T\003<\000\000\000\160\001l\005\165\001o\002A\000\211\000\000\000\236\002w\001\215\002u\002B\002x\002\142\001\216\000\000\000\160\004}\001\217\000\166\000\160\001\198\003\007\001\218\001\184\000\000\002G\000\000\001\185\004\195\002H\001@\003\014\000\000\001\199\004\000\003b\000\000\000\000\000\000\000\000\001\182\001\205\003\015\000\000\000\152\004\196\002J\000^\004\199\004Y\000\213\000-\002A\000-\000\214\005 \002w\005/\000\000\003\006\002x\000\000\002L\000\000\000\000\000\000\003=\005\167\003\\\000\000\000\000\000\000\000\000\003\"\004\161\000\000\000\160\003'\000\000\0034\001\214\000\227\000\000\003\007\000\000\001\184\000\000\000\000\000\000\001\185\000\160\001)\000\000\000\166\000\000\000\000\000\211\000\000\000\232\000\000\001\215\005\132\001\182\001\205\002\133\001\216\000\000\002\200\004Z\001\217\000\000\004a\002B\002\161\001\218\000-\000\000\002\134\000\000\005/\000\000\003\006\001\198\000\000\000\000\000\000\000\000\002G\004b\004Y\000\000\002H\001@\003\014\000\000\001\199\005U\003b\002\202\000^\000\000\000\000\000\213\000\000\003\015\003\007\000\214\001\184\002J\000\000\000\000\001\185\000\000\002\133\002\198\000\000\002\196\000\000\000\000\000\000\000\000\000\228\002\161\005v\002L\000\\\002\134\000\000\003=\000e\003\\\000\000\000\000\000\227\002B\003\"\000\000\000\000\000\160\003'\002\208\0034\001\214\000\000\001\198\000\000\002\164\002\199\004Z\002G\000\000\000\000\005!\002H\001@\003\014\005w\001\199\000\000\000\000\002\165\004\195\001\215\005#\005$\005=\005W\001\216\000^\000\000\005z\001\217\000\000\000_\004\233\000\000\001\218\000`\004\196\000\000\000\000\004\199\004Y\000\000\000\000\000\000\002L\000\000\000\000\000\237\003\029\005|\000\000\000\000\000\000\002\164\002B\003\"\000\160\000\000\000\160\003'\000i\0034\001\214\004\195\001\198\000\000\000\000\002\165\000\000\002G\000-\000\228\000\000\002H\001@\003\014\005w\001\199\000\000\000\000\004\196\000\186\001\215\004\199\004Y\005=\005W\001\216\004\133\000\000\005z\001\217\000\000\000\000\000\000\002u\001\218\000\000\002\142\004Z\000-\000/\0000\0002\000\000\004\134\002L\004\137\004Y\000\000\003\029\005|\001\182\001\205\000\000\004n\000\000\003\"\000\000\000\000\000\160\003'\000\000\0034\001\214\000-\000\000\000\000\000\000\005/\0004\003\006\000\000\000\000\000\000\000\211\000\000\000\231\002A\000\000\000j\000\000\002w\004Z\001\215\000\000\002x\002u\000\000\001\216\002\142\000\000\000\000\001\217\000\000\003\007\000\000\001\184\001\218\000\188\000\000\001\185\000\000\000\211\000k\000\238\004a\004Z\000\000\000-\000/\001v\0002\005y\001\182\001\205\000\000\000\000\000^\000\000\000\000\000\213\000\\\004b\004Y\000\214\000q\000-\000\000\000\138\002A\002S\005\015\003\006\002w\000\000\000\000\000\000\002x\0004\000\000\000\000\000\000\000\000\002u\004\236\000^\002\137\000\000\000\213\000m\000\152\000\227\000\214\000\139\000\000\000\000\003\007\000\140\001\184\000\000\000\000\000\000\001\185\000o\000^\000\000\000\000\000\000\000\000\000_\000\000\000\000\000\000\000`\000\000\000\000\000\000\000\000\002\133\000\227\001@\002\203\004Z\000\000\000\000\002B\000^\002\161\004\243\004\006\002w\002\134\001B\003\130\002x\001\198\000\160\001~\000i\000\166\002G\001\182\001\205\001i\002H\001@\003\014\005w\001\199\000\000\000\000\000\000\000\000\004\218\000-\000\000\005=\005W\002S\000\000\003\006\005z\000\000\000\000\000-\000\000\000\160\001l\000-\001o\002\133\000\228\005 \002\200\000\000\000\000\000\000\002L\000\000\002\161\000\000\003\029\005|\002\134\003\007\000-\001\184\002B\003\"\001@\001\185\000\160\003'\002\206\0034\001\214\000\000\001\198\002Z\000\228\002\164\001B\002G\000\000\002\202\000\000\002H\001@\003\014\000\000\001\199\000\000\001i\000\000\002\165\001\215\004a\003\128\000j\003\015\001\216\003\130\000\000\003w\001\217\005\013\000\000\002\133\000\000\001\218\000\000\004l\000\000\004b\004Y\000\160\001l\000\000\001o\002L\002\134\000\000\000k\003\029\003y\000\000\002\207\001\000\000\000\000\000\003\"\000\000\002\164\000\160\003'\000\000\0034\001\214\000\000\000\000\000\\\001\182\001\205\000\000\000e\000\000\002\165\001\001\002Q\000\000\000\000\000\000\001\002\000\000\000-\002B\001\003\001\215\002S\003\001\003\006\001\004\001\216\004a\000\000\001\198\001\217\000\000\000m\000\000\002G\001\218\000\000\004Z\002H\001@\003\014\000\000\001\199\000\000\004b\004Y\000t\000^\003\007\000\152\001\184\003\015\000_\001@\001\185\003w\000`\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005#\0050\000-\000\134\000\000\000\000\000\152\002L\000\000\000\000\000\000\003\029\003y\000\000\000\000\000\000\000\000\000i\003\"\000\000\000\000\000\160\003'\000\000\0034\001\214\000\000\000\000\000\000\001\182\001\205\000\160\001\128\000\000\000\166\000\160\002\235\003\031\002\249\000\000\004Z\000\000\000-\000\000\000\000\001\215\002S\003 \003<\000\000\001\216\000\000\000\160\001\141\001\217\000\166\000\000\005E\000\000\001\218\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\182\001\252\003\007\000\000\001\184\002B\000\000\000\000\001\185\000\000\001\182\001\202\004y\004a\000\000\001\198\000\000\000\000\000\000\000\000\002G\001\182\001\205\000\000\002H\001@\003\014\000j\001\199\003?\004b\004Y\000\000\000\000\000-\000\000\000\000\003\015\002S\003 \003<\003A\000\000\000^\000\000\001\184\000\137\000\000\000\000\001\185\000\000\000k\000\000\000^\000\000\001\184\000\000\002L\000\000\001\185\004a\003\029\003C\000\000\003\007\000\000\001\184\000\000\003\"\000\000\001\185\000\160\003E\001@\0034\001\214\000\138\004b\004Y\004w\000\000\000\000\000\000\001\182\001\205\005F\000\000\000\\\000\000\000\000\004Z\000q\000\000\002B\000\000\001\215\000\000\000m\000\000\000\000\001\216\000\139\003J\001\198\001\217\000\140\000\000\000\000\002G\001\218\000\000\000o\002H\001@\003\014\000\000\001\199\005I\000\000\000\160\005J\000\000\000\166\001\182\001\205\003\015\002A\000\000\001\184\002J\000^\003D\001\185\000\000\000\000\000_\000-\004Z\000\000\000`\002S\003 \003<\000\000\001\198\002L\000\000\000\000\000\000\003=\000\000\003>\000\000\000\000\001\198\002B\003\"\001\199\000\000\000\160\003'\000\000\0034\001\214\000i\001\198\003\007\001\199\001\184\000\000\002G\000\000\001\185\000\000\002H\001@\003\014\000\000\001\199\000\000\000\000\000\000\000\000\001\215\000\000\001\182\001\205\003\015\001\216\000\000\000\000\002J\001\217\000\000\000\000\000\000\000\000\001\218\000-\004u\000\000\000\000\002S\003T\003<\000\000\000\211\002L\000\236\000\000\000\000\003=\000\000\003>\000\000\000\000\000\000\002B\003\"\000\000\000\000\000\160\003'\000\000\0034\001\214\000\000\001\198\003\007\000\000\001\184\000\000\002G\000\000\001\185\000\000\002H\000\000\000\000\000\000\001\199\000\000\000\000\000\000\000j\001\215\004\153\001\182\001\205\000^\001\216\000\000\000\213\002J\001\217\000\000\000\214\002B\000\000\001\218\000-\000\000\000\000\000\000\002S\003T\003<\001\198\000k\002L\000\000\000\000\002G\000\000\000\000\000\000\002H\001@\003\014\000\000\001\199\004a\000\000\000\227\000\000\000\000\000\000\001\214\000\000\003\015\003\007\000\000\001\184\002J\000\000\000\000\001\185\000\000\004b\004Y\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\215\000\000\002L\000\000\000\000\001\216\003=\000m\003>\001\217\000\000\000\000\002B\003\"\001\218\002u\000\160\003'\002\142\0034\001\214\000v\001\198\000\000\000\\\000\000\000\000\002G\000g\000\000\000\000\002H\001@\003\014\000\000\001\199\000\000\003[\000\000\000\000\001\215\000\000\001\182\001\205\003\015\001\216\000\000\000\000\002J\001\217\000\000\004Z\000\000\000\000\001\218\000-\000\228\000\000\002A\002S\003T\003<\002w\000\000\002L\000\000\002x\000^\003=\000\211\003\\\000\230\000_\000\000\002B\003\"\000`\000\000\000\160\003'\000\000\0034\001\214\000\000\001\198\003\007\000\000\001\184\000\000\002G\000\000\001\185\000\000\002H\001@\003\014\000\000\001\199\000\000\003]\000\000\000i\001\215\000\000\001\182\001\205\003\015\001\216\000\000\000\000\002J\001\217\000^\000\000\000\000\000\213\001\218\000-\000\000\000\214\000\000\002S\003z\003<\001\001\000\000\002L\000\000\000\000\000\000\003=\000\000\003\\\000\000\000\000\000\000\000\000\003\"\001\008\000\000\000\160\003'\000\000\0034\001\214\000\000\000\227\003\007\000\000\001\184\000\000\000\000\000\000\001\185\000\000\001\182\001\201\000\000\000\000\002\133\004\165\000\000\002\200\000\000\001\215\000\000\001\182\001\205\002\161\001\216\000\\\000\000\002\134\001\217\000e\000\000\002B\000\000\001\218\000-\000\000\000j\003|\002S\003z\003<\001\198\000\000\000\000\000\000\000\000\002G\000\000\002\202\000-\002H\001@\003\014\000^\001\199\001\184\003o\000\000\004\195\001\185\000k\000\000\000\000\003\015\003\007\000\000\001\184\002J\000^\000\000\001\185\000\000\000\000\000_\000\000\004\196\000\000\000`\004\199\004Y\000\000\000\228\000\000\002L\000\000\000l\000\000\003=\001\026\003\\\002\205\000\000\000\000\002B\003\"\000\000\002\164\000\160\003'\003~\0034\001\214\000i\001\198\000\000\000\000\000m\000\000\002G\004\232\002\165\000n\002H\001@\003\014\000\000\001\199\000\000\000\000\000\000\000o\001\215\000\000\001\182\001\205\003\015\001\216\000\000\000\000\002J\001\217\003\144\000\000\000\000\000\000\001\218\000-\000\000\004Z\004\235\002S\003 \003<\000\000\000\000\002L\000\000\000\000\000\000\003=\000\000\003}\000\000\000\000\001\198\002B\003\"\000\000\000\000\000\160\003'\000\000\0034\001\214\000\000\001\198\003\007\001\199\001\184\000\000\002G\000\000\001\185\000\000\002H\001@\003\014\000\000\001\199\000\000\000\000\000\000\000j\001\215\000\000\001\182\001\205\003\015\001\216\000\000\000\152\002J\001\217\000\000\000\000\000\000\000\000\001\218\000-\000\000\000\000\000\137\002S\000\000\003\006\000\000\000k\002L\000\000\000\000\000\000\003=\000\000\003}\000\000\000\000\000\000\000\000\003\"\000\000\000\000\000\160\003'\000\000\0034\001\214\001\182\001\200\003\007\000\000\001\184\000\138\000\000\000\000\001\185\000\000\000\160\004\227\000\000\000\166\000\000\000\000\000\000\000\000\004\238\001\215\000\000\000\000\000\000\000\000\001\216\000\000\000m\000\000\001\217\002u\000\139\002B\002\142\001\218\000\140\003\250\001\182\001\205\000\000\003\130\000o\001\198\000\000\000^\000\000\001\184\002G\001\182\001\205\001\185\002H\001@\003\014\000\000\001\199\002:\004\005\004a\000\000\000\211\000-\000\238\000\000\003\015\002S\000\000\003\006\002J\000\000\000\000\000\000\000\000\000^\000\000\004b\004Y\002w\000\000\000\000\002A\002x\001\184\000\000\002L\000\000\001\185\000\000\003=\000\000\003>\003\007\000\000\001\184\002B\003\"\000\000\001\185\000\160\003'\000\000\0034\001\214\000^\001\198\000\000\000\213\000\000\000\000\002G\000\214\000\000\000\000\002H\001@\003\014\000\000\001\199\000-\0003\000\000\0002\001\215\004a\004\008\000\000\003\015\001\216\003\130\000\000\003w\001\217\000\000\000\000\000\000\004Z\001\218\000\227\000\000\000\000\004b\004Y\000\000\000\000\000\000\001\198\002L\000\000\0004\000\000\003\029\003y\000\000\000\000\000\000\000\000\000\000\003\"\001\199\000\000\000\160\003'\000\000\0034\001\214\000\000\001\182\001\205\000\000\000\000\000\000\002B\000\000\000\\\002\133\000\000\000\211\000g\000\238\000-\000\000\001\198\002B\002S\001\215\003\006\002G\002\134\000\000\001\216\002H\000\000\001\198\001\217\001\199\000\000\000\000\002G\001\218\000\000\004Z\002H\001@\003\014\000\000\001\199\000\000\002J\000\000\003\007\000\000\001\184\004a\000\000\003\015\001\185\000^\000\228\003w\000^\000\000\000_\000\213\002L\000\000\000`\000\214\000\000\000\000\004b\004Y\000\000\000\000\000\000\002L\000\000\000\000\000\000\003\029\003y\000\000\001\214\004\n\000\254\004\174\003\"\003\130\000\000\000\160\003'\000i\0034\001\214\000\227\000\000\000\000\002\143\000\000\000\000\001@\000\000\001\215\000\000\000\000\000\000\001\000\001\216\000\000\000\000\000\000\001\217\001B\001\215\000\000\000\000\001\218\000\000\001\216\000\000\001\182\001\205\001\217\001i\000\000\000\000\001\001\001\218\0058\000\000\004Z\001\002\000\000\000-\000\000\001\003\000\000\002S\003 \003<\001\004\002B\000\211\000\000\000\238\000\000\000\160\001l\000\000\001o\004\172\001\198\000\000\000\000\000\000\000\000\002G\000\000\000\000\000\000\002H\001@\003\014\003\007\001\199\001\184\000\000\000\000\000\000\001\185\000\000\000j\000\000\003\015\000\228\000\000\000\000\003w\001\182\001\183\000\000\000\000\000\000\000\000\000\000\000^\000\000\000\000\000\213\000\000\000\000\000\000\000\214\002L\000\000\000k\000\000\003\029\003y\000\000\004\016\000\000\000\000\000\000\003\"\000\000\000\000\000\160\003'\000\000\0034\001\214\000\000\000\000\000\000\000\000\001\182\001\205\000\000\000\227\000l\000^\001\000\001\184\005[\000\000\000\000\001\185\000\000\000-\000\000\001\215\000\000\002S\003 \003<\001\216\000\000\000\000\004\216\001\217\000m\001\001\000\000\000\000\001\218\000\148\001\002\000\000\000\000\000\000\001\003\001\182\001\203\002B\000o\001\004\000\000\000\000\003\007\000\000\001\184\000\000\000\000\001\198\001\185\000\000\000\000\000\000\002G\000\000\000\000\000\000\002H\001@\003\014\000\000\001\199\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\015\000\000\000\000\000\\\002J\000\000\000\000\000e\000\000\000^\000\000\001\184\000\000\000\228\000\000\001\185\000\000\000\000\000\000\000\000\002L\000\000\000\000\000-\003=\000\000\003>\003\139\001\182\001\205\000\000\003\"\000\000\000\000\000\160\003'\001\198\0034\001\214\004\018\000\000\000-\000\000\000\000\000\000\002S\000^\003<\000\000\001\199\000\000\000_\000\000\002Z\000\000\000`\000\000\000\000\001\215\000\000\000\000\001\000\000\000\001\216\002B\000\000\001\240\001\217\000\000\000\000\000\000\003\007\001\218\001\184\001\198\000\000\000\000\001\185\000\000\002G\000i\001\001\000\000\002H\001@\003\014\001\002\001\199\000\000\000\000\001\003\000\000\001\182\001\205\000\000\001\004\003\015\000\000\000-\000\000\002J\000\000\000\000\003@\000\000\000-\000\000\000\000\000\000\002S\001\198\003\006\000\000\000\000\000\000\000\211\002L\000\238\000\000\000\000\003=\000\000\003>\001\199\000\000\000\000\000\000\003\"\003\158\000\000\000\160\003'\000\000\0034\001\214\003\007\000\000\001\184\000\000\000\000\000\000\001\185\000\000\000\000\000\000\000\211\000\000\000\238\000\000\000\000\000\211\000\000\000\229\000\000\001\215\000\000\001\182\001\205\000^\001\216\000j\000\213\002B\001\217\001@\000\214\000\000\003\005\001\218\000-\001\242\000\000\001\198\002S\000\000\003\006\002\223\002G\000\000\000\137\000\000\002H\001@\003\014\000k\001\199\000\000\000\000\000^\000\000\001\215\000\213\000\227\000^\003\015\000\214\000\213\000\000\003\141\003\007\000\214\001\184\000\000\000\000\001\218\001\185\000\000\000\000\000\000\000\138\000\160\002\235\000\000\002\249\002L\000\000\000\000\000\000\003=\000\000\003\143\000\000\000\227\000\000\000\000\003\"\002B\000\227\000\160\003'\000m\0034\001\214\000\000\000\139\000\000\001\198\000\000\000\140\001@\000\000\002G\000\000\000\000\000o\002H\001@\003\014\000\000\001\199\000\000\003\164\001\215\000\000\001\182\001\205\000\000\001\216\003\015\000\000\000\000\001\217\003\027\000\000\000\000\003!\001\218\000-\000\000\000\000\000\000\002S\000\228\003\006\000\000\000\000\000\000\000\000\002L\000\000\000\000\000\000\003\029\003\030\000\000\000\160\003\176\000\000\003\182\003\"\002B\000\000\000\160\003'\000\000\0034\001\214\003\007\004\020\001\184\001\198\000\000\000\228\001\185\000\000\002G\000\000\000\228\000\000\002H\001@\003\014\000\000\001\199\000\000\000\000\001\215\000\000\001\182\001\205\001\000\001\216\003\015\000\000\000\000\001\217\003\027\000\000\004$\000\000\001\218\000-\000\000\000\000\000\000\002S\000\000\003\006\000\000\000\000\001\001\000\000\002L\000\000\000\000\001\002\003\029\003\030\000\000\001\003\001\000\000\000\000\000\003\"\001\004\000\000\000\160\003'\000\000\0034\001\214\003\007\000\000\001\184\000\000\000\000\000\000\001\185\000\000\000\000\001\001\000\211\000\000\000\236\000\000\001\002\000\211\000\000\000\212\001\003\001\215\000\000\001\182\001\205\001\004\001\216\000\000\000\000\002B\001\217\000\000\000\000\000\000\000\000\001\218\000-\000\000\000\000\001\198\002S\000\000\003\006\000\000\002G\000\000\000\000\000\000\002H\001@\003\014\000\000\001\199\000\000\000\000\000^\000\000\000\000\000\213\000\000\000^\003\015\000\214\000\213\000\000\003\027\003\007\000\214\001\184\000\000\000\000\000\000\001\185\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002L\000\000\000\000\000\000\003\029\003\030\001\182\001\205\000\227\000\000\000\000\003\"\002B\000\227\000\160\003'\000\000\0034\001\214\000-\000\000\000\000\001\198\002S\000\000\003\006\000\000\002G\000\000\000\000\000\000\002H\001@\003\014\000\000\001\199\000\000\000\000\001\215\000\000\000\000\003_\000\000\001\216\003\015\000\000\000\000\001\217\003X\003\007\000\000\001\184\001\218\000\000\000\000\001\185\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002L\000\000\000\000\000\000\003\029\003Z\001\182\001\205\000\000\000\000\002u\003\"\002B\002\136\000\160\003'\000\000\0034\001\214\000-\000\000\000\000\001\198\002S\000\228\003\006\000\000\002G\000\000\000\228\000\000\002H\001@\003\014\000\000\001\199\000\000\000\211\001\215\000\238\000\000\003W\002u\001\216\003\015\002\135\000\000\001\217\003X\003\007\000\000\001\184\001\218\000^\000\000\001\185\000\000\002w\000\000\000\000\000\000\002x\000\000\000-\002L\000\000\005\012\000\000\003\029\003Z\000-\000\000\001\028\000\000\002S\003\"\002B\000\000\000\160\003'\000^\0034\001\214\000\213\000\000\000^\001\198\000\214\000\000\002w\000\000\002G\001\001\002x\000\000\002H\001@\003\014\000\000\001\199\004(\000\000\001\215\000\000\003k\000\000\001\004\001\216\003\015\000\000\000\000\001\217\003l\000\000\000\227\000\000\001\218\001U\000\000\000\000\000\000\000\000\000-\001k\000\000\0002\000\000\000\000\002L\000\000\000\000\001O\003\029\003n\001\182\001\205\000\000\000\000\002u\003\"\002B\002v\000\160\003'\000\000\0034\001\214\000-\000\000\000\000\001\198\002S\0004\003\006\002\133\002G\000\000\000\000\000\000\002H\001@\003\014\000\000\001\199\000\000\000\000\001\215\002\134\000\000\003i\000\000\001\216\003\015\000\000\000\000\001\217\003X\003\007\000\000\001\184\001\218\000^\000\000\001\185\000\000\002w\002\133\000\000\000\000\002x\000\000\000\000\002L\000\000\000\228\000\000\003\029\003Z\000\000\002\134\000\000\000\000\000\000\003\"\001@\000\000\000\160\003'\000\000\0034\001\214\001@\003\014\000\000\003v\000\000\001P\000\000\000\000\000\000\005\013\001\182\001\205\003\015\000\000\000\000\000\000\000\000\000\000\000\000\001\215\000\000\000\000\000\000\000-\001\216\001\182\001\203\002S\001\217\003\006\000\000\001\000\001[\001\218\001f\000\000\004-\001X\000\000\000\160\001Y\005\016\000\166\003\"\000\000\000\000\000\160\003'\000\000\0034\000\000\001\001\001@\003\007\000\000\001\184\001\002\002B\000\000\001\185\001\003\000\000\000\000\000\000\001B\001\004\000\000\001\198\000^\000\000\001\184\002\133\002G\000\000\001\185\001i\002H\001@\003\014\000\000\001\199\000\000\000\000\000\000\002\134\000\000\000\000\001\182\001\205\003\015\003{\000\000\000\000\003w\000\000\000\000\000\000\0054\000\160\001l\000-\001o\000\000\000\000\002S\000\000\003\006\000\000\000\000\002L\000\000\000\000\000\000\003\029\003y\000\000\000\000\000\000\000\000\000\000\003\"\000\000\000\000\000\160\003'\000\000\0034\001\214\000\000\000\000\003\007\000\000\001\184\000\000\000\000\000\000\001\185\000\000\001\182\001\205\000\000\000\000\000\000\000\000\002B\000\000\000\\\001\215\000\000\000\000\000e\000-\001\216\000\000\001\198\003\157\001\217\000\000\000\000\002G\000\000\001\218\000\000\002H\001@\003\014\000\000\001\199\000\000\001\198\000\000\000\000\000\000\000\000\003\189\000\000\003\015\001\182\001\203\000\000\003w\003\192\001\199\001\184\000\000\000\000\000\000\001\185\000\000\000^\000\000\000\000\000\000\000\000\000_\000\000\002L\000\000\000`\000\000\003\029\003y\001\182\001\205\003\198\000\000\000\000\003\"\000\000\002\031\000\160\003'\000\\\0034\001\214\000-\000q\000\000\000\000\003\157\000^\002B\001\184\000i\000\000\000\000\001\185\000\000\000\000\000\000\000\000\001\198\003\236\000\000\001\215\001\210\002G\001%\003\240\001\216\002H\001@\003\014\001\217\001\199\003\192\000\000\001\184\001\218\001\215\000\000\001\185\000\000\003\015\000\000\000^\000\000\0055\000\000\000\000\000_\000\000\000\000\001\220\000`\000\000\000\000\000\\\003\198\000\000\000\000\000g\000\000\002L\000\000\000\000\000\000\003\029\0057\000\000\000\000\000\000\001\198\000\000\003\"\000\000\000\000\000\160\003'\000i\0034\001\214\001@\003\199\000\000\001\199\000\000\000\000\000\000\000\000\001\182\001\205\000\000\000j\003\200\000\000\000\000\000\000\003\238\000\000\000^\001\215\000\000\000-\000\000\000_\001\216\003\157\000\000\000`\001\217\001\198\000\137\000\000\000\000\001\218\000\000\000k\000\000\000\000\000\000\000\000\000\000\000\000\001\199\003\214\003\191\000\000\000\160\003\239\000\000\003\226\001\214\003\192\000i\001\184\001\198\000\000\000\211\001\185\000\236\000\000\000\138\000\000\000\000\000\000\001@\003\199\000\000\001\199\000\000\000\\\001\215\000\000\000\000\000e\003\198\001\216\003\200\000j\000\000\001\217\003\212\000m\000-\000\000\001\218\000\139\000\000\000\000\000\000\000\140\000\000\000\000\000\211\000\000\000\236\000o\000\000\000\000\000\000\000^\000\000\000k\000\213\000\000\000\000\000\000\000\214\003\214\000\000\001\215\000\160\003\219\000^\003\226\001\214\000\000\000\000\000_\000\000\000\000\000\000\000`\000\000\001\222\000\000\000\000\000\136\000\000\000\000\000\000\000\000\000\000\000j\000\227\001\215\000^\000\000\000\000\000\213\001\216\000\\\000\000\000\214\001\217\000e\000\000\000i\000m\001\218\000\000\000\000\000\\\001\198\000-\000\000\000e\000k\000\000\000\000\000\000\000\000\000o\001@\003\199\000-\001\199\000\000\000\000\000\000\000\227\000\000\000\000\000\000\000\000\003\200\000\000\000\000\000\000\003\212\000\000\000\000\000l\000\000\000^\000\000\000\000\000\000\000\000\000_\000\000\000\000\000\000\000`\000\000\000^\000\000\000\000\000\000\000\000\000_\000\000\000\000\000m\000`\000\000\003\214\000\000\000\151\000\160\003\219\000\000\003\226\001\214\000\228\000\000\000\000\000o\000i\000\000\000\000\000\000\000\000\000\000\000\152\000\000\000\000\000j\000\000\000i\000\000\000\000\000\000\001\215\002u\000\\\000\000\002\142\001\216\000e\000\000\000\000\001\217\000\155\000\156\000\158\000\159\001\218\000-\000\000\000\228\000k\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\160\000\165\000\000\000\166\000\000\000\000\000\138\000^\000^\000\000\000\000\002w\001\001\000_\000\000\002x\000\000\000`\000\\\000\000\000\000\000\000\000q\000\000\000\000\000\152\001\n\000m\000j\000\000\000\000\000\139\000\000\000-\000\000\000\140\000\152\000\000\000\000\000j\000\000\000o\000i\000\171\000\155\000\218\000\158\000\159\001\001\000\000\000\000\000\000\000k\000\000\000\000\000\155\001\189\000\158\000\159\000\000\000\000\000^\001\012\000k\000\000\000\000\000_\000\000\000\000\000\000\000`\000\160\000\165\000\000\000\166\000\000\000\000\000\138\000\000\000\000\000\000\000\000\000\160\000\165\000\000\000\166\000\000\001U\000\138\000\000\000\000\000\000\000\000\000\000\000\000\000i\000\000\000\000\000m\000\000\000\000\001O\000\139\000\000\000\000\000\000\000\140\000\\\002\133\000m\000\000\000e\000o\000\139\000\171\000\000\000\000\000\140\000\000\000\152\000-\002\134\000j\000o\000\000\000\171\000\000\000\000\000\000\000\000\000\\\000\000\000\000\000\000\000e\000\000\000\000\000\000\000\155\002D\000\158\000\159\000\000\000-\000\000\000\\\000k\000\000\000\000\000q\000^\000\000\000\000\000\000\000\000\000_\000\000\000\000\000\000\000`\000\000\000\000\000\000\000\000\000\000\000\160\000\165\000\000\000\166\000\000\000\000\000\138\000\000\000^\001@\000j\000\000\000\000\000_\000\000\000\000\000\000\000`\000\211\000i\000\238\001P\000\000\000^\000\000\002\164\000\000\000m\000_\000\000\000\000\000\139\000`\000\000\000k\000\140\000\\\000\000\000\000\002\171\000e\000o\000i\000\171\000\000\000\000\000\000\000\000\001[\000-\001\\\000\000\000\000\001X\000\000\000\160\001Y\000i\000\166\000\\\000\000\000^\000\000\000e\000\213\000\000\000\000\000\000\000\214\000\000\000\000\000\000\000-\000\000\000\000\000\000\000\000\000\000\000\000\000^\000m\000\000\000\000\000\000\000_\000\000\000\000\000\000\000`\000\000\000\000\000\000\000\000\000\000\000x\000\227\000\152\000\000\000\000\000j\000\000\000\\\000^\000\000\000\000\000g\000\000\000_\000\000\000\000\000\000\000`\000\000\000i\000\000\000\155\002|\000\158\000\159\000\152\000\000\000\000\000j\000k\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000i\000j\000\155\003$\000\158\000\159\000\160\000\165\000^\000\166\000k\000\000\000\138\000_\000\000\000\\\000\000\000`\000\000\000e\000\000\001#\001%\000\000\000\000\000k\000\000\000\000\000-\000\160\000\165\000\000\000\166\000m\000\000\000\138\000\000\000\139\000\000\000\228\000-\000\140\000i\000\000\000\000\000\000\000\000\000o\000\000\000\171\000\000\000\000\000\000\000\000\000\152\000\000\000m\000j\000^\000\000\000\139\000\000\000\000\000_\000\140\0043\000\000\000`\000\000\000\000\000o\000m\000\171\000\155\003\216\000\158\000\159\000\152\000\000\000\000\000j\000k\000\000\000\000\000\000\000z\000\000\001\000\000\000\000\000\000\000\000\000\000i\000\000\001U\000\000\000\000\000\000\000\000\000\188\000\160\000\165\000\000\000\166\000k\000\000\000\138\001\001\001O\000\000\000\000\000\000\001\002\000\000\000\000\000\000\001\003\001\182\001\205\000-\000\000\001\004\000j\000\160\001'\000\000\000\166\000m\000\000\000\138\000\000\000\139\000\000\000\000\000\\\000\140\003H\000\000\000e\000\000\000\000\000o\000\000\000\171\000\000\000\000\000k\000-\000\000\000\000\000m\000\000\000\000\000\000\000\139\000\000\000\000\000\\\000\140\000\000\002A\000e\001\184\000\000\000o\000\000\001\185\000\000\000\000\000\152\000-\000l\000j\001U\000\000\000\000\000\000\000^\000\000\000\000\000\000\001@\000_\000\000\000\000\000\000\000`\001O\000\173\000\000\000\000\000\159\000m\001P\000\000\000\000\000k\000\240\000\000\000\000\000^\000\000\000\000\000\000\000\000\000_\000o\000\000\000\000\000`\003N\000i\000\000\000\000\001\210\000\160\000\165\000\000\000\166\000\\\001[\000\138\001a\000e\000\000\001X\000\000\000\160\001Y\000\000\000\166\000\000\000-\000\000\000i\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000m\000\000\000\000\000\000\000\139\000\000\000\000\000\000\000\140\002B\000\000\000\000\000\000\000\000\000o\000\000\000\171\000\000\001@\001\198\000^\000\000\000\000\000\000\002G\000_\000\000\000\000\002H\000`\001P\000\000\001\199\000\000\000\\\000\000\000\000\000\000\000e\000\000\000\000\000\000\000\000\000\000\000\000\003P\000\152\000-\000\000\000j\000\000\000\000\000\000\000\000\000i\000\000\000\000\001[\000\000\001\137\000\000\002L\001X\000\000\000\160\001Y\000\000\000\166\000\183\000\152\000\000\000\000\000j\000k\000\\\000\000\000\000\000^\000g\001\214\000\000\000\000\000_\000\000\000\000\000\000\000`\000\000\000\000\000\000\000\000\000\195\000\160\001-\000\000\000\166\000k\000\\\000\138\001\215\000\000\000e\000\000\000\000\001\216\000\000\000\000\000\000\001\217\000\000\000-\000i\000\000\001\218\000\000\000\160\000\197\000^\000\166\000m\000\000\000\138\000_\000\139\000\000\000\000\000`\000\140\000\000\000\000\000\000\000\152\000\000\000o\000j\000\000\000\000\000\000\000\000\000\000\000^\000\000\000m\000\000\000\000\000_\000\139\000\000\000\000\000`\000\140\000i\000\000\000\195\000\000\000\\\000o\000\000\000k\000e\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000-\000\000\000\000\000\000\000\000\000\000\000i\000\000\000\000\000\160\000\234\000\000\000\166\000\000\000\000\000\138\000\000\000\000\000\000\000\000\000\152\000\000\000\000\000j\000\000\000\000\000\000\000\000\000\000\000\000\000^\000\000\000\000\000\000\000\000\000_\000m\000\000\000\000\000`\000\139\000\000\000\183\000\000\000\140\000\000\000\000\000k\000\000\000\000\000o\001\182\001\205\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000j\000i\000\000\000\160\0016\000\000\000\166\002:\003Q\000\138\000\\\000\000\000\000\000\000\000e\000\000\000\000\000\000\000\000\000\000\000\152\000\000\000\000\000j\000k\000\000\000\000\000\000\000\000\000\000\000m\002A\000\000\001\184\000\139\000\000\000\000\001\185\000\140\000\000\000\000\000\000\001\165\000\000\000o\001\182\001\205\000k\000\000\000l\000\000\000\000\000\000\000^\000\000\000\000\000\000\000\000\000_\000\000\000\000\000\000\000`\000\000\002:\003G\000\160\001\167\000\000\000\166\000m\000\000\000\138\002!\000\000\000\242\000\000\000\000\000\152\000\000\000\000\000j\000\000\000\000\000o\000\000\000\000\000i\002A\000\000\001\184\001\182\001\205\000m\001\185\000\000\000\000\000\139\000\000\000\000\001\165\000\140\000\000\001\182\001\203\000k\000\000\000o\000\000\000\000\002:\002;\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\182\001\205\000\000\002B\000\000\000\160\001\250\000\000\000\166\000\000\000\000\000\138\000\000\001\198\000\000\002A\000\000\001\184\002G\002:\002F\001\185\002H\000\000\000\000\000\000\001\199\000^\000\000\001\184\000\000\000\000\000m\001\185\000\000\000\000\000\139\000\000\000\\\002J\000\140\000\000\000e\002A\000\000\001\184\000o\000\000\000j\001\185\000\000\000\000\000\000\000\000\000\000\002L\000\000\000\000\000\000\000\000\002B\000\\\000\000\000\000\000\000\000e\000\000\000\137\000\000\000\000\001\198\000\000\000k\001\214\000-\002G\000\000\000\000\000\000\002H\000\000\000^\000\000\001\199\000\000\000\000\000_\000\000\000\000\000\000\000`\000\000\000\000\001\215\000\000\000\000\002J\000\138\001\216\000\000\000\000\002#\001\217\000\000\000^\000\000\002B\001\218\000\000\000_\000\000\000\000\002L\000`\000\000\000i\001\198\000\211\000m\000\236\000\000\002G\000\139\000\\\000\000\002H\000\140\000e\001\198\001\199\001\214\000\000\000o\000\000\002B\000\000\000-\000\000\000i\000\000\000\000\001\199\002J\000\000\001\198\000\000\000\000\000\000\000\000\002G\001\215\000\000\000\000\002H\000\000\001\216\000\000\001\199\002L\001\217\000^\000\000\000\000\000\213\001\218\000\000\000^\000\214\001\182\001\203\002J\000_\000\000\000\000\000\000\000`\001\214\000\000\000\000\000\000\000\000\000\000\000\000\001\182\001\205\000\000\002L\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\227\000j\001\215\000\000\000\000\000\000\000i\001\216\002:\003S\001\214\001\217\000\000\000\000\001\215\000\000\001\218\000^\000\000\001\184\000\137\000\152\000\000\001\185\000j\000k\000\000\000\000\001\224\000\000\001\215\000\000\002A\000\000\001\184\001\216\000\000\000\000\001\185\001\217\000\000\000\000\000\000\002e\001\218\000\000\001\182\001\205\000k\000\000\000\138\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\182\001\205\000\000\000\000\000\000\000\000\000\000\002:\004\026\000\160\002g\000\000\000\166\000m\000\000\000\138\000\000\000\139\000\000\002:\004\028\000\140\000\228\000\000\000\000\000\152\000\000\000o\000j\000\000\000\000\002A\000\000\001\184\000\000\000\000\000m\001\185\000\000\000\000\000\139\000\000\000\000\002A\000\140\001\184\000\211\002e\000\236\001\185\000o\000\000\000k\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\198\000\000\001\182\001\205\000\000\002B\000\\\000\000\000\000\000\000\000e\000\160\002\140\001\199\000\166\001\198\000\000\000\138\000\000\000\000\002G\002:\004\030\000\000\002H\000\000\000\000\000\000\001\199\000^\001\001\000\000\000\213\000\000\000\000\000\000\000\214\000\000\000m\000\\\000\000\002J\000\139\000e\001\014\002A\000\140\001\184\000\000\000^\000\000\001\185\000o\000\000\000_\000\000\000\000\002L\000`\000\000\000\000\000\000\002B\000\227\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\198\000\000\002B\001\214\000\000\002G\000\000\000\000\001\215\002H\000^\000i\001\198\001\199\000\000\000_\000\000\002G\000\000\000`\000\000\002H\001\226\001\215\000\000\001\199\002J\000\000\001\216\000\000\000\000\000\000\001\217\000\000\000\000\000\000\000\000\001\218\002J\000\000\000\000\000\000\002L\000\000\000i\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002L\000\\\000\000\000\000\000\000\000e\001\214\000\000\000\000\000-\002B\002b\000\000\000\000\000\000\000\000\000\000\000\228\001\214\000\000\001\198\000\000\000\000\000\000\000\000\002G\001\215\000\000\002\216\002H\000\000\001\216\000\000\001\199\000\000\001\217\002u\000j\001\215\002\142\001\218\000\000\000\000\001\216\000^\000\000\002J\001\217\000\000\000_\000\000\000\000\001\218\000`\000\\\000\000\002\156\000\000\000e\000\000\000\000\000k\002L\001U\000\000\000\\\000\000\000\000\000\000\000e\000j\000\000\000\000\000\000\000\000\000\000\000\000\001O\000i\000^\001\214\000\000\000\000\002w\000\000\001\001\000\138\002x\000\000\000\188\000\000\000\\\000\000\000\000\000k\000e\000\000\000^\000\000\001\016\001\215\000\000\000_\000\000\000\000\001\216\000`\000m\000^\001\217\000\000\000\139\000\000\000_\001\218\000\140\000\000\000`\000\\\000\138\000\000\000o\000e\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000i\000\000\000\000\000^\000\000\000\000\000\000\000\000\000_\000m\000\000\000i\000`\000\139\000\000\000\000\000\000\000\140\002\154\001@\000\000\000\000\000\000\000o\000\000\000\000\000\000\000j\000\000\000\\\000^\001P\000\000\000e\000\000\000_\000\000\000i\000\000\000`\000\000\000\000\000\000\000\000\000\000\000\000\002\156\000\000\000\000\002\133\000\000\000k\000\000\000\000\000\000\000\\\000\000\000\000\001[\000e\002W\000\000\002\134\001X\000i\000\160\001Y\000\000\000\166\000\000\000\000\002\233\000^\000\000\000\000\000\000\000\138\000_\000\000\000\000\000j\000`\002\245\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000j\000\000\000\000\000\000\000\000\000\000\000m\000^\002\156\000\000\000\139\000\000\000_\000k\000\140\000i\000`\002\253\000\000\002\156\000o\000\000\000\000\000\000\000k\000\000\000j\000\000\000\\\000\000\000\000\000\000\000e\000\000\000\000\000\000\000\000\000\000\000\138\000\\\002\164\000i\000\000\000e\003\n\002\156\000\000\000\000\000\000\000\138\000k\000\000\000\000\000j\002\173\000\000\000\000\000\000\000\000\000m\000\000\000\000\000\000\000\139\000\000\000\\\000\000\000\140\000\000\000e\000m\000^\002\156\000o\000\139\000\138\000_\000k\000\140\000\000\000`\000\\\000^\000\000\000o\000e\003\025\000_\000\000\000\000\000\000\000`\000\000\000\000\000\000\000j\000m\000\000\000\000\000\000\000\139\000\000\000\138\000\\\000\140\000i\000\000\000e\000^\000\000\000o\000\000\0030\000_\002\156\000\000\000i\000`\000\000\000k\000\000\000j\000\000\000m\000^\000\000\000\000\000\139\000\000\000_\000\000\000\140\000\000\000`\000\\\000\000\000\000\000o\000e\000\000\002\156\000\000\000i\000\000\000\138\000k\000^\000\000\000\000\000\000\000\\\000_\000\000\000\000\000e\000`\000\000\000\000\000i\000\000\000\000\000\000\000\000\000\000\000\000\000m\000\000\000\000\000\000\000\139\000\138\000\000\000\000\000\140\000\000\000\000\0038\000^\000\000\000o\000i\000\000\000_\000\000\000\000\000j\000`\003\162\000\000\000\000\000\000\000m\000\000\000^\000\000\000\139\000j\000\000\000_\000\140\000\000\000\000\000`\000\000\002\156\000o\000\\\000\000\000\000\000k\000e\000i\000\000\003\174\000\000\002\156\000\000\000\000\000\000\000\000\000k\000\000\000j\000\000\000\000\000\000\000\000\000i\000\000\003\180\000\000\000\000\000\000\000\000\000\138\000\000\000\000\000\000\000j\000\000\000\000\002\156\000\000\000\000\000\000\000\138\000k\000\000\000\000\000^\000\000\003\187\000\000\000\000\000_\000m\000\000\002\156\000`\000\139\000j\000\000\000k\000\140\000\000\000\000\000m\000\000\000\000\000o\000\139\000\138\000\000\000\000\000\140\000\211\000\000\000\236\000\000\002\156\000o\000\\\003\196\000i\000k\000e\000\000\000\138\000\000\000\000\000\000\000j\000m\000\\\000\000\000\000\000\139\000e\003\210\000\000\000\140\000\000\000\000\000-\000\000\005\007\000o\000j\000m\000\138\002\156\000\000\000\139\000\000\000\000\000k\000\140\000\000\000^\000\000\000\000\000\213\000o\000\000\000^\000\214\002\156\000\000\000\000\000_\000m\000k\000\000\000`\000\139\000\000\000^\000\000\000\140\000\000\000\138\000_\000\000\000\000\000o\000`\000\000\000\000\000\000\000\\\000\000\000\000\000\227\000e\003\224\000\000\000\138\001U\000i\000\000\000\000\000m\000\\\000j\000\000\000\139\000e\000\000\000\000\000\140\000i\001O\000\000\000\000\005j\000o\000\000\000m\000\000\000\000\000\000\000\139\002\156\000\000\000\000\000\140\000\000\000k\000\000\000\000\000\000\000o\000^\000\000\000\000\000\000\000\000\000_\000\000\000\000\000\000\000`\000\211\000\000\000\236\000^\001\182\001\203\000\000\000\000\000_\000\000\000\138\000\000\000`\000\\\000\000\000\000\000\\\000e\000\000\000\000\000e\000\000\000\000\000\000\000i\000\000\000\000\003\231\000\\\000\000\000\228\000m\000e\000\000\000\000\000\139\000j\000i\000\000\000\140\000\000\000\000\001@\000^\000\000\000o\000\213\000^\000j\001\184\000\214\000\000\000\000\001\185\001P\002\156\000^\000\000\000\000\000^\000k\000_\000\000\000\000\000_\000`\000\000\005\020\000`\000\000\000\000\000^\000k\000\000\000\000\000\000\000_\000\227\000\000\000\000\000`\001[\000\000\002\229\000\000\000\138\001X\000\000\000\160\001Y\000i\000\166\000\\\000i\000\000\000\\\000e\000\138\001\001\000e\000\000\000\000\000\000\000\000\000j\000i\000m\000\\\000\000\000\000\000\139\000e\001\018\000\000\000\140\000\000\000\000\000j\000m\000\000\000o\000\000\000\139\0010\000\000\000\000\000\140\000\000\000k\000\000\000\000\000\000\000o\000\000\000\000\000^\005\020\000\000\000^\000\000\000_\000k\000\000\000_\000`\000\000\000\000\000`\001\198\000\000\000^\000\000\000\000\000\138\000\000\000_\000\000\000\228\000\000\000`\000\000\001\199\000\000\000\000\000\\\000\000\000\138\000\000\000e\000i\000j\000\000\000i\000j\000m\000\000\000\000\000\000\000\139\000\000\000\000\000\000\000\140\000\000\000i\000j\000\000\000m\000o\000\175\000\000\000\139\000\190\000\000\000k\000\140\000\000\000k\000\000\000\000\000\000\000o\000\000\000\000\000\221\000\000\000\000\000^\000\000\000k\000\000\000\000\000_\000\000\000\000\000\000\000`\000\000\000\000\000\138\000\000\000\000\000\138\000\000\000\000\001\001\000\000\000\\\001\215\000\000\000\000\000e\000\000\000\000\000\138\000\211\000\000\000\236\000\000\001\020\000m\000i\001\228\000m\000\139\000\000\000\000\000\139\000\140\000j\000\000\000\140\000j\000\000\000o\000m\000\000\000o\000\000\000\139\000\000\000\000\000\000\000\140\000j\000\000\000\000\000\000\000\250\000o\000^\001\152\000\000\000k\000\000\000_\000k\000\000\000^\000`\000\000\000\213\000\000\001\156\000\000\000\214\000\000\000\000\000k\000\\\000\000\000\000\000\000\000e\000\000\000\000\000\000\000\000\000\138\000\000\000\000\000\138\000\000\000\000\000i\000\000\000\\\000\000\000\000\000\000\000e\000\000\000\227\000\138\000\000\000\000\000\000\000\000\000\000\000m\000\000\000j\000m\000\139\000\000\000\000\000\139\000\140\002u\000\000\000\140\002\142\000^\000o\000m\000\000\000o\000_\000\139\000\000\001\192\000`\000\140\000\000\000\000\000k\000\\\000\000\000o\000^\000e\000\000\000\000\000\000\000_\000\000\000\000\000\000\000`\000\000\000\000\000\000\000\000\000\000\000\\\000\000\000i\000\000\000e\000\000\000\138\002A\000\000\000\000\000\000\002w\000\000\000\000\000\000\002x\000\000\000\000\000\\\000i\000j\002u\000e\000\000\002\142\000^\000\000\000m\000\228\000\000\000_\000\139\000\000\000\000\000`\000\140\000\000\000\000\000\000\001\255\000\000\000o\000\000\000^\000k\000\\\000\000\000\000\000_\000e\000\000\000\000\000`\000\000\000\000\000\000\000\000\000\000\000\000\000i\000\000\000^\000\000\000\000\000^\000\000\000_\000\000\002w\000\138\000`\000\000\002x\000\000\000\000\000\000\000\\\000i\000\000\000\000\000e\000\000\000j\000\000\000\000\000\000\002u\000\000\000^\002\142\000m\000\000\000\000\000_\000\139\000i\001\001\000`\000\140\000j\000\000\002\023\000\000\000\\\000o\000\000\000k\000g\002\133\000\000\001\022\002\160\000\000\000\000\000\000\000\000\000\\\002\161\002>\000^\000g\002\134\000i\000k\000_\000\000\000\000\000\000\000`\000^\000\000\000\138\000\000\002w\000\000\000\000\000\000\002x\000\000\000j\000\000\000\000\000\000\000\000\000\000\000\000\000^\000\000\000\138\000\000\000\000\000_\000m\000i\000\000\000`\000\139\000j\002\127\000^\000\140\000\000\000\000\000k\000_\002\133\000o\000\000\000`\000m\000\000\002u\000\000\000\139\002\142\000j\002\145\000\140\002\134\000\000\000i\000k\000\000\000o\000\000\000\000\000\000\000\000\000\138\002u\002\164\000\000\002\142\000i\002\147\000\000\000-\000\000\000\000\000k\000-\000\000\000j\000\000\002\165\000\000\000\138\000\000\000\000\000m\000\000\000-\000\000\000\139\002A\000\000\000\000\000\140\002w\000\000\000-\003\150\002x\000o\000\138\000\000\000k\000m\000\000\000\000\002\133\000\139\002A\000j\000\000\000\140\002w\000\000\000\000\000\000\002x\000o\000\000\002\134\000\000\000m\000\000\002\164\000\000\000\139\001U\000\138\003\254\000\140\001U\000\000\000\000\000k\000\000\000o\000j\002\175\000\000\000\000\001O\001U\000\000\000\000\001O\000\000\000\000\000-\000m\000j\001U\000\000\000\139\000\000\000\000\001O\000\140\000\000\000\138\000\000\000k\000\000\000o\000\000\001O\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000k\000\000\000\000\000\000\000\000\000\000\000m\000\000\000\000\000\000\000\139\000\000\000l\000\000\000\140\002\164\000\000\000\000\002\133\000\000\000o\002\163\000\000\000\000\000\000\000l\000\000\002\161\001U\002\177\000\\\002\134\000\000\000m\000q\000\000\002\133\000\000\001\207\002\212\001@\000\000\001O\000\000\001@\002\161\000m\000o\000\000\002\134\000\000\001\209\001P\000\000\000\000\001@\001P\000\000\000\000\000\000\000o\000\000\000\000\000\000\001@\000\000\000\000\001P\000\000\000\000\000\000\000\000\000\000\000^\000\000\000\000\001P\000\000\000_\001[\000\000\002\240\000`\001[\001X\003\021\000\160\001Y\001X\000\166\000\160\001Y\000\000\000\166\001[\000\000\003+\000\000\000\000\001X\002\164\000\160\001Y\001[\000\166\003\170\000\000\000i\001X\000\000\000\160\001Y\000\000\000\166\002\165\001@\000\000\000\\\002\164\000\000\000\\\000q\000\000\000\000\000q\000\000\000\000\001P\000\000\000\000\000\\\000\000\002\165\000\\\000q\000\000\000\\\000q\000\000\000\000\000q\000\000\000\000\000\\\000\000\000\000\000\000\000q\000\000\000\000\000\000\000\000\000\000\000\\\001[\000\000\003\206\000q\000\000\001X\000^\000\160\001Y\000^\000\166\000_\000\000\000\000\000_\000`\000\000\000\000\000`\000^\000\000\000\211\000^\000\236\000_\000^\000\000\000_\000`\000\000\000_\000`\000^\000j\000`\001\182\001\203\000_\000\000\000\000\000i\000`\000^\000i\000\211\000\000\000\236\000_\000\000\000\000\000\000\000`\000\000\000i\000\000\000\000\000i\000k\000\000\000i\000\000\000\211\000\000\000\236\000^\000\000\000i\000\213\000\000\000\000\000\000\000\214\000\211\000\000\000\236\000\000\000i\000\000\000^\000\000\001\184\001\182\001\203\000\000\001\185\000\000\000\000\000^\000\000\000\000\000\213\000\000\001\182\001\203\000\214\000\000\000\000\000\000\000\227\000\000\000\000\000\000\000\000\000m\000^\000\000\000\000\000\213\000\000\001\182\001\203\000\214\000\000\000\000\000\000\000^\000\000\000|\000\213\000\000\000j\000\227\000\214\000j\000^\000\000\001\184\000\000\001\182\001\203\001\185\000\000\000\000\000j\000\000\000^\000j\001\184\000\227\000j\000\000\001\185\000\000\000\000\000k\000\000\000j\000k\000\000\000\227\000\000\000\000\000^\000\000\001\184\000\000\000j\000k\001\185\000\000\000k\000\000\000\000\000k\000\000\001\182\001\203\000\000\000\000\000\000\000k\000^\000\000\001\184\000\000\000\000\000\000\001\185\000\228\001\198\000k\002u\000\000\000\000\002\142\000\000\000\000\000\000\001\182\001\203\000m\000\000\001\199\000m\000\000\000\000\001\182\001\203\000\000\000\000\000\000\000\228\000\000\000m\000~\000\000\000m\000\128\000^\000m\001\184\000\000\000\000\000\000\001\185\000\000\000m\000\130\000\228\000\000\000\132\000\000\000\000\000\142\000^\001\198\000m\000\000\002w\000\228\000\144\000^\002x\001\184\000\000\000\000\001\198\001\185\001\199\000^\000\146\001\184\000\000\000\000\002u\001\185\001\001\002\142\000\000\001\199\000\000\002u\000\000\001\198\002\142\000\000\000\000\000\000\000\000\001\215\001\024\002u\000\000\000\000\002\142\000\000\001\199\002u\000\000\001\001\002\142\000\000\001\198\001\230\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\030\000\000\001\199\001\001\000^\000\000\000\000\000\000\002w\000\000\000\000\000^\002x\000\000\001\001\002w\000\000\001 \000\000\002x\002u\000^\001\215\002\142\000\000\002w\001\198\000^\001\"\002x\000\000\002w\000\000\001\215\000\000\002x\001\232\000\000\002u\001\199\000\000\002\142\002\133\000\000\000\000\000\000\000\000\001\234\000\000\001\198\001\215\000\000\000\000\000\000\000\000\002\134\000\000\001\198\000\000\000\000\000\000\000\000\001\199\000^\001\236\000\000\000\000\002w\000\000\001\215\001\199\002x\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000^\000\000\001\238\000\000\002w\000\000\000\000\000\000\002x\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\133\001\215\000\000\000\000\000\000\000\000\000\000\002\133\000\000\000\000\000\000\000\000\000\000\002\134\000\000\001\244\000\000\002\133\000\000\002\164\002\134\000\000\000\000\002\133\001\215\000\000\000\000\000\000\000\000\000\000\002\134\000\000\001\215\002\179\000\000\000\000\002\134\000\000\001\246\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\248\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\133\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\134\000\000\000\000\000\000\000\000\002\133\000\000\000\000\000\000\000\000\002\164\000\000\000\000\000\000\000\000\000\000\000\000\002\164\002\134\000\000\000\000\000\000\000\000\000\000\002\181\000\000\000\000\002\164\000\000\000\000\000\000\002\183\000\000\002\164\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\185\000\000\000\000\000\000\000\000\000\000\002\187\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\164\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\189\000\000\000\000\000\000\002\164\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\191")) + + let semantic_action = + [| + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + raise (MenhirLib.TableInterpreter.Accept _1)); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_eexpr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_aexpr = +# 1656 "parser_cocci_menhir.mly" + ( Ast0.set_arg_exp _1 ) +# 1465 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 65 "parser_cocci_menhir.mly" + (Parse_aux.list_info) +# 1486 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_aexpr = +# 1658 "parser_cocci_menhir.mly" + ( let (nm,lenname,pure,clt) = _1 in + let nm = P.clt2mcode nm clt in + let lenname = + match lenname with + Some nm -> Some(P.clt2mcode nm clt) + | None -> None in + Ast0.wrap(Ast0.MetaExprList(nm,lenname,pure)) ) +# 1499 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_ctype = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_aexpr = +# 1666 "parser_cocci_menhir.mly" + ( Ast0.set_arg_exp(Ast0.wrap(Ast0.TypeExp(_1))) ) +# 1523 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_any_strict = +# 1712 "parser_cocci_menhir.mly" + ( Ast.WhenAny ) +# 1545 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_any_strict = +# 1713 "parser_cocci_menhir.mly" + ( Ast.WhenStrict ) +# 1567 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_any_strict = +# 1714 "parser_cocci_menhir.mly" + ( Ast.WhenForall ) +# 1589 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_any_strict = +# 1715 "parser_cocci_menhir.mly" + ( Ast.WhenExists ) +# 1611 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_cast_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1190 "parser_cocci_menhir.mly" + ( _1 ) +# 1635 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 1667 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1192 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Mul _1 _2 _3 ) +# 1675 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 96 "parser_cocci_menhir.mly" + (Ast_cocci.arithOp * Data.clt) +# 1707 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1194 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in P.arith_op op _1 clt _3 ) +# 1715 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 97 "parser_cocci_menhir.mly" + (Data.clt) +# 1747 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1196 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Plus _1 _2 _3 ) +# 1755 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 97 "parser_cocci_menhir.mly" + (Data.clt) +# 1787 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1198 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Minus _1 _2 _3 ) +# 1795 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 95 "parser_cocci_menhir.mly" + (Ast_cocci.arithOp * Data.clt) +# 1827 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1200 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in P.arith_op op _1 clt _3 ) +# 1835 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 94 "parser_cocci_menhir.mly" + (Ast_cocci.logicalOp * Data.clt) +# 1867 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1202 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in P.logic_op op _1 clt _3 ) +# 1875 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 93 "parser_cocci_menhir.mly" + (Data.clt) +# 1907 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1204 "parser_cocci_menhir.mly" + ( P.logic_op Ast.Eq _1 _2 _3 ) +# 1915 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 93 "parser_cocci_menhir.mly" + (Data.clt) +# 1947 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1206 "parser_cocci_menhir.mly" + ( P.logic_op Ast.NotEq _1 _2 _3 ) +# 1955 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 92 "parser_cocci_menhir.mly" + (Data.clt) +# 1987 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1208 "parser_cocci_menhir.mly" + ( P.arith_op Ast.And _1 _2 _3 ) +# 1995 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 90 "parser_cocci_menhir.mly" + (Data.clt) +# 2027 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1210 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Or _1 _2 _3 ) +# 2035 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 91 "parser_cocci_menhir.mly" + (Data.clt) +# 2067 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1212 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Xor _1 _2 _3 ) +# 2075 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 89 "parser_cocci_menhir.mly" + (Data.clt) +# 2107 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1214 "parser_cocci_menhir.mly" + ( P.logic_op Ast.AndLog _1 _2 _3 ) +# 2115 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _3 in + let _2 : ( +# 88 "parser_cocci_menhir.mly" + (Data.clt) +# 2147 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_dot_expressions_ = +# 1216 "parser_cocci_menhir.mly" + ( P.logic_op Ast.OrLog _1 _2 _3 ) +# 2155 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_cast_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1190 "parser_cocci_menhir.mly" + ( _1 ) +# 2179 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 2211 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1192 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Mul _1 _2 _3 ) +# 2219 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 96 "parser_cocci_menhir.mly" + (Ast_cocci.arithOp * Data.clt) +# 2251 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1194 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in P.arith_op op _1 clt _3 ) +# 2259 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 97 "parser_cocci_menhir.mly" + (Data.clt) +# 2291 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1196 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Plus _1 _2 _3 ) +# 2299 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 97 "parser_cocci_menhir.mly" + (Data.clt) +# 2331 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1198 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Minus _1 _2 _3 ) +# 2339 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 95 "parser_cocci_menhir.mly" + (Ast_cocci.arithOp * Data.clt) +# 2371 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1200 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in P.arith_op op _1 clt _3 ) +# 2379 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 94 "parser_cocci_menhir.mly" + (Ast_cocci.logicalOp * Data.clt) +# 2411 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1202 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in P.logic_op op _1 clt _3 ) +# 2419 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 93 "parser_cocci_menhir.mly" + (Data.clt) +# 2451 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1204 "parser_cocci_menhir.mly" + ( P.logic_op Ast.Eq _1 _2 _3 ) +# 2459 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 93 "parser_cocci_menhir.mly" + (Data.clt) +# 2491 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1206 "parser_cocci_menhir.mly" + ( P.logic_op Ast.NotEq _1 _2 _3 ) +# 2499 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 92 "parser_cocci_menhir.mly" + (Data.clt) +# 2531 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1208 "parser_cocci_menhir.mly" + ( P.arith_op Ast.And _1 _2 _3 ) +# 2539 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 90 "parser_cocci_menhir.mly" + (Data.clt) +# 2571 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1210 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Or _1 _2 _3 ) +# 2579 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 91 "parser_cocci_menhir.mly" + (Data.clt) +# 2611 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1212 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Xor _1 _2 _3 ) +# 2619 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 89 "parser_cocci_menhir.mly" + (Data.clt) +# 2651 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1214 "parser_cocci_menhir.mly" + ( P.logic_op Ast.AndLog _1 _2 _3 ) +# 2659 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _3 in + let _2 : ( +# 88 "parser_cocci_menhir.mly" + (Data.clt) +# 2691 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_invalid_ = +# 1216 "parser_cocci_menhir.mly" + ( P.logic_op Ast.OrLog _1 _2 _3 ) +# 2699 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_cast_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1190 "parser_cocci_menhir.mly" + ( _1 ) +# 2723 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 2755 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1192 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Mul _1 _2 _3 ) +# 2763 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 96 "parser_cocci_menhir.mly" + (Ast_cocci.arithOp * Data.clt) +# 2795 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1194 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in P.arith_op op _1 clt _3 ) +# 2803 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 97 "parser_cocci_menhir.mly" + (Data.clt) +# 2835 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1196 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Plus _1 _2 _3 ) +# 2843 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 97 "parser_cocci_menhir.mly" + (Data.clt) +# 2875 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1198 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Minus _1 _2 _3 ) +# 2883 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 95 "parser_cocci_menhir.mly" + (Ast_cocci.arithOp * Data.clt) +# 2915 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1200 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in P.arith_op op _1 clt _3 ) +# 2923 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 94 "parser_cocci_menhir.mly" + (Ast_cocci.logicalOp * Data.clt) +# 2955 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1202 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in P.logic_op op _1 clt _3 ) +# 2963 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 93 "parser_cocci_menhir.mly" + (Data.clt) +# 2995 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1204 "parser_cocci_menhir.mly" + ( P.logic_op Ast.Eq _1 _2 _3 ) +# 3003 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 93 "parser_cocci_menhir.mly" + (Data.clt) +# 3035 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1206 "parser_cocci_menhir.mly" + ( P.logic_op Ast.NotEq _1 _2 _3 ) +# 3043 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 92 "parser_cocci_menhir.mly" + (Data.clt) +# 3075 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1208 "parser_cocci_menhir.mly" + ( P.arith_op Ast.And _1 _2 _3 ) +# 3083 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 90 "parser_cocci_menhir.mly" + (Data.clt) +# 3115 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1210 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Or _1 _2 _3 ) +# 3123 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 91 "parser_cocci_menhir.mly" + (Data.clt) +# 3155 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1212 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Xor _1 _2 _3 ) +# 3163 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 89 "parser_cocci_menhir.mly" + (Data.clt) +# 3195 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1214 "parser_cocci_menhir.mly" + ( P.logic_op Ast.AndLog _1 _2 _3 ) +# 3203 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _3 in + let _2 : ( +# 88 "parser_cocci_menhir.mly" + (Data.clt) +# 3235 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_eexpr_nest_expressions_ = +# 1216 "parser_cocci_menhir.mly" + ( P.logic_op Ast.OrLog _1 _2 _3 ) +# 3243 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_cast_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1190 "parser_cocci_menhir.mly" + ( _1 ) +# 3267 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 3299 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1192 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Mul _1 _2 _3 ) +# 3307 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 96 "parser_cocci_menhir.mly" + (Ast_cocci.arithOp * Data.clt) +# 3339 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1194 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in P.arith_op op _1 clt _3 ) +# 3347 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 97 "parser_cocci_menhir.mly" + (Data.clt) +# 3379 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1196 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Plus _1 _2 _3 ) +# 3387 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 97 "parser_cocci_menhir.mly" + (Data.clt) +# 3419 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1198 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Minus _1 _2 _3 ) +# 3427 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 95 "parser_cocci_menhir.mly" + (Ast_cocci.arithOp * Data.clt) +# 3459 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1200 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in P.arith_op op _1 clt _3 ) +# 3467 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 94 "parser_cocci_menhir.mly" + (Ast_cocci.logicalOp * Data.clt) +# 3499 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1202 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in P.logic_op op _1 clt _3 ) +# 3507 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 93 "parser_cocci_menhir.mly" + (Data.clt) +# 3539 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1204 "parser_cocci_menhir.mly" + ( P.logic_op Ast.Eq _1 _2 _3 ) +# 3547 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 93 "parser_cocci_menhir.mly" + (Data.clt) +# 3579 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1206 "parser_cocci_menhir.mly" + ( P.logic_op Ast.NotEq _1 _2 _3 ) +# 3587 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 92 "parser_cocci_menhir.mly" + (Data.clt) +# 3619 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1208 "parser_cocci_menhir.mly" + ( P.arith_op Ast.And _1 _2 _3 ) +# 3627 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 90 "parser_cocci_menhir.mly" + (Data.clt) +# 3659 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1210 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Or _1 _2 _3 ) +# 3667 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 91 "parser_cocci_menhir.mly" + (Data.clt) +# 3699 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1212 "parser_cocci_menhir.mly" + ( P.arith_op Ast.Xor _1 _2 _3 ) +# 3707 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 89 "parser_cocci_menhir.mly" + (Data.clt) +# 3739 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1214 "parser_cocci_menhir.mly" + ( P.logic_op Ast.AndLog _1 _2 _3 ) +# 3747 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_arith_expr_expr_invalid_ = Obj.magic _3 in + let _2 : ( +# 88 "parser_cocci_menhir.mly" + (Data.clt) +# 3779 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_arith_expr_expr_invalid_ = +# 1216 "parser_cocci_menhir.mly" + ( P.logic_op Ast.OrLog _1 _2 _3 ) +# 3787 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_arity = +# 435 "parser_cocci_menhir.mly" + ( Ast.UNIQUE ) +# 3809 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_arity = +# 436 "parser_cocci_menhir.mly" + ( Ast.OPT ) +# 3831 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_arity = +# 437 "parser_cocci_menhir.mly" + ( Ast.MULTI ) +# 3853 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_arity = +# 438 "parser_cocci_menhir.mly" + ( Ast.NONE ) +# 3870 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let r : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 3901 "parser_cocci_menhir.ml" + ) = Obj.magic r in + let i : 'tv_option_eexpr_ = Obj.magic i in + let l : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 3907 "parser_cocci_menhir.ml" + ) = Obj.magic l in + let _startpos = _startpos_l_ in + let _endpos = _endpos_r_ in + let _v : 'tv_array_dec = +# 1004 "parser_cocci_menhir.mly" + ( (l,i,r) ) +# 3914 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_cond_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_assign_expr_eexpr_dot_expressions_ = +# 1162 "parser_cocci_menhir.mly" + ( _1 ) +# 3938 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_assign_expr_bis = Obj.magic _3 in + let _2 : ( +# 107 "parser_cocci_menhir.mly" + (Ast_cocci.assignOp * Data.clt) +# 3970 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_unary_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_assign_expr_eexpr_dot_expressions_ = +# 1164 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in + Ast0.wrap(Ast0.Assignment(_1,P.clt2mcode op clt, + Ast0.set_arg_exp _3,false)) ) +# 3980 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_assign_expr_bis = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 4012 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_unary_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_assign_expr_eexpr_dot_expressions_ = +# 1168 "parser_cocci_menhir.mly" + ( Ast0.wrap + (Ast0.Assignment + (_1,P.clt2mcode Ast.SimpleAssign _2,Ast0.set_arg_exp _3,false)) ) +# 4022 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_cond_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_assign_expr_eexpr_nest_expressions_ = +# 1162 "parser_cocci_menhir.mly" + ( _1 ) +# 4046 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_assign_expr_bis = Obj.magic _3 in + let _2 : ( +# 107 "parser_cocci_menhir.mly" + (Ast_cocci.assignOp * Data.clt) +# 4078 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_unary_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_assign_expr_eexpr_nest_expressions_ = +# 1164 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in + Ast0.wrap(Ast0.Assignment(_1,P.clt2mcode op clt, + Ast0.set_arg_exp _3,false)) ) +# 4088 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_assign_expr_bis = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 4120 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_unary_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_assign_expr_eexpr_nest_expressions_ = +# 1168 "parser_cocci_menhir.mly" + ( Ast0.wrap + (Ast0.Assignment + (_1,P.clt2mcode Ast.SimpleAssign _2,Ast0.set_arg_exp _3,false)) ) +# 4130 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_cond_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_assign_expr_expr_invalid_ = +# 1162 "parser_cocci_menhir.mly" + ( _1 ) +# 4154 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_assign_expr_bis = Obj.magic _3 in + let _2 : ( +# 107 "parser_cocci_menhir.mly" + (Ast_cocci.assignOp * Data.clt) +# 4186 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_unary_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_assign_expr_expr_invalid_ = +# 1164 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in + Ast0.wrap(Ast0.Assignment(_1,P.clt2mcode op clt, + Ast0.set_arg_exp _3,false)) ) +# 4196 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_assign_expr_bis = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 4228 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_unary_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_assign_expr_expr_invalid_ = +# 1168 "parser_cocci_menhir.mly" + ( Ast0.wrap + (Ast0.Assignment + (_1,P.clt2mcode Ast.SimpleAssign _2,Ast0.set_arg_exp _3,false)) ) +# 4238 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_cond_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_assign_expr_bis = +# 1173 "parser_cocci_menhir.mly" + ( _1 ) +# 4262 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_assign_expr_bis = Obj.magic _3 in + let _2 : ( +# 107 "parser_cocci_menhir.mly" + (Ast_cocci.assignOp * Data.clt) +# 4294 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_unary_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_assign_expr_bis = +# 1175 "parser_cocci_menhir.mly" + ( let (op,clt) = _2 in + Ast0.wrap(Ast0.Assignment(_1,P.clt2mcode op clt, + Ast0.set_arg_exp _3,false)) ) +# 4304 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_assign_expr_bis = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 4336 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_unary_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_assign_expr_bis = +# 1179 "parser_cocci_menhir.mly" + ( Ast0.wrap + (Ast0.Assignment + (_1,P.clt2mcode Ast.SimpleAssign _2,Ast0.set_arg_exp _3,false)) ) +# 4346 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_assign_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_basic_expr_eexpr_dot_expressions_ = +# 1159 "parser_cocci_menhir.mly" + ( _1 ) +# 4370 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_assign_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_basic_expr_eexpr_nest_expressions_ = +# 1159 "parser_cocci_menhir.mly" + ( _1 ) +# 4394 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_assign_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_basic_expr_expr_invalid_ = +# 1159 "parser_cocci_menhir.mly" + ( _1 ) +# 4418 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_fun_start = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 4450 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 4455 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_case_line = +# 876 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Default(P.clt2mcode "default" _1,P.clt2mcode ":" _2,_3)) ) +# 4462 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let _4 : 'tv_fun_start = Obj.magic _4 in + let _3 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 4499 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_eexpr = Obj.magic _2 in + let _1 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 4505 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_case_line = +# 878 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Case(P.clt2mcode "case" _1,_2,P.clt2mcode ":" _3,_4)) ) +# 4512 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_unary_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_cast_expr_eexpr_dot_expressions_ = +# 1219 "parser_cocci_menhir.mly" + ( _1 ) +# 4536 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let e : 'tv_cast_expr_eexpr_dot_expressions_ = Obj.magic e in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 4573 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let t : 'tv_ctype = Obj.magic t in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 4579 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let _startpos = _startpos_lp_ in + let _endpos = _endpos_e_ in + let _v : 'tv_cast_expr_eexpr_dot_expressions_ = +# 1221 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Cast (P.clt2mcode "(" lp, t, + P.clt2mcode ")" rp, e)) ) +# 4587 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_unary_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_cast_expr_eexpr_invalid_ = +# 1219 "parser_cocci_menhir.mly" + ( _1 ) +# 4611 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let e : 'tv_cast_expr_eexpr_invalid_ = Obj.magic e in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 4648 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let t : 'tv_ctype = Obj.magic t in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 4654 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let _startpos = _startpos_lp_ in + let _endpos = _endpos_e_ in + let _v : 'tv_cast_expr_eexpr_invalid_ = +# 1221 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Cast (P.clt2mcode "(" lp, t, + P.clt2mcode ")" rp, e)) ) +# 4662 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_unary_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_cast_expr_eexpr_nest_expressions_ = +# 1219 "parser_cocci_menhir.mly" + ( _1 ) +# 4686 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let e : 'tv_cast_expr_eexpr_nest_expressions_ = Obj.magic e in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 4723 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let t : 'tv_ctype = Obj.magic t in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 4729 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let _startpos = _startpos_lp_ in + let _endpos = _endpos_e_ in + let _v : 'tv_cast_expr_eexpr_nest_expressions_ = +# 1221 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Cast (P.clt2mcode "(" lp, t, + P.clt2mcode ")" rp, e)) ) +# 4737 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_unary_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_cast_expr_expr_invalid_ = +# 1219 "parser_cocci_menhir.mly" + ( _1 ) +# 4761 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let e : 'tv_cast_expr_expr_invalid_ = Obj.magic e in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 4798 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let t : 'tv_ctype = Obj.magic t in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 4804 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let _startpos = _startpos_lp_ in + let _endpos = _endpos_e_ in + let _v : 'tv_cast_expr_expr_invalid_ = +# 1221 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Cast (P.clt2mcode "(" lp, t, + P.clt2mcode ")" rp, e)) ) +# 4812 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_separated_nonempty_list_TComma_TString_ = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_choose_iso = +# 227 "parser_cocci_menhir.mly" + ( List.map P.id2name _2 ) +# 4840 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 4866 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 4871 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_comma_decls_TEllipsis_decl_ = +# 1470 "parser_cocci_menhir.mly" + ( function dot_builder -> + [Ast0.wrap(Ast0.PComma(P.clt2mcode "," _1)); + dot_builder _2] ) +# 4880 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_one_dec_decl_ = Obj.magic _2 in + let _1 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 4907 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_comma_decls_TEllipsis_decl_ = +# 1474 "parser_cocci_menhir.mly" + ( function dot_builder -> + [Ast0.wrap(Ast0.PComma(P.clt2mcode "," _1)); _2] ) +# 4915 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 4941 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 4946 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_comma_decls_TEllipsis_name_opt_decl_ = +# 1470 "parser_cocci_menhir.mly" + ( function dot_builder -> + [Ast0.wrap(Ast0.PComma(P.clt2mcode "," _1)); + dot_builder _2] ) +# 4955 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_one_dec_name_opt_decl_ = Obj.magic _2 in + let _1 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 4982 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_comma_decls_TEllipsis_name_opt_decl_ = +# 1474 "parser_cocci_menhir.mly" + ( function dot_builder -> + [Ast0.wrap(Ast0.PComma(P.clt2mcode "," _1)); _2] ) +# 4990 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_comma_initializers_edots_when_TEllipsis_initialize__ = +# 1051 "parser_cocci_menhir.mly" + ( [] ) +# 5007 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let r : 'tv_comma_initializers2_edots_when_TEllipsis_initialize__ = Obj.magic r in + let d : 'tv_edots_when_TEllipsis_initialize_ = Obj.magic d in + let _startpos = _startpos_d_ in + let _endpos = _endpos_r_ in + let _v : 'tv_comma_initializers_edots_when_TEllipsis_initialize__ = +# 1053 "parser_cocci_menhir.mly" + ( (function dot_builder -> [dot_builder d])::r ) +# 5037 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = c; + MenhirLib.EngineTypes.startp = _startpos_c_; + MenhirLib.EngineTypes.endp = _endpos_c_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let r : 'tv_comma_initializers_edots_when_TEllipsis_initialize__ = Obj.magic r in + let c : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 5069 "parser_cocci_menhir.ml" + ) = Obj.magic c in + let i : 'tv_initialize2 = Obj.magic i in + let _startpos = _startpos_i_ in + let _endpos = _endpos_r_ in + let _v : 'tv_comma_initializers_edots_when_TEllipsis_initialize__ = +# 1055 "parser_cocci_menhir.mly" + ( (function dot_builder -> [i; Ast0.wrap(Ast0.IComma(P.clt2mcode "," c))]):: + r ) +# 5078 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_comma_initializers2_edots_when_TEllipsis_initialize__ = +# 1059 "parser_cocci_menhir.mly" + ( [] ) +# 5095 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = c; + MenhirLib.EngineTypes.startp = _startpos_c_; + MenhirLib.EngineTypes.endp = _endpos_c_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let r : 'tv_comma_initializers_edots_when_TEllipsis_initialize__ = Obj.magic r in + let c : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 5127 "parser_cocci_menhir.ml" + ) = Obj.magic c in + let i : 'tv_initialize2 = Obj.magic i in + let _startpos = _startpos_i_ in + let _endpos = _endpos_r_ in + let _v : 'tv_comma_initializers2_edots_when_TEllipsis_initialize__ = +# 1061 "parser_cocci_menhir.mly" + ( (function dot_builder -> [i; Ast0.wrap(Ast0.IComma(P.clt2mcode "," c))]):: + r ) +# 5136 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_separated_nonempty_list_TComma_any_strict_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_comma_list_any_strict_ = +# 1688 "parser_cocci_menhir.mly" + ( _1 ) +# 5160 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_separated_nonempty_list_TComma_ctype_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_comma_list_ctype_ = +# 1688 "parser_cocci_menhir.mly" + ( _1 ) +# 5184 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_separated_nonempty_list_TComma_d_ident_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_comma_list_d_ident_ = +# 1688 "parser_cocci_menhir.mly" + ( _1 ) +# 5208 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_separated_nonempty_list_TComma_dexpr_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_comma_list_dexpr_ = +# 1688 "parser_cocci_menhir.mly" + ( _1 ) +# 5232 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_separated_nonempty_list_TComma_ident_or_const_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_comma_list_ident_or_const_ = +# 1688 "parser_cocci_menhir.mly" + ( _1 ) +# 5256 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_separated_nonempty_list_TComma_meta_ident_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_comma_list_meta_ident_ = +# 1688 "parser_cocci_menhir.mly" + ( _1 ) +# 5280 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_separated_nonempty_list_TComma_pure_ident_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_comma_list_pure_ident_ = +# 1688 "parser_cocci_menhir.mly" + ( _1 ) +# 5304 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_comma_list_pure_ident_or_meta_ident_ = +# 1688 "parser_cocci_menhir.mly" + ( _1 ) +# 5328 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_ceq__ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_ceq__ = +# 1688 "parser_cocci_menhir.mly" + ( _1 ) +# 5352 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_eq__ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eq__ = +# 1688 "parser_cocci_menhir.mly" + ( _1 ) +# 5376 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = +# 1688 "parser_cocci_menhir.mly" + ( _1 ) +# 5400 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_pos__ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_pos__ = +# 1688 "parser_cocci_menhir.mly" + ( _1 ) +# 5424 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_cond_expr_eexpr_dot_expressions_ = +# 1184 "parser_cocci_menhir.mly" + ( _1 ) +# 5448 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = dd; + MenhirLib.EngineTypes.startp = _startpos_dd_; + MenhirLib.EngineTypes.endp = _endpos_dd_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let r : 'tv_cond_expr_eexpr_dot_expressions_ = Obj.magic r in + let dd : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 5490 "parser_cocci_menhir.ml" + ) = Obj.magic dd in + let t : 'tv_option_eexpr_ = Obj.magic t in + let w : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 5496 "parser_cocci_menhir.ml" + ) = Obj.magic w in + let l : 'tv_arith_expr_eexpr_dot_expressions_ = Obj.magic l in + let _startpos = _startpos_l_ in + let _endpos = _endpos_r_ in + let _v : 'tv_cond_expr_eexpr_dot_expressions_ = +# 1186 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.CondExpr (l, P.clt2mcode "?" w, t, + P.clt2mcode ":" dd, r)) ) +# 5505 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_cond_expr_eexpr_nest_expressions_ = +# 1184 "parser_cocci_menhir.mly" + ( _1 ) +# 5529 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = dd; + MenhirLib.EngineTypes.startp = _startpos_dd_; + MenhirLib.EngineTypes.endp = _endpos_dd_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let r : 'tv_cond_expr_eexpr_nest_expressions_ = Obj.magic r in + let dd : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 5571 "parser_cocci_menhir.ml" + ) = Obj.magic dd in + let t : 'tv_option_eexpr_ = Obj.magic t in + let w : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 5577 "parser_cocci_menhir.ml" + ) = Obj.magic w in + let l : 'tv_arith_expr_eexpr_nest_expressions_ = Obj.magic l in + let _startpos = _startpos_l_ in + let _endpos = _endpos_r_ in + let _v : 'tv_cond_expr_eexpr_nest_expressions_ = +# 1186 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.CondExpr (l, P.clt2mcode "?" w, t, + P.clt2mcode ":" dd, r)) ) +# 5586 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_arith_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_cond_expr_expr_invalid_ = +# 1184 "parser_cocci_menhir.mly" + ( _1 ) +# 5610 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = dd; + MenhirLib.EngineTypes.startp = _startpos_dd_; + MenhirLib.EngineTypes.endp = _endpos_dd_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let r : 'tv_cond_expr_expr_invalid_ = Obj.magic r in + let dd : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 5652 "parser_cocci_menhir.ml" + ) = Obj.magic dd in + let t : 'tv_option_eexpr_ = Obj.magic t in + let w : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 5658 "parser_cocci_menhir.ml" + ) = Obj.magic w in + let l : 'tv_arith_expr_expr_invalid_ = Obj.magic l in + let _startpos = _startpos_l_ in + let _endpos = _endpos_r_ in + let _v : 'tv_cond_expr_expr_invalid_ = +# 1186 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.CondExpr (l, P.clt2mcode "?" w, t, + P.clt2mcode ":" dd, r)) ) +# 5667 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 54 "parser_cocci_menhir.mly" + (Data.clt) +# 5688 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_const_vol = +# 797 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.Const _1 ) +# 5695 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 54 "parser_cocci_menhir.mly" + (Data.clt) +# 5716 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_const_vol = +# 798 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.Volatile _1 ) +# 5723 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_continue_struct_decl_list = +# 516 "parser_cocci_menhir.mly" + ( [] ) +# 5740 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_struct_decl_list_start = Obj.magic _2 in + let _1 : 'tv_struct_decl = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_continue_struct_decl_list = +# 517 "parser_cocci_menhir.mly" + ( _1@_2 ) +# 5770 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_struct_decl = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_continue_struct_decl_list = +# 518 "parser_cocci_menhir.mly" + ( _1 ) +# 5794 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ty; + MenhirLib.EngineTypes.startp = _startpos_ty_; + MenhirLib.EngineTypes.endp = _endpos_ty_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let m : 'tv_list_TMul_ = Obj.magic m in + let ty : 'tv_generic_ctype = Obj.magic ty in + let _startpos = _startpos_ty_ in + let _endpos = _endpos_m_ in + let _v : 'tv_ctype = let cv = + +# 39 "standard.mly" + ( None ) +# 5825 "parser_cocci_menhir.ml" + + in + +# 522 "parser_cocci_menhir.mly" + ( P.pointerify (P.make_cv cv ty) m ) +# 5831 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ty; + MenhirLib.EngineTypes.startp = _startpos_ty_; + MenhirLib.EngineTypes.endp = _endpos_ty_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let m : 'tv_list_TMul_ = Obj.magic m in + let ty : 'tv_generic_ctype = Obj.magic ty in + let x0 : 'tv_const_vol = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_m_ in + let _v : 'tv_ctype = let cv = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 5869 "parser_cocci_menhir.ml" + + in + +# 522 "parser_cocci_menhir.mly" + ( P.pointerify (P.make_cv cv ty) m ) +# 5875 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let m : 'tv_nonempty_list_TMul_ = Obj.magic m in + let t : ( +# 50 "parser_cocci_menhir.mly" + (Data.clt) +# 5902 "parser_cocci_menhir.ml" + ) = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_m_ in + let _v : 'tv_ctype = let cv = + +# 39 "standard.mly" + ( None ) +# 5910 "parser_cocci_menhir.ml" + + in + +# 524 "parser_cocci_menhir.mly" + ( let ty = + Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in + P.pointerify (P.make_cv cv ty) m ) +# 5918 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let m : 'tv_nonempty_list_TMul_ = Obj.magic m in + let t : ( +# 50 "parser_cocci_menhir.mly" + (Data.clt) +# 5950 "parser_cocci_menhir.ml" + ) = Obj.magic t in + let x0 : 'tv_const_vol = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_m_ in + let _v : 'tv_ctype = let cv = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 5960 "parser_cocci_menhir.ml" + + in + +# 524 "parser_cocci_menhir.mly" + ( let ty = + Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in + P.pointerify (P.make_cv cv ty) m ) +# 5968 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 5999 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let t : 'tv_midzero_list_ctype_ctype_ = Obj.magic t in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 6005 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let _startpos = _startpos_lp_ in + let _endpos = _endpos_rp_ in + let _v : 'tv_ctype = +# 529 "parser_cocci_menhir.mly" + ( let (mids,code) = t in + Ast0.wrap + (Ast0.DisjType(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) ) +# 6014 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 51 "parser_cocci_menhir.mly" + (Data.clt) +# 6035 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_ctype_qualif = +# 542 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.Unsigned _1 ) +# 6042 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 51 "parser_cocci_menhir.mly" + (Data.clt) +# 6063 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_ctype_qualif = +# 543 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.Signed _1 ) +# 6070 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_list_array_dec_ = Obj.magic _2 in + let _1 : 'tv_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_d_ident = +# 995 "parser_cocci_menhir.mly" + ( (_1, + function t -> + List.fold_right + (function (l,i,r) -> + function rest -> + Ast0.wrap + (Ast0.Array(rest,P.clt2mcode "[" l,i,P.clt2mcode "]" r))) + _2 t) ) +# 6107 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let i : 'tv_ident = Obj.magic i in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_i_ in + let _v : 'tv_decl = +# 768 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Param(t, Some i)) ) +# 6137 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = rp1; + MenhirLib.EngineTypes.startp = _startpos_rp1_; + MenhirLib.EngineTypes.endp = _endpos_rp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp1; + MenhirLib.EngineTypes.startp = _startpos_lp1_; + MenhirLib.EngineTypes.endp = _endpos_lp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let rp1 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 6193 "parser_cocci_menhir.ml" + ) = Obj.magic rp1 in + let d : 'tv_decl_list_name_opt_decl_ = Obj.magic d in + let lp1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 6199 "parser_cocci_menhir.ml" + ) = Obj.magic lp1 in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 6204 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let i : 'tv_ident = Obj.magic i in + let s : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 6210 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 6215 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let t : 'tv_fn_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_rp1_ in + let _v : 'tv_decl = +# 771 "parser_cocci_menhir.mly" + ( let fnptr = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp,P.clt2mcode "*" s,P.clt2mcode ")" rp, + P.clt2mcode "(" lp1,d,P.clt2mcode ")" rp1)) in + Ast0.wrap(Ast0.Param(fnptr, Some i)) ) +# 6228 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let t : ( +# 50 "parser_cocci_menhir.mly" + (Data.clt) +# 6249 "parser_cocci_menhir.ml" + ) = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_t_ in + let _v : 'tv_decl = +# 778 "parser_cocci_menhir.mly" + ( let ty = Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in + Ast0.wrap(Ast0.VoidParam(ty)) ) +# 6257 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 64 "parser_cocci_menhir.mly" + (Parse_aux.info) +# 6278 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl = +# 781 "parser_cocci_menhir.mly" + ( let (nm,pure,clt) = _1 in + Ast0.wrap(Ast0.MetaParam(P.clt2mcode nm clt,pure)) ) +# 6286 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 59 "parser_cocci_menhir.mly" + (string * Data.clt) +# 6307 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl_ident = +# 1420 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Id(P.id2mcode _1)) ) +# 6314 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 62 "parser_cocci_menhir.mly" + (Parse_aux.idinfo) +# 6335 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl_ident = +# 1422 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,clt) = _1 in + Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) ) +# 6343 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_decl_list_start_decl_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl_list_decl_ = +# 1443 "parser_cocci_menhir.mly" + (let circle x = + match Ast0.unwrap x with Ast0.Pcircles(_) -> true | _ -> false in + if List.exists circle _1 + then Ast0.wrap(Ast0.CIRCLES(_1)) + else Ast0.wrap(Ast0.DOTS(_1)) ) +# 6371 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_decl_list_start_name_opt_decl_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl_list_name_opt_decl_ = +# 1443 "parser_cocci_menhir.mly" + (let circle x = + match Ast0.unwrap x with Ast0.Pcircles(_) -> true | _ -> false in + if List.exists circle _1 + then Ast0.wrap(Ast0.CIRCLES(_1)) + else Ast0.wrap(Ast0.DOTS(_1)) ) +# 6399 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_one_dec_decl_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl_list_start_decl_ = +# 1450 "parser_cocci_menhir.mly" + ( [_1] ) +# 6423 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_decl_list_start_decl_ = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 6455 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_one_dec_decl_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_decl_list_start_decl_ = +# 1452 "parser_cocci_menhir.mly" + ( _1::Ast0.wrap(Ast0.PComma(P.clt2mcode "," _2))::_3 ) +# 6463 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_list_comma_decls_TEllipsis_decl__ = Obj.magic _2 in + let _1 : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 6490 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_decl_list_start_decl_ = +# 1454 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Pdots(P.clt2mcode "..." _1)):: + (List.concat(List.map (function x -> x (P.mkpdots "...")) _2)) ) +# 6498 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_one_dec_name_opt_decl_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl_list_start_name_opt_decl_ = +# 1450 "parser_cocci_menhir.mly" + ( [_1] ) +# 6522 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_decl_list_start_name_opt_decl_ = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 6554 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_one_dec_name_opt_decl_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_decl_list_start_name_opt_decl_ = +# 1452 "parser_cocci_menhir.mly" + ( _1::Ast0.wrap(Ast0.PComma(P.clt2mcode "," _2))::_3 ) +# 6562 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_list_comma_decls_TEllipsis_name_opt_decl__ = Obj.magic _2 in + let _1 : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 6589 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_decl_list_start_name_opt_decl_ = +# 1454 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Pdots(P.clt2mcode "..." _1)):: + (List.concat(List.map (function x -> x (P.mkpdots "...")) _2)) ) +# 6597 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 64 "parser_cocci_menhir.mly" + (Parse_aux.info) +# 6618 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl_statement = +# 1067 "parser_cocci_menhir.mly" + ( let (nm,pure,clt) = _1 in + [Ast0.wrap(Ast0.MetaStmt(P.clt2mcode nm clt,pure))] ) +# 6626 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_decl_var = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl_statement = +# 1070 "parser_cocci_menhir.mly" + ( List.map + (function x -> + Ast0.wrap + (Ast0.Decl((Ast0.default_info(),Ast0.context_befaft()),x))) + _1 ) +# 6654 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_statement = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl_statement = +# 1075 "parser_cocci_menhir.mly" + ( [_1] ) +# 6678 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 6709 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let t : 'tv_midzero_list_fun_start_fun_start_ = Obj.magic t in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 6715 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_decl_statement = +# 1084 "parser_cocci_menhir.mly" + ( let (mids,code) = t in + if List.for_all + (function x -> + match Ast0.unwrap x with Ast0.DOTS([]) -> true | _ -> false) + code + then [] + else + [Ast0.wrap(Ast0.Disj(P.clt2mcode "(" _1, code, mids, + P.clt2mcode ")" _3))] ) +# 6730 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 64 "parser_cocci_menhir.mly" + (Parse_aux.info) +# 6751 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl_statement_expr = +# 1097 "parser_cocci_menhir.mly" + ( let (nm,pure,clt) = _1 in + [Ast0.wrap(Ast0.MetaStmt(P.clt2mcode nm clt,pure))] ) +# 6759 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_decl_var = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl_statement_expr = +# 1100 "parser_cocci_menhir.mly" + ( List.map + (function x -> + Ast0.wrap + (Ast0.Decl((Ast0.default_info(),Ast0.context_befaft()),x))) + _1 ) +# 6787 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_statement = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_decl_statement_expr = +# 1105 "parser_cocci_menhir.mly" + ( [_1] ) +# 6811 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 6842 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let t : 'tv_midzero_list_fun_after_stm_fun_after_dots_or_ = Obj.magic t in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 6848 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_decl_statement_expr = +# 1114 "parser_cocci_menhir.mly" + ( let (mids,code) = t in + if List.for_all (function [] -> true | _ -> false) code + then [] + else + let dot_code = + List.map (function x -> Ast0.wrap(Ast0.DOTS x)) code in + [Ast0.wrap(Ast0.Disj(P.clt2mcode "(" _1, dot_code, mids, + P.clt2mcode ")" _3))] ) +# 6862 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 6888 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = +# 886 "parser_cocci_menhir.mly" + ( [Ast0.wrap(Ast0.TyDecl(t,P.clt2mcode ";" pv))] ) +# 6896 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 6927 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_comma_list_d_ident_ = Obj.magic d in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let s = + +# 39 "standard.mly" + ( None ) +# 6937 "parser_cocci_menhir.ml" + + in + +# 888 "parser_cocci_menhir.mly" + ( List.map + (function (id,fn) -> + Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv))) + d ) +# 6946 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 6982 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_comma_list_d_ident_ = Obj.magic d in + let t : 'tv_ctype = Obj.magic t in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 6994 "parser_cocci_menhir.ml" + + in + +# 888 "parser_cocci_menhir.mly" + ( List.map + (function (id,fn) -> + Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv))) + d ) +# 7003 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = f; + MenhirLib.EngineTypes.startp = _startpos_f_; + MenhirLib.EngineTypes.endp = _endpos_f_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let f : 'tv_funproto = Obj.magic f in + let _startpos = _startpos_f_ in + let _endpos = _endpos_f_ in + let _v : 'tv_decl_var = +# 892 "parser_cocci_menhir.mly" + ( [f] ) +# 7027 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7068 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7074 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let d : 'tv_d_ident = Obj.magic d in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let s = + +# 39 "standard.mly" + ( None ) +# 7084 "parser_cocci_menhir.ml" + + in + +# 894 "parser_cocci_menhir.mly" + (let (id,fn) = d in + [Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv))]) +# 7091 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7137 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7143 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let d : 'tv_d_ident = Obj.magic d in + let t : 'tv_ctype = Obj.magic t in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 7155 "parser_cocci_menhir.ml" + + in + +# 894 "parser_cocci_menhir.mly" + (let (id,fn) = d in + [Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv))]) +# 7162 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7193 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_comma_list_d_ident_ = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let _startpos = _startpos_i_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let cv = + +# 39 "standard.mly" + ( None ) +# 7203 "parser_cocci_menhir.ml" + + in + let s = + +# 39 "standard.mly" + ( None ) +# 7210 "parser_cocci_menhir.ml" + + in + +# 899 "parser_cocci_menhir.mly" + ( List.map + (function (id,fn) -> + let idtype = + P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.UnInit(s,fn idtype,id,P.clt2mcode ";" pv))) + d ) +# 7221 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7257 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_comma_list_d_ident_ = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x0 : 'tv_const_vol = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let cv = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 7269 "parser_cocci_menhir.ml" + + in + let s = + +# 39 "standard.mly" + ( None ) +# 7276 "parser_cocci_menhir.ml" + + in + +# 899 "parser_cocci_menhir.mly" + ( List.map + (function (id,fn) -> + let idtype = + P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.UnInit(s,fn idtype,id,P.clt2mcode ";" pv))) + d ) +# 7287 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7323 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_comma_list_d_ident_ = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let cv = + +# 39 "standard.mly" + ( None ) +# 7334 "parser_cocci_menhir.ml" + + in + let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 7342 "parser_cocci_menhir.ml" + + in + +# 899 "parser_cocci_menhir.mly" + ( List.map + (function (id,fn) -> + let idtype = + P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.UnInit(s,fn idtype,id,P.clt2mcode ";" pv))) + d ) +# 7353 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = x1; + MenhirLib.EngineTypes.startp = _startpos_x1_; + MenhirLib.EngineTypes.endp = _endpos_x1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7394 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_comma_list_d_ident_ = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x1 : 'tv_const_vol = Obj.magic x1 in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let cv = + let x = x1 in + +# 41 "standard.mly" + ( Some x ) +# 7407 "parser_cocci_menhir.ml" + + in + let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 7415 "parser_cocci_menhir.ml" + + in + +# 899 "parser_cocci_menhir.mly" + ( List.map + (function (id,fn) -> + let idtype = + P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.UnInit(s,fn idtype,id,P.clt2mcode ";" pv))) + d ) +# 7426 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7467 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7473 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let _startpos = _startpos_i_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let cv = + +# 39 "standard.mly" + ( None ) +# 7483 "parser_cocci_menhir.ml" + + in + let s = + +# 39 "standard.mly" + ( None ) +# 7490 "parser_cocci_menhir.ml" + + in + +# 907 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + !Data.add_type_name (P.id2name i); + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + [Ast0.wrap(Ast0.Init(s,fn idtype,id,P.clt2mcode "=" q,e, + P.clt2mcode ";" pv))] ) +# 7500 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7546 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7552 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x0 : 'tv_const_vol = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let cv = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 7564 "parser_cocci_menhir.ml" + + in + let s = + +# 39 "standard.mly" + ( None ) +# 7571 "parser_cocci_menhir.ml" + + in + +# 907 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + !Data.add_type_name (P.id2name i); + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + [Ast0.wrap(Ast0.Init(s,fn idtype,id,P.clt2mcode "=" q,e, + P.clt2mcode ";" pv))] ) +# 7581 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7627 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7633 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let cv = + +# 39 "standard.mly" + ( None ) +# 7644 "parser_cocci_menhir.ml" + + in + let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 7652 "parser_cocci_menhir.ml" + + in + +# 907 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + !Data.add_type_name (P.id2name i); + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + [Ast0.wrap(Ast0.Init(s,fn idtype,id,P.clt2mcode "=" q,e, + P.clt2mcode ";" pv))] ) +# 7662 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = x1; + MenhirLib.EngineTypes.startp = _startpos_x1_; + MenhirLib.EngineTypes.endp = _endpos_x1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7713 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7719 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x1 : 'tv_const_vol = Obj.magic x1 in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let cv = + let x = x1 in + +# 41 "standard.mly" + ( Some x ) +# 7732 "parser_cocci_menhir.ml" + + in + let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 7740 "parser_cocci_menhir.ml" + + in + +# 907 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + !Data.add_type_name (P.id2name i); + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + [Ast0.wrap(Ast0.Init(s,fn idtype,id,P.clt2mcode "=" q,e, + P.clt2mcode ";" pv))] ) +# 7750 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp2; + MenhirLib.EngineTypes.startp = _startpos_rp2_; + MenhirLib.EngineTypes.endp = _endpos_rp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp2; + MenhirLib.EngineTypes.startp = _startpos_lp2_; + MenhirLib.EngineTypes.endp = _endpos_lp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp1; + MenhirLib.EngineTypes.startp = _startpos_rp1_; + MenhirLib.EngineTypes.endp = _endpos_rp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = st; + MenhirLib.EngineTypes.startp = _startpos_st_; + MenhirLib.EngineTypes.endp = _endpos_st_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp1; + MenhirLib.EngineTypes.startp = _startpos_lp1_; + MenhirLib.EngineTypes.endp = _endpos_lp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7811 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let rp2 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 7816 "parser_cocci_menhir.ml" + ) = Obj.magic rp2 in + let p : 'tv_decl_list_name_opt_decl_ = Obj.magic p in + let lp2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 7822 "parser_cocci_menhir.ml" + ) = Obj.magic lp2 in + let rp1 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 7827 "parser_cocci_menhir.ml" + ) = Obj.magic rp1 in + let d : 'tv_d_ident = Obj.magic d in + let st : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 7833 "parser_cocci_menhir.ml" + ) = Obj.magic st in + let lp1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 7838 "parser_cocci_menhir.ml" + ) = Obj.magic lp1 in + let t : 'tv_fn_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let s = + +# 39 "standard.mly" + ( None ) +# 7847 "parser_cocci_menhir.ml" + + in + +# 917 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + [Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv))] ) +# 7859 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp2; + MenhirLib.EngineTypes.startp = _startpos_rp2_; + MenhirLib.EngineTypes.endp = _endpos_rp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp2; + MenhirLib.EngineTypes.startp = _startpos_lp2_; + MenhirLib.EngineTypes.endp = _endpos_lp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp1; + MenhirLib.EngineTypes.startp = _startpos_rp1_; + MenhirLib.EngineTypes.endp = _endpos_rp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = st; + MenhirLib.EngineTypes.startp = _startpos_st_; + MenhirLib.EngineTypes.endp = _endpos_st_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp1; + MenhirLib.EngineTypes.startp = _startpos_lp1_; + MenhirLib.EngineTypes.endp = _endpos_lp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 7925 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let rp2 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 7930 "parser_cocci_menhir.ml" + ) = Obj.magic rp2 in + let p : 'tv_decl_list_name_opt_decl_ = Obj.magic p in + let lp2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 7936 "parser_cocci_menhir.ml" + ) = Obj.magic lp2 in + let rp1 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 7941 "parser_cocci_menhir.ml" + ) = Obj.magic rp1 in + let d : 'tv_d_ident = Obj.magic d in + let st : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 7947 "parser_cocci_menhir.ml" + ) = Obj.magic st in + let lp1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 7952 "parser_cocci_menhir.ml" + ) = Obj.magic lp1 in + let t : 'tv_fn_ctype = Obj.magic t in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 7963 "parser_cocci_menhir.ml" + + in + +# 917 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + [Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv))] ) +# 7975 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _5; + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let _5 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 8016 "parser_cocci_menhir.ml" + ) = Obj.magic _5 in + let _4 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 8021 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr_list_option = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 8027 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_decl_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__5_ in + let _v : 'tv_decl_var = +# 925 "parser_cocci_menhir.mly" + ( [Ast0.wrap(Ast0.MacroDecl(_1,P.clt2mcode "(" _2,_3, + P.clt2mcode ")" _4,P.clt2mcode ";" _5))] ) +# 8036 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp2; + MenhirLib.EngineTypes.startp = _startpos_rp2_; + MenhirLib.EngineTypes.endp = _endpos_rp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp2; + MenhirLib.EngineTypes.startp = _startpos_lp2_; + MenhirLib.EngineTypes.endp = _endpos_lp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp1; + MenhirLib.EngineTypes.startp = _startpos_rp1_; + MenhirLib.EngineTypes.endp = _endpos_rp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = st; + MenhirLib.EngineTypes.startp = _startpos_st_; + MenhirLib.EngineTypes.endp = _endpos_st_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp1; + MenhirLib.EngineTypes.startp = _startpos_lp1_; + MenhirLib.EngineTypes.endp = _endpos_lp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 8107 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 8113 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let rp2 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 8118 "parser_cocci_menhir.ml" + ) = Obj.magic rp2 in + let p : 'tv_decl_list_name_opt_decl_ = Obj.magic p in + let lp2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 8124 "parser_cocci_menhir.ml" + ) = Obj.magic lp2 in + let rp1 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 8129 "parser_cocci_menhir.ml" + ) = Obj.magic rp1 in + let d : 'tv_d_ident = Obj.magic d in + let st : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 8135 "parser_cocci_menhir.ml" + ) = Obj.magic st in + let lp1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 8140 "parser_cocci_menhir.ml" + ) = Obj.magic lp1 in + let t : 'tv_fn_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let s = + +# 39 "standard.mly" + ( None ) +# 8149 "parser_cocci_menhir.ml" + + in + +# 931 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + [Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv))]) +# 8161 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp2; + MenhirLib.EngineTypes.startp = _startpos_rp2_; + MenhirLib.EngineTypes.endp = _endpos_rp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp2; + MenhirLib.EngineTypes.startp = _startpos_lp2_; + MenhirLib.EngineTypes.endp = _endpos_lp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp1; + MenhirLib.EngineTypes.startp = _startpos_rp1_; + MenhirLib.EngineTypes.endp = _endpos_rp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = st; + MenhirLib.EngineTypes.startp = _startpos_st_; + MenhirLib.EngineTypes.endp = _endpos_st_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp1; + MenhirLib.EngineTypes.startp = _startpos_lp1_; + MenhirLib.EngineTypes.endp = _endpos_lp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 8237 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 8243 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let rp2 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 8248 "parser_cocci_menhir.ml" + ) = Obj.magic rp2 in + let p : 'tv_decl_list_name_opt_decl_ = Obj.magic p in + let lp2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 8254 "parser_cocci_menhir.ml" + ) = Obj.magic lp2 in + let rp1 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 8259 "parser_cocci_menhir.ml" + ) = Obj.magic rp1 in + let d : 'tv_d_ident = Obj.magic d in + let st : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 8265 "parser_cocci_menhir.ml" + ) = Obj.magic st in + let lp1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 8270 "parser_cocci_menhir.ml" + ) = Obj.magic lp1 in + let t : 'tv_fn_ctype = Obj.magic t in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 8281 "parser_cocci_menhir.ml" + + in + +# 931 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + [Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv))]) +# 8293 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = id; + MenhirLib.EngineTypes.startp = _startpos_id_; + MenhirLib.EngineTypes.endp = _endpos_id_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 8329 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let id : 'tv_typedef_ident = Obj.magic id in + let t : 'tv_ctype = Obj.magic t in + let s : ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 8336 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_decl_var = +# 939 "parser_cocci_menhir.mly" + ( let s = P.clt2mcode "typedef" s in + [Ast0.wrap(Ast0.Typedef(s,t,id,P.clt2mcode ";" pv))] ) +# 8344 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_define_param_list_start = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_define_param_list = +# 660 "parser_cocci_menhir.mly" + (let circle x = + match Ast0.unwrap x with Ast0.DPcircles(_) -> true | _ -> false in + if List.exists circle _1 + then Ast0.wrap(Ast0.CIRCLES(_1)) + else Ast0.wrap(Ast0.DOTS(_1)) ) +# 8372 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_define_param_list = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_define_param_list_option = +# 684 "parser_cocci_menhir.mly" + ( _1 ) +# 8396 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_define_param_list_option = +# 685 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.DOTS([])) ) +# 8413 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_define_param_list_start = +# 667 "parser_cocci_menhir.mly" + ( [Ast0.wrap(Ast0.DParam _1)] ) +# 8437 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_define_param_list_start = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 8469 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_define_param_list_start = +# 669 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.DParam _1):: + Ast0.wrap(Ast0.DPComma(P.clt2mcode "," _2))::_3 ) +# 8478 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let r : 'tv_list_dp_comma_args_TEllipsis__ = Obj.magic r in + let d : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 8505 "parser_cocci_menhir.ml" + ) = Obj.magic d in + let _startpos = _startpos_d_ in + let _endpos = _endpos_r_ in + let _v : 'tv_define_param_list_start = +# 672 "parser_cocci_menhir.mly" + ( (P.mkdpdots "..." d):: + (List.concat (List.map (function x -> x (P.mkdpdots "...")) r)) ) +# 8513 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 80 "parser_cocci_menhir.mly" + (Data.clt * token) +# 8534 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_defineop = +# 621 "parser_cocci_menhir.mly" + ( let (clt,ident) = _1 in + function body -> + Ast0.wrap + (Ast0.Define + (P.clt2mcode "#define" clt, + (match ident with + TMetaId((nm,constraints,pure,clt)) -> + Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) + | TIdent(nm_pure) -> + Ast0.wrap(Ast0.Id(P.id2mcode nm_pure)) + | _ -> + raise + (Semantic_cocci.Semantic + "unexpected name for a #define")), + Ast0.wrap Ast0.NoParams, + body)) ) +# 8556 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 8587 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_define_param_list_option = Obj.magic _2 in + let _1 : ( +# 81 "parser_cocci_menhir.mly" + (Data.clt * token * int) +# 8593 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_defineop = +# 638 "parser_cocci_menhir.mly" + ( let (clt,ident,parenoff) = _1 in + let (arity,line,lline,offset,col,strbef,straft,pos) = clt in + let lp = + P.clt2mcode "(" (arity,line,lline,parenoff,0,[],[],Ast0.NoMetaPos) in + function body -> + Ast0.wrap + (Ast0.Define + (P.clt2mcode "#define" clt, + (match ident with + TMetaId((nm,constraints,pure,clt)) -> + Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) + | TIdent(nm_pure) -> + Ast0.wrap(Ast0.Id(P.id2mcode nm_pure)) + | _ -> + raise + (Semantic_cocci.Semantic + "unexpected name for a #define")), + Ast0.wrap (Ast0.DParams (lp,_2,P.clt2mcode ")" _3)),body)) ) +# 8617 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_pnrule = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_dep = +# 215 "parser_cocci_menhir.mly" + ( _1 ) +# 8641 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_dep = Obj.magic _3 in + let _1 : 'tv_dep = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_dep = +# 216 "parser_cocci_menhir.mly" + ( Ast.AndDep(_1, _3) ) +# 8675 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_dep = Obj.magic _3 in + let _1 : 'tv_dep = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_dep = +# 217 "parser_cocci_menhir.mly" + ( Ast.OrDep (_1, _3) ) +# 8709 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_depends = +# 211 "parser_cocci_menhir.mly" + ( Ast.NoDep ) +# 8726 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = parents; + MenhirLib.EngineTypes.startp = _startpos_parents_; + MenhirLib.EngineTypes.endp = _endpos_parents_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let parents : 'tv_dep = Obj.magic parents in + let _startpos = _startpos__1_ in + let _endpos = _endpos_parents_ in + let _v : 'tv_depends = +# 212 "parser_cocci_menhir.mly" + ( parents ) +# 8758 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_basic_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_dexpr = +# 1134 "parser_cocci_menhir.mly" + ( _1 ) +# 8782 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_separated_nonempty_list_TComma_pure_ident_ = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_disable = +# 230 "parser_cocci_menhir.mly" + ( List.map P.id2name _2 ) +# 8810 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 8831 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_dot_expressions = +# 1143 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Edots(P.clt2mcode "..." _1,None)) ) +# 8838 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_nest_expressions = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_dot_expressions = +# 1144 "parser_cocci_menhir.mly" + ( _1 ) +# 8862 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = c; + MenhirLib.EngineTypes.startp = _startpos_c_; + MenhirLib.EngineTypes.endp = _endpos_c_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let d : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 8888 "parser_cocci_menhir.ml" + ) = Obj.magic d in + let c : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 8893 "parser_cocci_menhir.ml" + ) = Obj.magic c in + let _startpos = _startpos_c_ in + let _endpos = _endpos_d_ in + let _v : 'tv_dp_comma_args_TEllipsis_ = +# 677 "parser_cocci_menhir.mly" + ( function dot_builder -> + [Ast0.wrap(Ast0.DPComma(P.clt2mcode "," c)); dot_builder d] ) +# 8901 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_ident = Obj.magic _2 in + let _1 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 8928 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_dp_comma_args_TEllipsis_ = +# 680 "parser_cocci_menhir.mly" + ( function dot_builder -> + [Ast0.wrap(Ast0.DPComma(P.clt2mcode "," _1)); + Ast0.wrap(Ast0.DParam _2)] ) +# 8937 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let d : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 8958 "parser_cocci_menhir.ml" + ) = Obj.magic d in + let _startpos = _startpos_d_ in + let _endpos = _endpos_d_ in + let _v : 'tv_edots_when_TEllipsis_eexpr_ = +# 1698 "parser_cocci_menhir.mly" + ( (d,None) ) +# 8965 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let w : 'tv_eexpr = Obj.magic w in + let d : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 9004 "parser_cocci_menhir.ml" + ) = Obj.magic d in + let _startpos = _startpos_d_ in + let _endpos = _endpos__5_ in + let _v : 'tv_edots_when_TEllipsis_eexpr_ = +# 1699 "parser_cocci_menhir.mly" + ( (d,Some w) ) +# 9011 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let d : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 9032 "parser_cocci_menhir.ml" + ) = Obj.magic d in + let _startpos = _startpos_d_ in + let _endpos = _endpos_d_ in + let _v : 'tv_edots_when_TEllipsis_initialize_ = +# 1698 "parser_cocci_menhir.mly" + ( (d,None) ) +# 9039 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let w : 'tv_initialize = Obj.magic w in + let d : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 9078 "parser_cocci_menhir.ml" + ) = Obj.magic d in + let _startpos = _startpos_d_ in + let _endpos = _endpos__5_ in + let _v : 'tv_edots_when_TEllipsis_initialize_ = +# 1699 "parser_cocci_menhir.mly" + ( (d,Some w) ) +# 9085 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let d : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 9106 "parser_cocci_menhir.ml" + ) = Obj.magic d in + let _startpos = _startpos_d_ in + let _endpos = _endpos_d_ in + let _v : 'tv_edots_when_TEllipsis_struct_decl_ = +# 1698 "parser_cocci_menhir.mly" + ( (d,None) ) +# 9113 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let w : 'tv_struct_decl = Obj.magic w in + let d : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 9152 "parser_cocci_menhir.ml" + ) = Obj.magic d in + let _startpos = _startpos_d_ in + let _endpos = _endpos__5_ in + let _v : 'tv_edots_when_TEllipsis_struct_decl_ = +# 1699 "parser_cocci_menhir.mly" + ( (d,Some w) ) +# 9159 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_basic_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_eexpr = +# 1132 "parser_cocci_menhir.mly" + ( _1 ) +# 9183 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_eexpr_list_start = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_eexpr_list = +# 1642 "parser_cocci_menhir.mly" + (let circle x = + match Ast0.unwrap x with Ast0.Ecircles(_) -> true | _ -> false in + let star x = + match Ast0.unwrap x with Ast0.Estars(_) -> true | _ -> false in + if List.exists circle _1 + then Ast0.wrap(Ast0.CIRCLES(_1)) + else + if List.exists star _1 + then Ast0.wrap(Ast0.STARS(_1)) + else Ast0.wrap(Ast0.DOTS(_1)) ) +# 9216 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_eexpr_list = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_eexpr_list_option = +# 1681 "parser_cocci_menhir.mly" + ( _1 ) +# 9240 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_eexpr_list_option = +# 1682 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.DOTS([])) ) +# 9257 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_aexpr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_eexpr_list_start = +# 1669 "parser_cocci_menhir.mly" + ( [_1] ) +# 9281 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_eexpr_list_start = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 9313 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_aexpr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_eexpr_list_start = +# 1671 "parser_cocci_menhir.mly" + ( _1::Ast0.wrap(Ast0.EComma(P.clt2mcode "," _2))::_3 ) +# 9321 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = cl; + MenhirLib.EngineTypes.startp = _startpos_cl_; + MenhirLib.EngineTypes.endp = _endpos_cl_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let cl : 'tv_comma_list_dexpr_ = Obj.magic cl in + let _startpos = _startpos__1_ in + let _endpos = _endpos__6_ in + let _v : 'tv_error_words = +# 1481 "parser_cocci_menhir.mly" + ( [Ast0.wrap(Ast0.ERRORWORDS(cl))] ) +# 9365 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_exists = +# 233 "parser_cocci_menhir.mly" + ( Ast.Exists ) +# 9387 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_exists = +# 234 "parser_cocci_menhir.mly" + ( Ast.Forall ) +# 9409 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_exists = +# 235 "parser_cocci_menhir.mly" + ( Ast.ReverseForall ) +# 9435 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_exists = +# 236 "parser_cocci_menhir.mly" + ( Ast.Undetermined ) +# 9452 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_basic_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_expr = +# 1130 "parser_cocci_menhir.mly" + ( _1 ) +# 9476 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let r : 'tv_no_dot_start_end_dexpr_edots_when_TEllipsis_eexpr__ = Obj.magic r in + let _startpos = _startpos_r_ in + let _endpos = _endpos_r_ in + let _v : 'tv_expr_dots_TEllipsis_ = +# 1311 "parser_cocci_menhir.mly" + ( r ) +# 9500 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_extends = +# 206 "parser_cocci_menhir.mly" + ( () ) +# 9517 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = parent; + MenhirLib.EngineTypes.startp = _startpos_parent_; + MenhirLib.EngineTypes.endp = _endpos_parent_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let parent : ( +# 47 "parser_cocci_menhir.mly" + (string) +# 9542 "parser_cocci_menhir.ml" + ) = Obj.magic parent in + let _startpos = _startpos__1_ in + let _endpos = _endpos_parent_ in + let _v : 'tv_extends = +# 208 "parser_cocci_menhir.mly" + ( !Data.install_bindings (parent) ) +# 9549 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 82 "parser_cocci_menhir.mly" + (string * Data.clt) +# 9575 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 82 "parser_cocci_menhir.mly" + (string * Data.clt) +# 9580 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_filespec = +# 580 "parser_cocci_menhir.mly" + ( [Ast0.wrap + (Ast0.FILEINFO(P.id2mcode _1, + P.id2mcode _2))] ) +# 9589 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ty; + MenhirLib.EngineTypes.startp = _startpos_ty_; + MenhirLib.EngineTypes.endp = _endpos_ty_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let m : 'tv_list_TMul_ = Obj.magic m in + let ty : 'tv_generic_ctype = Obj.magic ty in + let _startpos = _startpos_ty_ in + let _endpos = _endpos_m_ in + let _v : 'tv_fn_ctype = +# 535 "parser_cocci_menhir.mly" + ( P.pointerify ty m ) +# 9619 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let m : 'tv_list_TMul_ = Obj.magic m in + let t : ( +# 50 "parser_cocci_menhir.mly" + (Data.clt) +# 9646 "parser_cocci_menhir.ml" + ) = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_m_ in + let _v : 'tv_fn_ctype = +# 537 "parser_cocci_menhir.mly" + ( P.pointerify + (Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None))) + m ) +# 9655 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_fninfo = +# 723 "parser_cocci_menhir.mly" + ( [] ) +# 9672 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fninfo = Obj.magic _2 in + let _1 : 'tv_storage = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fninfo = +# 725 "parser_cocci_menhir.mly" + ( try + let _ = + List.find (function Ast0.FStorage(_) -> true | _ -> false) _2 in + raise (Semantic_cocci.Semantic "duplicate storage") + with Not_found -> (Ast0.FStorage(_1))::_2 ) +# 9706 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let r : 'tv_fninfo_nt = Obj.magic r in + let t : 'tv_fn_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_r_ in + let _v : 'tv_fninfo = +# 730 "parser_cocci_menhir.mly" + ( (Ast0.FType(t))::r ) +# 9736 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fninfo = Obj.magic _2 in + let _1 : ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 9763 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fninfo = +# 732 "parser_cocci_menhir.mly" + ( try + let _ = List.find (function Ast0.FInline(_) -> true | _ -> false) _2 in + raise (Semantic_cocci.Semantic "duplicate inline") + with Not_found -> (Ast0.FInline(P.clt2mcode "inline" _1))::_2 ) +# 9773 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fninfo = Obj.magic _2 in + let _1 : ( +# 55 "parser_cocci_menhir.mly" + (string * Data.clt) +# 9800 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fninfo = +# 737 "parser_cocci_menhir.mly" + ( try + let _ = List.find (function Ast0.FAttr(_) -> true | _ -> false) _2 in + raise (Semantic_cocci.Semantic "multiple attributes") + with Not_found -> (Ast0.FAttr(P.id2mcode _1))::_2 ) +# 9810 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_fninfo_nt = +# 743 "parser_cocci_menhir.mly" + ( [] ) +# 9827 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fninfo_nt = Obj.magic _2 in + let _1 : 'tv_storage = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fninfo_nt = +# 745 "parser_cocci_menhir.mly" + ( try + let _ = + List.find (function Ast0.FStorage(_) -> true | _ -> false) _2 in + raise (Semantic_cocci.Semantic "duplicate storage") + with Not_found -> (Ast0.FStorage(_1))::_2 ) +# 9861 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fninfo_nt = Obj.magic _2 in + let _1 : ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 9888 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fninfo_nt = +# 751 "parser_cocci_menhir.mly" + ( try + let _ = List.find (function Ast0.FInline(_) -> true | _ -> false) _2 in + raise (Semantic_cocci.Semantic "duplicate inline") + with Not_found -> (Ast0.FInline(P.clt2mcode "inline" _1))::_2 ) +# 9898 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fninfo_nt = Obj.magic _2 in + let _1 : ( +# 55 "parser_cocci_menhir.mly" + (string * Data.clt) +# 9925 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fninfo_nt = +# 756 "parser_cocci_menhir.mly" + ( try + let _ = List.find (function Ast0.FAttr(_) -> true | _ -> false) _2 in + raise (Semantic_cocci.Semantic "duplicate init") + with Not_found -> (Ast0.FAttr(P.id2mcode _1))::_2 ) +# 9935 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_fun_after_dots = +# 1590 "parser_cocci_menhir.mly" + ([]) +# 9952 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fun_after_exp = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fun_after_dots = +# 1591 "parser_cocci_menhir.mly" + (_2) +# 9980 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fun_after_exp = Obj.magic _2 in + let _1 : 'tv_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fun_after_dots = +# 1592 "parser_cocci_menhir.mly" + (Ast0.wrap(Ast0.Exp(_1))::_2) +# 10010 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fun_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fun_after_dots = +# 1593 "parser_cocci_menhir.mly" + (_1@_2) +# 10040 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_fun_after_dots_or = +# 1600 "parser_cocci_menhir.mly" + ([]) +# 10057 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fun_after_exp_or = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fun_after_dots_or = +# 1601 "parser_cocci_menhir.mly" + (_2) +# 10085 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fun_after_exp_or = Obj.magic _2 in + let _1 : 'tv_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fun_after_dots_or = +# 1602 "parser_cocci_menhir.mly" + (Ast0.wrap(Ast0.Exp(_1))::_2) +# 10115 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fun_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fun_after_dots_or = +# 1603 "parser_cocci_menhir.mly" + (_1@_2) +# 10145 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fun_after_dots = Obj.magic _2 in + let _1 : 'tv_stm_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fun_after_exp = +# 1596 "parser_cocci_menhir.mly" + (_1::_2) +# 10175 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_fun_after_exp_or = +# 1606 "parser_cocci_menhir.mly" + ([]) +# 10192 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fun_after_dots = Obj.magic _2 in + let _1 : 'tv_stm_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fun_after_exp_or = +# 1607 "parser_cocci_menhir.mly" + (_1::_2) +# 10222 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_fun_after_stm = +# 1585 "parser_cocci_menhir.mly" + ([]) +# 10239 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fun_after_dots = Obj.magic _2 in + let _1 : 'tv_stm_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fun_after_stm = +# 1586 "parser_cocci_menhir.mly" + (_1::_2) +# 10269 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_fun_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_fun_after_stm = +# 1587 "parser_cocci_menhir.mly" + (_1@_2) +# 10299 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_fun_after_stm = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_fun_start = +# 1582 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.DOTS(_1)) ) +# 10323 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_pure_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_func_ident = +# 1400 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Id(P.id2mcode _1)) ) +# 10347 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 61 "parser_cocci_menhir.mly" + (Parse_aux.idinfo) +# 10368 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_func_ident = +# 1402 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,clt) = _1 in + Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) ) +# 10376 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 61 "parser_cocci_menhir.mly" + (Parse_aux.idinfo) +# 10397 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_func_ident = +# 1405 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,clt) = _1 in + Ast0.wrap(Ast0.MetaFunc(P.clt2mcode nm clt,constraints,pure)) ) +# 10405 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 61 "parser_cocci_menhir.mly" + (Parse_aux.idinfo) +# 10426 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_func_ident = +# 1408 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,clt) = _1 in + Ast0.wrap + (Ast0.MetaLocalFunc(P.clt2mcode nm clt,constraints,pure)) ) +# 10435 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = rb; + MenhirLib.EngineTypes.startp = _startpos_rb_; + MenhirLib.EngineTypes.endp = _endpos_rb_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lb; + MenhirLib.EngineTypes.startp = _startpos_lb_; + MenhirLib.EngineTypes.endp = _endpos_lb_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = f; + MenhirLib.EngineTypes.startp = _startpos_f_; + MenhirLib.EngineTypes.endp = _endpos_f_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let rb : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 10495 "parser_cocci_menhir.ml" + ) = Obj.magic rb in + let b : 'tv_fun_start = Obj.magic b in + let lb : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 10501 "parser_cocci_menhir.ml" + ) = Obj.magic lb in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 10506 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let d : 'tv_decl_list_decl_ = Obj.magic d in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 10512 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let i : 'tv_func_ident = Obj.magic i in + let f : 'tv_fninfo = Obj.magic f in + let _startpos = _startpos_f_ in + let _endpos = _endpos_rb_ in + let _v : 'tv_fundecl = +# 715 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.FunDecl((Ast0.default_info(),Ast0.context_befaft()), + f, i, + P.clt2mcode "(" lp, d, + P.clt2mcode ")" rp, + P.clt2mcode "{" lb, b, + P.clt2mcode "}" rb)) ) +# 10526 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pt; + MenhirLib.EngineTypes.startp = _startpos_pt_; + MenhirLib.EngineTypes.endp = _endpos_pt_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = id; + MenhirLib.EngineTypes.startp = _startpos_id_; + MenhirLib.EngineTypes.endp = _endpos_id_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pt : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 10572 "parser_cocci_menhir.ml" + ) = Obj.magic pt in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 10577 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let d : 'tv_decl_list_name_opt_decl_ = Obj.magic d in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 10583 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let id : 'tv_func_ident = Obj.magic id in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pt_ in + let _v : 'tv_funproto = let s = + +# 39 "standard.mly" + ( None ) +# 10593 "parser_cocci_menhir.ml" + + in + +# 692 "parser_cocci_menhir.mly" + ( Ast0.wrap + (Ast0.UnInit + (s, + Ast0.wrap + (Ast0.FunctionType(Some t, + P.clt2mcode "(" lp, d, P.clt2mcode ")" rp)), + id, P.clt2mcode ";" pt)) ) +# 10605 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pt; + MenhirLib.EngineTypes.startp = _startpos_pt_; + MenhirLib.EngineTypes.endp = _endpos_pt_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = id; + MenhirLib.EngineTypes.startp = _startpos_id_; + MenhirLib.EngineTypes.endp = _endpos_id_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pt : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 10656 "parser_cocci_menhir.ml" + ) = Obj.magic pt in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 10661 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let d : 'tv_decl_list_name_opt_decl_ = Obj.magic d in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 10667 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let id : 'tv_func_ident = Obj.magic id in + let t : 'tv_ctype = Obj.magic t in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pt_ in + let _v : 'tv_funproto = let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 10679 "parser_cocci_menhir.ml" + + in + +# 692 "parser_cocci_menhir.mly" + ( Ast0.wrap + (Ast0.UnInit + (s, + Ast0.wrap + (Ast0.FunctionType(Some t, + P.clt2mcode "(" lp, d, P.clt2mcode ")" rp)), + id, P.clt2mcode ";" pt)) ) +# 10691 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pt; + MenhirLib.EngineTypes.startp = _startpos_pt_; + MenhirLib.EngineTypes.endp = _endpos_pt_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = id; + MenhirLib.EngineTypes.startp = _startpos_id_; + MenhirLib.EngineTypes.endp = _endpos_id_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pt : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 10737 "parser_cocci_menhir.ml" + ) = Obj.magic pt in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 10742 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let d : 'tv_decl_list_name_opt_decl_ = Obj.magic d in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 10748 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let id : 'tv_func_ident = Obj.magic id in + let t : ( +# 50 "parser_cocci_menhir.mly" + (Data.clt) +# 10754 "parser_cocci_menhir.ml" + ) = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pt_ in + let _v : 'tv_funproto = let s = + +# 39 "standard.mly" + ( None ) +# 10762 "parser_cocci_menhir.ml" + + in + +# 701 "parser_cocci_menhir.mly" + ( let t = Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in + Ast0.wrap + (Ast0.UnInit + (s, + Ast0.wrap + (Ast0.FunctionType(Some t, + P.clt2mcode "(" lp, d, P.clt2mcode ")" rp)), + id, P.clt2mcode ";" pt)) ) +# 10775 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pt; + MenhirLib.EngineTypes.startp = _startpos_pt_; + MenhirLib.EngineTypes.endp = _endpos_pt_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = id; + MenhirLib.EngineTypes.startp = _startpos_id_; + MenhirLib.EngineTypes.endp = _endpos_id_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pt : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 10826 "parser_cocci_menhir.ml" + ) = Obj.magic pt in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 10831 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let d : 'tv_decl_list_name_opt_decl_ = Obj.magic d in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 10837 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let id : 'tv_func_ident = Obj.magic id in + let t : ( +# 50 "parser_cocci_menhir.mly" + (Data.clt) +# 10843 "parser_cocci_menhir.ml" + ) = Obj.magic t in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pt_ in + let _v : 'tv_funproto = let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 10853 "parser_cocci_menhir.ml" + + in + +# 701 "parser_cocci_menhir.mly" + ( let t = Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in + Ast0.wrap + (Ast0.UnInit + (s, + Ast0.wrap + (Ast0.FunctionType(Some t, + P.clt2mcode "(" lp, d, P.clt2mcode ")" rp)), + id, P.clt2mcode ";" pt)) ) +# 10866 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let q : 'tv_ctype_qualif = Obj.magic q in + let _startpos = _startpos_q_ in + let _endpos = _endpos_q_ in + let _v : 'tv_generic_ctype = +# 442 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.ImplicitInt(q)) ) +# 10890 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ty; + MenhirLib.EngineTypes.startp = _startpos_ty_; + MenhirLib.EngineTypes.endp = _endpos_ty_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let ty : ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 10911 "parser_cocci_menhir.ml" + ) = Obj.magic ty in + let _startpos = _startpos_ty_ in + let _endpos = _endpos_ty_ in + let _v : 'tv_generic_ctype = let q = + +# 39 "standard.mly" + ( None ) +# 10919 "parser_cocci_menhir.ml" + + in + +# 444 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.CharType ty, q)) ) +# 10925 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = ty; + MenhirLib.EngineTypes.startp = _startpos_ty_; + MenhirLib.EngineTypes.endp = _endpos_ty_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let ty : ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 10951 "parser_cocci_menhir.ml" + ) = Obj.magic ty in + let x0 : 'tv_ctype_qualif = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_ty_ in + let _v : 'tv_generic_ctype = let q = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 10961 "parser_cocci_menhir.ml" + + in + +# 444 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.CharType ty, q)) ) +# 10967 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ty; + MenhirLib.EngineTypes.startp = _startpos_ty_; + MenhirLib.EngineTypes.endp = _endpos_ty_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let ty : ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 10988 "parser_cocci_menhir.ml" + ) = Obj.magic ty in + let _startpos = _startpos_ty_ in + let _endpos = _endpos_ty_ in + let _v : 'tv_generic_ctype = let q = + +# 39 "standard.mly" + ( None ) +# 10996 "parser_cocci_menhir.ml" + + in + +# 446 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.ShortType ty, q)) ) +# 11002 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = ty; + MenhirLib.EngineTypes.startp = _startpos_ty_; + MenhirLib.EngineTypes.endp = _endpos_ty_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let ty : ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 11028 "parser_cocci_menhir.ml" + ) = Obj.magic ty in + let x0 : 'tv_ctype_qualif = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_ty_ in + let _v : 'tv_generic_ctype = let q = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 11038 "parser_cocci_menhir.ml" + + in + +# 446 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.ShortType ty, q)) ) +# 11044 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ty; + MenhirLib.EngineTypes.startp = _startpos_ty_; + MenhirLib.EngineTypes.endp = _endpos_ty_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let ty : ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 11065 "parser_cocci_menhir.ml" + ) = Obj.magic ty in + let _startpos = _startpos_ty_ in + let _endpos = _endpos_ty_ in + let _v : 'tv_generic_ctype = let q = + +# 39 "standard.mly" + ( None ) +# 11073 "parser_cocci_menhir.ml" + + in + +# 448 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.IntType ty, q)) ) +# 11079 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = ty; + MenhirLib.EngineTypes.startp = _startpos_ty_; + MenhirLib.EngineTypes.endp = _endpos_ty_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let ty : ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 11105 "parser_cocci_menhir.ml" + ) = Obj.magic ty in + let x0 : 'tv_ctype_qualif = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_ty_ in + let _v : 'tv_generic_ctype = let q = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 11115 "parser_cocci_menhir.ml" + + in + +# 448 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.IntType ty, q)) ) +# 11121 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let t : ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 11142 "parser_cocci_menhir.ml" + ) = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_t_ in + let _v : 'tv_generic_ctype = +# 450 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.DoubleType t, None)) ) +# 11149 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let t : ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 11170 "parser_cocci_menhir.ml" + ) = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_t_ in + let _v : 'tv_generic_ctype = +# 452 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.FloatType t, None)) ) +# 11177 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ty; + MenhirLib.EngineTypes.startp = _startpos_ty_; + MenhirLib.EngineTypes.endp = _endpos_ty_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let ty : ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 11198 "parser_cocci_menhir.ml" + ) = Obj.magic ty in + let _startpos = _startpos_ty_ in + let _endpos = _endpos_ty_ in + let _v : 'tv_generic_ctype = let q = + +# 39 "standard.mly" + ( None ) +# 11206 "parser_cocci_menhir.ml" + + in + +# 454 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.LongType ty, q)) ) +# 11212 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = ty; + MenhirLib.EngineTypes.startp = _startpos_ty_; + MenhirLib.EngineTypes.endp = _endpos_ty_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let ty : ( +# 49 "parser_cocci_menhir.mly" + (Data.clt) +# 11238 "parser_cocci_menhir.ml" + ) = Obj.magic ty in + let x0 : 'tv_ctype_qualif = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_ty_ in + let _v : 'tv_generic_ctype = let q = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 11248 "parser_cocci_menhir.ml" + + in + +# 454 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.LongType ty, q)) ) +# 11254 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let i : 'tv_ident = Obj.magic i in + let s : 'tv_struct_or_union = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_i_ in + let _v : 'tv_generic_ctype = +# 456 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.StructUnionName(s, Some i)) ) +# 11284 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let r : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 11320 "parser_cocci_menhir.ml" + ) = Obj.magic r in + let d : 'tv_struct_decl_list = Obj.magic d in + let l : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 11326 "parser_cocci_menhir.ml" + ) = Obj.magic l in + let s : 'tv_struct_or_union = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_r_ in + let _v : 'tv_generic_ctype = let i = + +# 39 "standard.mly" + ( None ) +# 11335 "parser_cocci_menhir.ml" + + in + +# 459 "parser_cocci_menhir.mly" + ( (if i = None && !Data.in_iso + then failwith "structures must be named in the iso file"); + Ast0.wrap(Ast0.StructUnionDef(Ast0.wrap(Ast0.StructUnionName(s, i)), + P.clt2mcode "{" l, + d, P.clt2mcode "}" r)) ) +# 11345 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let r : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 11386 "parser_cocci_menhir.ml" + ) = Obj.magic r in + let d : 'tv_struct_decl_list = Obj.magic d in + let l : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 11392 "parser_cocci_menhir.ml" + ) = Obj.magic l in + let x0 : 'tv_ident = Obj.magic x0 in + let s : 'tv_struct_or_union = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_r_ in + let _v : 'tv_generic_ctype = let i = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 11403 "parser_cocci_menhir.ml" + + in + +# 459 "parser_cocci_menhir.mly" + ( (if i = None && !Data.in_iso + then failwith "structures must be named in the iso file"); + Ast0.wrap(Ast0.StructUnionDef(Ast0.wrap(Ast0.StructUnionName(s, i)), + P.clt2mcode "{" l, + d, P.clt2mcode "}" r)) ) +# 11413 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let r : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 11449 "parser_cocci_menhir.ml" + ) = Obj.magic r in + let d : 'tv_struct_decl_list = Obj.magic d in + let l : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 11455 "parser_cocci_menhir.ml" + ) = Obj.magic l in + let s : ( +# 64 "parser_cocci_menhir.mly" + (Parse_aux.info) +# 11460 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_r_ in + let _v : 'tv_generic_ctype = +# 465 "parser_cocci_menhir.mly" + ( let (nm,pure,clt) = s in + let ty = + Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) in + Ast0.wrap + (Ast0.StructUnionDef(ty,P.clt2mcode "{" l,d,P.clt2mcode "}" r)) ) +# 11471 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let p : ( +# 59 "parser_cocci_menhir.mly" + (string * Data.clt) +# 11501 "parser_cocci_menhir.ml" + ) = Obj.magic p in + let r : ( +# 47 "parser_cocci_menhir.mly" + (string) +# 11506 "parser_cocci_menhir.ml" + ) = Obj.magic r in + let _startpos = _startpos_r_ in + let _endpos = _endpos_p_ in + let _v : 'tv_generic_ctype = +# 471 "parser_cocci_menhir.mly" + ( let nm = (r,P.id2name p) in + (* this is only possible when we are in a metavar decl. Otherwise, + it will be represented already as a MetaType *) + let _ = P.check_meta(Ast.MetaTypeDecl(Ast.NONE,nm)) in + Ast0.wrap(Ast0.MetaType(P.clt2mcode nm (P.id2clt p), + Ast0.Impure (*will be ignored*))) ) +# 11518 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let p : ( +# 59 "parser_cocci_menhir.mly" + (string * Data.clt) +# 11539 "parser_cocci_menhir.ml" + ) = Obj.magic p in + let _startpos = _startpos_p_ in + let _endpos = _endpos_p_ in + let _v : 'tv_generic_ctype = +# 478 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.TypeName(P.id2mcode p)) ) +# 11546 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let p : ( +# 64 "parser_cocci_menhir.mly" + (Parse_aux.info) +# 11567 "parser_cocci_menhir.ml" + ) = Obj.magic p in + let _startpos = _startpos_p_ in + let _endpos = _endpos_p_ in + let _v : 'tv_generic_ctype = +# 480 "parser_cocci_menhir.mly" + ( let (nm,pure,clt) = p in + Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) ) +# 11575 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_pure_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_ident = +# 1413 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Id(P.id2mcode _1)) ) +# 11599 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 61 "parser_cocci_menhir.mly" + (Parse_aux.idinfo) +# 11620 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_ident = +# 1415 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,clt) = _1 in + Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) ) +# 11628 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let i : 'tv_pure_ident = Obj.magic i in + let _startpos = _startpos_i_ in + let _endpos = _endpos_i_ in + let _v : 'tv_ident_or_const = +# 1371 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i)))) ) +# 11652 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 11673 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_ident_or_const = +# 1373 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Int x) clt)) ) +# 11681 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 11706 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_incl = +# 247 "parser_cocci_menhir.mly" + ( Common.Left(P.id2name _2) ) +# 11713 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 78 "parser_cocci_menhir.mly" + (string) +# 11738 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_incl = +# 248 "parser_cocci_menhir.mly" + ( Common.Right _2 ) +# 11745 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _1 : 'tv_list_incl_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : ( +# 145 "parser_cocci_menhir.mly" + ((string,string) Common.either list) +# 11773 "parser_cocci_menhir.ml" + ) = +# 243 "parser_cocci_menhir.mly" + ( _1 ) +# 11777 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _1 : 'tv_list_incl_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : ( +# 145 "parser_cocci_menhir.mly" + ((string,string) Common.either list) +# 11805 "parser_cocci_menhir.ml" + ) = +# 244 "parser_cocci_menhir.mly" + ( _1 ) +# 11809 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 79 "parser_cocci_menhir.mly" + (string * Data.clt) +# 11830 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_includes = +# 586 "parser_cocci_menhir.mly" + ( Ast0.wrap + (Ast0.Include(P.clt2mcode "#include" (P.drop_aft (P.id2clt _1)), + let (arity,ln,lln,offset,col,strbef,straft,pos) = + P.id2clt _1 in + let clt = + (arity,ln,lln,offset,0,strbef,straft,pos) in + P.clt2mcode + (Ast.Local (Parse_aux.str2inc (P.id2name _1))) + (P.drop_bef clt))) ) +# 11845 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 79 "parser_cocci_menhir.mly" + (string * Data.clt) +# 11866 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_includes = +# 596 "parser_cocci_menhir.mly" + ( Ast0.wrap + (Ast0.Include(P.clt2mcode "#include" (P.drop_aft (P.id2clt _1)), + let (arity,ln,lln,offset,col,strbef,straft,pos) = + P.id2clt _1 in + let clt = + (arity,ln,lln,offset,0,strbef,straft,pos) in + P.clt2mcode + (Ast.NonLocal (Parse_aux.str2inc (P.id2name _1))) + (P.drop_bef clt))) ) +# 11881 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let t : 'tv_ctype = Obj.magic t in + let d : 'tv_defineop = Obj.magic d in + let _startpos = _startpos_d_ in + let _endpos = _endpos__3_ in + let _v : 'tv_includes = +# 606 "parser_cocci_menhir.mly" + ( let ty = Ast0.wrap(Ast0.TopExp(Ast0.wrap(Ast0.TypeExp(t)))) in + d (Ast0.wrap(Ast0.DOTS([ty]))) ) +# 11916 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let b : 'tv_toplevel_seq_start_toplevel_after_dots_ = Obj.magic b in + let _1 : 'tv_defineop = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_includes = +# 609 "parser_cocci_menhir.mly" + ( let body = + match b with + [e] -> + (match Ast0.unwrap e with + Ast0.Exp(e1) -> + [Ast0.rewrap e (Ast0.TopExp(Ast0.set_arg_exp (e1)))] + | _ -> b) + | _ -> b in + _1 (Ast0.wrap(Ast0.DOTS(body))) ) +# 11958 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_eexpr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_initialize = +# 1008 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.InitExpr(_1)) ) +# 11982 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 12013 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_initialize_list = Obj.magic _2 in + let _1 : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 12019 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_initialize = +# 1010 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.InitList(P.clt2mcode "{" _1,_2,P.clt2mcode "}" _3)) ) +# 12026 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 12052 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 12057 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_initialize = +# 1012 "parser_cocci_menhir.mly" + ( Ast0.wrap + (Ast0.InitList(P.clt2mcode "{" _1,Ast0.wrap(Ast0.DOTS []), + P.clt2mcode "}" _2)) ) +# 12066 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_arith_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_initialize2 = +# 1019 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.InitExpr(_1)) ) +# 12090 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 12121 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_initialize_list = Obj.magic _2 in + let _1 : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 12127 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_initialize2 = +# 1021 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.InitList(P.clt2mcode "{" _1,_2,P.clt2mcode "}" _3)) ) +# 12134 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 12160 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 12165 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_initialize2 = +# 1023 "parser_cocci_menhir.mly" + ( Ast0.wrap + (Ast0.InitList(P.clt2mcode "{" _1,Ast0.wrap(Ast0.DOTS []), + P.clt2mcode "}" _2)) ) +# 12174 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let _4 : 'tv_initialize2 = Obj.magic _4 in + let _3 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 12211 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_ident = Obj.magic _2 in + let _1 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 12217 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_initialize2 = +# 1028 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.InitGccDotName(P.clt2mcode "." _1,_2,P.clt2mcode "=" _3,_4)) ) +# 12224 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_initialize2 = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 12256 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_initialize2 = +# 1030 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.InitGccName(_1,P.clt2mcode ":" _2,_3)) ) +# 12264 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _5; + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let _5 : 'tv_initialize2 = Obj.magic _5 in + let _4 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 12306 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 12311 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_eexpr = Obj.magic _2 in + let _1 : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 12317 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__5_ in + let _v : 'tv_initialize2 = +# 1032 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.InitGccIndex(P.clt2mcode "[" _1,_2,P.clt2mcode "]" _3, + P.clt2mcode "=" _4,_5)) ) +# 12325 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _7; + MenhirLib.EngineTypes.startp = _startpos__7_; + MenhirLib.EngineTypes.endp = _endpos__7_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _6; + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _5; + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let _7 : 'tv_initialize2 = Obj.magic _7 in + let _6 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 12377 "parser_cocci_menhir.ml" + ) = Obj.magic _6 in + let _5 : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 12382 "parser_cocci_menhir.ml" + ) = Obj.magic _5 in + let _4 : 'tv_eexpr = Obj.magic _4 in + let _3 : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 12388 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_eexpr = Obj.magic _2 in + let _1 : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 12394 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__7_ in + let _v : 'tv_initialize2 = +# 1035 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.InitGccRange(P.clt2mcode "[" _1,_2,P.clt2mcode "..." _3, + _4,P.clt2mcode "]" _5,P.clt2mcode "=" _6,_7)) ) +# 12402 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_initialize_list_start = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_initialize_list = +# 1039 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.DOTS(_1)) ) +# 12426 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 12452 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_initialize2 = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_initialize_list_start = +# 1042 "parser_cocci_menhir.mly" + ( [_1;Ast0.wrap(Ast0.IComma(P.clt2mcode "," _2))] ) +# 12460 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_initialize_list_start = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 12492 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_initialize2 = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_initialize_list_start = +# 1044 "parser_cocci_menhir.mly" + ( _1::Ast0.wrap(Ast0.IComma(P.clt2mcode "," _2))::_3 ) +# 12500 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let r : 'tv_comma_initializers_edots_when_TEllipsis_initialize__ = Obj.magic r in + let d : 'tv_edots_when_TEllipsis_initialize_ = Obj.magic d in + let _startpos = _startpos_d_ in + let _endpos = _endpos_r_ in + let _v : 'tv_initialize_list_start = +# 1047 "parser_cocci_menhir.mly" + ( (P.mkidots "..." d):: + (List.concat(List.map (function x -> x (P.mkidots "...")) r)) ) +# 12531 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_invalid = +# 1140 "parser_cocci_menhir.mly" + ( raise (Semantic_cocci.Semantic "not matchable") ) +# 12553 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_is_expression = +# 239 "parser_cocci_menhir.mly" + ( false ) +# 12570 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_is_expression = +# 240 "parser_cocci_menhir.mly" + ( true ) +# 12592 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos__1_ in + let _endpos = _endpos_t_ in + let _v : 'tv_iso_ctype_ = +# 1752 "parser_cocci_menhir.mly" + ( Common.Left t ) +# 12620 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos__1_ in + let _endpos = _endpos_t_ in + let _v : 'tv_iso_ctype_ = +# 1753 "parser_cocci_menhir.mly" + ( Common.Right t ) +# 12648 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let t : 'tv_decl_var = Obj.magic t in + let _startpos = _startpos__1_ in + let _endpos = _endpos_t_ in + let _v : 'tv_iso_decl_var_ = +# 1752 "parser_cocci_menhir.mly" + ( Common.Left t ) +# 12676 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let t : 'tv_decl_var = Obj.magic t in + let _startpos = _startpos__1_ in + let _endpos = _endpos_t_ in + let _v : 'tv_iso_decl_var_ = +# 1753 "parser_cocci_menhir.mly" + ( Common.Right t ) +# 12704 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let t : 'tv_dexpr = Obj.magic t in + let _startpos = _startpos__1_ in + let _endpos = _endpos_t_ in + let _v : 'tv_iso_dexpr_ = +# 1752 "parser_cocci_menhir.mly" + ( Common.Left t ) +# 12732 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let t : 'tv_dexpr = Obj.magic t in + let _startpos = _startpos__1_ in + let _endpos = _endpos_t_ in + let _v : 'tv_iso_dexpr_ = +# 1753 "parser_cocci_menhir.mly" + ( Common.Right t ) +# 12760 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let t : 'tv_nest_start = Obj.magic t in + let _startpos = _startpos__1_ in + let _endpos = _endpos_t_ in + let _v : 'tv_iso_nest_start_ = +# 1752 "parser_cocci_menhir.mly" + ( Common.Left t ) +# 12788 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let t : 'tv_nest_start = Obj.magic t in + let _startpos = _startpos__1_ in + let _endpos = _endpos_t_ in + let _v : 'tv_iso_nest_start_ = +# 1753 "parser_cocci_menhir.mly" + ( Common.Right t ) +# 12816 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let t : 'tv_single_statement = Obj.magic t in + let _startpos = _startpos__1_ in + let _endpos = _endpos_t_ in + let _v : 'tv_iso_single_statement_ = +# 1752 "parser_cocci_menhir.mly" + ( Common.Left t ) +# 12844 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let t : 'tv_single_statement = Obj.magic t in + let _startpos = _startpos__1_ in + let _endpos = _endpos_t_ in + let _v : 'tv_iso_single_statement_ = +# 1753 "parser_cocci_menhir.mly" + ( Common.Right t ) +# 12872 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = el; + MenhirLib.EngineTypes.startp = _startpos_el_; + MenhirLib.EngineTypes.endp = _endpos_el_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e1; + MenhirLib.EngineTypes.startp = _startpos_e1_; + MenhirLib.EngineTypes.endp = _endpos_e1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let el : 'tv_list_iso_dexpr__ = Obj.magic el in + let e1 : 'tv_dexpr = Obj.magic e1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : ( +# 161 "parser_cocci_menhir.mly" + (Ast0_cocci.anything list list) +# 12910 "parser_cocci_menhir.ml" + ) = +# 1724 "parser_cocci_menhir.mly" + ( P.iso_adjust (function x -> Ast0.ExprTag x) e1 el ) +# 12914 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = el; + MenhirLib.EngineTypes.startp = _startpos_el_; + MenhirLib.EngineTypes.endp = _endpos_el_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e1; + MenhirLib.EngineTypes.startp = _startpos_e1_; + MenhirLib.EngineTypes.endp = _endpos_e1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let el : 'tv_list_iso_dexpr__ = Obj.magic el in + let e1 : 'tv_dexpr = Obj.magic e1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : ( +# 161 "parser_cocci_menhir.mly" + (Ast0_cocci.anything list list) +# 12952 "parser_cocci_menhir.ml" + ) = +# 1726 "parser_cocci_menhir.mly" + ( P.iso_adjust (function x -> Ast0.ArgExprTag x) e1 el ) +# 12956 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = el; + MenhirLib.EngineTypes.startp = _startpos_el_; + MenhirLib.EngineTypes.endp = _endpos_el_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e1; + MenhirLib.EngineTypes.startp = _startpos_e1_; + MenhirLib.EngineTypes.endp = _endpos_e1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let el : 'tv_list_iso_dexpr__ = Obj.magic el in + let e1 : 'tv_dexpr = Obj.magic e1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : ( +# 161 "parser_cocci_menhir.mly" + (Ast0_cocci.anything list list) +# 12994 "parser_cocci_menhir.ml" + ) = +# 1728 "parser_cocci_menhir.mly" + ( P.iso_adjust (function x -> Ast0.TestExprTag x) e1 el ) +# 12998 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = sl; + MenhirLib.EngineTypes.startp = _startpos_sl_; + MenhirLib.EngineTypes.endp = _endpos_sl_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = s1; + MenhirLib.EngineTypes.startp = _startpos_s1_; + MenhirLib.EngineTypes.endp = _endpos_s1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let sl : 'tv_list_iso_single_statement__ = Obj.magic sl in + let s1 : 'tv_single_statement = Obj.magic s1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : ( +# 161 "parser_cocci_menhir.mly" + (Ast0_cocci.anything list list) +# 13036 "parser_cocci_menhir.ml" + ) = +# 1730 "parser_cocci_menhir.mly" + ( P.iso_adjust (function x -> Ast0.StmtTag x) s1 sl ) +# 13040 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = tl; + MenhirLib.EngineTypes.startp = _startpos_tl_; + MenhirLib.EngineTypes.endp = _endpos_tl_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t1; + MenhirLib.EngineTypes.startp = _startpos_t1_; + MenhirLib.EngineTypes.endp = _endpos_t1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let tl : 'tv_list_iso_ctype__ = Obj.magic tl in + let t1 : 'tv_ctype = Obj.magic t1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : ( +# 161 "parser_cocci_menhir.mly" + (Ast0_cocci.anything list list) +# 13078 "parser_cocci_menhir.ml" + ) = +# 1732 "parser_cocci_menhir.mly" + ( P.iso_adjust (function x -> Ast0.TypeCTag x) t1 tl ) +# 13082 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = el; + MenhirLib.EngineTypes.startp = _startpos_el_; + MenhirLib.EngineTypes.endp = _endpos_el_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e1; + MenhirLib.EngineTypes.startp = _startpos_e1_; + MenhirLib.EngineTypes.endp = _endpos_e1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let el : 'tv_list_iso_nest_start__ = Obj.magic el in + let e1 : 'tv_nest_start = Obj.magic e1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : ( +# 161 "parser_cocci_menhir.mly" + (Ast0_cocci.anything list list) +# 13120 "parser_cocci_menhir.ml" + ) = +# 1734 "parser_cocci_menhir.mly" + ( P.iso_adjust (function x -> Ast0.DotsStmtTag x) e1 el ) +# 13124 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = dl; + MenhirLib.EngineTypes.startp = _startpos_dl_; + MenhirLib.EngineTypes.endp = _endpos_dl_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d1; + MenhirLib.EngineTypes.startp = _startpos_d1_; + MenhirLib.EngineTypes.endp = _endpos_d1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let dl : 'tv_list_iso_decl_var__ = Obj.magic dl in + let d1 : 'tv_decl_var = Obj.magic d1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : ( +# 161 "parser_cocci_menhir.mly" + (Ast0_cocci.anything list list) +# 13162 "parser_cocci_menhir.ml" + ) = +# 1736 "parser_cocci_menhir.mly" + ( let check_one = function + [x] -> x + | _ -> + raise + (Semantic_cocci.Semantic + "only one variable per declaration in an isomorphism rule") in + let d1 = check_one d1 in + let dl = + List.map + (function + Common.Left x -> Common.Left(check_one x) + | Common.Right x -> Common.Right(check_one x)) + dl in + P.iso_adjust (function x -> Ast0.DeclTag x) d1 dl ) +# 13179 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let m : 'tv_metadec = Obj.magic m in + let _startpos = _startpos_m_ in + let _endpos = _endpos_m_ in + let _v : ( +# 164 "parser_cocci_menhir.mly" + ((Ast_cocci.metavar,Ast_cocci.metavar) Common.either list) +# 13203 "parser_cocci_menhir.ml" + ) = +# 181 "parser_cocci_menhir.mly" + ( m "" ) +# 13207 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = nm; + MenhirLib.EngineTypes.startp = _startpos_nm_; + MenhirLib.EngineTypes.endp = _endpos_nm_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let nm : 'tv_pure_ident = Obj.magic nm in + let _startpos = _startpos_nm_ in + let _endpos = _endpos__2_ in + let _v : ( +# 148 "parser_cocci_menhir.mly" + (Ast_cocci.rulename) +# 13235 "parser_cocci_menhir.ml" + ) = +# 196 "parser_cocci_menhir.mly" + ( P.make_iso_rule_name_result (P.id2name nm) ) +# 13239 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 59 "parser_cocci_menhir.mly" + (string * Data.clt) +# 13260 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_iter_ident = +# 1427 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Id(P.id2mcode _1)) ) +# 13267 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 62 "parser_cocci_menhir.mly" + (Parse_aux.idinfo) +# 13288 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_iter_ident = +# 1429 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,clt) = _1 in + Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) ) +# 13296 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_TMul_ = +# 114 "standard.mly" + ( [] ) +# 13313 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_TMul_ = Obj.magic xs in + let x : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 13340 "parser_cocci_menhir.ml" + ) = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_TMul_ = +# 116 "standard.mly" + ( x :: xs ) +# 13347 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_array_dec_ = +# 114 "standard.mly" + ( [] ) +# 13364 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_array_dec_ = Obj.magic xs in + let x : 'tv_array_dec = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_array_dec_ = +# 116 "standard.mly" + ( x :: xs ) +# 13394 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_case_line_ = +# 114 "standard.mly" + ( [] ) +# 13411 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_case_line_ = Obj.magic xs in + let x : 'tv_case_line = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_case_line_ = +# 116 "standard.mly" + ( x :: xs ) +# 13441 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_comma_decls_TEllipsis_decl__ = +# 114 "standard.mly" + ( [] ) +# 13458 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_comma_decls_TEllipsis_decl__ = Obj.magic xs in + let x : 'tv_comma_decls_TEllipsis_decl_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_comma_decls_TEllipsis_decl__ = +# 116 "standard.mly" + ( x :: xs ) +# 13488 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_comma_decls_TEllipsis_name_opt_decl__ = +# 114 "standard.mly" + ( [] ) +# 13505 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_comma_decls_TEllipsis_name_opt_decl__ = Obj.magic xs in + let x : 'tv_comma_decls_TEllipsis_name_opt_decl_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_comma_decls_TEllipsis_name_opt_decl__ = +# 116 "standard.mly" + ( x :: xs ) +# 13535 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_dp_comma_args_TEllipsis__ = +# 114 "standard.mly" + ( [] ) +# 13552 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_dp_comma_args_TEllipsis__ = Obj.magic xs in + let x : 'tv_dp_comma_args_TEllipsis_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_dp_comma_args_TEllipsis__ = +# 116 "standard.mly" + ( x :: xs ) +# 13582 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_incl_ = +# 114 "standard.mly" + ( [] ) +# 13599 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_incl_ = Obj.magic xs in + let x : 'tv_incl = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_incl_ = +# 116 "standard.mly" + ( x :: xs ) +# 13629 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_iso_ctype__ = +# 114 "standard.mly" + ( [] ) +# 13646 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_iso_ctype__ = Obj.magic xs in + let x : 'tv_iso_ctype_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_iso_ctype__ = +# 116 "standard.mly" + ( x :: xs ) +# 13676 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_iso_decl_var__ = +# 114 "standard.mly" + ( [] ) +# 13693 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_iso_decl_var__ = Obj.magic xs in + let x : 'tv_iso_decl_var_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_iso_decl_var__ = +# 116 "standard.mly" + ( x :: xs ) +# 13723 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_iso_dexpr__ = +# 114 "standard.mly" + ( [] ) +# 13740 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_iso_dexpr__ = Obj.magic xs in + let x : 'tv_iso_dexpr_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_iso_dexpr__ = +# 116 "standard.mly" + ( x :: xs ) +# 13770 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_iso_nest_start__ = +# 114 "standard.mly" + ( [] ) +# 13787 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_iso_nest_start__ = Obj.magic xs in + let x : 'tv_iso_nest_start_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_iso_nest_start__ = +# 116 "standard.mly" + ( x :: xs ) +# 13817 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_iso_single_statement__ = +# 114 "standard.mly" + ( [] ) +# 13834 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_iso_single_statement__ = Obj.magic xs in + let x : 'tv_iso_single_statement_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_iso_single_statement__ = +# 116 "standard.mly" + ( x :: xs ) +# 13864 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_mzl_ctype__ = +# 114 "standard.mly" + ( [] ) +# 13881 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_mzl_ctype__ = Obj.magic xs in + let x : 'tv_mzl_ctype_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_mzl_ctype__ = +# 116 "standard.mly" + ( x :: xs ) +# 13911 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_mzl_eexpr__ = +# 114 "standard.mly" + ( [] ) +# 13928 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_mzl_eexpr__ = Obj.magic xs in + let x : 'tv_mzl_eexpr_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_mzl_eexpr__ = +# 116 "standard.mly" + ( x :: xs ) +# 13958 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_mzl_fun_after_dots_or__ = +# 114 "standard.mly" + ( [] ) +# 13975 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_mzl_fun_after_dots_or__ = Obj.magic xs in + let x : 'tv_mzl_fun_after_dots_or_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_mzl_fun_after_dots_or__ = +# 116 "standard.mly" + ( x :: xs ) +# 14005 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_mzl_fun_start__ = +# 114 "standard.mly" + ( [] ) +# 14022 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_mzl_fun_start__ = Obj.magic xs in + let x : 'tv_mzl_fun_start_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_mzl_fun_start__ = +# 116 "standard.mly" + ( x :: xs ) +# 14052 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_mzl_rule_elem_statement__ = +# 114 "standard.mly" + ( [] ) +# 14069 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_mzl_rule_elem_statement__ = Obj.magic xs in + let x : 'tv_mzl_rule_elem_statement_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_mzl_rule_elem_statement__ = +# 116 "standard.mly" + ( x :: xs ) +# 14099 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_mzl_statement__ = +# 114 "standard.mly" + ( [] ) +# 14116 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_mzl_statement__ = Obj.magic xs in + let x : 'tv_mzl_statement_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_mzl_statement__ = +# 116 "standard.mly" + ( x :: xs ) +# 14146 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_pair_edots_when_TEllipsis_eexpr__dexpr__ = +# 114 "standard.mly" + ( [] ) +# 14163 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = y0; + MenhirLib.EngineTypes.startp = _startpos_y0_; + MenhirLib.EngineTypes.endp = _endpos_y0_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_list_pair_edots_when_TEllipsis_eexpr__dexpr__ = Obj.magic xs in + let y0 : 'tv_dexpr = Obj.magic y0 in + let x0 : 'tv_edots_when_TEllipsis_eexpr_ = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_pair_edots_when_TEllipsis_eexpr__dexpr__ = let x = + let y = y0 in + let x = x0 in + +# 70 "standard.mly" + ( (x, y) ) +# 14202 "parser_cocci_menhir.ml" + + in + +# 116 "standard.mly" + ( x :: xs ) +# 14208 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_list_whenppdecs_ = +# 114 "standard.mly" + ( [] ) +# 14225 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_list_whenppdecs_ = Obj.magic xs in + let x : 'tv_whenppdecs = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_list_whenppdecs_ = +# 116 "standard.mly" + ( x :: xs ) +# 14255 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_loption_choose_iso_ = +# 57 "standard.mly" + ( [] ) +# 14272 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_choose_iso = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_loption_choose_iso_ = +# 59 "standard.mly" + ( x ) +# 14296 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_loption_disable_ = +# 57 "standard.mly" + ( [] ) +# 14313 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_disable = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_loption_disable_ = +# 59 "standard.mly" + ( x ) +# 14337 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_loption_error_words_ = +# 57 "standard.mly" + ( [] ) +# 14354 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_error_words = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_loption_error_words_ = +# 59 "standard.mly" + ( x ) +# 14378 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_loption_filespec_ = +# 57 "standard.mly" + ( [] ) +# 14395 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_filespec = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_loption_filespec_ = +# 59 "standard.mly" + ( x ) +# 14419 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_loption_minus_start_ = +# 57 "standard.mly" + ( [] ) +# 14436 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_minus_start = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_loption_minus_start_ = +# 59 "standard.mly" + ( x ) +# 14460 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_loption_not_ceq_ = +# 57 "standard.mly" + ( [] ) +# 14477 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_not_ceq = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_loption_not_ceq_ = +# 59 "standard.mly" + ( x ) +# 14501 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_loption_not_eq_ = +# 57 "standard.mly" + ( [] ) +# 14518 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_not_eq = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_loption_not_eq_ = +# 59 "standard.mly" + ( x ) +# 14542 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_loption_not_eqe_ = +# 57 "standard.mly" + ( [] ) +# 14559 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_not_eqe = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_loption_not_eqe_ = +# 59 "standard.mly" + ( x ) +# 14583 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_loption_not_pos_ = +# 57 "standard.mly" + ( [] ) +# 14600 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_not_pos = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_loption_not_pos_ = +# 59 "standard.mly" + ( x ) +# 14624 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_loption_plus_start_ = +# 57 "standard.mly" + ( [] ) +# 14641 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_plus_start = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_loption_plus_start_ = +# 59 "standard.mly" + ( x ) +# 14665 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_t_ in + let _v : 'tv_meta_exp_type = +# 429 "parser_cocci_menhir.mly" + ( [Ast0_cocci.ast0_type_to_type t] ) +# 14689 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let m : 'tv_list_TMul_ = Obj.magic m in + let t : 'tv_comma_list_ctype_ = Obj.magic t in + let _startpos = _startpos__1_ in + let _endpos = _endpos_m_ in + let _v : 'tv_meta_exp_type = +# 431 "parser_cocci_menhir.mly" + ( List.map + (function x -> P.ty_pointerify (Ast0_cocci.ast0_type_to_type x) m) + t ) +# 14729 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_pure_ident = Obj.magic _3 in + let _1 : ( +# 47 "parser_cocci_menhir.mly" + (string) +# 14760 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_meta_ident = +# 1325 "parser_cocci_menhir.mly" + ( (Some _1,P.id2name _3) ) +# 14767 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let m : 'tv_metadec = Obj.magic m in + let _startpos = _startpos_m_ in + let _endpos = _endpos_m_ in + let _v : ( +# 156 "parser_cocci_menhir.mly" + ((Ast_cocci.metavar,Ast_cocci.metavar) Common.either list) +# 14791 "parser_cocci_menhir.ml" + ) = +# 180 "parser_cocci_menhir.mly" + ( m (!Ast0.rule_name) ) +# 14795 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__6_ in + let _v : 'tv_metadec = let kindfn = + +# 294 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaFreshIdDecl(arity,name)) in + !Data.add_id_meta name [] pure; tok) ) +# 14846 "parser_cocci_menhir.ml" + + in + +# 253 "parser_cocci_menhir.mly" + ( P.create_metadec ar ispure kindfn ids ) +# 14852 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = let kindfn = + +# 298 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaParamDecl(arity,name)) in + !Data.add_param_meta name pure; tok) ) +# 14899 "parser_cocci_menhir.ml" + + in + +# 253 "parser_cocci_menhir.mly" + ( P.create_metadec ar ispure kindfn ids ) +# 14905 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__6_ in + let _v : 'tv_metadec = let kindfn = + +# 302 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaParamListDecl(arity,name,None)) in + !Data.add_paramlist_meta name None pure; tok) ) +# 14956 "parser_cocci_menhir.ml" + + in + +# 253 "parser_cocci_menhir.mly" + ( P.create_metadec ar ispure kindfn ids ) +# 14962 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__6_ in + let _v : 'tv_metadec = let kindfn = + +# 306 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaExpListDecl(arity,name,None)) in + !Data.add_explist_meta name None pure; tok) ) +# 15013 "parser_cocci_menhir.ml" + + in + +# 253 "parser_cocci_menhir.mly" + ( P.create_metadec ar ispure kindfn ids ) +# 15019 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = let kindfn = + +# 310 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaTypeDecl(arity,name)) in + !Data.add_type_meta name pure; tok) ) +# 15066 "parser_cocci_menhir.ml" + + in + +# 253 "parser_cocci_menhir.mly" + ( P.create_metadec ar ispure kindfn ids ) +# 15072 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = let kindfn = + +# 314 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaStmDecl(arity,name)) in + !Data.add_stm_meta name pure; tok) ) +# 15119 "parser_cocci_menhir.ml" + + in + +# 253 "parser_cocci_menhir.mly" + ( P.create_metadec ar ispure kindfn ids ) +# 15125 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__6_ in + let _v : 'tv_metadec = let kindfn = + +# 318 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaStmListDecl(arity,name)) in + !Data.add_stmlist_meta name pure; tok) ) +# 15176 "parser_cocci_menhir.ml" + + in + +# 253 "parser_cocci_menhir.mly" + ( P.create_metadec ar ispure kindfn ids ) +# 15182 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = let kindfn = + +# 322 "parser_cocci_menhir.mly" + ( (fun arity (_,name) pure check_meta -> + if arity = Ast.NONE && pure = Ast0.Impure + then (!Data.add_type_name name; []) + else raise (Semantic_cocci.Semantic "bad typedef")) ) +# 15230 "parser_cocci_menhir.ml" + + in + +# 253 "parser_cocci_menhir.mly" + ( P.create_metadec ar ispure kindfn ids ) +# 15236 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__6_ in + let _v : 'tv_metadec = let kindfn = + +# 327 "parser_cocci_menhir.mly" + ( (fun arity (_,name) pure check_meta -> + if arity = Ast.NONE && pure = Ast0.Impure + then (!Data.add_declarer_name name; []) + else raise (Semantic_cocci.Semantic "bad declarer")) ) +# 15288 "parser_cocci_menhir.ml" + + in + +# 253 "parser_cocci_menhir.mly" + ( P.create_metadec ar ispure kindfn ids ) +# 15294 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__6_ in + let _v : 'tv_metadec = let kindfn = + +# 332 "parser_cocci_menhir.mly" + ( (fun arity (_,name) pure check_meta -> + if arity = Ast.NONE && pure = Ast0.Impure + then (!Data.add_iterator_name name; []) + else raise (Semantic_cocci.Semantic "bad iterator")) ) +# 15346 "parser_cocci_menhir.ml" + + in + +# 253 "parser_cocci_menhir.mly" + ( P.create_metadec ar ispure kindfn ids ) +# 15352 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eq__ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = let kindfn = + +# 340 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaIdDecl(arity,name)) in + !Data.add_id_meta name constraints pure; tok) ) +# 15399 "parser_cocci_menhir.ml" + + in + +# 257 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 15405 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eq__ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = let kindfn = + +# 344 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaFuncDecl(arity,name)) in + !Data.add_func_meta name constraints pure; tok) ) +# 15452 "parser_cocci_menhir.ml" + + in + +# 257 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 15458 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eq__ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__6_ in + let _v : 'tv_metadec = let kindfn = + +# 348 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaLocalFuncDecl(arity,name)) in + !Data.add_local_func_meta name constraints pure; + tok) ) +# 15510 "parser_cocci_menhir.ml" + + in + +# 257 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 15516 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eq__ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = let kindfn = + +# 353 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaDeclarerDecl(arity,name)) in + !Data.add_declarer_meta name constraints pure; tok) ) +# 15563 "parser_cocci_menhir.ml" + + in + +# 257 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 15569 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eq__ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = let kindfn = + +# 357 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaIteratorDecl(arity,name)) in + !Data.add_iterator_meta name constraints pure; tok) ) +# 15616 "parser_cocci_menhir.ml" + + in + +# 257 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 15622 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = let kindfn = + +# 363 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaErrDecl(arity,name)) in + !Data.add_err_meta name constraints pure; tok) ) +# 15669 "parser_cocci_menhir.ml" + + in + +# 261 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 15675 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = l0; + MenhirLib.EngineTypes.startp = _startpos_l0_; + MenhirLib.EngineTypes.endp = _endpos_l0_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = Obj.magic ids in + let l0 : 'tv_option_TLocal_ = Obj.magic l0 in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__6_ in + let _v : 'tv_metadec = let kindfn = + let l = l0 in + let ty = + +# 39 "standard.mly" + ( None ) +# 15728 "parser_cocci_menhir.ml" + + in + +# 367 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + match l with + None -> + !Data.add_idexp_meta ty name constraints pure; + check_meta(Ast.MetaIdExpDecl(arity,name,ty)) + | Some _ -> + !Data.add_local_idexp_meta ty name constraints pure; + check_meta(Ast.MetaLocalIdExpDecl(arity,name,ty))) ) +# 15741 "parser_cocci_menhir.ml" + + in + +# 261 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 15747 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__7_; + MenhirLib.EngineTypes.endp = _endpos__7_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = x00; + MenhirLib.EngineTypes.startp = _startpos_x00_; + MenhirLib.EngineTypes.endp = _endpos_x00_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = l0; + MenhirLib.EngineTypes.startp = _startpos_l0_; + MenhirLib.EngineTypes.endp = _endpos_l0_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = Obj.magic ids in + let x00 : 'tv_meta_exp_type = Obj.magic x00 in + let l0 : 'tv_option_TLocal_ = Obj.magic l0 in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__7_ in + let _v : 'tv_metadec = let kindfn = + let x0 = x00 in + let l = l0 in + let ty = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 15808 "parser_cocci_menhir.ml" + + in + +# 367 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + match l with + None -> + !Data.add_idexp_meta ty name constraints pure; + check_meta(Ast.MetaIdExpDecl(arity,name,ty)) + | Some _ -> + !Data.add_local_idexp_meta ty name constraints pure; + check_meta(Ast.MetaLocalIdExpDecl(arity,name,ty))) ) +# 15821 "parser_cocci_menhir.ml" + + in + +# 261 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 15827 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__7_; + MenhirLib.EngineTypes.endp = _endpos__7_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = m0; + MenhirLib.EngineTypes.startp = _startpos_m0_; + MenhirLib.EngineTypes.endp = _endpos_m0_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = l0; + MenhirLib.EngineTypes.startp = _startpos_l0_; + MenhirLib.EngineTypes.endp = _endpos_l0_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = Obj.magic ids in + let m0 : 'tv_nonempty_list_TMul_ = Obj.magic m0 in + let l0 : 'tv_option_TLocal_ = Obj.magic l0 in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__7_ in + let _v : 'tv_metadec = let kindfn = + let m = m0 in + let l = l0 in + +# 376 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let ty = Some [P.ty_pointerify Type_cocci.Unknown m] in + match l with + None -> + !Data.add_idexp_meta ty name constraints pure; + check_meta(Ast.MetaIdExpDecl(arity,name,ty)) + | Some _ -> + !Data.add_local_idexp_meta ty name constraints pure; + check_meta(Ast.MetaLocalIdExpDecl(arity,name,ty))) ) +# 15894 "parser_cocci_menhir.ml" + + in + +# 261 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 15900 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = m0; + MenhirLib.EngineTypes.startp = _startpos_m0_; + MenhirLib.EngineTypes.endp = _endpos_m0_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = Obj.magic ids in + let m0 : 'tv_nonempty_list_TMul_ = Obj.magic m0 in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__6_ in + let _v : 'tv_metadec = let kindfn = + let m = m0 in + +# 386 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let ty = Some [P.ty_pointerify Type_cocci.Unknown m] in + let tok = check_meta(Ast.MetaExpDecl(arity,name,ty)) in + !Data.add_exp_meta ty name constraints pure; tok) ) +# 15955 "parser_cocci_menhir.ml" + + in + +# 261 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 15961 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__7_; + MenhirLib.EngineTypes.endp = _endpos__7_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = vl0; + MenhirLib.EngineTypes.startp = _startpos_vl0_; + MenhirLib.EngineTypes.endp = _endpos_vl0_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = Obj.magic ids in + let vl0 : 'tv_meta_exp_type = Obj.magic vl0 in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__7_ in + let _v : 'tv_metadec = let kindfn = + let vl = vl0 in + +# 391 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let ty = Some (List.map (function x -> Type_cocci.Array x) vl) in + let tok = check_meta(Ast.MetaExpDecl(arity,name,ty)) in + !Data.add_exp_meta ty name constraints pure; tok) ) +# 16020 "parser_cocci_menhir.ml" + + in + +# 261 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 16026 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = let kindfn = + let ty = + +# 39 "standard.mly" + ( None ) +# 16072 "parser_cocci_menhir.ml" + + in + +# 396 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaConstDecl(arity,name,ty)) in + !Data.add_const_meta ty name constraints pure; tok) ) +# 16080 "parser_cocci_menhir.ml" + + in + +# 261 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 16086 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = x00; + MenhirLib.EngineTypes.startp = _startpos_x00_; + MenhirLib.EngineTypes.endp = _endpos_x00_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = Obj.magic ids in + let x00 : 'tv_meta_exp_type = Obj.magic x00 in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__6_ in + let _v : 'tv_metadec = let kindfn = + let x0 = x00 in + let ty = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 16140 "parser_cocci_menhir.ml" + + in + +# 396 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaConstDecl(arity,name,ty)) in + !Data.add_const_meta ty name constraints pure; tok) ) +# 16148 "parser_cocci_menhir.ml" + + in + +# 261 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 16154 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_ceq__ = Obj.magic ids in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = let kindfn = + +# 402 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaExpDecl(arity,name,None)) in + !Data.add_exp_meta None name constraints pure; tok) ) +# 16201 "parser_cocci_menhir.ml" + + in + +# 265 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 16207 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = vl0; + MenhirLib.EngineTypes.startp = _startpos_vl0_; + MenhirLib.EngineTypes.endp = _endpos_vl0_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_ceq__ = Obj.magic ids in + let vl0 : 'tv_meta_exp_type = Obj.magic vl0 in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = let kindfn = + let vl = vl0 in + +# 406 "parser_cocci_menhir.mly" + ( (fun arity name pure check_meta constraints -> + let ty = Some vl in + List.iter + (function c -> + match Ast0.unwrap c with + Ast0.Constant(_) -> + if not + (List.exists + (function + Type_cocci.BaseType(Type_cocci.IntType,_) -> true + | Type_cocci.BaseType(Type_cocci.ShortType,_) -> true + | Type_cocci.BaseType(Type_cocci.LongType,_) -> true + | _ -> false) + vl) + then failwith "metavariable with int constraint must be an int" + | _ -> ()) + constraints; + let tok = check_meta(Ast.MetaExpDecl(arity,name,ty)) in + !Data.add_exp_meta ty name constraints pure; tok) ) +# 16273 "parser_cocci_menhir.ml" + + in + +# 265 "parser_cocci_menhir.mly" + ( P.create_metadec_ne ar ispure kindfn ids ) +# 16279 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_with_not_eq_not_pos__ = Obj.magic ids in + let a : 'tv_option_TPosAny_ = Obj.magic a in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__5_ in + let _v : 'tv_metadec = +# 268 "parser_cocci_menhir.mly" + ( let kindfn arity name pure check_meta constraints = + let tok = check_meta(Ast.MetaPosDecl(arity,name)) in + let any = match a with None -> Ast.PER | Some _ -> Ast.ALL in + !Data.add_pos_meta name constraints any; tok in + P.create_metadec_ne ar false kindfn ids ) +# 16327 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__9_; + MenhirLib.EngineTypes.endp = _endpos__9_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__7_; + MenhirLib.EngineTypes.endp = _endpos__7_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = id; + MenhirLib.EngineTypes.startp = _startpos_id_; + MenhirLib.EngineTypes.endp = _endpos_id_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_ = Obj.magic ids in + let id : 'tv_pure_ident_or_meta_ident = Obj.magic id in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__9_ in + let _v : 'tv_metadec = +# 276 "parser_cocci_menhir.mly" + ( P.create_len_metadec ar ispure + (fun lenname arity name pure check_meta -> + let tok = + check_meta(Ast.MetaParamListDecl(arity,name,Some lenname)) in + !Data.add_paramlist_meta name (Some lenname) pure; tok) + id ids ) +# 16394 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__9_; + MenhirLib.EngineTypes.endp = _endpos__9_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ids; + MenhirLib.EngineTypes.startp = _startpos_ids_; + MenhirLib.EngineTypes.endp = _endpos_ids_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__7_; + MenhirLib.EngineTypes.endp = _endpos__7_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = id; + MenhirLib.EngineTypes.startp = _startpos_id_; + MenhirLib.EngineTypes.endp = _endpos_id_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ispure; + MenhirLib.EngineTypes.startp = _startpos_ispure_; + MenhirLib.EngineTypes.endp = _endpos_ispure_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = ar; + MenhirLib.EngineTypes.startp = _startpos_ar_; + MenhirLib.EngineTypes.endp = _endpos_ar_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ids : 'tv_comma_list_pure_ident_or_meta_ident_ = Obj.magic ids in + let id : 'tv_pure_ident_or_meta_ident = Obj.magic id in + let ispure : 'tv_pure = Obj.magic ispure in + let ar : 'tv_arity = Obj.magic ar in + let _startpos = _startpos_ar_ in + let _endpos = _endpos__9_ in + let _v : 'tv_metadec = +# 285 "parser_cocci_menhir.mly" + ( P.create_len_metadec ar ispure + (fun lenname arity name pure check_meta -> + let tok = + check_meta(Ast.MetaExpListDecl(arity,name,Some lenname)) in + !Data.add_explist_meta name (Some lenname) pure; tok) + id ids ) +# 16461 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_list_mzl_ctype__ = Obj.magic b in + let a : 'tv_ctype = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_midzero_list_ctype_ctype_ = +# 1692 "parser_cocci_menhir.mly" + ( let (mids,code) = List.split b in (mids,(a::code)) ) +# 16491 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_list_mzl_eexpr__ = Obj.magic b in + let a : 'tv_eexpr = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_midzero_list_eexpr_eexpr_ = +# 1692 "parser_cocci_menhir.mly" + ( let (mids,code) = List.split b in (mids,(a::code)) ) +# 16521 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_list_mzl_eexpr__ = Obj.magic b in + let a : 'tv_expr = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_midzero_list_expr_eexpr_ = +# 1692 "parser_cocci_menhir.mly" + ( let (mids,code) = List.split b in (mids,(a::code)) ) +# 16551 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_list_mzl_fun_after_dots_or__ = Obj.magic b in + let a : 'tv_fun_after_stm = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_midzero_list_fun_after_stm_fun_after_dots_or_ = +# 1692 "parser_cocci_menhir.mly" + ( let (mids,code) = List.split b in (mids,(a::code)) ) +# 16581 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_list_mzl_fun_start__ = Obj.magic b in + let a : 'tv_fun_start = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_midzero_list_fun_start_fun_start_ = +# 1692 "parser_cocci_menhir.mly" + ( let (mids,code) = List.split b in (mids,(a::code)) ) +# 16611 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_list_mzl_rule_elem_statement__ = Obj.magic b in + let a : 'tv_rule_elem_statement = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_midzero_list_rule_elem_statement_rule_elem_statement_ = +# 1692 "parser_cocci_menhir.mly" + ( let (mids,code) = List.split b in (mids,(a::code)) ) +# 16641 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_list_mzl_statement__ = Obj.magic b in + let a : 'tv_statement = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_midzero_list_statement_statement_ = +# 1692 "parser_cocci_menhir.mly" + ( let (mids,code) = List.split b in (mids,(a::code)) ) +# 16671 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = ew; + MenhirLib.EngineTypes.startp = _startpos_ew_; + MenhirLib.EngineTypes.endp = _endpos_ew_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = f; + MenhirLib.EngineTypes.startp = _startpos_f_; + MenhirLib.EngineTypes.endp = _endpos_f_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let ew : 'tv_loption_error_words_ = Obj.magic ew in + let b : 'tv_loption_minus_start_ = Obj.magic b in + let f : 'tv_loption_filespec_ = Obj.magic f in + let _startpos = _startpos_f_ in + let _endpos = _endpos_ew_ in + let _v : 'tv_minus_body = +# 554 "parser_cocci_menhir.mly" + ( match f@b@ew with + [] -> raise (Semantic_cocci.Semantic "minus slice can't be empty") + | code -> Top_level.top_level code ) +# 16709 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = ew; + MenhirLib.EngineTypes.startp = _startpos_ew_; + MenhirLib.EngineTypes.endp = _endpos_ew_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = f; + MenhirLib.EngineTypes.startp = _startpos_f_; + MenhirLib.EngineTypes.endp = _endpos_f_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let ew : 'tv_loption_error_words_ = Obj.magic ew in + let b : 'tv_top_eexpr = Obj.magic b in + let f : 'tv_loption_filespec_ = Obj.magic f in + let _startpos = _startpos_f_ in + let _endpos = _endpos_ew_ in + let _v : 'tv_minus_exp_body = +# 568 "parser_cocci_menhir.mly" + ( match f@[b]@ew with + [] -> raise (Semantic_cocci.Semantic "minus slice can't be empty") + | code -> Top_level.top_level code ) +# 16747 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _1 : 'tv_minus_exp_body = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : ( +# 136 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 16775 "parser_cocci_menhir.ml" + ) = +# 176 "parser_cocci_menhir.mly" + ( _1 ) +# 16779 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let m : 'tv_minus_exp_body = Obj.magic m in + let _startpos = _startpos_m_ in + let _endpos = _endpos__2_ in + let _v : ( +# 136 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 16807 "parser_cocci_menhir.ml" + ) = +# 176 "parser_cocci_menhir.mly" + ( m ) +# 16811 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let m : 'tv_minus_exp_body = Obj.magic m in + let _startpos = _startpos_m_ in + let _endpos = _endpos__2_ in + let _v : ( +# 136 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 16839 "parser_cocci_menhir.ml" + ) = +# 177 "parser_cocci_menhir.mly" + ( m ) +# 16843 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _1 : 'tv_minus_body = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : ( +# 133 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 16871 "parser_cocci_menhir.ml" + ) = +# 172 "parser_cocci_menhir.mly" + ( _1 ) +# 16875 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let m : 'tv_minus_body = Obj.magic m in + let _startpos = _startpos_m_ in + let _endpos = _endpos__2_ in + let _v : ( +# 133 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 16903 "parser_cocci_menhir.ml" + ) = +# 172 "parser_cocci_menhir.mly" + ( m ) +# 16907 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = m; + MenhirLib.EngineTypes.startp = _startpos_m_; + MenhirLib.EngineTypes.endp = _endpos_m_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let m : 'tv_minus_body = Obj.magic m in + let _startpos = _startpos_m_ in + let _endpos = _endpos__2_ in + let _v : ( +# 133 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 16935 "parser_cocci_menhir.ml" + ) = +# 173 "parser_cocci_menhir.mly" + ( m ) +# 16939 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_fundecl = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_minus_start = +# 1514 "parser_cocci_menhir.mly" + ( [Ast0.wrap(Ast0.DECL(_1))] ) +# 16963 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_ctype = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_minus_start = +# 1515 "parser_cocci_menhir.mly" + ( [Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Ty(_1))))] ) +# 16987 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_toplevel_seq_start_toplevel_after_dots_init_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_minus_start = +# 1517 "parser_cocci_menhir.mly" + ( List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) _1 ) +# 17011 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_ctype = Obj.magic b in + let a : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 17038 "parser_cocci_menhir.ml" + ) = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_mzl_ctype_ = +# 1695 "parser_cocci_menhir.mly" + ( (P.clt2mcode "|" a, b) ) +# 17045 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_eexpr = Obj.magic b in + let a : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 17072 "parser_cocci_menhir.ml" + ) = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_mzl_eexpr_ = +# 1695 "parser_cocci_menhir.mly" + ( (P.clt2mcode "|" a, b) ) +# 17079 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_fun_after_dots_or = Obj.magic b in + let a : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 17106 "parser_cocci_menhir.ml" + ) = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_mzl_fun_after_dots_or_ = +# 1695 "parser_cocci_menhir.mly" + ( (P.clt2mcode "|" a, b) ) +# 17113 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_fun_start = Obj.magic b in + let a : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 17140 "parser_cocci_menhir.ml" + ) = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_mzl_fun_start_ = +# 1695 "parser_cocci_menhir.mly" + ( (P.clt2mcode "|" a, b) ) +# 17147 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_rule_elem_statement = Obj.magic b in + let a : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 17174 "parser_cocci_menhir.ml" + ) = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_mzl_rule_elem_statement_ = +# 1695 "parser_cocci_menhir.mly" + ( (P.clt2mcode "|" a, b) ) +# 17181 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let b : 'tv_statement = Obj.magic b in + let a : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 17208 "parser_cocci_menhir.ml" + ) = Obj.magic a in + let _startpos = _startpos_a_ in + let _endpos = _endpos_b_ in + let _v : 'tv_mzl_statement_ = +# 1695 "parser_cocci_menhir.mly" + ( (P.clt2mcode "|" a, b) ) +# 17215 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_decl = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_name_opt_decl = +# 785 "parser_cocci_menhir.mly" + ( _1 ) +# 17239 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_t_ in + let _v : 'tv_name_opt_decl = +# 786 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Param(t, None)) ) +# 17263 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = rp1; + MenhirLib.EngineTypes.startp = _startpos_rp1_; + MenhirLib.EngineTypes.endp = _endpos_rp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp1; + MenhirLib.EngineTypes.startp = _startpos_lp1_; + MenhirLib.EngineTypes.endp = _endpos_lp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let rp1 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 17314 "parser_cocci_menhir.ml" + ) = Obj.magic rp1 in + let d : 'tv_decl_list_name_opt_decl_ = Obj.magic d in + let lp1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 17320 "parser_cocci_menhir.ml" + ) = Obj.magic lp1 in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 17325 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let s : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 17330 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 17335 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let t : 'tv_fn_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_rp1_ in + let _v : 'tv_name_opt_decl = +# 789 "parser_cocci_menhir.mly" + ( let fnptr = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp,P.clt2mcode "*" s,P.clt2mcode ")" rp, + P.clt2mcode "(" lp1,d,P.clt2mcode ")" rp1)) in + Ast0.wrap(Ast0.Param(fnptr, None)) ) +# 17348 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_nest_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_nest_after_dots = +# 1616 "parser_cocci_menhir.mly" + (_1@_2) +# 17378 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_nest_after_exp = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_nest_after_dots = +# 1617 "parser_cocci_menhir.mly" + (_2) +# 17406 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_nest_after_exp = Obj.magic _2 in + let _1 : 'tv_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_nest_after_dots = +# 1618 "parser_cocci_menhir.mly" + ((Ast0.wrap(Ast0.Exp(_1)))::_2) +# 17436 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_nest_after_exp = +# 1626 "parser_cocci_menhir.mly" + ([]) +# 17453 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_nest_after_dots = Obj.magic _2 in + let _1 : 'tv_stm_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_nest_after_exp = +# 1627 "parser_cocci_menhir.mly" + (_1::_2) +# 17483 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_nest_after_stm = +# 1621 "parser_cocci_menhir.mly" + ([]) +# 17500 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_nest_after_dots = Obj.magic _2 in + let _1 : 'tv_stm_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_nest_after_stm = +# 1622 "parser_cocci_menhir.mly" + (_1::_2) +# 17530 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_nest_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_nest_after_stm = +# 1623 "parser_cocci_menhir.mly" + (_1@_2) +# 17560 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = c; + MenhirLib.EngineTypes.startp = _startpos_c_; + MenhirLib.EngineTypes.endp = _endpos_c_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let c : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 17596 "parser_cocci_menhir.ml" + ) = Obj.magic c in + let e : 'tv_expr_dots_TEllipsis_ = Obj.magic e in + let w : 'tv_option_whenexp_ = Obj.magic w in + let _1 : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 17603 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos_c_ in + let _v : 'tv_nest_expressions = +# 1148 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.NestExpr(P.clt2mcode "<..." _1, + Ast0.wrap(Ast0.DOTS(e (P.mkedots "..."))), + P.clt2mcode "...>" c, w, false)) ) +# 17612 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = c; + MenhirLib.EngineTypes.startp = _startpos_c_; + MenhirLib.EngineTypes.endp = _endpos_c_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let c : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 17648 "parser_cocci_menhir.ml" + ) = Obj.magic c in + let e : 'tv_expr_dots_TEllipsis_ = Obj.magic e in + let w : 'tv_option_whenexp_ = Obj.magic w in + let _1 : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 17655 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos_c_ in + let _v : 'tv_nest_expressions = +# 1152 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.NestExpr(P.clt2mcode "<+..." _1, + Ast0.wrap(Ast0.DOTS(e (P.mkedots "..."))), + P.clt2mcode "...+>" c, w, true)) ) +# 17664 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_nest_after_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_nest_start = +# 1613 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.DOTS(_1)) ) +# 17688 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : ( +# 167 "parser_cocci_menhir.mly" + (unit) +# 17710 "parser_cocci_menhir.ml" + ) = +# 1760 "parser_cocci_menhir.mly" + ( () ) +# 17714 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : ( +# 167 "parser_cocci_menhir.mly" + (unit) +# 17740 "parser_cocci_menhir.ml" + ) = +# 1761 "parser_cocci_menhir.mly" + ( () ) +# 17744 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : ( +# 167 "parser_cocci_menhir.mly" + (unit) +# 17766 "parser_cocci_menhir.ml" + ) = +# 1762 "parser_cocci_menhir.mly" + ( () ) +# 17770 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = dg; + MenhirLib.EngineTypes.startp = _startpos_dg_; + MenhirLib.EngineTypes.endp = _endpos_dg_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = g; + MenhirLib.EngineTypes.startp = _startpos_g_; + MenhirLib.EngineTypes.endp = _endpos_g_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let dg : 'tv_list_pair_edots_when_TEllipsis_eexpr__dexpr__ = Obj.magic dg in + let g : 'tv_dexpr = Obj.magic g in + let _startpos = _startpos_g_ in + let _endpos = _endpos_dg_ in + let _v : 'tv_no_dot_start_end_dexpr_edots_when_TEllipsis_eexpr__ = +# 1316 "parser_cocci_menhir.mly" + ( function dot_builder -> + g :: (List.concat(List.map (function (d,g) -> [dot_builder d;g]) dg)) ) +# 17801 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 17822 "parser_cocci_menhir.ml" + ) = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_nonempty_list_TMul_ = +# 124 "standard.mly" + ( [ x ] ) +# 17829 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let xs : 'tv_nonempty_list_TMul_ = Obj.magic xs in + let x : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 17856 "parser_cocci_menhir.ml" + ) = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_nonempty_list_TMul_ = +# 126 "standard.mly" + ( x :: xs ) +# 17863 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let i : 'tv_ident_or_const = Obj.magic i in + let _startpos = _startpos__1_ in + let _endpos = _endpos_i_ in + let _v : 'tv_not_ceq = +# 1362 "parser_cocci_menhir.mly" + ( (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + [i] ) +# 17893 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let l : 'tv_comma_list_ident_or_const_ = Obj.magic l in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_not_ceq = +# 1366 "parser_cocci_menhir.mly" + ( (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + l ) +# 17931 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let i : 'tv_pure_ident = Obj.magic i in + let _startpos = _startpos__1_ in + let _endpos = _endpos_i_ in + let _v : 'tv_not_eq = +# 1339 "parser_cocci_menhir.mly" + ( (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + [Ast0.wrap(Ast0.Id(P.id2mcode i))] ) +# 17961 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let l : 'tv_comma_list_pure_ident_ = Obj.magic l in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_not_eq = +# 1343 "parser_cocci_menhir.mly" + ( (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + List.map (function i -> Ast0.wrap(Ast0.Id(P.id2mcode i))) l ) +# 17999 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let i : 'tv_pure_ident = Obj.magic i in + let _startpos = _startpos__1_ in + let _endpos = _endpos_i_ in + let _v : 'tv_not_eqe = +# 1349 "parser_cocci_menhir.mly" + ( (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + [Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i))))] ) +# 18029 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let l : 'tv_comma_list_pure_ident_ = Obj.magic l in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_not_eqe = +# 1353 "parser_cocci_menhir.mly" + ( (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + List.map + (function i -> + Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i))))) + l ) +# 18070 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let i : 'tv_meta_ident = Obj.magic i in + let _startpos = _startpos__1_ in + let _endpos = _endpos_i_ in + let _v : 'tv_not_pos = +# 1378 "parser_cocci_menhir.mly" + ( (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + match i with + (None,_) -> failwith "constraint must be an inherited variable" + | (Some rule,name) -> + let i = (rule,name) in + P.check_meta(Ast.MetaPosDecl(Ast.NONE,i)); + [i] ) +# 18105 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let l : 'tv_comma_list_meta_ident_ = Obj.magic l in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_not_pos = +# 1387 "parser_cocci_menhir.mly" + ( (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + List.map + (function + (None,_) -> + failwith "constraint must be an inherited variable" + | (Some rule,name) -> + let i = (rule,name) in + P.check_meta(Ast.MetaPosDecl(Ast.NONE,i)); + i) + l ) +# 18151 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_decl = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_one_dec_decl_ = +# 1458 "parser_cocci_menhir.mly" + ( _1 ) +# 18175 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 65 "parser_cocci_menhir.mly" + (Parse_aux.list_info) +# 18196 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_one_dec_decl_ = +# 1460 "parser_cocci_menhir.mly" + ( let (nm,lenname,pure,clt) = _1 in + let nm = P.clt2mcode nm clt in + let lenname = + match lenname with + Some nm -> Some(P.clt2mcode nm clt) + | None -> None in + Ast0.wrap(Ast0.MetaParamList(nm,lenname,pure)) ) +# 18209 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_name_opt_decl = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_one_dec_name_opt_decl_ = +# 1458 "parser_cocci_menhir.mly" + ( _1 ) +# 18233 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 65 "parser_cocci_menhir.mly" + (Parse_aux.list_info) +# 18254 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_one_dec_name_opt_decl_ = +# 1460 "parser_cocci_menhir.mly" + ( let (nm,lenname,pure,clt) = _1 in + let nm = P.clt2mcode nm clt in + let lenname = + match lenname with + Some nm -> Some(P.clt2mcode nm clt) + | None -> None in + Ast0.wrap(Ast0.MetaParamList(nm,lenname,pure)) ) +# 18267 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18293 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = +# 944 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.TyDecl(t,P.clt2mcode ";" pv)) ) +# 18301 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18332 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_d_ident = Obj.magic d in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let s = + +# 39 "standard.mly" + ( None ) +# 18342 "parser_cocci_menhir.ml" + + in + +# 946 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv)) ) +# 18349 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18385 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_d_ident = Obj.magic d in + let t : 'tv_ctype = Obj.magic t in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 18397 "parser_cocci_menhir.ml" + + in + +# 946 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv)) ) +# 18404 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = f; + MenhirLib.EngineTypes.startp = _startpos_f_; + MenhirLib.EngineTypes.endp = _endpos_f_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let f : 'tv_funproto = Obj.magic f in + let _startpos = _startpos_f_ in + let _endpos = _endpos_f_ in + let _v : 'tv_one_decl_var = +# 948 "parser_cocci_menhir.mly" + ( f ) +# 18428 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18469 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18475 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let d : 'tv_d_ident = Obj.magic d in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let s = + +# 39 "standard.mly" + ( None ) +# 18485 "parser_cocci_menhir.ml" + + in + +# 950 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv)) ) +# 18492 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18538 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18544 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let d : 'tv_d_ident = Obj.magic d in + let t : 'tv_ctype = Obj.magic t in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 18556 "parser_cocci_menhir.ml" + + in + +# 950 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv)) ) +# 18563 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18594 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let _startpos = _startpos_i_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let cv = + +# 39 "standard.mly" + ( None ) +# 18604 "parser_cocci_menhir.ml" + + in + let s = + +# 39 "standard.mly" + ( None ) +# 18611 "parser_cocci_menhir.ml" + + in + +# 955 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.UnInit(s,fn idtype,id,P.clt2mcode ";" pv)) ) +# 18619 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18655 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x0 : 'tv_const_vol = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let cv = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 18667 "parser_cocci_menhir.ml" + + in + let s = + +# 39 "standard.mly" + ( None ) +# 18674 "parser_cocci_menhir.ml" + + in + +# 955 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.UnInit(s,fn idtype,id,P.clt2mcode ";" pv)) ) +# 18682 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18718 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let cv = + +# 39 "standard.mly" + ( None ) +# 18729 "parser_cocci_menhir.ml" + + in + let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 18737 "parser_cocci_menhir.ml" + + in + +# 955 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.UnInit(s,fn idtype,id,P.clt2mcode ";" pv)) ) +# 18745 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = x1; + MenhirLib.EngineTypes.startp = _startpos_x1_; + MenhirLib.EngineTypes.endp = _endpos_x1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18786 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x1 : 'tv_const_vol = Obj.magic x1 in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let cv = + let x = x1 in + +# 41 "standard.mly" + ( Some x ) +# 18799 "parser_cocci_menhir.ml" + + in + let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 18807 "parser_cocci_menhir.ml" + + in + +# 955 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.UnInit(s,fn idtype,id,P.clt2mcode ";" pv)) ) +# 18815 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18856 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18862 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let _startpos = _startpos_i_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let cv = + +# 39 "standard.mly" + ( None ) +# 18872 "parser_cocci_menhir.ml" + + in + let s = + +# 39 "standard.mly" + ( None ) +# 18879 "parser_cocci_menhir.ml" + + in + +# 960 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + !Data.add_type_name (P.id2name i); + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.Init(s,fn idtype,id,P.clt2mcode "=" q,e, + P.clt2mcode ";" pv)) ) +# 18889 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18935 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 18941 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x0 : 'tv_const_vol = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let cv = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 18953 "parser_cocci_menhir.ml" + + in + let s = + +# 39 "standard.mly" + ( None ) +# 18960 "parser_cocci_menhir.ml" + + in + +# 960 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + !Data.add_type_name (P.id2name i); + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.Init(s,fn idtype,id,P.clt2mcode "=" q,e, + P.clt2mcode ";" pv)) ) +# 18970 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 19016 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 19022 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let cv = + +# 39 "standard.mly" + ( None ) +# 19033 "parser_cocci_menhir.ml" + + in + let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 19041 "parser_cocci_menhir.ml" + + in + +# 960 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + !Data.add_type_name (P.id2name i); + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.Init(s,fn idtype,id,P.clt2mcode "=" q,e, + P.clt2mcode ";" pv)) ) +# 19051 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = x1; + MenhirLib.EngineTypes.startp = _startpos_x1_; + MenhirLib.EngineTypes.endp = _endpos_x1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 19102 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 19108 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x1 : 'tv_const_vol = Obj.magic x1 in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let cv = + let x = x1 in + +# 41 "standard.mly" + ( Some x ) +# 19121 "parser_cocci_menhir.ml" + + in + let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 19129 "parser_cocci_menhir.ml" + + in + +# 960 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + !Data.add_type_name (P.id2name i); + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.Init(s,fn idtype,id,P.clt2mcode "=" q,e, + P.clt2mcode ";" pv)) ) +# 19139 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp2; + MenhirLib.EngineTypes.startp = _startpos_rp2_; + MenhirLib.EngineTypes.endp = _endpos_rp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp2; + MenhirLib.EngineTypes.startp = _startpos_lp2_; + MenhirLib.EngineTypes.endp = _endpos_lp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp1; + MenhirLib.EngineTypes.startp = _startpos_rp1_; + MenhirLib.EngineTypes.endp = _endpos_rp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = st; + MenhirLib.EngineTypes.startp = _startpos_st_; + MenhirLib.EngineTypes.endp = _endpos_st_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp1; + MenhirLib.EngineTypes.startp = _startpos_lp1_; + MenhirLib.EngineTypes.endp = _endpos_lp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 19200 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let rp2 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 19205 "parser_cocci_menhir.ml" + ) = Obj.magic rp2 in + let p : 'tv_decl_list_name_opt_decl_ = Obj.magic p in + let lp2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 19211 "parser_cocci_menhir.ml" + ) = Obj.magic lp2 in + let rp1 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 19216 "parser_cocci_menhir.ml" + ) = Obj.magic rp1 in + let d : 'tv_d_ident = Obj.magic d in + let st : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 19222 "parser_cocci_menhir.ml" + ) = Obj.magic st in + let lp1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 19227 "parser_cocci_menhir.ml" + ) = Obj.magic lp1 in + let t : 'tv_fn_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let s = + +# 39 "standard.mly" + ( None ) +# 19236 "parser_cocci_menhir.ml" + + in + +# 970 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv)) ) +# 19248 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp2; + MenhirLib.EngineTypes.startp = _startpos_rp2_; + MenhirLib.EngineTypes.endp = _endpos_rp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp2; + MenhirLib.EngineTypes.startp = _startpos_lp2_; + MenhirLib.EngineTypes.endp = _endpos_lp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp1; + MenhirLib.EngineTypes.startp = _startpos_rp1_; + MenhirLib.EngineTypes.endp = _endpos_rp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = st; + MenhirLib.EngineTypes.startp = _startpos_st_; + MenhirLib.EngineTypes.endp = _endpos_st_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp1; + MenhirLib.EngineTypes.startp = _startpos_lp1_; + MenhirLib.EngineTypes.endp = _endpos_lp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 19314 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let rp2 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 19319 "parser_cocci_menhir.ml" + ) = Obj.magic rp2 in + let p : 'tv_decl_list_name_opt_decl_ = Obj.magic p in + let lp2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 19325 "parser_cocci_menhir.ml" + ) = Obj.magic lp2 in + let rp1 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 19330 "parser_cocci_menhir.ml" + ) = Obj.magic rp1 in + let d : 'tv_d_ident = Obj.magic d in + let st : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 19336 "parser_cocci_menhir.ml" + ) = Obj.magic st in + let lp1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 19341 "parser_cocci_menhir.ml" + ) = Obj.magic lp1 in + let t : 'tv_fn_ctype = Obj.magic t in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 19352 "parser_cocci_menhir.ml" + + in + +# 970 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv)) ) +# 19364 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _5; + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let _5 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 19405 "parser_cocci_menhir.ml" + ) = Obj.magic _5 in + let _4 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 19410 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr_list_option = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 19416 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_decl_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__5_ in + let _v : 'tv_one_decl_var = +# 978 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.MacroDecl(_1,P.clt2mcode "(" _2,_3, + P.clt2mcode ")" _4,P.clt2mcode ";" _5)) ) +# 19425 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp2; + MenhirLib.EngineTypes.startp = _startpos_rp2_; + MenhirLib.EngineTypes.endp = _endpos_rp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp2; + MenhirLib.EngineTypes.startp = _startpos_lp2_; + MenhirLib.EngineTypes.endp = _endpos_lp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp1; + MenhirLib.EngineTypes.startp = _startpos_rp1_; + MenhirLib.EngineTypes.endp = _endpos_rp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = st; + MenhirLib.EngineTypes.startp = _startpos_st_; + MenhirLib.EngineTypes.endp = _endpos_st_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp1; + MenhirLib.EngineTypes.startp = _startpos_lp1_; + MenhirLib.EngineTypes.endp = _endpos_lp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 19496 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 19502 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let rp2 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 19507 "parser_cocci_menhir.ml" + ) = Obj.magic rp2 in + let p : 'tv_decl_list_name_opt_decl_ = Obj.magic p in + let lp2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 19513 "parser_cocci_menhir.ml" + ) = Obj.magic lp2 in + let rp1 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 19518 "parser_cocci_menhir.ml" + ) = Obj.magic rp1 in + let d : 'tv_d_ident = Obj.magic d in + let st : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 19524 "parser_cocci_menhir.ml" + ) = Obj.magic st in + let lp1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 19529 "parser_cocci_menhir.ml" + ) = Obj.magic lp1 in + let t : 'tv_fn_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let s = + +# 39 "standard.mly" + ( None ) +# 19538 "parser_cocci_menhir.ml" + + in + +# 984 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv))) +# 19550 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = q; + MenhirLib.EngineTypes.startp = _startpos_q_; + MenhirLib.EngineTypes.endp = _endpos_q_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp2; + MenhirLib.EngineTypes.startp = _startpos_rp2_; + MenhirLib.EngineTypes.endp = _endpos_rp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp2; + MenhirLib.EngineTypes.startp = _startpos_lp2_; + MenhirLib.EngineTypes.endp = _endpos_lp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp1; + MenhirLib.EngineTypes.startp = _startpos_rp1_; + MenhirLib.EngineTypes.endp = _endpos_rp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = st; + MenhirLib.EngineTypes.startp = _startpos_st_; + MenhirLib.EngineTypes.endp = _endpos_st_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp1; + MenhirLib.EngineTypes.startp = _startpos_lp1_; + MenhirLib.EngineTypes.endp = _endpos_lp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 19626 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let e : 'tv_initialize = Obj.magic e in + let q : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 19632 "parser_cocci_menhir.ml" + ) = Obj.magic q in + let rp2 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 19637 "parser_cocci_menhir.ml" + ) = Obj.magic rp2 in + let p : 'tv_decl_list_name_opt_decl_ = Obj.magic p in + let lp2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 19643 "parser_cocci_menhir.ml" + ) = Obj.magic lp2 in + let rp1 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 19648 "parser_cocci_menhir.ml" + ) = Obj.magic rp1 in + let d : 'tv_d_ident = Obj.magic d in + let st : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 19654 "parser_cocci_menhir.ml" + ) = Obj.magic st in + let lp1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 19659 "parser_cocci_menhir.ml" + ) = Obj.magic lp1 in + let t : 'tv_fn_ctype = Obj.magic t in + let x0 : 'tv_storage = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_one_decl_var = let s = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 19670 "parser_cocci_menhir.ml" + + in + +# 984 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv))) +# 19682 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_option_TLocal_ = +# 29 "standard.mly" + ( None ) +# 19699 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : unit = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_option_TLocal_ = +# 31 "standard.mly" + ( Some x ) +# 19723 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_option_TPosAny_ = +# 29 "standard.mly" + ( None ) +# 19740 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : unit = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_option_TPosAny_ = +# 31 "standard.mly" + ( Some x ) +# 19764 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_option_eexpr_ = +# 29 "standard.mly" + ( None ) +# 19781 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_eexpr = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_option_eexpr_ = +# 31 "standard.mly" + ( Some x ) +# 19805 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_option_whenexp_ = +# 29 "standard.mly" + ( None ) +# 19822 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_whenexp = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_option_whenexp_ = +# 31 "standard.mly" + ( Some x ) +# 19846 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_plus_after_dots = +# 1563 "parser_cocci_menhir.mly" + ([]) +# 19863 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_plus_after_exp = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_plus_after_dots = +# 1564 "parser_cocci_menhir.mly" + (_2) +# 19891 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_plus_after_exp = Obj.magic _2 in + let _1 : 'tv_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_plus_after_dots = +# 1566 "parser_cocci_menhir.mly" + ( (Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Exp(_1)))))::_2 ) +# 19921 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_plus_after_stm = Obj.magic _2 in + let _1 : 'tv_fundecl = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_plus_after_dots = +# 1567 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.DECL(_1))::_2 ) +# 19951 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_plus_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_plus_after_dots = +# 1569 "parser_cocci_menhir.mly" + ( (List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) _1)@_2 ) +# 19981 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_plus_after_exp = +# 1559 "parser_cocci_menhir.mly" + ([]) +# 19998 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_plus_after_dots = Obj.magic _2 in + let _1 : 'tv_stm_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_plus_after_exp = +# 1560 "parser_cocci_menhir.mly" + ( (Ast0.wrap(Ast0.OTHER(_1)))::_2 ) +# 20028 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_plus_after_stm = +# 1572 "parser_cocci_menhir.mly" + ([]) +# 20045 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_plus_after_dots = Obj.magic _2 in + let _1 : 'tv_stm_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_plus_after_stm = +# 1573 "parser_cocci_menhir.mly" + ( (Ast0.wrap(Ast0.OTHER(_1)))::_2 ) +# 20075 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_plus_after_stm = Obj.magic _2 in + let _1 : 'tv_fundecl = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_plus_after_stm = +# 1574 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.DECL(_1))::_2 ) +# 20105 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_plus_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_plus_after_stm = +# 1576 "parser_cocci_menhir.mly" + ( (List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) _1)@_2 ) +# 20135 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = ew; + MenhirLib.EngineTypes.startp = _startpos_ew_; + MenhirLib.EngineTypes.endp = _endpos_ew_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = f; + MenhirLib.EngineTypes.startp = _startpos_f_; + MenhirLib.EngineTypes.endp = _endpos_f_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let ew : 'tv_loption_error_words_ = Obj.magic ew in + let b : 'tv_loption_plus_start_ = Obj.magic b in + let f : 'tv_loption_filespec_ = Obj.magic f in + let _startpos = _startpos_f_ in + let _endpos = _endpos_ew_ in + let _v : 'tv_plus_body = +# 562 "parser_cocci_menhir.mly" + ( Top_level.top_level (f@b@ew) ) +# 20171 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = ew; + MenhirLib.EngineTypes.startp = _startpos_ew_; + MenhirLib.EngineTypes.endp = _endpos_ew_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = f; + MenhirLib.EngineTypes.startp = _startpos_f_; + MenhirLib.EngineTypes.endp = _endpos_f_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let ew : 'tv_loption_error_words_ = Obj.magic ew in + let b : 'tv_top_eexpr = Obj.magic b in + let f : 'tv_loption_filespec_ = Obj.magic f in + let _startpos = _startpos_f_ in + let _endpos = _endpos_ew_ in + let _v : 'tv_plus_exp_body = +# 576 "parser_cocci_menhir.mly" + ( Top_level.top_level (f@[b]@ew) ) +# 20207 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _1 : 'tv_plus_exp_body = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : ( +# 142 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 20235 "parser_cocci_menhir.ml" + ) = +# 178 "parser_cocci_menhir.mly" + ( _1 ) +# 20239 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let p : 'tv_plus_exp_body = Obj.magic p in + let _startpos = _startpos_p_ in + let _endpos = _endpos__2_ in + let _v : ( +# 142 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 20267 "parser_cocci_menhir.ml" + ) = +# 178 "parser_cocci_menhir.mly" + ( p ) +# 20271 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let p : 'tv_plus_exp_body = Obj.magic p in + let _startpos = _startpos_p_ in + let _endpos = _endpos__2_ in + let _v : ( +# 142 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 20299 "parser_cocci_menhir.ml" + ) = +# 179 "parser_cocci_menhir.mly" + ( p ) +# 20303 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _1 : 'tv_plus_body = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : ( +# 139 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 20331 "parser_cocci_menhir.ml" + ) = +# 174 "parser_cocci_menhir.mly" + ( _1 ) +# 20335 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let p : 'tv_plus_body = Obj.magic p in + let _startpos = _startpos_p_ in + let _endpos = _endpos__2_ in + let _v : ( +# 139 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 20363 "parser_cocci_menhir.ml" + ) = +# 174 "parser_cocci_menhir.mly" + ( p ) +# 20367 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let p : 'tv_plus_body = Obj.magic p in + let _startpos = _startpos_p_ in + let _endpos = _endpos__2_ in + let _v : ( +# 139 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 20395 "parser_cocci_menhir.ml" + ) = +# 175 "parser_cocci_menhir.mly" + ( p ) +# 20399 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_ctype = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_plus_start = +# 1549 "parser_cocci_menhir.mly" + ( [Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Ty(_1))))] ) +# 20423 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_plus_after_dots = Obj.magic _2 in + let _1 : 'tv_stm_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_plus_start = +# 1551 "parser_cocci_menhir.mly" + ( (Ast0.wrap(Ast0.OTHER(_1)))::_2 ) +# 20453 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_plus_after_exp = Obj.magic _2 in + let _1 : 'tv_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_plus_start = +# 1553 "parser_cocci_menhir.mly" + ( (Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Exp(_1)))))::_2 ) +# 20483 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_plus_after_stm = Obj.magic _2 in + let _1 : 'tv_fundecl = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_plus_start = +# 1554 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.DECL(_1))::_2 ) +# 20513 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_plus_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_plus_start = +# 1556 "parser_cocci_menhir.mly" + ( (List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) _1)@_2 ) +# 20543 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 47 "parser_cocci_menhir.mly" + (string) +# 20564 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_pnrule = +# 220 "parser_cocci_menhir.mly" + ( Ast.Dep _1 ) +# 20571 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 47 "parser_cocci_menhir.mly" + (string) +# 20596 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_pnrule = +# 221 "parser_cocci_menhir.mly" + ( Ast.AntiDep _2 ) +# 20603 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 47 "parser_cocci_menhir.mly" + (string) +# 20628 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_pnrule = +# 222 "parser_cocci_menhir.mly" + ( Ast.EverDep _2 ) +# 20635 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 47 "parser_cocci_menhir.mly" + (string) +# 20660 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_pnrule = +# 223 "parser_cocci_menhir.mly" + ( Ast.NeverDep _2 ) +# 20667 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _2 : 'tv_dep = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_pnrule = +# 224 "parser_cocci_menhir.mly" + ( _2 ) +# 20699 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_primary_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_postfix_expr_eexpr_dot_expressions_ = +# 1249 "parser_cocci_menhir.mly" + ( _1 ) +# 20723 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let _4 : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 20759 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr = Obj.magic _3 in + let _2 : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 20765 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_postfix_expr_eexpr_dot_expressions_ = +# 1251 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.ArrayAccess (_1,P.clt2mcode "[" _2,_3, + P.clt2mcode "]" _4)) ) +# 20774 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_ident = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 20806 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_postfix_expr_eexpr_dot_expressions_ = +# 1254 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.RecordAccess(_1, P.clt2mcode "." _2, _3)) ) +# 20814 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_ident = Obj.magic _3 in + let _2 : ( +# 103 "parser_cocci_menhir.mly" + (Data.clt) +# 20846 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_postfix_expr_eexpr_dot_expressions_ = +# 1256 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.RecordPtAccess(_1, P.clt2mcode "->" _2, + _3)) ) +# 20855 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 20881 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_postfix_expr_eexpr_dot_expressions_ = +# 1259 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Postfix (_1, P.clt2mcode Ast.Inc _2)) ) +# 20889 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 20915 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_postfix_expr_eexpr_dot_expressions_ = +# 1261 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Postfix (_1, P.clt2mcode Ast.Dec _2)) ) +# 20923 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let _4 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 20959 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr_list_option = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 20965 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_postfix_expr_eexpr_dot_expressions_ = +# 1263 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.FunCall(_1,P.clt2mcode "(" _2, + _3, + P.clt2mcode ")" _4)) ) +# 20975 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_primary_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_postfix_expr_eexpr_invalid_ = +# 1249 "parser_cocci_menhir.mly" + ( _1 ) +# 20999 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let _4 : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 21035 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr = Obj.magic _3 in + let _2 : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 21041 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_postfix_expr_eexpr_invalid_ = +# 1251 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.ArrayAccess (_1,P.clt2mcode "[" _2,_3, + P.clt2mcode "]" _4)) ) +# 21050 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_ident = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 21082 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_postfix_expr_eexpr_invalid_ = +# 1254 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.RecordAccess(_1, P.clt2mcode "." _2, _3)) ) +# 21090 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_ident = Obj.magic _3 in + let _2 : ( +# 103 "parser_cocci_menhir.mly" + (Data.clt) +# 21122 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_postfix_expr_eexpr_invalid_ = +# 1256 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.RecordPtAccess(_1, P.clt2mcode "->" _2, + _3)) ) +# 21131 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 21157 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_postfix_expr_eexpr_invalid_ = +# 1259 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Postfix (_1, P.clt2mcode Ast.Inc _2)) ) +# 21165 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 21191 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_postfix_expr_eexpr_invalid_ = +# 1261 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Postfix (_1, P.clt2mcode Ast.Dec _2)) ) +# 21199 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let _4 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 21235 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr_list_option = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 21241 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_postfix_expr_eexpr_invalid_ = +# 1263 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.FunCall(_1,P.clt2mcode "(" _2, + _3, + P.clt2mcode ")" _4)) ) +# 21251 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_primary_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_postfix_expr_eexpr_nest_expressions_ = +# 1249 "parser_cocci_menhir.mly" + ( _1 ) +# 21275 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let _4 : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 21311 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr = Obj.magic _3 in + let _2 : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 21317 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_postfix_expr_eexpr_nest_expressions_ = +# 1251 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.ArrayAccess (_1,P.clt2mcode "[" _2,_3, + P.clt2mcode "]" _4)) ) +# 21326 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_ident = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 21358 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_postfix_expr_eexpr_nest_expressions_ = +# 1254 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.RecordAccess(_1, P.clt2mcode "." _2, _3)) ) +# 21366 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_ident = Obj.magic _3 in + let _2 : ( +# 103 "parser_cocci_menhir.mly" + (Data.clt) +# 21398 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_postfix_expr_eexpr_nest_expressions_ = +# 1256 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.RecordPtAccess(_1, P.clt2mcode "->" _2, + _3)) ) +# 21407 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 21433 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_postfix_expr_eexpr_nest_expressions_ = +# 1259 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Postfix (_1, P.clt2mcode Ast.Inc _2)) ) +# 21441 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 21467 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_postfix_expr_eexpr_nest_expressions_ = +# 1261 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Postfix (_1, P.clt2mcode Ast.Dec _2)) ) +# 21475 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let _4 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 21511 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr_list_option = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 21517 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_postfix_expr_eexpr_nest_expressions_ = +# 1263 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.FunCall(_1,P.clt2mcode "(" _2, + _3, + P.clt2mcode ")" _4)) ) +# 21527 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_primary_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_postfix_expr_expr_invalid_ = +# 1249 "parser_cocci_menhir.mly" + ( _1 ) +# 21551 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let _4 : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 21587 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr = Obj.magic _3 in + let _2 : ( +# 101 "parser_cocci_menhir.mly" + (Data.clt) +# 21593 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_postfix_expr_expr_invalid_ = +# 1251 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.ArrayAccess (_1,P.clt2mcode "[" _2,_3, + P.clt2mcode "]" _4)) ) +# 21602 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_ident = Obj.magic _3 in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 21634 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_postfix_expr_expr_invalid_ = +# 1254 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.RecordAccess(_1, P.clt2mcode "." _2, _3)) ) +# 21642 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : 'tv_ident = Obj.magic _3 in + let _2 : ( +# 103 "parser_cocci_menhir.mly" + (Data.clt) +# 21674 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_postfix_expr_expr_invalid_ = +# 1256 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.RecordPtAccess(_1, P.clt2mcode "->" _2, + _3)) ) +# 21683 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 21709 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_postfix_expr_expr_invalid_ = +# 1259 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Postfix (_1, P.clt2mcode Ast.Inc _2)) ) +# 21717 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 21743 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_postfix_expr_expr_invalid_ = +# 1261 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Postfix (_1, P.clt2mcode Ast.Dec _2)) ) +# 21751 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let _4 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 21787 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr_list_option = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 21793 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_postfix_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_postfix_expr_expr_invalid_ = +# 1263 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.FunCall(_1,P.clt2mcode "(" _2, + _3, + P.clt2mcode ")" _4)) ) +# 21803 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_func_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1268 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Ident(_1)) ) +# 21827 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 21848 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1270 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Int x) clt)) ) +# 21856 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 21877 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1273 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Float x) clt)) ) +# 21885 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 21906 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1276 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.String x) clt)) ) +# 21914 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 21935 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1279 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Char x) clt)) ) +# 21943 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 21964 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1282 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.CONST,pure)) ) +# 21973 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 63 "parser_cocci_menhir.mly" + (Parse_aux.expinfo) +# 21994 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1286 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,clt) = _1 in + Ast0.wrap(Ast0.MetaErr(P.clt2mcode nm clt,constraints,pure)) ) +# 22002 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 22023 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1289 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ANY,pure)) ) +# 22032 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 22053 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1293 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ID,pure)) ) +# 22062 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 22083 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1297 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.LocalID,pure)) ) +# 22092 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 22123 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_eexpr = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 22129 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1301 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Paren(P.clt2mcode "(" _1,_2, + P.clt2mcode ")" _3)) ) +# 22137 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 22168 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_midzero_list_eexpr_eexpr_ = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 22174 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1304 "parser_cocci_menhir.mly" + ( let (mids,code) = _2 in + Ast0.wrap(Ast0.DisjExpr(P.clt2mcode "(" _1, + code, mids, + P.clt2mcode ")" _3)) ) +# 22184 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_dot_expressions = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_dot_expressions_ = +# 1308 "parser_cocci_menhir.mly" + ( _1 ) +# 22208 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_func_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1268 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Ident(_1)) ) +# 22232 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 22253 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1270 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Int x) clt)) ) +# 22261 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 22282 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1273 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Float x) clt)) ) +# 22290 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 22311 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1276 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.String x) clt)) ) +# 22319 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 22340 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1279 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Char x) clt)) ) +# 22348 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 22369 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1282 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.CONST,pure)) ) +# 22378 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 63 "parser_cocci_menhir.mly" + (Parse_aux.expinfo) +# 22399 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1286 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,clt) = _1 in + Ast0.wrap(Ast0.MetaErr(P.clt2mcode nm clt,constraints,pure)) ) +# 22407 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 22428 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1289 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ANY,pure)) ) +# 22437 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 22458 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1293 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ID,pure)) ) +# 22467 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 22488 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1297 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.LocalID,pure)) ) +# 22497 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 22528 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_eexpr = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 22534 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1301 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Paren(P.clt2mcode "(" _1,_2, + P.clt2mcode ")" _3)) ) +# 22542 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 22573 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_midzero_list_eexpr_eexpr_ = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 22579 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1304 "parser_cocci_menhir.mly" + ( let (mids,code) = _2 in + Ast0.wrap(Ast0.DisjExpr(P.clt2mcode "(" _1, + code, mids, + P.clt2mcode ")" _3)) ) +# 22589 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_invalid = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_invalid_ = +# 1308 "parser_cocci_menhir.mly" + ( _1 ) +# 22613 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_func_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1268 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Ident(_1)) ) +# 22637 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 22658 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1270 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Int x) clt)) ) +# 22666 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 22687 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1273 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Float x) clt)) ) +# 22695 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 22716 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1276 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.String x) clt)) ) +# 22724 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 22745 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1279 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Char x) clt)) ) +# 22753 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 22774 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1282 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.CONST,pure)) ) +# 22783 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 63 "parser_cocci_menhir.mly" + (Parse_aux.expinfo) +# 22804 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1286 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,clt) = _1 in + Ast0.wrap(Ast0.MetaErr(P.clt2mcode nm clt,constraints,pure)) ) +# 22812 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 22833 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1289 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ANY,pure)) ) +# 22842 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 22863 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1293 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ID,pure)) ) +# 22872 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 22893 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1297 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.LocalID,pure)) ) +# 22902 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 22933 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_eexpr = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 22939 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1301 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Paren(P.clt2mcode "(" _1,_2, + P.clt2mcode ")" _3)) ) +# 22947 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 22978 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_midzero_list_eexpr_eexpr_ = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 22984 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1304 "parser_cocci_menhir.mly" + ( let (mids,code) = _2 in + Ast0.wrap(Ast0.DisjExpr(P.clt2mcode "(" _1, + code, mids, + P.clt2mcode ")" _3)) ) +# 22994 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_nest_expressions = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_eexpr_nest_expressions_ = +# 1308 "parser_cocci_menhir.mly" + ( _1 ) +# 23018 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_func_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1268 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Ident(_1)) ) +# 23042 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 23063 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1270 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Int x) clt)) ) +# 23071 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 23092 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1273 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Float x) clt)) ) +# 23100 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 23121 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1276 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.String x) clt)) ) +# 23129 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 23150 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1279 "parser_cocci_menhir.mly" + ( let (x,clt) = _1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Char x) clt)) ) +# 23158 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 23179 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1282 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.CONST,pure)) ) +# 23188 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 63 "parser_cocci_menhir.mly" + (Parse_aux.expinfo) +# 23209 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1286 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,clt) = _1 in + Ast0.wrap(Ast0.MetaErr(P.clt2mcode nm clt,constraints,pure)) ) +# 23217 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 23238 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1289 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ANY,pure)) ) +# 23247 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 23268 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1293 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ID,pure)) ) +# 23277 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 66 "parser_cocci_menhir.mly" + (Parse_aux.typed_info) +# 23298 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1297 "parser_cocci_menhir.mly" + ( let (nm,constraints,pure,ty,clt) = _1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.LocalID,pure)) ) +# 23307 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 23338 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_eexpr = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 23344 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1301 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Paren(P.clt2mcode "(" _1,_2, + P.clt2mcode ")" _3)) ) +# 23352 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 23383 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_midzero_list_expr_eexpr_ = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 23389 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1304 "parser_cocci_menhir.mly" + ( let (mids,code) = _2 in + Ast0.wrap(Ast0.DisjExpr(P.clt2mcode "(" _1, + code, mids, + P.clt2mcode ")" _3)) ) +# 23399 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_invalid = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_primary_expr_expr_invalid_ = +# 1308 "parser_cocci_menhir.mly" + ( _1 ) +# 23423 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_pure = +# 189 "parser_cocci_menhir.mly" + ( Ast0.Pure ) +# 23445 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_pure = +# 190 "parser_cocci_menhir.mly" + ( Ast0.Context ) +# 23467 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_pure = +# 191 "parser_cocci_menhir.mly" + ( Ast0.PureContext ) +# 23493 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_pure = +# 192 "parser_cocci_menhir.mly" + ( Ast0.PureContext ) +# 23519 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_pure = +# 193 "parser_cocci_menhir.mly" + ( Ast0.Impure ) +# 23536 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 59 "parser_cocci_menhir.mly" + (string * Data.clt) +# 23557 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_pure_ident = +# 1322 "parser_cocci_menhir.mly" + ( _1 ) +# 23564 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_pure_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_pure_ident_or_meta_ident = +# 1328 "parser_cocci_menhir.mly" + ( (None,P.id2name _1) ) +# 23588 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_meta_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_pure_ident_or_meta_ident = +# 1329 "parser_cocci_menhir.mly" + ( _1 ) +# 23612 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_pure_ident_or_meta_ident = +# 1330 "parser_cocci_menhir.mly" + ( (None,"list") ) +# 23634 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_pure_ident_or_meta_ident = +# 1331 "parser_cocci_menhir.mly" + ( (None,"error") ) +# 23656 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_pure_ident_or_meta_ident = +# 1332 "parser_cocci_menhir.mly" + ( (None,"type") ) +# 23678 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let l : 'tv_loption_not_ceq_ = Obj.magic l in + let i : 'tv_pure_ident_or_meta_ident = Obj.magic i in + let _startpos = _startpos_i_ in + let _endpos = _endpos_l_ in + let _v : 'tv_pure_ident_or_meta_ident_with_not_eq_not_ceq_ = +# 1335 "parser_cocci_menhir.mly" + ( (i,l) ) +# 23708 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let l : 'tv_loption_not_eq_ = Obj.magic l in + let i : 'tv_pure_ident_or_meta_ident = Obj.magic i in + let _startpos = _startpos_i_ in + let _endpos = _endpos_l_ in + let _v : 'tv_pure_ident_or_meta_ident_with_not_eq_not_eq_ = +# 1335 "parser_cocci_menhir.mly" + ( (i,l) ) +# 23738 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let l : 'tv_loption_not_eqe_ = Obj.magic l in + let i : 'tv_pure_ident_or_meta_ident = Obj.magic i in + let _startpos = _startpos_i_ in + let _endpos = _endpos_l_ in + let _v : 'tv_pure_ident_or_meta_ident_with_not_eq_not_eqe_ = +# 1335 "parser_cocci_menhir.mly" + ( (i,l) ) +# 23768 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = l; + MenhirLib.EngineTypes.startp = _startpos_l_; + MenhirLib.EngineTypes.endp = _endpos_l_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let l : 'tv_loption_not_pos_ = Obj.magic l in + let i : 'tv_pure_ident_or_meta_ident = Obj.magic i in + let _startpos = _startpos_i_ in + let _endpos = _endpos_l_ in + let _v : 'tv_pure_ident_or_meta_ident_with_not_eq_not_pos_ = +# 1335 "parser_cocci_menhir.mly" + ( (i,l) ) +# 23798 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : ( +# 130 "parser_cocci_menhir.mly" + (unit) +# 23815 "parser_cocci_menhir.ml" + ) = +# 171 "parser_cocci_menhir.mly" + ( ) +# 23819 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_one_decl_var = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_rule_elem_statement = +# 849 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Decl((Ast0.default_info(),Ast0.context_befaft()),_1)) ) +# 23843 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 23869 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_rule_elem_statement = +# 850 "parser_cocci_menhir.mly" + ( P.exp_stm _1 _2 ) +# 23877 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 23908 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_eexpr = Obj.magic _2 in + let _1 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 23914 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_rule_elem_statement = +# 851 "parser_cocci_menhir.mly" + ( P.ret_exp _1 _2 _3 ) +# 23921 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 23947 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 23952 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_rule_elem_statement = +# 852 "parser_cocci_menhir.mly" + ( P.ret _1 _2 ) +# 23959 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 23985 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 23990 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_rule_elem_statement = +# 853 "parser_cocci_menhir.mly" + ( P.break _1 _2 ) +# 23997 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 24023 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 24028 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_rule_elem_statement = +# 854 "parser_cocci_menhir.mly" + ( P.cont _1 _2 ) +# 24035 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 24066 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_midzero_list_rule_elem_statement_rule_elem_statement_ = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 24072 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_rule_elem_statement = +# 856 "parser_cocci_menhir.mly" + ( let (mids,code) = _2 in + Ast0.wrap + (Ast0.Disj(P.clt2mcode "(" _1, + List.map (function x -> Ast0.wrap(Ast0.DOTS([x]))) code, + mids, P.clt2mcode ")" _3)) ) +# 24083 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__7_; + MenhirLib.EngineTypes.endp = _endpos__7_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ee; + MenhirLib.EngineTypes.startp = _startpos_ee_; + MenhirLib.EngineTypes.endp = _endpos_ee_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ee : 'tv_is_expression = Obj.magic ee in + let e : 'tv_exists = Obj.magic e in + let a : 'tv_loption_disable_ = Obj.magic a in + let i : 'tv_loption_choose_iso_ = Obj.magic i in + let d : 'tv_depends = Obj.magic d in + let _startpos = _startpos__1_ in + let _endpos = _endpos__7_ in + let _v : ( +# 152 "parser_cocci_menhir.mly" + (Ast_cocci.rulename) +# 24139 "parser_cocci_menhir.ml" + ) = let nm = + +# 39 "standard.mly" + ( None ) +# 24144 "parser_cocci_menhir.ml" + + in + +# 201 "parser_cocci_menhir.mly" + ( P.make_cocci_rule_name_result nm d i a e ee ) +# 24150 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__8_; + MenhirLib.EngineTypes.endp = _endpos__8_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = ee; + MenhirLib.EngineTypes.startp = _startpos_ee_; + MenhirLib.EngineTypes.endp = _endpos_ee_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = e; + MenhirLib.EngineTypes.startp = _startpos_e_; + MenhirLib.EngineTypes.endp = _endpos_e_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = a; + MenhirLib.EngineTypes.startp = _startpos_a_; + MenhirLib.EngineTypes.endp = _endpos_a_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let ee : 'tv_is_expression = Obj.magic ee in + let e : 'tv_exists = Obj.magic e in + let a : 'tv_loption_disable_ = Obj.magic a in + let i : 'tv_loption_choose_iso_ = Obj.magic i in + let d : 'tv_depends = Obj.magic d in + let x0 : 'tv_pure_ident = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos__8_ in + let _v : ( +# 152 "parser_cocci_menhir.mly" + (Ast_cocci.rulename) +# 24212 "parser_cocci_menhir.ml" + ) = let nm = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 24218 "parser_cocci_menhir.ml" + + in + +# 201 "parser_cocci_menhir.mly" + ( P.make_cocci_rule_name_result nm d i a e ee ) +# 24224 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lang; + MenhirLib.EngineTypes.startp = _startpos_lang_; + MenhirLib.EngineTypes.endp = _endpos_lang_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = scr; + MenhirLib.EngineTypes.startp = _startpos_scr_; + MenhirLib.EngineTypes.endp = _endpos_scr_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let d : 'tv_depends = Obj.magic d in + let lang : 'tv_pure_ident = Obj.magic lang in + let scr : 'tv_pure_ident = Obj.magic scr in + let _startpos = _startpos_scr_ in + let _endpos = _endpos__5_ in + let _v : ( +# 152 "parser_cocci_menhir.mly" + (Ast_cocci.rulename) +# 24268 "parser_cocci_menhir.ml" + ) = +# 203 "parser_cocci_menhir.mly" + ( P.make_script_rule_name_result scr lang d ) +# 24272 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = cocci; + MenhirLib.EngineTypes.startp = _startpos_cocci_; + MenhirLib.EngineTypes.endp = _endpos_cocci_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = py; + MenhirLib.EngineTypes.startp = _startpos_py_; + MenhirLib.EngineTypes.endp = _endpos_py_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + } = _menhir_stack in + let cocci : 'tv_pure_ident = Obj.magic cocci in + let _3 : ( +# 47 "parser_cocci_menhir.mly" + (string) +# 24316 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let py : 'tv_pure_ident = Obj.magic py in + let _startpos = _startpos_py_ in + let _endpos = _endpos__6_ in + let _v : ( +# 158 "parser_cocci_menhir.mly" + (string * (string * string)) +# 24324 "parser_cocci_menhir.ml" + ) = +# 1765 "parser_cocci_menhir.mly" + ( (P.id2name py, (_3, P.id2name cocci)) ) +# 24328 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 24349 "parser_cocci_menhir.ml" + ) = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_TString_ = +# 144 "standard.mly" + ( [ x ] ) +# 24356 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_TString_ = Obj.magic xs in + let x : ( +# 86 "parser_cocci_menhir.mly" + (string * Data.clt) +# 24387 "parser_cocci_menhir.ml" + ) = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_TString_ = +# 146 "standard.mly" + ( x :: xs ) +# 24394 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_any_strict = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_any_strict_ = +# 144 "standard.mly" + ( [ x ] ) +# 24418 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_any_strict_ = Obj.magic xs in + let x : 'tv_any_strict = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_any_strict_ = +# 146 "standard.mly" + ( x :: xs ) +# 24452 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_ctype = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_ctype_ = +# 144 "standard.mly" + ( [ x ] ) +# 24476 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_ctype_ = Obj.magic xs in + let x : 'tv_ctype = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_ctype_ = +# 146 "standard.mly" + ( x :: xs ) +# 24510 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_d_ident = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_d_ident_ = +# 144 "standard.mly" + ( [ x ] ) +# 24534 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_d_ident_ = Obj.magic xs in + let x : 'tv_d_ident = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_d_ident_ = +# 146 "standard.mly" + ( x :: xs ) +# 24568 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_dexpr = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_dexpr_ = +# 144 "standard.mly" + ( [ x ] ) +# 24592 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_dexpr_ = Obj.magic xs in + let x : 'tv_dexpr = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_dexpr_ = +# 146 "standard.mly" + ( x :: xs ) +# 24626 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_ident_or_const = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_ident_or_const_ = +# 144 "standard.mly" + ( [ x ] ) +# 24650 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_ident_or_const_ = Obj.magic xs in + let x : 'tv_ident_or_const = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_ident_or_const_ = +# 146 "standard.mly" + ( x :: xs ) +# 24684 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_meta_ident = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_meta_ident_ = +# 144 "standard.mly" + ( [ x ] ) +# 24708 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_meta_ident_ = Obj.magic xs in + let x : 'tv_meta_ident = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_meta_ident_ = +# 146 "standard.mly" + ( x :: xs ) +# 24742 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_pure_ident = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_pure_ident_ = +# 144 "standard.mly" + ( [ x ] ) +# 24766 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_pure_ident_ = Obj.magic xs in + let x : 'tv_pure_ident = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_pure_ident_ = +# 146 "standard.mly" + ( x :: xs ) +# 24800 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_pure_ident_or_meta_ident = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_ = +# 144 "standard.mly" + ( [ x ] ) +# 24824 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_ = Obj.magic xs in + let x : 'tv_pure_ident_or_meta_ident = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_ = +# 146 "standard.mly" + ( x :: xs ) +# 24858 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_pure_ident_or_meta_ident_with_not_eq_not_ceq_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_ceq__ = +# 144 "standard.mly" + ( [ x ] ) +# 24882 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_ceq__ = Obj.magic xs in + let x : 'tv_pure_ident_or_meta_ident_with_not_eq_not_ceq_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_ceq__ = +# 146 "standard.mly" + ( x :: xs ) +# 24916 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_pure_ident_or_meta_ident_with_not_eq_not_eq_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_eq__ = +# 144 "standard.mly" + ( [ x ] ) +# 24940 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_eq__ = Obj.magic xs in + let x : 'tv_pure_ident_or_meta_ident_with_not_eq_not_eq_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_eq__ = +# 146 "standard.mly" + ( x :: xs ) +# 24974 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_pure_ident_or_meta_ident_with_not_eq_not_eqe_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = +# 144 "standard.mly" + ( [ x ] ) +# 24998 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = Obj.magic xs in + let x : 'tv_pure_ident_or_meta_ident_with_not_eq_not_eqe_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_eqe__ = +# 146 "standard.mly" + ( x :: xs ) +# 25032 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let x : 'tv_pure_ident_or_meta_ident_with_not_eq_not_pos_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_x_ in + let _v : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_pos__ = +# 144 "standard.mly" + ( [ x ] ) +# 25056 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = xs; + MenhirLib.EngineTypes.startp = _startpos_xs_; + MenhirLib.EngineTypes.endp = _endpos_xs_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x; + MenhirLib.EngineTypes.startp = _startpos_x_; + MenhirLib.EngineTypes.endp = _endpos_x_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let xs : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_pos__ = Obj.magic xs in + let x : 'tv_pure_ident_or_meta_ident_with_not_eq_not_pos_ = Obj.magic x in + let _startpos = _startpos_x_ in + let _endpos = _endpos_xs_ in + let _v : 'tv_separated_nonempty_list_TComma_pure_ident_or_meta_ident_with_not_eq_not_pos__ = +# 146 "standard.mly" + ( x :: xs ) +# 25090 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_statement = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_single_statement = +# 864 "parser_cocci_menhir.mly" + ( _1 ) +# 25114 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 25145 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_midzero_list_statement_statement_ = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 25151 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_single_statement = +# 868 "parser_cocci_menhir.mly" + ( let (mids,code) = _2 in + Ast0.wrap + (Ast0.Disj(P.clt2mcode "(" _1, + List.map (function x -> Ast0.wrap(Ast0.DOTS([x]))) code, + mids, P.clt2mcode ")" _3)) ) +# 25162 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_includes = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_statement = +# 803 "parser_cocci_menhir.mly" + ( _1 ) +# 25186 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 64 "parser_cocci_menhir.mly" + (Parse_aux.info) +# 25207 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_statement = +# 805 "parser_cocci_menhir.mly" + ( P.meta_stm _1 ) +# 25214 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 25240 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_statement = +# 807 "parser_cocci_menhir.mly" + ( P.exp_stm _1 _2 ) +# 25248 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _5; + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let _5 : 'tv_single_statement = Obj.magic _5 in + let _4 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 25290 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 25296 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 25301 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__5_ in + let _v : 'tv_statement = +# 809 "parser_cocci_menhir.mly" + ( P.ifthen _1 _2 _3 _4 _5 ) +# 25308 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _7; + MenhirLib.EngineTypes.startp = _startpos__7_; + MenhirLib.EngineTypes.endp = _endpos__7_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _6; + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _5; + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let _7 : 'tv_single_statement = Obj.magic _7 in + let _6 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 25360 "parser_cocci_menhir.ml" + ) = Obj.magic _6 in + let _5 : 'tv_single_statement = Obj.magic _5 in + let _4 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 25366 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 25372 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 25377 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__7_ in + let _v : 'tv_statement = +# 811 "parser_cocci_menhir.mly" + ( P.ifthenelse _1 _2 _3 _4 _5 _6 _7 ) +# 25384 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _9; + MenhirLib.EngineTypes.startp = _startpos__9_; + MenhirLib.EngineTypes.endp = _endpos__9_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _8; + MenhirLib.EngineTypes.startp = _startpos__8_; + MenhirLib.EngineTypes.endp = _endpos__8_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _7; + MenhirLib.EngineTypes.startp = _startpos__7_; + MenhirLib.EngineTypes.endp = _endpos__7_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _6; + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _5; + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let _9 : 'tv_single_statement = Obj.magic _9 in + let _8 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 25446 "parser_cocci_menhir.ml" + ) = Obj.magic _8 in + let _7 : 'tv_option_eexpr_ = Obj.magic _7 in + let _6 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 25452 "parser_cocci_menhir.ml" + ) = Obj.magic _6 in + let _5 : 'tv_option_eexpr_ = Obj.magic _5 in + let _4 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 25458 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_option_eexpr_ = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 25464 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 25469 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__9_ in + let _v : 'tv_statement = +# 814 "parser_cocci_menhir.mly" + ( P.forloop _1 _2 _3 _4 _5 _6 _7 _8 _9 ) +# 25476 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _5; + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let _5 : 'tv_single_statement = Obj.magic _5 in + let _4 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 25518 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 25524 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 25529 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__5_ in + let _v : 'tv_statement = +# 816 "parser_cocci_menhir.mly" + ( P.whileloop _1 _2 _3 _4 _5 ) +# 25536 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _7; + MenhirLib.EngineTypes.startp = _startpos__7_; + MenhirLib.EngineTypes.endp = _endpos__7_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _6; + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _5; + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let _7 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 25587 "parser_cocci_menhir.ml" + ) = Obj.magic _7 in + let _6 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 25592 "parser_cocci_menhir.ml" + ) = Obj.magic _6 in + let _5 : 'tv_eexpr = Obj.magic _5 in + let _4 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 25598 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 25603 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_single_statement = Obj.magic _2 in + let _1 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 25609 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__7_ in + let _v : 'tv_statement = +# 818 "parser_cocci_menhir.mly" + ( P.doloop _1 _2 _3 _4 _5 _6 _7 ) +# 25616 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _5; + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + } = _menhir_stack in + let _5 : 'tv_single_statement = Obj.magic _5 in + let _4 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 25658 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr_list_option = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 25664 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_iter_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__5_ in + let _v : 'tv_statement = +# 820 "parser_cocci_menhir.mly" + ( P.iterator _1 _2 _3 _4 _5 ) +# 25672 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _7; + MenhirLib.EngineTypes.startp = _startpos__7_; + MenhirLib.EngineTypes.endp = _endpos__7_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _6; + MenhirLib.EngineTypes.startp = _startpos__6_; + MenhirLib.EngineTypes.endp = _endpos__6_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _5; + MenhirLib.EngineTypes.startp = _startpos__5_; + MenhirLib.EngineTypes.endp = _endpos__5_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _4; + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let _7 : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 25723 "parser_cocci_menhir.ml" + ) = Obj.magic _7 in + let _6 : 'tv_list_case_line_ = Obj.magic _6 in + let _5 : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 25729 "parser_cocci_menhir.ml" + ) = Obj.magic _5 in + let _4 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 25734 "parser_cocci_menhir.ml" + ) = Obj.magic _4 in + let _3 : 'tv_eexpr = Obj.magic _3 in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 25740 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 25745 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__7_ in + let _v : 'tv_statement = +# 822 "parser_cocci_menhir.mly" + ( P.switch _1 _2 _3 _4 _5 _6 _7 ) +# 25752 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 25783 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_eexpr = Obj.magic _2 in + let _1 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 25789 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_statement = +# 823 "parser_cocci_menhir.mly" + ( P.ret_exp _1 _2 _3 ) +# 25796 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 25822 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 57 "parser_cocci_menhir.mly" + (Data.clt) +# 25827 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_statement = +# 824 "parser_cocci_menhir.mly" + ( P.ret _1 _2 ) +# 25834 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 25860 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 25865 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_statement = +# 825 "parser_cocci_menhir.mly" + ( P.break _1 _2 ) +# 25872 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 25898 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 25903 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_statement = +# 826 "parser_cocci_menhir.mly" + ( P.cont _1 _2 ) +# 25910 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 25936 "parser_cocci_menhir.ml" + ) = Obj.magic _2 in + let _1 : 'tv_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_statement = +# 827 "parser_cocci_menhir.mly" + ( P.label _1 _2 ) +# 25944 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 25975 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_ident = Obj.magic _2 in + let _1 : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 25981 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_statement = +# 828 "parser_cocci_menhir.mly" + ( P.goto _1 _2 _3 ) +# 25988 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _3; + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _3 : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 26019 "parser_cocci_menhir.ml" + ) = Obj.magic _3 in + let _2 : 'tv_fun_start = Obj.magic _2 in + let _1 : ( +# 100 "parser_cocci_menhir.mly" + (Data.clt) +# 26025 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_statement = +# 830 "parser_cocci_menhir.mly" + ( P.seq _1 _2 _3 ) +# 26032 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let w : 'tv_list_whenppdecs_ = Obj.magic w in + let _1 : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 26059 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos_w_ in + let _v : 'tv_stm_dots = +# 834 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Dots(P.clt2mcode "..." _1, List.concat w)) ) +# 26066 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = c; + MenhirLib.EngineTypes.startp = _startpos_c_; + MenhirLib.EngineTypes.endp = _endpos_c_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let c : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 26102 "parser_cocci_menhir.ml" + ) = Obj.magic c in + let b : 'tv_nest_start = Obj.magic b in + let w : 'tv_list_whenppdecs_ = Obj.magic w in + let _1 : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 26109 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos_c_ in + let _v : 'tv_stm_dots = +# 836 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Nest(P.clt2mcode "<..." _1, b, + P.clt2mcode "...>" c, List.concat w, false)) ) +# 26117 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = c; + MenhirLib.EngineTypes.startp = _startpos_c_; + MenhirLib.EngineTypes.endp = _endpos_c_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = b; + MenhirLib.EngineTypes.startp = _startpos_b_; + MenhirLib.EngineTypes.endp = _endpos_b_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let c : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 26153 "parser_cocci_menhir.ml" + ) = Obj.magic c in + let b : 'tv_nest_start = Obj.magic b in + let w : 'tv_list_whenppdecs_ = Obj.magic w in + let _1 : ( +# 72 "parser_cocci_menhir.mly" + (Data.clt) +# 26160 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos_c_ in + let _v : 'tv_stm_dots = +# 839 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Nest(P.clt2mcode "<+..." _1, b, + P.clt2mcode "...+>" c, List.concat w, true)) ) +# 26168 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let s : ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 26189 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_s_ in + let _v : 'tv_storage = +# 762 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.Static s ) +# 26196 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let s : ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 26217 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_s_ in + let _v : 'tv_storage = +# 763 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.Auto s ) +# 26224 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let s : ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 26245 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_s_ in + let _v : 'tv_storage = +# 764 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.Register s ) +# 26252 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let s : ( +# 53 "parser_cocci_menhir.mly" + (Data.clt) +# 26273 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_s_ in + let _v : 'tv_storage = +# 765 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.Extern s ) +# 26280 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_struct_decl = +# 488 "parser_cocci_menhir.mly" + ( [] ) +# 26302 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 26333 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_d_ident = Obj.magic d in + let t : 'tv_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_struct_decl = +# 490 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + [Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv))] ) +# 26343 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp2; + MenhirLib.EngineTypes.startp = _startpos_rp2_; + MenhirLib.EngineTypes.endp = _endpos_rp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = p; + MenhirLib.EngineTypes.startp = _startpos_p_; + MenhirLib.EngineTypes.endp = _endpos_p_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp2; + MenhirLib.EngineTypes.startp = _startpos_lp2_; + MenhirLib.EngineTypes.endp = _endpos_lp2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = rp1; + MenhirLib.EngineTypes.startp = _startpos_rp1_; + MenhirLib.EngineTypes.endp = _endpos_rp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = st; + MenhirLib.EngineTypes.startp = _startpos_st_; + MenhirLib.EngineTypes.endp = _endpos_st_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp1; + MenhirLib.EngineTypes.startp = _startpos_lp1_; + MenhirLib.EngineTypes.endp = _endpos_lp1_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + }; + }; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 26404 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let rp2 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 26409 "parser_cocci_menhir.ml" + ) = Obj.magic rp2 in + let p : 'tv_decl_list_name_opt_decl_ = Obj.magic p in + let lp2 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 26415 "parser_cocci_menhir.ml" + ) = Obj.magic lp2 in + let rp1 : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 26420 "parser_cocci_menhir.ml" + ) = Obj.magic rp1 in + let d : 'tv_d_ident = Obj.magic d in + let st : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 26426 "parser_cocci_menhir.ml" + ) = Obj.magic st in + let lp1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 26431 "parser_cocci_menhir.ml" + ) = Obj.magic lp1 in + let t : 'tv_fn_ctype = Obj.magic t in + let _startpos = _startpos_t_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_struct_decl = +# 494 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + [Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv))] ) +# 26445 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 26476 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let _startpos = _startpos_i_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_struct_decl = let cv = + +# 39 "standard.mly" + ( None ) +# 26486 "parser_cocci_menhir.ml" + + in + +# 502 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + [Ast0.wrap(Ast0.UnInit(None,fn idtype,id,P.clt2mcode ";" pv))] ) +# 26494 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = pv; + MenhirLib.EngineTypes.startp = _startpos_pv_; + MenhirLib.EngineTypes.endp = _endpos_pv_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = i; + MenhirLib.EngineTypes.startp = _startpos_i_; + MenhirLib.EngineTypes.endp = _endpos_i_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = x0; + MenhirLib.EngineTypes.startp = _startpos_x0_; + MenhirLib.EngineTypes.endp = _endpos_x0_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let pv : ( +# 106 "parser_cocci_menhir.mly" + (Data.clt) +# 26530 "parser_cocci_menhir.ml" + ) = Obj.magic pv in + let d : 'tv_d_ident = Obj.magic d in + let i : 'tv_pure_ident = Obj.magic i in + let x0 : 'tv_const_vol = Obj.magic x0 in + let _startpos = _startpos_x0_ in + let _endpos = _endpos_pv_ in + let _v : 'tv_struct_decl = let cv = + let x = x0 in + +# 41 "standard.mly" + ( Some x ) +# 26542 "parser_cocci_menhir.ml" + + in + +# 502 "parser_cocci_menhir.mly" + ( let (id,fn) = d in + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + [Ast0.wrap(Ast0.UnInit(None,fn idtype,id,P.clt2mcode ";" pv))] ) +# 26550 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_struct_decl_list_start = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_struct_decl_list = +# 507 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.DOTS(_1)) ) +# 26574 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_struct_decl = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_struct_decl_list_start = +# 510 "parser_cocci_menhir.mly" + ( _1 ) +# 26598 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_struct_decl_list_start = Obj.magic _2 in + let _1 : 'tv_struct_decl = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_struct_decl_list_start = +# 511 "parser_cocci_menhir.mly" + ( _1@_2 ) +# 26628 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = r; + MenhirLib.EngineTypes.startp = _startpos_r_; + MenhirLib.EngineTypes.endp = _endpos_r_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = d; + MenhirLib.EngineTypes.startp = _startpos_d_; + MenhirLib.EngineTypes.endp = _endpos_d_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let r : 'tv_continue_struct_decl_list = Obj.magic r in + let d : 'tv_edots_when_TEllipsis_struct_decl_ = Obj.magic d in + let _startpos = _startpos_d_ in + let _endpos = _endpos_r_ in + let _v : 'tv_struct_decl_list_start = +# 513 "parser_cocci_menhir.mly" + ( (P.mkddots "..." d)::r ) +# 26658 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let s : ( +# 50 "parser_cocci_menhir.mly" + (Data.clt) +# 26679 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_s_ in + let _v : 'tv_struct_or_union = +# 484 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.Struct s ) +# 26686 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = u; + MenhirLib.EngineTypes.startp = _startpos_u_; + MenhirLib.EngineTypes.endp = _endpos_u_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let u : ( +# 50 "parser_cocci_menhir.mly" + (Data.clt) +# 26707 "parser_cocci_menhir.ml" + ) = Obj.magic u in + let _startpos = _startpos_u_ in + let _endpos = _endpos_u_ in + let _v : 'tv_struct_or_union = +# 485 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.Union u ) +# 26714 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_eexpr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_top_eexpr = +# 1137 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Exp(_1)))) ) +# 26738 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_toplevel_after_dots = +# 1534 "parser_cocci_menhir.mly" + ([]) +# 26755 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_exp = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_after_dots = +# 1535 "parser_cocci_menhir.mly" + (_2) +# 26783 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_exp = Obj.magic _2 in + let _1 : 'tv_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_after_dots = +# 1536 "parser_cocci_menhir.mly" + ((Ast0.wrap(Ast0.Exp(_1)))::_2) +# 26813 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_after_dots = +# 1537 "parser_cocci_menhir.mly" + (_1@_2) +# 26843 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_exp = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_after_dots_init = +# 1525 "parser_cocci_menhir.mly" + (_2) +# 26871 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_exp = Obj.magic _2 in + let _1 : 'tv_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_after_dots_init = +# 1526 "parser_cocci_menhir.mly" + ((Ast0.wrap(Ast0.Exp(_1)))::_2) +# 26901 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_after_dots_init = +# 1527 "parser_cocci_menhir.mly" + (_1@_2) +# 26931 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_toplevel_after_exp = +# 1530 "parser_cocci_menhir.mly" + ([]) +# 26948 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_dots = Obj.magic _2 in + let _1 : 'tv_stm_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_after_exp = +# 1531 "parser_cocci_menhir.mly" + (_1::_2) +# 26978 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let _menhir_s = _menhir_env.MenhirLib.EngineTypes.current in + let _startpos = _menhir_env.MenhirLib.EngineTypes.lexbuf.Lexing.lex_start_p in + let _endpos = _startpos in + let _v : 'tv_toplevel_after_stm = +# 1540 "parser_cocci_menhir.mly" + ([]) +# 26995 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_dots = Obj.magic _2 in + let _1 : 'tv_stm_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_after_stm = +# 1541 "parser_cocci_menhir.mly" + (_1::_2) +# 27025 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_after_stm = +# 1542 "parser_cocci_menhir.mly" + (_1@_2) +# 27055 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_dots = Obj.magic _2 in + let _1 : 'tv_stm_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_seq_start_toplevel_after_dots_ = +# 1520 "parser_cocci_menhir.mly" + ( _1::_2 ) +# 27085 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_exp = Obj.magic _2 in + let _1 : 'tv_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_seq_start_toplevel_after_dots_ = +# 1521 "parser_cocci_menhir.mly" + ( (Ast0.wrap(Ast0.Exp(_1)))::_2 ) +# 27115 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_seq_start_toplevel_after_dots_ = +# 1522 "parser_cocci_menhir.mly" + ( _1@_2 ) +# 27145 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_dots_init = Obj.magic _2 in + let _1 : 'tv_stm_dots = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_seq_start_toplevel_after_dots_init_ = +# 1520 "parser_cocci_menhir.mly" + ( _1::_2 ) +# 27175 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_exp = Obj.magic _2 in + let _1 : 'tv_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_seq_start_toplevel_after_dots_init_ = +# 1521 "parser_cocci_menhir.mly" + ( (Ast0.wrap(Ast0.Exp(_1)))::_2 ) +# 27205 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_toplevel_seq_start_toplevel_after_dots_init_ = +# 1522 "parser_cocci_menhir.mly" + ( _1@_2 ) +# 27235 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_pure_ident = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_typedef_ident = +# 1434 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.TypeName(P.id2mcode _1)) ) +# 27259 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 64 "parser_cocci_menhir.mly" + (Parse_aux.info) +# 27280 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_typedef_ident = +# 1436 "parser_cocci_menhir.mly" + ( let (nm,pure,clt) = _1 in + Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) ) +# 27288 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_postfix_expr_eexpr_dot_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_unary_expr_eexpr_dot_expressions_ = +# 1225 "parser_cocci_menhir.mly" + ( _1 ) +# 27312 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_dot_expressions_ = Obj.magic _2 in + let _1 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 27339 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_dot_expressions_ = +# 1227 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Infix (_2, P.clt2mcode Ast.Inc _1)) ) +# 27346 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_dot_expressions_ = Obj.magic _2 in + let _1 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 27373 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_dot_expressions_ = +# 1229 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Infix (_2, P.clt2mcode Ast.Dec _1)) ) +# 27380 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_dot_expressions_ = Obj.magic _2 in + let _1 : 'tv_unary_op = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_dot_expressions_ = +# 1231 "parser_cocci_menhir.mly" + ( let mcode = _1 in Ast0.wrap(Ast0.Unary(_2, mcode)) ) +# 27410 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_dot_expressions_ = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 27437 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_dot_expressions_ = +# 1233 "parser_cocci_menhir.mly" + ( let mcode = P.clt2mcode Ast.Not _1 in + Ast0.wrap(Ast0.Unary(_2, mcode)) ) +# 27445 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_dot_expressions_ = Obj.magic _2 in + let _1 : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 27472 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_dot_expressions_ = +# 1236 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.SizeOfExpr (P.clt2mcode "sizeof" _1, _2)) ) +# 27479 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 27515 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let t : 'tv_ctype = Obj.magic t in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 27521 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let s : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 27526 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_rp_ in + let _v : 'tv_unary_expr_eexpr_dot_expressions_ = +# 1238 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.SizeOfType (P.clt2mcode "sizeof" s, + P.clt2mcode "(" lp,t, + P.clt2mcode ")" rp)) ) +# 27535 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_postfix_expr_eexpr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_unary_expr_eexpr_invalid_ = +# 1225 "parser_cocci_menhir.mly" + ( _1 ) +# 27559 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_invalid_ = Obj.magic _2 in + let _1 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 27586 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_invalid_ = +# 1227 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Infix (_2, P.clt2mcode Ast.Inc _1)) ) +# 27593 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_invalid_ = Obj.magic _2 in + let _1 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 27620 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_invalid_ = +# 1229 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Infix (_2, P.clt2mcode Ast.Dec _1)) ) +# 27627 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_invalid_ = Obj.magic _2 in + let _1 : 'tv_unary_op = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_invalid_ = +# 1231 "parser_cocci_menhir.mly" + ( let mcode = _1 in Ast0.wrap(Ast0.Unary(_2, mcode)) ) +# 27657 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_invalid_ = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 27684 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_invalid_ = +# 1233 "parser_cocci_menhir.mly" + ( let mcode = P.clt2mcode Ast.Not _1 in + Ast0.wrap(Ast0.Unary(_2, mcode)) ) +# 27692 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_invalid_ = Obj.magic _2 in + let _1 : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 27719 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_invalid_ = +# 1236 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.SizeOfExpr (P.clt2mcode "sizeof" _1, _2)) ) +# 27726 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 27762 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let t : 'tv_ctype = Obj.magic t in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 27768 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let s : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 27773 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_rp_ in + let _v : 'tv_unary_expr_eexpr_invalid_ = +# 1238 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.SizeOfType (P.clt2mcode "sizeof" s, + P.clt2mcode "(" lp,t, + P.clt2mcode ")" rp)) ) +# 27782 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_postfix_expr_eexpr_nest_expressions_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_unary_expr_eexpr_nest_expressions_ = +# 1225 "parser_cocci_menhir.mly" + ( _1 ) +# 27806 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_nest_expressions_ = Obj.magic _2 in + let _1 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 27833 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_nest_expressions_ = +# 1227 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Infix (_2, P.clt2mcode Ast.Inc _1)) ) +# 27840 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_nest_expressions_ = Obj.magic _2 in + let _1 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 27867 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_nest_expressions_ = +# 1229 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Infix (_2, P.clt2mcode Ast.Dec _1)) ) +# 27874 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_nest_expressions_ = Obj.magic _2 in + let _1 : 'tv_unary_op = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_nest_expressions_ = +# 1231 "parser_cocci_menhir.mly" + ( let mcode = _1 in Ast0.wrap(Ast0.Unary(_2, mcode)) ) +# 27904 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_nest_expressions_ = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 27931 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_nest_expressions_ = +# 1233 "parser_cocci_menhir.mly" + ( let mcode = P.clt2mcode Ast.Not _1 in + Ast0.wrap(Ast0.Unary(_2, mcode)) ) +# 27939 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_eexpr_nest_expressions_ = Obj.magic _2 in + let _1 : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 27966 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_eexpr_nest_expressions_ = +# 1236 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.SizeOfExpr (P.clt2mcode "sizeof" _1, _2)) ) +# 27973 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 28009 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let t : 'tv_ctype = Obj.magic t in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 28015 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let s : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 28020 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_rp_ in + let _v : 'tv_unary_expr_eexpr_nest_expressions_ = +# 1238 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.SizeOfType (P.clt2mcode "sizeof" s, + P.clt2mcode "(" lp,t, + P.clt2mcode ")" rp)) ) +# 28029 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : 'tv_postfix_expr_expr_invalid_ = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_unary_expr_expr_invalid_ = +# 1225 "parser_cocci_menhir.mly" + ( _1 ) +# 28053 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_expr_invalid_ = Obj.magic _2 in + let _1 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 28080 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_expr_invalid_ = +# 1227 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Infix (_2, P.clt2mcode Ast.Inc _1)) ) +# 28087 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_expr_invalid_ = Obj.magic _2 in + let _1 : ( +# 84 "parser_cocci_menhir.mly" + (Data.clt) +# 28114 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_expr_invalid_ = +# 1229 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.Infix (_2, P.clt2mcode Ast.Dec _1)) ) +# 28121 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_expr_invalid_ = Obj.magic _2 in + let _1 : 'tv_unary_op = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_expr_invalid_ = +# 1231 "parser_cocci_menhir.mly" + ( let mcode = _1 in Ast0.wrap(Ast0.Unary(_2, mcode)) ) +# 28151 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_expr_invalid_ = Obj.magic _2 in + let _1 : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 28178 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_expr_invalid_ = +# 1233 "parser_cocci_menhir.mly" + ( let mcode = P.clt2mcode Ast.Not _1 in + Ast0.wrap(Ast0.Unary(_2, mcode)) ) +# 28186 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_unary_expr_expr_invalid_ = Obj.magic _2 in + let _1 : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 28213 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_unary_expr_expr_invalid_ = +# 1236 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.SizeOfExpr (P.clt2mcode "sizeof" _1, _2)) ) +# 28220 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = rp; + MenhirLib.EngineTypes.startp = _startpos_rp_; + MenhirLib.EngineTypes.endp = _endpos_rp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = t; + MenhirLib.EngineTypes.startp = _startpos_t_; + MenhirLib.EngineTypes.endp = _endpos_t_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = lp; + MenhirLib.EngineTypes.startp = _startpos_lp_; + MenhirLib.EngineTypes.endp = _endpos_lp_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = s; + MenhirLib.EngineTypes.startp = _startpos_s_; + MenhirLib.EngineTypes.endp = _endpos_s_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let rp : ( +# 76 "parser_cocci_menhir.mly" + (Data.clt) +# 28256 "parser_cocci_menhir.ml" + ) = Obj.magic rp in + let t : 'tv_ctype = Obj.magic t in + let lp : ( +# 75 "parser_cocci_menhir.mly" + (Data.clt) +# 28262 "parser_cocci_menhir.ml" + ) = Obj.magic lp in + let s : ( +# 58 "parser_cocci_menhir.mly" + (Data.clt) +# 28267 "parser_cocci_menhir.ml" + ) = Obj.magic s in + let _startpos = _startpos_s_ in + let _endpos = _endpos_rp_ in + let _v : 'tv_unary_expr_expr_invalid_ = +# 1238 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.SizeOfType (P.clt2mcode "sizeof" s, + P.clt2mcode "(" lp,t, + P.clt2mcode ")" rp)) ) +# 28276 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 92 "parser_cocci_menhir.mly" + (Data.clt) +# 28297 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_unary_op = +# 1242 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.GetRef _1 ) +# 28304 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 28325 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_unary_op = +# 1243 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.DeRef _1 ) +# 28332 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 97 "parser_cocci_menhir.mly" + (Data.clt) +# 28353 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_unary_op = +# 1244 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.UnPlus _1 ) +# 28360 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 97 "parser_cocci_menhir.mly" + (Data.clt) +# 28381 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_unary_op = +# 1245 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.UnMinus _1 ) +# 28388 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let _1 : ( +# 98 "parser_cocci_menhir.mly" + (Data.clt) +# 28409 "parser_cocci_menhir.ml" + ) = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__1_ in + let _v : 'tv_unary_op = +# 1246 "parser_cocci_menhir.mly" + ( P.clt2mcode Ast.Tilde _1 ) +# 28416 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_exp = Obj.magic _2 in + let _1 : 'tv_expr = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_when_start = +# 1634 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.DOTS((Ast0.wrap(Ast0.Exp(_1)))::_2)) ) +# 28446 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = _1; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + } = _menhir_stack in + let _2 : 'tv_toplevel_after_stm = Obj.magic _2 in + let _1 : 'tv_decl_statement = Obj.magic _1 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__2_ in + let _v : 'tv_when_start = +# 1636 "parser_cocci_menhir.mly" + ( Ast0.wrap(Ast0.DOTS(_1@_2)) ) +# 28476 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let w : 'tv_eexpr = Obj.magic w in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_whenexp = +# 1156 "parser_cocci_menhir.mly" + ( w ) +# 28512 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = _menhir_stack; + } = _menhir_stack in + let w : 'tv_whens_when_start_rule_elem_statement_ = Obj.magic w in + let _startpos = _startpos_w_ in + let _endpos = _endpos_w_ in + let _v : 'tv_whenppdecs = +# 843 "parser_cocci_menhir.mly" + ( w ) +# 28536 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let w : 'tv_when_start = Obj.magic w in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_whens_when_start_rule_elem_statement_ = +# 1706 "parser_cocci_menhir.mly" + ( [Ast0.WhenNot w] ) +# 28572 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__4_; + MenhirLib.EngineTypes.endp = _endpos__4_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = w; + MenhirLib.EngineTypes.startp = _startpos_w_; + MenhirLib.EngineTypes.endp = _endpos_w_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + }; + } = _menhir_stack in + let w : 'tv_rule_elem_statement = Obj.magic w in + let _startpos = _startpos__1_ in + let _endpos = _endpos__4_ in + let _v : 'tv_whens_when_start_rule_elem_statement_ = +# 1707 "parser_cocci_menhir.mly" + ( [Ast0.WhenAlways w] ) +# 28608 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + (fun _menhir_env -> + let _menhir_stack = _menhir_env.MenhirLib.EngineTypes.stack in + let { + MenhirLib.EngineTypes.startp = _startpos__3_; + MenhirLib.EngineTypes.endp = _endpos__3_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.semv = _2; + MenhirLib.EngineTypes.startp = _startpos__2_; + MenhirLib.EngineTypes.endp = _endpos__2_; + MenhirLib.EngineTypes.next = { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.startp = _startpos__1_; + MenhirLib.EngineTypes.endp = _endpos__1_; + MenhirLib.EngineTypes.next = _menhir_stack; + }; + }; + } = _menhir_stack in + let _2 : 'tv_comma_list_any_strict_ = Obj.magic _2 in + let _startpos = _startpos__1_ in + let _endpos = _endpos__3_ in + let _v : 'tv_whens_when_start_rule_elem_statement_ = +# 1709 "parser_cocci_menhir.mly" + ( List.map (function x -> Ast0.WhenModifier(x)) _2 ) +# 28640 "parser_cocci_menhir.ml" + in + _menhir_env.MenhirLib.EngineTypes.stack <- { + MenhirLib.EngineTypes.state = _menhir_s; + MenhirLib.EngineTypes.semv = Obj.repr _v; + MenhirLib.EngineTypes.startp = _startpos; + MenhirLib.EngineTypes.endp = _endpos; + MenhirLib.EngineTypes.next = _menhir_stack; + }); + |] + + let recovery = + false + + let trace = + None + + end) + +let rec script_meta_main = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 1479 lexer lexbuf) : ( +# 158 "parser_cocci_menhir.mly" + (string * (string * string)) +# 28664 "parser_cocci_menhir.ml" + )) + +and rule_name = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 1424 lexer lexbuf) : ( +# 152 "parser_cocci_menhir.mly" + (Ast_cocci.rulename) +# 28672 "parser_cocci_menhir.ml" + )) + +and reinit = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 1422 lexer lexbuf) : ( +# 130 "parser_cocci_menhir.mly" + (unit) +# 28680 "parser_cocci_menhir.ml" + )) + +and plus_main = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 1387 lexer lexbuf) : ( +# 139 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 28688 "parser_cocci_menhir.ml" + )) + +and plus_exp_main = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 1378 lexer lexbuf) : ( +# 142 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 28696 "parser_cocci_menhir.ml" + )) + +and never_used = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 1372 lexer lexbuf) : ( +# 167 "parser_cocci_menhir.mly" + (unit) +# 28704 "parser_cocci_menhir.ml" + )) + +and minus_main = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 1301 lexer lexbuf) : ( +# 133 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 28712 "parser_cocci_menhir.ml" + )) + +and minus_exp_main = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 1277 lexer lexbuf) : ( +# 136 "parser_cocci_menhir.mly" + (Ast0_cocci.rule) +# 28720 "parser_cocci_menhir.ml" + )) + +and meta_main = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 1274 lexer lexbuf) : ( +# 156 "parser_cocci_menhir.mly" + ((Ast_cocci.metavar,Ast_cocci.metavar) Common.either list) +# 28728 "parser_cocci_menhir.ml" + )) + +and iso_rule_name = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 1270 lexer lexbuf) : ( +# 148 "parser_cocci_menhir.mly" + (Ast_cocci.rulename) +# 28736 "parser_cocci_menhir.ml" + )) + +and iso_meta_main = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 1078 lexer lexbuf) : ( +# 164 "parser_cocci_menhir.mly" + ((Ast_cocci.metavar,Ast_cocci.metavar) Common.either list) +# 28744 "parser_cocci_menhir.ml" + )) + +and iso_main = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 10 lexer lexbuf) : ( +# 161 "parser_cocci_menhir.mly" + (Ast0_cocci.anything list list) +# 28752 "parser_cocci_menhir.ml" + )) + +and include_main = + fun lexer lexbuf -> + (Obj.magic (MenhirInterpreter.entry 0 lexer lexbuf) : ( +# 145 "parser_cocci_menhir.mly" + ((string,string) Common.either list) +# 28760 "parser_cocci_menhir.ml" + )) + + + diff --git a/parsing_cocci/parser_cocci_menhir.mli b/parsing_cocci/parser_cocci_menhir.mli new file mode 100644 index 0000000..3acc076 --- /dev/null +++ b/parsing_cocci/parser_cocci_menhir.mli @@ -0,0 +1,180 @@ +exception Error + +type token = + | Tvolatile of (Data.clt) + | Tvoid of (Data.clt) + | Tunsigned of (Data.clt) + | Tunion of (Data.clt) + | Ttypedef of (Data.clt) + | Tstruct of (Data.clt) + | Tstatic of (Data.clt) + | Tsigned of (Data.clt) + | Tshort of (Data.clt) + | Tregister of (Data.clt) + | Tlong of (Data.clt) + | Tlist + | Tint of (Data.clt) + | Tinline of (Data.clt) + | Tfloat of (Data.clt) + | Textern of (Data.clt) + | Tdouble of (Data.clt) + | Tconst of (Data.clt) + | Tchar of (Data.clt) + | Tauto of (Data.clt) + | Tattr of (string * Data.clt) + | TXor of (Data.clt) + | TWords + | TWhy0 + | TWhy of (Data.clt) + | TWhile of (Data.clt) + | TWhen of (Data.clt) + | TUsing + | TTypedef + | TTypeId of (string * Data.clt) + | TType + | TTilde of (Data.clt) + | TSwitch of (Data.clt) + | TString of (string * Data.clt) + | TStrict of (Data.clt) + | TStatement + | TSizeof of (Data.clt) + | TShOp of (Ast_cocci.arithOp * Data.clt) + | TScriptData of (string) + | TRuleName of (string) + | TRightIso + | TReverse + | TReturn of (Data.clt) + | TPure + | TPtrOp of (Data.clt) + | TPtVirg of (Data.clt) + | TPragma of (string) + | TPosition + | TPosAny + | TPlusFile of (string * Data.clt) + | TPlus0 + | TPlus of (Data.clt) + | TPathIsoFile of (string) + | TParameter + | TPOEllipsis of (Data.clt) + | TPCEllipsis of (Data.clt) + | TPArob + | TOrLog of (Data.clt) + | TOr of (Data.clt) + | TOn + | TOPar0 of (Data.clt) + | TOPar of (Data.clt) + | TOEllipsis of (Data.clt) + | TOCro of (Data.clt) + | TOBrace of (Data.clt) + | TNothing + | TNotEq of (Data.clt) + | TNever + | TName + | TMul of (Data.clt) + | TMinusFile of (string * Data.clt) + | TMinus of (Data.clt) + | TMid0 of (Data.clt) + | TMetaType of (Parse_aux.info) + | TMetaStmList of (Parse_aux.info) + | TMetaStm of (Parse_aux.info) + | TMetaPos of (Parse_aux.pos_info) + | TMetaParamList of (Parse_aux.list_info) + | TMetaParam of (Parse_aux.info) + | TMetaLocalIdExp of (Parse_aux.typed_info) + | TMetaLocalFunc of (Parse_aux.idinfo) + | TMetaIterator of (Parse_aux.idinfo) + | TMetaIdExp of (Parse_aux.typed_info) + | TMetaId of (Parse_aux.idinfo) + | TMetaFunc of (Parse_aux.idinfo) + | TMetaExpList of (Parse_aux.list_info) + | TMetaExp of (Parse_aux.typed_info) + | TMetaErr of (Parse_aux.expinfo) + | TMetaDeclarer of (Parse_aux.idinfo) + | TMetaConst of (Parse_aux.typed_info) + | TMPtVirg + | TLogOp of (Ast_cocci.logicalOp * Data.clt) + | TLocal + | TLineEnd of (Data.clt) + | TIteratorId of (string * Data.clt) + | TIterator + | TIsoType + | TIsoTopLevel + | TIsoTestExpression + | TIsoStatement + | TIsoExpression + | TIsoDeclaration + | TIsoArgExpression + | TIso + | TInvalid + | TInt of (string * Data.clt) + | TIncludeNL of (string * Data.clt) + | TIncludeL of (string * Data.clt) + | TInc of (Data.clt) + | TIf of (Data.clt) + | TIdentifier + | TIdent of (string * Data.clt) + | TIdExpression + | TGoto of (Data.clt) + | TFunction + | TFunDecl of (Data.clt) + | TFresh + | TForall + | TFor of (Data.clt) + | TFloat of (string * Data.clt) + | TExtends + | TExpression + | TExists + | TEver + | TError + | TEqEq of (Data.clt) + | TEq of (Data.clt) + | TElse of (Data.clt) + | TEllipsis of (Data.clt) + | TDotDot of (Data.clt) + | TDot of (Data.clt) + | TDo of (Data.clt) + | TDmOp of (Ast_cocci.arithOp * Data.clt) + | TDisable + | TDepends + | TDefineParam of (Data.clt * token * int) + | TDefine of (Data.clt * token) + | TDefault of (Data.clt) + | TDeclarerId of (string * Data.clt) + | TDeclarer + | TDec of (Data.clt) + | TContinue of (Data.clt) + | TContext + | TConstant + | TComma of (Data.clt) + | TChar of (string * Data.clt) + | TCase of (Data.clt) + | TCPar0 of (Data.clt) + | TCPar of (Data.clt) + | TCEllipsis of (Data.clt) + | TCCro of (Data.clt) + | TCBrace of (Data.clt) + | TBreak of (Data.clt) + | TBang0 + | TBang of (Data.clt) + | TAssign of (Ast_cocci.assignOp * Data.clt) + | TArobArob + | TArob + | TAny of (Data.clt) + | TAndLog of (Data.clt) + | TAnd of (Data.clt) + | EOF + + +val script_meta_main: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> (string * (string * string)) +val rule_name: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> (Ast_cocci.rulename) +val reinit: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> (unit) +val plus_main: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> (Ast0_cocci.rule) +val plus_exp_main: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> (Ast0_cocci.rule) +val never_used: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> (unit) +val minus_main: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> (Ast0_cocci.rule) +val minus_exp_main: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> (Ast0_cocci.rule) +val meta_main: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> ((Ast_cocci.metavar,Ast_cocci.metavar) Common.either list) +val iso_rule_name: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> (Ast_cocci.rulename) +val iso_meta_main: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> ((Ast_cocci.metavar,Ast_cocci.metavar) Common.either list) +val iso_main: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> (Ast0_cocci.anything list list) +val include_main: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> ((string,string) Common.either list) \ No newline at end of file diff --git a/parsing_cocci/parser_cocci_menhir.mly b/parsing_cocci/parser_cocci_menhir.mly new file mode 100644 index 0000000..a3be6b6 --- /dev/null +++ b/parsing_cocci/parser_cocci_menhir.mly @@ -0,0 +1,1765 @@ +/* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*/ + + +%{ + +(* Not clear how to allow function declarations to specify a return type +and how to allow both to be specified as static, because they are in +different rules. The rules seem to have to be combined, which would allow +functions to be declared as local variables *) + +(* Not clear how to let a function have a parameter of type void. At the +moment, void is allowed to be the type of a variable, which is wrong, and a +parameter needs both a type and an identifier *) +module Ast0 = Ast0_cocci +module Ast = Ast_cocci +module P = Parse_aux +%} + +%token EOF + +%token TIdentifier TExpression TStatement TFunction TLocal TType TParameter +%token TIdExpression +%token Tlist TFresh TConstant TError TWords TWhy0 TPlus0 TBang0 +%token TPure TContext +%token TTypedef TDeclarer TIterator TName TPosition TPosAny +%token TUsing TDisable TExtends TDepends TOn TEver TNever TExists TForall +%token TReverse TNothing +%token TRuleName + +%token Tchar Tshort Tint Tdouble Tfloat Tlong +%token Tvoid Tstruct Tunion +%token Tunsigned Tsigned + +%token Tstatic Tauto Tregister Textern Tinline Ttypedef +%token Tconst Tvolatile +%token Tattr + +%token TIf TElse TWhile TFor TDo TSwitch TCase TDefault TReturn +%token TBreak TContinue TGoto TSizeof TFunDecl +%token TIdent TTypeId TDeclarerId TIteratorId + +%token TMetaId TMetaFunc TMetaLocalFunc +%token TMetaIterator TMetaDeclarer +%token TMetaErr +%token TMetaParam TMetaStm TMetaStmList TMetaType +%token TMetaParamList TMetaExpList +%token TMetaExp TMetaIdExp TMetaLocalIdExp TMetaConst +%token TMetaPos + +%token TArob TArobArob TPArob +%token TScriptData + +%token TEllipsis TOEllipsis TCEllipsis TPOEllipsis TPCEllipsis +%token TWhen TAny TStrict TLineEnd + +%token TWhy TDotDot TBang TOPar TOPar0 +%token TMid0 TCPar TCPar0 + +%token TPragma TPathIsoFile +%token TIncludeL TIncludeNL +%token TDefine +%token TDefineParam +%token TMinusFile TPlusFile + +%token TInc TDec + +%token TString TChar TFloat TInt + +%token TOrLog +%token TAndLog +%token TOr +%token TXor +%token TAnd +%token TEqEq TNotEq +%token TLogOp /* TInf TSup TInfEq TSupEq */ +%token TShOp /* TShl TShr */ +%token TDmOp /* TDiv TMod */ +%token TPlus TMinus +%token TMul TTilde + +%token TOBrace TCBrace +%token TOCro TCCro + +%token TPtrOp + +%token TMPtVirg +%token TEq TDot TComma TPtVirg +%token TAssign + +%token TIso TRightIso TIsoExpression TIsoStatement TIsoDeclaration TIsoType +%token TIsoTopLevel TIsoArgExpression TIsoTestExpression + +%token TInvalid + +/* operator precedence */ +%nonassoc TIf +%nonassoc TElse + +%left TOrLog +%left TAndLog +%left TOr +%left TXor +%left TAnd +%left TEqEq TNotEq +%left TLogOp /* TInf TSup TInfEq TSupEq */ +%left TShOp /* TShl TShr */ +%left TPlus TMinus +%left TMul TDmOp /* TDiv TMod */ + +%start reinit +%type reinit + +%start minus_main +%type minus_main + +%start minus_exp_main +%type minus_exp_main + +%start plus_main +%type plus_main + +%start plus_exp_main +%type plus_exp_main + +%start include_main +%type <(string,string) Common.either list> include_main + +%start iso_rule_name +%type +iso_rule_name + +%start rule_name +%type +rule_name + +%start meta_main +%type <(Ast_cocci.metavar,Ast_cocci.metavar) Common.either list> meta_main + +%start script_meta_main + +%start iso_main +%type iso_main + +%start iso_meta_main +%type <(Ast_cocci.metavar,Ast_cocci.metavar) Common.either list> iso_meta_main + +%start never_used +%type never_used + +%% + +reinit: { } +minus_main: minus_body EOF { $1 } | m=minus_body TArobArob { m } +| m=minus_body TArob { m } +plus_main: plus_body EOF { $1 } | p=plus_body TArobArob { p } +| p=plus_body TArob { p } +minus_exp_main: minus_exp_body EOF { $1 } | m=minus_exp_body TArobArob { m } +| m=minus_exp_body TArob { m } +plus_exp_main: plus_exp_body EOF { $1 } | p=plus_exp_body TArobArob { p } +| p=plus_exp_body TArob { p } +meta_main: m=metadec { m (!Ast0.rule_name) } +iso_meta_main: m=metadec { m "" } + +/***************************************************************************** +* +* +*****************************************************************************/ + +pure: + TPure { Ast0.Pure } +| TContext { Ast0.Context } +| TPure TContext { Ast0.PureContext } +| TContext TPure { Ast0.PureContext } +| /* empty */ { Ast0.Impure } + +iso_rule_name: + nm=pure_ident TArob { P.make_iso_rule_name_result (P.id2name nm) } + +rule_name: + nm=ioption(pure_ident) extends d=depends i=loption(choose_iso) + a=loption(disable) e=exists ee=is_expression TArob + { P.make_cocci_rule_name_result nm d i a e ee } + | scr=pure_ident TDotDot lang=pure_ident d=depends TArob + { P.make_script_rule_name_result scr lang d } + +extends: + /* empty */ { () } +| TExtends parent=TRuleName + { !Data.install_bindings (parent) } + +depends: + /* empty */ { Ast.NoDep } +| TDepends TOn parents=dep { parents } + +dep: + pnrule { $1 } +| dep TAndLog dep { Ast.AndDep($1, $3) } +| dep TOrLog dep { Ast.OrDep ($1, $3) } + +pnrule: + TRuleName { Ast.Dep $1 } +| TBang TRuleName { Ast.AntiDep $2 } +| TEver TRuleName { Ast.EverDep $2 } +| TNever TRuleName { Ast.NeverDep $2 } +| TOPar dep TCPar { $2 } + +choose_iso: + TUsing separated_nonempty_list(TComma,TString) { List.map P.id2name $2 } + +disable: + TDisable separated_nonempty_list(TComma,pure_ident) { List.map P.id2name $2 } + +exists: + TExists { Ast.Exists } +| TForall { Ast.Forall } +| TReverse TForall { Ast.ReverseForall } +| { Ast.Undetermined } + +is_expression: // for more flexible parsing of top level expressions + { false } +| TExpression { true } + +include_main: + list(incl) TArob { $1 } +| list(incl) TArobArob { $1 } + +incl: + TUsing TString { Common.Left(P.id2name $2) } +| TUsing TPathIsoFile { Common.Right $2 } + +metadec: + ar=arity ispure=pure + kindfn=metakind ids=comma_list(pure_ident_or_meta_ident) TMPtVirg + { P.create_metadec ar ispure kindfn ids } +| ar=arity ispure=pure + kindfn=metakind_atomic + ids=comma_list(pure_ident_or_meta_ident_with_not_eq(not_eq)) TMPtVirg + { P.create_metadec_ne ar ispure kindfn ids } +| ar=arity ispure=pure + kindfn=metakind_atomic_expi + ids=comma_list(pure_ident_or_meta_ident_with_not_eq(not_eqe)) TMPtVirg + { P.create_metadec_ne ar ispure kindfn ids } +| ar=arity ispure=pure + kindfn=metakind_atomic_expe + ids=comma_list(pure_ident_or_meta_ident_with_not_eq(not_ceq)) TMPtVirg + { P.create_metadec_ne ar ispure kindfn ids } +| ar=arity TPosition a=option(TPosAny) + ids=comma_list(pure_ident_or_meta_ident_with_not_eq(not_pos)) TMPtVirg + { let kindfn arity name pure check_meta constraints = + let tok = check_meta(Ast.MetaPosDecl(arity,name)) in + let any = match a with None -> Ast.PER | Some _ -> Ast.ALL in + !Data.add_pos_meta name constraints any; tok in + P.create_metadec_ne ar false kindfn ids } +| ar=arity ispure=pure + TParameter Tlist TOCro id=pure_ident_or_meta_ident TCCro + ids=comma_list(pure_ident_or_meta_ident) TMPtVirg + { P.create_len_metadec ar ispure + (fun lenname arity name pure check_meta -> + let tok = + check_meta(Ast.MetaParamListDecl(arity,name,Some lenname)) in + !Data.add_paramlist_meta name (Some lenname) pure; tok) + id ids } +| ar=arity ispure=pure + TExpression Tlist TOCro id=pure_ident_or_meta_ident TCCro + ids=comma_list(pure_ident_or_meta_ident) TMPtVirg + { P.create_len_metadec ar ispure + (fun lenname arity name pure check_meta -> + let tok = + check_meta(Ast.MetaExpListDecl(arity,name,Some lenname)) in + !Data.add_explist_meta name (Some lenname) pure; tok) + id ids } + +%inline metakind: + TFresh TIdentifier + { (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaFreshIdDecl(arity,name)) in + !Data.add_id_meta name [] pure; tok) } +| TParameter + { (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaParamDecl(arity,name)) in + !Data.add_param_meta name pure; tok) } +| TParameter Tlist + { (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaParamListDecl(arity,name,None)) in + !Data.add_paramlist_meta name None pure; tok) } +| TExpression Tlist + { (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaExpListDecl(arity,name,None)) in + !Data.add_explist_meta name None pure; tok) } +| TType + { (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaTypeDecl(arity,name)) in + !Data.add_type_meta name pure; tok) } +| TStatement + { (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaStmDecl(arity,name)) in + !Data.add_stm_meta name pure; tok) } +| TStatement Tlist + { (fun arity name pure check_meta -> + let tok = check_meta(Ast.MetaStmListDecl(arity,name)) in + !Data.add_stmlist_meta name pure; tok) } +| TTypedef + { (fun arity (_,name) pure check_meta -> + if arity = Ast.NONE && pure = Ast0.Impure + then (!Data.add_type_name name; []) + else raise (Semantic_cocci.Semantic "bad typedef")) } +| TDeclarer TName + { (fun arity (_,name) pure check_meta -> + if arity = Ast.NONE && pure = Ast0.Impure + then (!Data.add_declarer_name name; []) + else raise (Semantic_cocci.Semantic "bad declarer")) } +| TIterator TName + { (fun arity (_,name) pure check_meta -> + if arity = Ast.NONE && pure = Ast0.Impure + then (!Data.add_iterator_name name; []) + else raise (Semantic_cocci.Semantic "bad iterator")) } + + +%inline metakind_atomic: + TIdentifier + { (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaIdDecl(arity,name)) in + !Data.add_id_meta name constraints pure; tok) } +| TFunction + { (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaFuncDecl(arity,name)) in + !Data.add_func_meta name constraints pure; tok) } +| TLocal TFunction + { (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaLocalFuncDecl(arity,name)) in + !Data.add_local_func_meta name constraints pure; + tok) } +| TDeclarer + { (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaDeclarerDecl(arity,name)) in + !Data.add_declarer_meta name constraints pure; tok) } +| TIterator + { (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaIteratorDecl(arity,name)) in + !Data.add_iterator_meta name constraints pure; tok) } + +%inline metakind_atomic_expi: + TError + { (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaErrDecl(arity,name)) in + !Data.add_err_meta name constraints pure; tok) } +| l=option(TLocal) TIdExpression ty=ioption(meta_exp_type) + { (fun arity name pure check_meta constraints -> + match l with + None -> + !Data.add_idexp_meta ty name constraints pure; + check_meta(Ast.MetaIdExpDecl(arity,name,ty)) + | Some _ -> + !Data.add_local_idexp_meta ty name constraints pure; + check_meta(Ast.MetaLocalIdExpDecl(arity,name,ty))) } +| l=option(TLocal) TIdExpression m=nonempty_list(TMul) + { (fun arity name pure check_meta constraints -> + let ty = Some [P.ty_pointerify Type_cocci.Unknown m] in + match l with + None -> + !Data.add_idexp_meta ty name constraints pure; + check_meta(Ast.MetaIdExpDecl(arity,name,ty)) + | Some _ -> + !Data.add_local_idexp_meta ty name constraints pure; + check_meta(Ast.MetaLocalIdExpDecl(arity,name,ty))) } +| TExpression m=nonempty_list(TMul) + { (fun arity name pure check_meta constraints -> + let ty = Some [P.ty_pointerify Type_cocci.Unknown m] in + let tok = check_meta(Ast.MetaExpDecl(arity,name,ty)) in + !Data.add_exp_meta ty name constraints pure; tok) } +| vl=meta_exp_type TOCro TCCro + { (fun arity name pure check_meta constraints -> + let ty = Some (List.map (function x -> Type_cocci.Array x) vl) in + let tok = check_meta(Ast.MetaExpDecl(arity,name,ty)) in + !Data.add_exp_meta ty name constraints pure; tok) } +| TConstant ty=ioption(meta_exp_type) + { (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaConstDecl(arity,name,ty)) in + !Data.add_const_meta ty name constraints pure; tok) } + +%inline metakind_atomic_expe: + TExpression + { (fun arity name pure check_meta constraints -> + let tok = check_meta(Ast.MetaExpDecl(arity,name,None)) in + !Data.add_exp_meta None name constraints pure; tok) } +| vl=meta_exp_type // no error if use $1 but doesn't type check + { (fun arity name pure check_meta constraints -> + let ty = Some vl in + List.iter + (function c -> + match Ast0.unwrap c with + Ast0.Constant(_) -> + if not + (List.exists + (function + Type_cocci.BaseType(Type_cocci.IntType,_) -> true + | Type_cocci.BaseType(Type_cocci.ShortType,_) -> true + | Type_cocci.BaseType(Type_cocci.LongType,_) -> true + | _ -> false) + vl) + then failwith "metavariable with int constraint must be an int" + | _ -> ()) + constraints; + let tok = check_meta(Ast.MetaExpDecl(arity,name,ty)) in + !Data.add_exp_meta ty name constraints pure; tok) } + + +meta_exp_type: + t=ctype + { [Ast0_cocci.ast0_type_to_type t] } +| TOBrace t=comma_list(ctype) TCBrace m=list(TMul) + { List.map + (function x -> P.ty_pointerify (Ast0_cocci.ast0_type_to_type x) m) + t } + +arity: TBang0 { Ast.UNIQUE } + | TWhy0 { Ast.OPT } + | TPlus0 { Ast.MULTI } + | /* empty */ { Ast.NONE } + +generic_ctype: + q=ctype_qualif + { Ast0.wrap(Ast0.ImplicitInt(q)) } + | q=ioption(ctype_qualif) ty=Tchar + { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.CharType ty, q)) } + | q=ioption(ctype_qualif) ty=Tshort + { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.ShortType ty, q)) } + | q=ioption(ctype_qualif) ty=Tint + { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.IntType ty, q)) } + | t=Tdouble + { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.DoubleType t, None)) } + | t=Tfloat + { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.FloatType t, None)) } + | q=ioption(ctype_qualif) ty=Tlong + { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.LongType ty, q)) } + | s=struct_or_union i=ident + { Ast0.wrap(Ast0.StructUnionName(s, Some i)) } + | s=struct_or_union i=ioption(ident) + l=TOBrace d=struct_decl_list r=TCBrace + { (if i = None && !Data.in_iso + then failwith "structures must be named in the iso file"); + Ast0.wrap(Ast0.StructUnionDef(Ast0.wrap(Ast0.StructUnionName(s, i)), + P.clt2mcode "{" l, + d, P.clt2mcode "}" r)) } + | s=TMetaType l=TOBrace d=struct_decl_list r=TCBrace + { let (nm,pure,clt) = s in + let ty = + Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) in + Ast0.wrap + (Ast0.StructUnionDef(ty,P.clt2mcode "{" l,d,P.clt2mcode "}" r)) } + | r=TRuleName TDot p=TIdent + { let nm = (r,P.id2name p) in + (* this is only possible when we are in a metavar decl. Otherwise, + it will be represented already as a MetaType *) + let _ = P.check_meta(Ast.MetaTypeDecl(Ast.NONE,nm)) in + Ast0.wrap(Ast0.MetaType(P.clt2mcode nm (P.id2clt p), + Ast0.Impure (*will be ignored*))) } + | p=TTypeId + { Ast0.wrap(Ast0.TypeName(P.id2mcode p)) } + | p=TMetaType + { let (nm,pure,clt) = p in + Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) } + +struct_or_union: + s=Tstruct { P.clt2mcode Ast.Struct s } + | u=Tunion { P.clt2mcode Ast.Union u } + +struct_decl: + TNothing { [] } + | t=ctype d=d_ident pv=TPtVirg + { let (id,fn) = d in + [Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv))] } + | t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar + lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar pv=TPtVirg + { let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + [Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv))] } + | cv=ioption(const_vol) i=pure_ident d=d_ident pv=TPtVirg + { let (id,fn) = d in + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + [Ast0.wrap(Ast0.UnInit(None,fn idtype,id,P.clt2mcode ";" pv))] } + +struct_decl_list: + struct_decl_list_start { Ast0.wrap(Ast0.DOTS($1)) } + +struct_decl_list_start: + struct_decl { $1 } +| struct_decl struct_decl_list_start { $1@$2 } +| d=edots_when(TEllipsis,struct_decl) r=continue_struct_decl_list + { (P.mkddots "..." d)::r } + +continue_struct_decl_list: + /* empty */ { [] } +| struct_decl struct_decl_list_start { $1@$2 } +| struct_decl { $1 } + +ctype: + cv=ioption(const_vol) ty=generic_ctype m=list(TMul) + { P.pointerify (P.make_cv cv ty) m } + | cv=ioption(const_vol) t=Tvoid m=nonempty_list(TMul) + { let ty = + Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in + P.pointerify (P.make_cv cv ty) m } + | lp=TOPar0 t=midzero_list(ctype,ctype) rp=TCPar0 + /* more hacks */ + { let (mids,code) = t in + Ast0.wrap + (Ast0.DisjType(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) } + + +fn_ctype: // allows metavariables + ty=generic_ctype m=list(TMul) { P.pointerify ty m } + | t=Tvoid m=list(TMul) + { P.pointerify + (Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None))) + m } + +ctype_qualif: + Tunsigned { P.clt2mcode Ast.Unsigned $1 } + | Tsigned { P.clt2mcode Ast.Signed $1 } + +/*****************************************************************************/ + +/* have to inline everything to avoid conflicts? switch to proper +declarations, statements, and expressions for the subterms */ + +minus_body: + f=loption(filespec) + b=loption(minus_start) + ew=loption(error_words) + { match f@b@ew with + [] -> raise (Semantic_cocci.Semantic "minus slice can't be empty") + | code -> Top_level.top_level code } + +plus_body: + f=loption(filespec) + b=loption(plus_start) + ew=loption(error_words) + { Top_level.top_level (f@b@ew) } + +minus_exp_body: + f=loption(filespec) + b=top_eexpr + ew=loption(error_words) + { match f@[b]@ew with + [] -> raise (Semantic_cocci.Semantic "minus slice can't be empty") + | code -> Top_level.top_level code } + +plus_exp_body: + f=loption(filespec) + b=top_eexpr + ew=loption(error_words) + { Top_level.top_level (f@[b]@ew) } + +filespec: + TMinusFile TPlusFile + { [Ast0.wrap + (Ast0.FILEINFO(P.id2mcode $1, + P.id2mcode $2))] } + +includes: + TIncludeL + { Ast0.wrap + (Ast0.Include(P.clt2mcode "#include" (P.drop_aft (P.id2clt $1)), + let (arity,ln,lln,offset,col,strbef,straft,pos) = + P.id2clt $1 in + let clt = + (arity,ln,lln,offset,0,strbef,straft,pos) in + P.clt2mcode + (Ast.Local (Parse_aux.str2inc (P.id2name $1))) + (P.drop_bef clt))) } +| TIncludeNL + { Ast0.wrap + (Ast0.Include(P.clt2mcode "#include" (P.drop_aft (P.id2clt $1)), + let (arity,ln,lln,offset,col,strbef,straft,pos) = + P.id2clt $1 in + let clt = + (arity,ln,lln,offset,0,strbef,straft,pos) in + P.clt2mcode + (Ast.NonLocal (Parse_aux.str2inc (P.id2name $1))) + (P.drop_bef clt))) } +| d=defineop t=ctype TLineEnd + { let ty = Ast0.wrap(Ast0.TopExp(Ast0.wrap(Ast0.TypeExp(t)))) in + d (Ast0.wrap(Ast0.DOTS([ty]))) } +| defineop b=toplevel_seq_start(toplevel_after_dots) TLineEnd + { let body = + match b with + [e] -> + (match Ast0.unwrap e with + Ast0.Exp(e1) -> + [Ast0.rewrap e (Ast0.TopExp(Ast0.set_arg_exp (e1)))] + | _ -> b) + | _ -> b in + $1 (Ast0.wrap(Ast0.DOTS(body))) } + +defineop: + TDefine + { let (clt,ident) = $1 in + function body -> + Ast0.wrap + (Ast0.Define + (P.clt2mcode "#define" clt, + (match ident with + TMetaId((nm,constraints,pure,clt)) -> + Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) + | TIdent(nm_pure) -> + Ast0.wrap(Ast0.Id(P.id2mcode nm_pure)) + | _ -> + raise + (Semantic_cocci.Semantic + "unexpected name for a #define")), + Ast0.wrap Ast0.NoParams, + body)) } +| TDefineParam define_param_list_option TCPar + { let (clt,ident,parenoff) = $1 in + let (arity,line,lline,offset,col,strbef,straft,pos) = clt in + let lp = + P.clt2mcode "(" (arity,line,lline,parenoff,0,[],[],Ast0.NoMetaPos) in + function body -> + Ast0.wrap + (Ast0.Define + (P.clt2mcode "#define" clt, + (match ident with + TMetaId((nm,constraints,pure,clt)) -> + Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) + | TIdent(nm_pure) -> + Ast0.wrap(Ast0.Id(P.id2mcode nm_pure)) + | _ -> + raise + (Semantic_cocci.Semantic + "unexpected name for a #define")), + Ast0.wrap (Ast0.DParams (lp,$2,P.clt2mcode ")" $3)),body)) } + +/* ---------------------------------------------------------------------- */ + +define_param_list: define_param_list_start + {let circle x = + match Ast0.unwrap x with Ast0.DPcircles(_) -> true | _ -> false in + if List.exists circle $1 + then Ast0.wrap(Ast0.CIRCLES($1)) + else Ast0.wrap(Ast0.DOTS($1)) } + +define_param_list_start: + ident { [Ast0.wrap(Ast0.DParam $1)] } + | ident TComma define_param_list_start + { Ast0.wrap(Ast0.DParam $1):: + Ast0.wrap(Ast0.DPComma(P.clt2mcode "," $2))::$3 } + | d=TEllipsis r=list(dp_comma_args(TEllipsis)) + { (P.mkdpdots "..." d):: + (List.concat (List.map (function x -> x (P.mkdpdots "...")) r)) } + +dp_comma_args(dotter): + c=TComma d=dotter + { function dot_builder -> + [Ast0.wrap(Ast0.DPComma(P.clt2mcode "," c)); dot_builder d] } +| TComma ident + { function dot_builder -> + [Ast0.wrap(Ast0.DPComma(P.clt2mcode "," $1)); + Ast0.wrap(Ast0.DParam $2)] } + +define_param_list_option: define_param_list { $1 } + | /* empty */ { Ast0.wrap(Ast0.DOTS([])) } + +/*****************************************************************************/ + +funproto: + s=ioption(storage) t=ctype + id=func_ident lp=TOPar d=decl_list(name_opt_decl) rp=TCPar pt=TPtVirg + { Ast0.wrap + (Ast0.UnInit + (s, + Ast0.wrap + (Ast0.FunctionType(Some t, + P.clt2mcode "(" lp, d, P.clt2mcode ")" rp)), + id, P.clt2mcode ";" pt)) } +| s=ioption(storage) t=Tvoid + id=func_ident lp=TOPar d=decl_list(name_opt_decl) rp=TCPar pt=TPtVirg + { let t = Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in + Ast0.wrap + (Ast0.UnInit + (s, + Ast0.wrap + (Ast0.FunctionType(Some t, + P.clt2mcode "(" lp, d, P.clt2mcode ")" rp)), + id, P.clt2mcode ";" pt)) } + + +fundecl: + f=fninfo + TFunDecl i=func_ident lp=TOPar d=decl_list(decl) rp=TCPar + lb=TOBrace b=fun_start rb=TCBrace + { Ast0.wrap(Ast0.FunDecl((Ast0.default_info(),Ast0.context_befaft()), + f, i, + P.clt2mcode "(" lp, d, + P.clt2mcode ")" rp, + P.clt2mcode "{" lb, b, + P.clt2mcode "}" rb)) } + +fninfo: + /* empty */ { [] } + | storage fninfo + { try + let _ = + List.find (function Ast0.FStorage(_) -> true | _ -> false) $2 in + raise (Semantic_cocci.Semantic "duplicate storage") + with Not_found -> (Ast0.FStorage($1))::$2 } + | t=fn_ctype r=fninfo_nt { (Ast0.FType(t))::r } + | Tinline fninfo + { try + let _ = List.find (function Ast0.FInline(_) -> true | _ -> false) $2 in + raise (Semantic_cocci.Semantic "duplicate inline") + with Not_found -> (Ast0.FInline(P.clt2mcode "inline" $1))::$2 } + | Tattr fninfo + { try + let _ = List.find (function Ast0.FAttr(_) -> true | _ -> false) $2 in + raise (Semantic_cocci.Semantic "multiple attributes") + with Not_found -> (Ast0.FAttr(P.id2mcode $1))::$2 } + +fninfo_nt: + /* empty */ { [] } + | storage fninfo_nt + { try + let _ = + List.find (function Ast0.FStorage(_) -> true | _ -> false) $2 in + raise (Semantic_cocci.Semantic "duplicate storage") + with Not_found -> (Ast0.FStorage($1))::$2 } + | Tinline fninfo_nt + { try + let _ = List.find (function Ast0.FInline(_) -> true | _ -> false) $2 in + raise (Semantic_cocci.Semantic "duplicate inline") + with Not_found -> (Ast0.FInline(P.clt2mcode "inline" $1))::$2 } + | Tattr fninfo_nt + { try + let _ = List.find (function Ast0.FAttr(_) -> true | _ -> false) $2 in + raise (Semantic_cocci.Semantic "duplicate init") + with Not_found -> (Ast0.FAttr(P.id2mcode $1))::$2 } + +storage: + s=Tstatic { P.clt2mcode Ast.Static s } + | s=Tauto { P.clt2mcode Ast.Auto s } + | s=Tregister { P.clt2mcode Ast.Register s } + | s=Textern { P.clt2mcode Ast.Extern s } + +decl: t=ctype i=ident + { Ast0.wrap(Ast0.Param(t, Some i)) } + | t=fn_ctype lp=TOPar s=TMul i=ident rp=TCPar + lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar + { let fnptr = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp,P.clt2mcode "*" s,P.clt2mcode ")" rp, + P.clt2mcode "(" lp1,d,P.clt2mcode ")" rp1)) in + Ast0.wrap(Ast0.Param(fnptr, Some i)) } + | t=Tvoid + { let ty = Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in + Ast0.wrap(Ast0.VoidParam(ty)) } + | TMetaParam + { let (nm,pure,clt) = $1 in + Ast0.wrap(Ast0.MetaParam(P.clt2mcode nm clt,pure)) } + +name_opt_decl: + decl { $1 } + | t=ctype { Ast0.wrap(Ast0.Param(t, None)) } + | t=fn_ctype lp=TOPar s=TMul rp=TCPar + lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar + { let fnptr = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp,P.clt2mcode "*" s,P.clt2mcode ")" rp, + P.clt2mcode "(" lp1,d,P.clt2mcode ")" rp1)) in + Ast0.wrap(Ast0.Param(fnptr, None)) } + +const_vol: + Tconst { P.clt2mcode Ast.Const $1 } + | Tvolatile { P.clt2mcode Ast.Volatile $1 } + +/*****************************************************************************/ + +statement: + includes { $1 } /* shouldn't be allowed to be a single_statement... */ +| TMetaStm + { P.meta_stm $1 } +| expr TPtVirg + { P.exp_stm $1 $2 } +| TIf TOPar eexpr TCPar single_statement %prec TIf + { P.ifthen $1 $2 $3 $4 $5 } +| TIf TOPar eexpr TCPar single_statement TElse single_statement + { P.ifthenelse $1 $2 $3 $4 $5 $6 $7 } +| TFor TOPar option(eexpr) TPtVirg option(eexpr) TPtVirg + option(eexpr) TCPar single_statement + { P.forloop $1 $2 $3 $4 $5 $6 $7 $8 $9 } +| TWhile TOPar eexpr TCPar single_statement + { P.whileloop $1 $2 $3 $4 $5 } +| TDo single_statement TWhile TOPar eexpr TCPar TPtVirg + { P.doloop $1 $2 $3 $4 $5 $6 $7 } +| iter_ident TOPar eexpr_list_option TCPar single_statement + { P.iterator $1 $2 $3 $4 $5 } +| TSwitch TOPar eexpr TCPar TOBrace list(case_line) TCBrace + { P.switch $1 $2 $3 $4 $5 $6 $7 } +| TReturn eexpr TPtVirg { P.ret_exp $1 $2 $3 } +| TReturn TPtVirg { P.ret $1 $2 } +| TBreak TPtVirg { P.break $1 $2 } +| TContinue TPtVirg { P.cont $1 $2 } +| ident TDotDot { P.label $1 $2 } +| TGoto ident TPtVirg { P.goto $1 $2 $3 } +| TOBrace fun_start TCBrace + { P.seq $1 $2 $3 } + +stm_dots: + TEllipsis w=list(whenppdecs) + { Ast0.wrap(Ast0.Dots(P.clt2mcode "..." $1, List.concat w)) } +| TOEllipsis w=list(whenppdecs) b=nest_start c=TCEllipsis + { Ast0.wrap(Ast0.Nest(P.clt2mcode "<..." $1, b, + P.clt2mcode "...>" c, List.concat w, false)) } +| TPOEllipsis w=list(whenppdecs) b=nest_start c=TPCEllipsis + { Ast0.wrap(Ast0.Nest(P.clt2mcode "<+..." $1, b, + P.clt2mcode "...+>" c, List.concat w, true)) } + +whenppdecs: w=whens(when_start,rule_elem_statement) + { w } + +/* a statement that fits into a single rule_elem. should nests be included? +what about statement metavariables? */ +rule_elem_statement: + one_decl_var + { Ast0.wrap(Ast0.Decl((Ast0.default_info(),Ast0.context_befaft()),$1)) } +| expr TPtVirg { P.exp_stm $1 $2 } +| TReturn eexpr TPtVirg { P.ret_exp $1 $2 $3 } +| TReturn TPtVirg { P.ret $1 $2 } +| TBreak TPtVirg { P.break $1 $2 } +| TContinue TPtVirg { P.cont $1 $2 } +| TOPar0 midzero_list(rule_elem_statement,rule_elem_statement) TCPar0 + { let (mids,code) = $2 in + Ast0.wrap + (Ast0.Disj(P.clt2mcode "(" $1, + List.map (function x -> Ast0.wrap(Ast0.DOTS([x]))) code, + mids, P.clt2mcode ")" $3)) } + +/* a statement on its own */ +single_statement: + statement { $1 } + | TOPar0 midzero_list(statement,statement) TCPar0 + /* degenerate case, elements are single statements and thus don't + contain dots */ + { let (mids,code) = $2 in + Ast0.wrap + (Ast0.Disj(P.clt2mcode "(" $1, + List.map (function x -> Ast0.wrap(Ast0.DOTS([x]))) code, + mids, P.clt2mcode ")" $3)) } + +case_line: + TDefault TDotDot fun_start + { Ast0.wrap(Ast0.Default(P.clt2mcode "default" $1,P.clt2mcode ":" $2,$3)) } + | TCase eexpr TDotDot fun_start + { Ast0.wrap(Ast0.Case(P.clt2mcode "case" $1,$2,P.clt2mcode ":" $3,$4)) } + +/* In the following, an identifier as a type is not fully supported. Indeed, +the language is ambiguous: what is foo * bar; */ +/* The AST DisjDecl cannot be generated because it would be ambiguous with +a disjunction on a statement with a declaration in each branch */ +decl_var: + t=ctype pv=TPtVirg + { [Ast0.wrap(Ast0.TyDecl(t,P.clt2mcode ";" pv))] } + | s=ioption(storage) t=ctype d=comma_list(d_ident) pv=TPtVirg + { List.map + (function (id,fn) -> + Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv))) + d } + | f=funproto { [f] } + | s=ioption(storage) t=ctype d=d_ident q=TEq e=initialize pv=TPtVirg + {let (id,fn) = d in + [Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv))]} + /* type is a typedef name */ + | s=ioption(storage) cv=ioption(const_vol) i=pure_ident + d=comma_list(d_ident) pv=TPtVirg + { List.map + (function (id,fn) -> + let idtype = + P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.UnInit(s,fn idtype,id,P.clt2mcode ";" pv))) + d } + | s=ioption(storage) cv=ioption(const_vol) i=pure_ident d=d_ident q=TEq + e=initialize pv=TPtVirg + { let (id,fn) = d in + !Data.add_type_name (P.id2name i); + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + [Ast0.wrap(Ast0.Init(s,fn idtype,id,P.clt2mcode "=" q,e, + P.clt2mcode ";" pv))] } + /* function pointer type */ + | s=ioption(storage) + t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar + lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar + pv=TPtVirg + { let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + [Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv))] } + | decl_ident TOPar eexpr_list_option TCPar TPtVirg + { [Ast0.wrap(Ast0.MacroDecl($1,P.clt2mcode "(" $2,$3, + P.clt2mcode ")" $4,P.clt2mcode ";" $5))] } + | s=ioption(storage) + t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar + lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar + q=TEq e=initialize pv=TPtVirg + { let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + [Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv))]} + | s=Ttypedef t=ctype id=typedef_ident pv=TPtVirg + { let s = P.clt2mcode "typedef" s in + [Ast0.wrap(Ast0.Typedef(s,t,id,P.clt2mcode ";" pv))] } + +one_decl_var: + t=ctype pv=TPtVirg + { Ast0.wrap(Ast0.TyDecl(t,P.clt2mcode ";" pv)) } + | s=ioption(storage) t=ctype d=d_ident pv=TPtVirg + { let (id,fn) = d in + Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv)) } + | f=funproto { f } + | s=ioption(storage) t=ctype d=d_ident q=TEq e=initialize pv=TPtVirg + { let (id,fn) = d in + Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv)) } + /* type is a typedef name */ + | s=ioption(storage) cv=ioption(const_vol) i=pure_ident + d=d_ident pv=TPtVirg + { let (id,fn) = d in + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.UnInit(s,fn idtype,id,P.clt2mcode ";" pv)) } + | s=ioption(storage) cv=ioption(const_vol) i=pure_ident d=d_ident q=TEq + e=initialize pv=TPtVirg + { let (id,fn) = d in + !Data.add_type_name (P.id2name i); + let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in + Ast0.wrap(Ast0.Init(s,fn idtype,id,P.clt2mcode "=" q,e, + P.clt2mcode ";" pv)) } + /* function pointer type */ + | s=ioption(storage) + t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar + lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar + pv=TPtVirg + { let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv)) } + | decl_ident TOPar eexpr_list_option TCPar TPtVirg + { Ast0.wrap(Ast0.MacroDecl($1,P.clt2mcode "(" $2,$3, + P.clt2mcode ")" $4,P.clt2mcode ";" $5)) } + | s=ioption(storage) + t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar + lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar + q=TEq e=initialize pv=TPtVirg + { let (id,fn) = d in + let t = + Ast0.wrap + (Ast0.FunctionPointer + (t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1, + P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in + Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv))} + + +d_ident: + ident list(array_dec) + { ($1, + function t -> + List.fold_right + (function (l,i,r) -> + function rest -> + Ast0.wrap + (Ast0.Array(rest,P.clt2mcode "[" l,i,P.clt2mcode "]" r))) + $2 t) } + +array_dec: l=TOCro i=option(eexpr) r=TCCro { (l,i,r) } + +initialize: + eexpr + { Ast0.wrap(Ast0.InitExpr($1)) } + | TOBrace initialize_list TCBrace + { Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3)) } + | TOBrace TCBrace + { Ast0.wrap + (Ast0.InitList(P.clt2mcode "{" $1,Ast0.wrap(Ast0.DOTS []), + P.clt2mcode "}" $2)) } + +initialize2: + /*arithexpr and not eexpr because can have ambiguity with comma*/ + /*dots and nests probably not allowed at top level, haven't looked into why*/ + arith_expr(eexpr,invalid) { Ast0.wrap(Ast0.InitExpr($1)) } +| TOBrace initialize_list TCBrace + { Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3)) } +| TOBrace TCBrace + { Ast0.wrap + (Ast0.InitList(P.clt2mcode "{" $1,Ast0.wrap(Ast0.DOTS []), + P.clt2mcode "}" $2)) } + /* gccext:, labeled elements */ +| TDot ident TEq initialize2 + { Ast0.wrap(Ast0.InitGccDotName(P.clt2mcode "." $1,$2,P.clt2mcode "=" $3,$4)) } +| ident TDotDot initialize2 + { Ast0.wrap(Ast0.InitGccName($1,P.clt2mcode ":" $2,$3)) } /* in old kernel */ +| TOCro eexpr TCCro TEq initialize2 + { Ast0.wrap(Ast0.InitGccIndex(P.clt2mcode "[" $1,$2,P.clt2mcode "]" $3, + P.clt2mcode "=" $4,$5)) } +| TOCro eexpr TEllipsis eexpr TCCro TEq initialize2 + { Ast0.wrap(Ast0.InitGccRange(P.clt2mcode "[" $1,$2,P.clt2mcode "..." $3, + $4,P.clt2mcode "]" $5,P.clt2mcode "=" $6,$7)) } + +initialize_list: + initialize_list_start { Ast0.wrap(Ast0.DOTS($1)) } + +initialize_list_start: + initialize2 TComma { [$1;Ast0.wrap(Ast0.IComma(P.clt2mcode "," $2))] } +| initialize2 TComma initialize_list_start + { $1::Ast0.wrap(Ast0.IComma(P.clt2mcode "," $2))::$3 } +| d=edots_when(TEllipsis,initialize) + r=comma_initializers(edots_when(TEllipsis,initialize)) + { (P.mkidots "..." d):: + (List.concat(List.map (function x -> x (P.mkidots "...")) r)) } + +comma_initializers(dotter): + /* empty */ { [] } +| d=dotter r=comma_initializers2(dotter) + { (function dot_builder -> [dot_builder d])::r } +| i=initialize2 c=TComma r=comma_initializers(dotter) + { (function dot_builder -> [i; Ast0.wrap(Ast0.IComma(P.clt2mcode "," c))]):: + r } + +comma_initializers2(dotter): + /* empty */ { [] } +| i=initialize2 c=TComma r=comma_initializers(dotter) + { (function dot_builder -> [i; Ast0.wrap(Ast0.IComma(P.clt2mcode "," c))]):: + r } + +/* a statement that is part of a list */ +decl_statement: + TMetaStmList + { let (nm,pure,clt) = $1 in + [Ast0.wrap(Ast0.MetaStmt(P.clt2mcode nm clt,pure))] } + | decl_var + { List.map + (function x -> + Ast0.wrap + (Ast0.Decl((Ast0.default_info(),Ast0.context_befaft()),x))) + $1 } + | statement { [$1] } + /* this doesn't allow expressions at top level, because the parser doesn't + know whether there is one. If there is one, this is not sequencible. + If there is not one, then it is. It seems complicated to get around + this at the parser level. We would have to have a check afterwards to + allow this. One case where this would be useful is for a when. Now + we allow a sequence of whens, so one can be on only statements and + one can be on only expressions. */ + | TOPar0 t=midzero_list(fun_start,fun_start) TCPar0 + { let (mids,code) = t in + if List.for_all + (function x -> + match Ast0.unwrap x with Ast0.DOTS([]) -> true | _ -> false) + code + then [] + else + [Ast0.wrap(Ast0.Disj(P.clt2mcode "(" $1, code, mids, + P.clt2mcode ")" $3))] } + +/* a statement that is part of a list */ +decl_statement_expr: + TMetaStmList + { let (nm,pure,clt) = $1 in + [Ast0.wrap(Ast0.MetaStmt(P.clt2mcode nm clt,pure))] } + | decl_var + { List.map + (function x -> + Ast0.wrap + (Ast0.Decl((Ast0.default_info(),Ast0.context_befaft()),x))) + $1 } + | statement { [$1] } + /* this doesn't allow expressions at top level, because the parser doesn't + know whether there is one. If there is one, this is not sequencible. + If there is not one, then it is. It seems complicated to get around + this at the parser level. We would have to have a check afterwards to + allow this. One case where this would be useful is for a when. Now + we allow a sequence of whens, so one can be on only statements and + one can be on only expressions. */ + | TOPar0 t=midzero_list(fun_after_stm,fun_after_dots_or) TCPar0 + { let (mids,code) = t in + if List.for_all (function [] -> true | _ -> false) code + then [] + else + let dot_code = + List.map (function x -> Ast0.wrap(Ast0.DOTS x)) code in + [Ast0.wrap(Ast0.Disj(P.clt2mcode "(" $1, dot_code, mids, + P.clt2mcode ")" $3))] } + +/*****************************************************************************/ + +/* The following cannot contain <... ...> at the top level. This can only +be allowed as an expression when the expression is delimited on both sides +by expression-specific markers. In that case, the rule eexpr is used, which +allows <... ...> anywhere. Hopefully, this will not be too much of a problem +in practice. */ +expr: basic_expr(expr,invalid) { $1 } +/* allows ... and nests */ +eexpr: basic_expr(eexpr,dot_expressions) { $1 } +/* allows nests but not .... */ +dexpr: basic_expr(eexpr,nest_expressions) { $1 } + +top_eexpr: + eexpr { Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Exp($1)))) } + +invalid: + TInvalid { raise (Semantic_cocci.Semantic "not matchable") } + +dot_expressions: + TEllipsis { Ast0.wrap(Ast0.Edots(P.clt2mcode "..." $1,None)) } +| nest_expressions { $1 } + +nest_expressions: + TOEllipsis w=option(whenexp) e=expr_dots(TEllipsis) c=TCEllipsis + { Ast0.wrap(Ast0.NestExpr(P.clt2mcode "<..." $1, + Ast0.wrap(Ast0.DOTS(e (P.mkedots "..."))), + P.clt2mcode "...>" c, w, false)) } +| TPOEllipsis w=option(whenexp) e=expr_dots(TEllipsis) c=TPCEllipsis + { Ast0.wrap(Ast0.NestExpr(P.clt2mcode "<+..." $1, + Ast0.wrap(Ast0.DOTS(e (P.mkedots "..."))), + P.clt2mcode "...+>" c, w, true)) } + +whenexp: TWhen TNotEq w=eexpr TLineEnd { w } + +basic_expr(recurser,primary_extra): + assign_expr(recurser,primary_extra) { $1 } + +assign_expr(r,pe): + cond_expr(r,pe) { $1 } + | unary_expr(r,pe) TAssign assign_expr_bis + { let (op,clt) = $2 in + Ast0.wrap(Ast0.Assignment($1,P.clt2mcode op clt, + Ast0.set_arg_exp $3,false)) } + | unary_expr(r,pe) TEq assign_expr_bis + { Ast0.wrap + (Ast0.Assignment + ($1,P.clt2mcode Ast.SimpleAssign $2,Ast0.set_arg_exp $3,false)) } + +assign_expr_bis: + cond_expr(eexpr,dot_expressions) { $1 } + | unary_expr(eexpr,dot_expressions) TAssign assign_expr_bis + { let (op,clt) = $2 in + Ast0.wrap(Ast0.Assignment($1,P.clt2mcode op clt, + Ast0.set_arg_exp $3,false)) } + | unary_expr(eexpr,dot_expressions) TEq assign_expr_bis + { Ast0.wrap + (Ast0.Assignment + ($1,P.clt2mcode Ast.SimpleAssign $2,Ast0.set_arg_exp $3,false)) } + +cond_expr(r,pe): + arith_expr(r,pe) { $1 } + | l=arith_expr(r,pe) w=TWhy t=option(eexpr) dd=TDotDot r=cond_expr(r,pe) + { Ast0.wrap(Ast0.CondExpr (l, P.clt2mcode "?" w, t, + P.clt2mcode ":" dd, r)) } + +arith_expr(r,pe): + cast_expr(r,pe) { $1 } + | arith_expr(r,pe) TMul arith_expr(r,pe) + { P.arith_op Ast.Mul $1 $2 $3 } + | arith_expr(r,pe) TDmOp arith_expr(r,pe) + { let (op,clt) = $2 in P.arith_op op $1 clt $3 } + | arith_expr(r,pe) TPlus arith_expr(r,pe) + { P.arith_op Ast.Plus $1 $2 $3 } + | arith_expr(r,pe) TMinus arith_expr(r,pe) + { P.arith_op Ast.Minus $1 $2 $3 } + | arith_expr(r,pe) TShOp arith_expr(r,pe) + { let (op,clt) = $2 in P.arith_op op $1 clt $3 } + | arith_expr(r,pe) TLogOp arith_expr(r,pe) + { let (op,clt) = $2 in P.logic_op op $1 clt $3 } + | arith_expr(r,pe) TEqEq arith_expr(r,pe) + { P.logic_op Ast.Eq $1 $2 $3 } + | arith_expr(r,pe) TNotEq arith_expr(r,pe) + { P.logic_op Ast.NotEq $1 $2 $3 } + | arith_expr(r,pe) TAnd arith_expr(r,pe) + { P.arith_op Ast.And $1 $2 $3 } + | arith_expr(r,pe) TOr arith_expr(r,pe) + { P.arith_op Ast.Or $1 $2 $3 } + | arith_expr(r,pe) TXor arith_expr(r,pe) + { P.arith_op Ast.Xor $1 $2 $3 } + | arith_expr(r,pe) TAndLog arith_expr(r,pe) + { P.logic_op Ast.AndLog $1 $2 $3 } + | arith_expr(r,pe) TOrLog arith_expr(r,pe) + { P.logic_op Ast.OrLog $1 $2 $3 } + +cast_expr(r,pe): + unary_expr(r,pe) { $1 } + | lp=TOPar t=ctype rp=TCPar e=cast_expr(r,pe) + { Ast0.wrap(Ast0.Cast (P.clt2mcode "(" lp, t, + P.clt2mcode ")" rp, e)) } + +unary_expr(r,pe): + postfix_expr(r,pe) { $1 } + | TInc unary_expr(r,pe) + { Ast0.wrap(Ast0.Infix ($2, P.clt2mcode Ast.Inc $1)) } + | TDec unary_expr(r,pe) + { Ast0.wrap(Ast0.Infix ($2, P.clt2mcode Ast.Dec $1)) } + | unary_op unary_expr(r,pe) + { let mcode = $1 in Ast0.wrap(Ast0.Unary($2, mcode)) } + | TBang unary_expr(r,pe) + { let mcode = P.clt2mcode Ast.Not $1 in + Ast0.wrap(Ast0.Unary($2, mcode)) } + | TSizeof unary_expr(r,pe) + { Ast0.wrap(Ast0.SizeOfExpr (P.clt2mcode "sizeof" $1, $2)) } + | s=TSizeof lp=TOPar t=ctype rp=TCPar + { Ast0.wrap(Ast0.SizeOfType (P.clt2mcode "sizeof" s, + P.clt2mcode "(" lp,t, + P.clt2mcode ")" rp)) } + +unary_op: TAnd { P.clt2mcode Ast.GetRef $1 } + | TMul { P.clt2mcode Ast.DeRef $1 } + | TPlus { P.clt2mcode Ast.UnPlus $1 } + | TMinus { P.clt2mcode Ast.UnMinus $1 } + | TTilde { P.clt2mcode Ast.Tilde $1 } + +postfix_expr(r,pe): + primary_expr(r,pe) { $1 } + | postfix_expr(r,pe) TOCro eexpr TCCro + { Ast0.wrap(Ast0.ArrayAccess ($1,P.clt2mcode "[" $2,$3, + P.clt2mcode "]" $4)) } + | postfix_expr(r,pe) TDot ident + { Ast0.wrap(Ast0.RecordAccess($1, P.clt2mcode "." $2, $3)) } + | postfix_expr(r,pe) TPtrOp ident + { Ast0.wrap(Ast0.RecordPtAccess($1, P.clt2mcode "->" $2, + $3)) } + | postfix_expr(r,pe) TInc + { Ast0.wrap(Ast0.Postfix ($1, P.clt2mcode Ast.Inc $2)) } + | postfix_expr(r,pe) TDec + { Ast0.wrap(Ast0.Postfix ($1, P.clt2mcode Ast.Dec $2)) } + | postfix_expr(r,pe) TOPar eexpr_list_option TCPar + { Ast0.wrap(Ast0.FunCall($1,P.clt2mcode "(" $2, + $3, + P.clt2mcode ")" $4)) } + +primary_expr(recurser,primary_extra): + func_ident { Ast0.wrap(Ast0.Ident($1)) } + | TInt + { let (x,clt) = $1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Int x) clt)) } + | TFloat + { let (x,clt) = $1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Float x) clt)) } + | TString + { let (x,clt) = $1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.String x) clt)) } + | TChar + { let (x,clt) = $1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Char x) clt)) } + | TMetaConst + { let (nm,constraints,pure,ty,clt) = $1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.CONST,pure)) } + | TMetaErr + { let (nm,constraints,pure,clt) = $1 in + Ast0.wrap(Ast0.MetaErr(P.clt2mcode nm clt,constraints,pure)) } + | TMetaExp + { let (nm,constraints,pure,ty,clt) = $1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ANY,pure)) } + | TMetaIdExp + { let (nm,constraints,pure,ty,clt) = $1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ID,pure)) } + | TMetaLocalIdExp + { let (nm,constraints,pure,ty,clt) = $1 in + Ast0.wrap + (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.LocalID,pure)) } + | TOPar eexpr TCPar + { Ast0.wrap(Ast0.Paren(P.clt2mcode "(" $1,$2, + P.clt2mcode ")" $3)) } + | TOPar0 midzero_list(recurser,eexpr) TCPar0 + { let (mids,code) = $2 in + Ast0.wrap(Ast0.DisjExpr(P.clt2mcode "(" $1, + code, mids, + P.clt2mcode ")" $3)) } + | primary_extra { $1 } + +expr_dots(dotter): + r=no_dot_start_end(dexpr,edots_when(dotter,eexpr)) { r } + +// used in NEST +no_dot_start_end(grammar,dotter): + g=grammar dg=list(pair(dotter,grammar)) + { function dot_builder -> + g :: (List.concat(List.map (function (d,g) -> [dot_builder d;g]) dg)) } + +/*****************************************************************************/ + +pure_ident: + TIdent { $1 } + +meta_ident: + TRuleName TDot pure_ident { (Some $1,P.id2name $3) } + +pure_ident_or_meta_ident: + pure_ident { (None,P.id2name $1) } + | meta_ident { $1 } + | Tlist { (None,"list") } + | TError { (None,"error") } + | TType { (None,"type") } + +pure_ident_or_meta_ident_with_not_eq(not_eq): + i=pure_ident_or_meta_ident l=loption(not_eq) { (i,l) } + +not_eq: + TNotEq i=pure_ident + { (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + [Ast0.wrap(Ast0.Id(P.id2mcode i))] } + | TNotEq TOBrace l=comma_list(pure_ident) TCBrace + { (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + List.map (function i -> Ast0.wrap(Ast0.Id(P.id2mcode i))) l } + +not_eqe: + TNotEq i=pure_ident + { (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + [Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i))))] } + | TNotEq TOBrace l=comma_list(pure_ident) TCBrace + { (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + List.map + (function i -> + Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i))))) + l } + +not_ceq: + TNotEq i=ident_or_const + { (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + [i] } + | TNotEq TOBrace l=comma_list(ident_or_const) TCBrace + { (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + l } + +ident_or_const: + i=pure_ident { Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i)))) } + | TInt + { let (x,clt) = $1 in + Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Int x) clt)) } + +not_pos: + TNotEq i=meta_ident + { (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + match i with + (None,_) -> failwith "constraint must be an inherited variable" + | (Some rule,name) -> + let i = (rule,name) in + P.check_meta(Ast.MetaPosDecl(Ast.NONE,i)); + [i] } + | TNotEq TOBrace l=comma_list(meta_ident) TCBrace + { (if !Data.in_iso + then failwith "constraints not allowed in iso file"); + List.map + (function + (None,_) -> + failwith "constraint must be an inherited variable" + | (Some rule,name) -> + let i = (rule,name) in + P.check_meta(Ast.MetaPosDecl(Ast.NONE,i)); + i) + l } + +func_ident: pure_ident + { Ast0.wrap(Ast0.Id(P.id2mcode $1)) } + | TMetaId + { let (nm,constraints,pure,clt) = $1 in + Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) } + | TMetaFunc + { let (nm,constraints,pure,clt) = $1 in + Ast0.wrap(Ast0.MetaFunc(P.clt2mcode nm clt,constraints,pure)) } + | TMetaLocalFunc + { let (nm,constraints,pure,clt) = $1 in + Ast0.wrap + (Ast0.MetaLocalFunc(P.clt2mcode nm clt,constraints,pure)) } + +ident: pure_ident + { Ast0.wrap(Ast0.Id(P.id2mcode $1)) } + | TMetaId + { let (nm,constraints,pure,clt) = $1 in + Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) } + +decl_ident: + TDeclarerId + { Ast0.wrap(Ast0.Id(P.id2mcode $1)) } + | TMetaDeclarer + { let (nm,constraints,pure,clt) = $1 in + Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) } + +iter_ident: + TIteratorId + { Ast0.wrap(Ast0.Id(P.id2mcode $1)) } + | TMetaIterator + { let (nm,constraints,pure,clt) = $1 in + Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) } + +typedef_ident: + pure_ident + { Ast0.wrap(Ast0.TypeName(P.id2mcode $1)) } + | TMetaType + { let (nm,pure,clt) = $1 in + Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) } + +/*****************************************************************************/ + +decl_list(decl): + decl_list_start(decl) + {let circle x = + match Ast0.unwrap x with Ast0.Pcircles(_) -> true | _ -> false in + if List.exists circle $1 + then Ast0.wrap(Ast0.CIRCLES($1)) + else Ast0.wrap(Ast0.DOTS($1)) } + +decl_list_start(decl): + one_dec(decl) { [$1] } +| one_dec(decl) TComma decl_list_start(decl) + { $1::Ast0.wrap(Ast0.PComma(P.clt2mcode "," $2))::$3 } +| TEllipsis list(comma_decls(TEllipsis,decl)) + { Ast0.wrap(Ast0.Pdots(P.clt2mcode "..." $1)):: + (List.concat(List.map (function x -> x (P.mkpdots "...")) $2)) } + +one_dec(decl): + decl { $1 } +| TMetaParamList + { let (nm,lenname,pure,clt) = $1 in + let nm = P.clt2mcode nm clt in + let lenname = + match lenname with + Some nm -> Some(P.clt2mcode nm clt) + | None -> None in + Ast0.wrap(Ast0.MetaParamList(nm,lenname,pure)) } + +comma_decls(dotter,decl): + TComma dotter + { function dot_builder -> + [Ast0.wrap(Ast0.PComma(P.clt2mcode "," $1)); + dot_builder $2] } +| TComma one_dec(decl) + { function dot_builder -> + [Ast0.wrap(Ast0.PComma(P.clt2mcode "," $1)); $2] } + +/* ---------------------------------------------------------------------- */ + +error_words: + TError TWords TEq TOCro cl=comma_list(dexpr) TCCro + { [Ast0.wrap(Ast0.ERRORWORDS(cl))] } + +/* ---------------------------------------------------------------------- */ +/* sequences of statements and expressions */ + +/* There are number of cases that must be considered: + +1. Top level: + Dots and nests allowed at the beginning or end + Expressions allowed at the beginning or end + One function allowed, by itself +2. A function body: + Dots and nests allowed at the beginning or end + Expressions not allowed at the beginning or end + Functions not allowed +3. The body of a nest: + Dots and nests not allowed at the beginning or end + Expressions allowed at the beginning or end + Functions not allowed +4. Whencode: + Dots and nests not allowed at the beginning but allowed at the end + Expressions allowed at the beginning or end + Functions not allowed + +These are implemented by the rules minus_toplevel_sequence, +plus_toplevel_sequence, function_body_sequence, nest_body_sequence, and +when_body_sequence. +*/ +/* ------------------------------------------------------------------------ */ +/* Minus top level */ + +/* doesn't allow only ... */ +minus_start: + fundecl { [Ast0.wrap(Ast0.DECL($1))] } +| ctype { [Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Ty($1))))] } +| toplevel_seq_start(toplevel_after_dots_init) + { List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) $1 } + +toplevel_seq_start(after_dots_init): + stm_dots after_dots_init { $1::$2 } +| expr toplevel_after_exp { (Ast0.wrap(Ast0.Exp($1)))::$2 } +| decl_statement_expr toplevel_after_stm { $1@$2 } + +toplevel_after_dots_init: + TNothing toplevel_after_exp {$2} +| expr toplevel_after_exp {(Ast0.wrap(Ast0.Exp($1)))::$2} +| decl_statement_expr toplevel_after_stm {$1@$2} + +toplevel_after_exp: + /* empty */ {[]} +| stm_dots toplevel_after_dots {$1::$2} + +toplevel_after_dots: + /* empty */ {[]} +| TNothing toplevel_after_exp {$2} +| expr toplevel_after_exp {(Ast0.wrap(Ast0.Exp($1)))::$2} +| decl_statement_expr toplevel_after_stm {$1@$2} + +toplevel_after_stm: + /* empty */ {[]} +| stm_dots toplevel_after_dots {$1::$2} +| decl_statement toplevel_after_stm {$1@$2} + +/* ------------------------------------------------------------------------ */ +/* Plus top level */ + +/* does allow only ... also allows multiple top-level functions */ +plus_start: + ctype { [Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Ty($1))))] } +| stm_dots plus_after_dots + { (Ast0.wrap(Ast0.OTHER($1)))::$2 } +| expr plus_after_exp + { (Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Exp($1)))))::$2 } +| fundecl plus_after_stm { Ast0.wrap(Ast0.DECL($1))::$2 } +| decl_statement_expr plus_after_stm + { (List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) $1)@$2 } + +plus_after_exp: + /* empty */ {[]} +| stm_dots plus_after_dots { (Ast0.wrap(Ast0.OTHER($1)))::$2 } + +plus_after_dots: + /* empty */ {[]} +| TNothing plus_after_exp {$2} +| expr plus_after_exp + { (Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Exp($1)))))::$2 } +| fundecl plus_after_stm { Ast0.wrap(Ast0.DECL($1))::$2 } +| decl_statement_expr plus_after_stm + { (List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) $1)@$2 } + +plus_after_stm: + /* empty */ {[]} +| stm_dots plus_after_dots { (Ast0.wrap(Ast0.OTHER($1)))::$2 } +| fundecl plus_after_stm { Ast0.wrap(Ast0.DECL($1))::$2 } +| decl_statement plus_after_stm + { (List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) $1)@$2 } + +/* ------------------------------------------------------------------------ */ +/* Function body */ + +fun_start: + fun_after_stm { Ast0.wrap(Ast0.DOTS($1)) } + +fun_after_stm: + /* empty */ {[]} +| stm_dots fun_after_dots {$1::$2} +| decl_statement fun_after_stm {$1@$2} + +fun_after_dots: + /* empty */ {[]} +| TNothing fun_after_exp {$2} +| expr fun_after_exp {Ast0.wrap(Ast0.Exp($1))::$2} +| decl_statement_expr fun_after_stm {$1@$2} + +fun_after_exp: + stm_dots fun_after_dots {$1::$2} + +/* hack to allow mixing statements and expressions in an or */ +fun_after_dots_or: + /* empty */ {[]} +| TNothing fun_after_exp_or {$2} +| expr fun_after_exp_or {Ast0.wrap(Ast0.Exp($1))::$2} +| decl_statement_expr fun_after_stm {$1@$2} + +fun_after_exp_or: + /* empty */ {[]} +| stm_dots fun_after_dots {$1::$2} + +/* ------------------------------------------------------------------------ */ +/* Nest body */ + +nest_start: + nest_after_dots { Ast0.wrap(Ast0.DOTS($1)) } + +nest_after_dots: + decl_statement_expr nest_after_stm {$1@$2} +| TNothing nest_after_exp {$2} +| expr nest_after_exp {(Ast0.wrap(Ast0.Exp($1)))::$2} + +nest_after_stm: + /* empty */ {[]} +| stm_dots nest_after_dots {$1::$2} +| decl_statement nest_after_stm {$1@$2} + +nest_after_exp: + /* empty */ {[]} +| stm_dots nest_after_dots {$1::$2} + +/* ------------------------------------------------------------------------ */ +/*Whencode*/ + +when_start: + expr toplevel_after_exp + { Ast0.wrap(Ast0.DOTS((Ast0.wrap(Ast0.Exp($1)))::$2)) } +| decl_statement toplevel_after_stm + { Ast0.wrap(Ast0.DOTS($1@$2)) } + +/* ---------------------------------------------------------------------- */ + +eexpr_list: + eexpr_list_start + {let circle x = + match Ast0.unwrap x with Ast0.Ecircles(_) -> true | _ -> false in + let star x = + match Ast0.unwrap x with Ast0.Estars(_) -> true | _ -> false in + if List.exists circle $1 + then Ast0.wrap(Ast0.CIRCLES($1)) + else + if List.exists star $1 + then Ast0.wrap(Ast0.STARS($1)) + else Ast0.wrap(Ast0.DOTS($1)) } + +/* arg expr. may contain a type or a explist metavariable */ +aexpr: + eexpr + { Ast0.set_arg_exp $1 } + | TMetaExpList + { let (nm,lenname,pure,clt) = $1 in + let nm = P.clt2mcode nm clt in + let lenname = + match lenname with + Some nm -> Some(P.clt2mcode nm clt) + | None -> None in + Ast0.wrap(Ast0.MetaExprList(nm,lenname,pure)) } + | ctype + { Ast0.set_arg_exp(Ast0.wrap(Ast0.TypeExp($1))) } + +eexpr_list_start: + aexpr { [$1] } + | aexpr TComma eexpr_list_start + { $1::Ast0.wrap(Ast0.EComma(P.clt2mcode "," $2))::$3 } + +comma_args(dotter): + c=TComma d=dotter + { function dot_builder -> + [Ast0.wrap(Ast0.EComma(P.clt2mcode "," c)); dot_builder d] } +| TComma aexpr + { function dot_builder -> + [Ast0.wrap(Ast0.EComma(P.clt2mcode "," $1)); $2] } + +eexpr_list_option: eexpr_list { $1 } + | /* empty */ { Ast0.wrap(Ast0.DOTS([])) } + +/****************************************************************************/ + +// non-empty lists - drop separator +comma_list(elem): + separated_nonempty_list(TComma,elem) { $1 } + +midzero_list(elem,aft): + a=elem b=list(mzl(aft)) + { let (mids,code) = List.split b in (mids,(a::code)) } + +mzl(elem): + a=TMid0 b=elem { (P.clt2mcode "|" a, b) } + +edots_when(dotter,when_grammar): + d=dotter { (d,None) } + | d=dotter TWhen TNotEq w=when_grammar TLineEnd { (d,Some w) } + +dots_when(dotter,when_grammar,simple_when_grammar): + d=dotter w=list(whens(when_grammar,simple_when_grammar)) + { (d,List.concat w) } + +whens(when_grammar,simple_when_grammar): + TWhen TNotEq w=when_grammar TLineEnd { [Ast0.WhenNot w] } + | TWhen TEq w=simple_when_grammar TLineEnd { [Ast0.WhenAlways w] } + | TWhen comma_list(any_strict) TLineEnd + { List.map (function x -> Ast0.WhenModifier(x)) $2 } + +any_strict: + TAny { Ast.WhenAny } + | TStrict { Ast.WhenStrict } + | TForall { Ast.WhenForall } + | TExists { Ast.WhenExists } + +/***************************************************************************** +* +* +*****************************************************************************/ + +iso_main: + TIsoExpression e1=dexpr el=list(iso(dexpr)) EOF + { P.iso_adjust (function x -> Ast0.ExprTag x) e1 el } +| TIsoArgExpression e1=dexpr el=list(iso(dexpr)) EOF + { P.iso_adjust (function x -> Ast0.ArgExprTag x) e1 el } +| TIsoTestExpression e1=dexpr el=list(iso(dexpr)) EOF + { P.iso_adjust (function x -> Ast0.TestExprTag x) e1 el } +| TIsoStatement s1=single_statement sl=list(iso(single_statement)) EOF + { P.iso_adjust (function x -> Ast0.StmtTag x) s1 sl } +| TIsoType t1=ctype tl=list(iso(ctype)) EOF + { P.iso_adjust (function x -> Ast0.TypeCTag x) t1 tl } +| TIsoTopLevel e1=nest_start el=list(iso(nest_start)) EOF + { P.iso_adjust (function x -> Ast0.DotsStmtTag x) e1 el } +| TIsoDeclaration d1=decl_var dl=list(iso(decl_var)) EOF + { let check_one = function + [x] -> x + | _ -> + raise + (Semantic_cocci.Semantic + "only one variable per declaration in an isomorphism rule") in + let d1 = check_one d1 in + let dl = + List.map + (function + Common.Left x -> Common.Left(check_one x) + | Common.Right x -> Common.Right(check_one x)) + dl in + P.iso_adjust (function x -> Ast0.DeclTag x) d1 dl } + +iso(term): + TIso t=term { Common.Left t } + | TRightIso t=term { Common.Right t } + +/***************************************************************************** +* +* +*****************************************************************************/ + +never_used: TPragma { () } + | TPArob TMetaPos { () } + | TScriptData { () } + +script_meta_main: py=pure_ident TShOp TRuleName TDot cocci=pure_ident TMPtVirg + { (P.id2name py, ($3, P.id2name cocci)) } diff --git a/parsing_cocci/plus.ml b/parsing_cocci/plus.ml new file mode 100644 index 0000000..0474afa --- /dev/null +++ b/parsing_cocci/plus.ml @@ -0,0 +1,227 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* The plus fragments are converted to a list of lists of lists. +Innermost list: Elements have type anything. For any pair of successive +elements, n and n+1, the ending line of n is the same as the starting line +of n+1. +Middle lists: For any pair of successive elements, n and n+1, the ending +line of n is one less than the starting line of n+1. +Outer list: For any pair of successive elements, n and n+1, the ending +line of n is more than one less than the starting line of n+1. *) + +(* For nests and disjs, we are relying on the fact that <... ...> ( | ) +must appear on lines by themselves, meaning that the various + fragments +can't be contiguous to each other or to unrelated things. *) + +module Ast = Ast_cocci +module V = Visitor_ast + +(* --------------------------------------------------------------------- *) + +type res = + Open of Ast.anything * int * int * int * int + | Closed of (Ast.anything * int * int * int * int) list + +let mcode fn = function + (term, Ast.PLUS(info)) -> + let line = info.Ast.line in + let lline = info.Ast.logical_line in + [Open (fn term,line,line,lline,lline)] + | _ -> [Closed []] + +let mk_fullType x = Ast.FullTypeTag x +let mk_baseType x = Ast.BaseTypeTag x +let mk_structUnion x = Ast.StructUnionTag x +let mk_sign x = Ast.SignTag x +let mk_ident x = Ast.IdentTag x +let mk_expression x = Ast.ExpressionTag x +let mk_constant x = Ast.ConstantTag x +let mk_unaryOp x = Ast.UnaryOpTag x +let mk_assignOp x = Ast.AssignOpTag x +let mk_fixOp x = Ast.FixOpTag x +let mk_binaryOp x = Ast.BinaryOpTag x +let mk_arithOp x = Ast.ArithOpTag x +let mk_logicalOp x = Ast.LogicalOpTag x +let mk_declaration x = Ast.DeclarationTag x +let mk_storage x = Ast.StorageTag x +let mk_rule_elem x = Ast.Rule_elemTag x +let mk_const_vol x = Ast.ConstVolTag x +let mk_token x = Ast.Token x + +let get_real_start = function + Open (_,line,_,_,_) -> line + | _ -> failwith "not possible" + +let get_real_finish = function + Open (_,_,line,_,_) -> line + | _ -> failwith "not possible" + +let get_start = function + Open (_,_,_,line,_) -> line + | _ -> failwith "not possible" + +let get_finish = function + Open (_,_,_,_,line) -> line + | _ -> failwith "not possible" + +let get_option fn = function + None -> [] + | Some x -> [fn x] + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Step 1: coalesce + terms, record starting and ending line numbers *) + +let rec close l = + let rec loop = function + [] -> [] + | Open(x,start,finish,lstart,lfinish)::rest -> + (x,start,finish,lstart,lfinish)::(loop rest) + | (Closed l)::rest -> l @ (loop rest) in + Closed (loop l) + +let test term subterms = + if List.for_all (function Open(_,_,_,_,_) -> true | _ -> false) subterms + then [Open(term, + get_real_start (List.hd subterms), + get_real_finish (List.hd (List.rev subterms)), + get_start (List.hd subterms), + get_finish (List.hd (List.rev subterms)))] + else [close subterms] + +(* --------------------------------------------------------------------- *) +(* Dots *) + +let dots recursor k dotlist = [close (k dotlist)] + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +let ident recursor k i = test (Ast.IdentTag i) (k i) + +(* --------------------------------------------------------------------- *) +(* Expression *) + +let expression recursor k = function + Ast.DisjExpr(exps) -> + [close (List.concat(List.map recursor.V.combiner_expression exps))] + | Ast.Edots(_,_) -> [Closed []] (* must be context *) + | Ast.Ecircles(_,_) -> [Closed []] (* must be context *) + | Ast.Estars(_,_) -> [Closed []] (* must be context *) + | Ast.OptExp(_) | Ast.UniqueExp(_) | Ast.MultiExp(_) -> failwith "impossible" + | e -> test (Ast.ExpressionTag e) (k e) + +(* --------------------------------------------------------------------- *) +(* Types *) + +and fullType recursor k ft = test (Ast.FullTypeTag ft) (k ft) + +and typeC recursor k t = k t + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +let declaration recursor k d = test (Ast.DeclarationTag d) (k d) + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +let parameterTypeDef recursor k = function + Ast.Pdots(_) -> [Closed []] + | Ast.Pcircles(_) -> [Closed []] + | p -> test (Ast.ParameterTypeDefTag p) (k p) + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +let rec rule_elem recursor k re = test (Ast.Rule_elemTag re) (k re) + +let rec statement recursor k = function + Ast.Disj(stmt_dots_list) -> + [close + (List.concat + (List.map recursor.V.combiner_statement_dots stmt_dots_list))] + | Ast.Dots(_,_,_) -> [Closed []] + | Ast.Circles(_,_,_) -> [Closed []] + | Ast.Stars(_,_,_) -> [Closed []] + | s -> test (Ast.StatementTag s) (k s) + +let rec meta recursor k m = test (Ast.MetaTag m) (k m) + +let top_level recursor k = function + Ast.FILEINFO(_,_) -> [Closed []] + | Ast.ERRORWORDS(exps) -> [Closed []] + | t -> test (Ast.Code t) (k t) + +let anything recursor k a = failwith "not called" + +let collect_tokens = + let recursor = + V.combiner (@) [] + (mcode mk_token) (mcode mk_constant) (mcode mk_assignOp) (mcode mk_fixOp) + (mcode mk_unaryOp) (mcode mk_binaryOp) (mcode mk_const_vol) + (mcode mk_baseType) (mcode mk_sign) (mcode mk_structUnion) + (mcode mk_storage) dots dots dots + ident expression fullType typeC parameterTypeDef declaration + rule_elem statement meta top_level anything in + recursor.V.combiner_top_level + +let rule code = List.concat(List.map collect_tokens code) + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Step 2: find neighbors *) + +let rec find_neighbors = function + [] -> [] + | (x1,real_start1,real_finish1,start1,finish1)::rest -> + (match find_neighbors rest with + ((((x2,real_start2,real_finish2,start2,finish2):: + rest_inner)::rest_middle)::rest_outer) + as rest -> + if finish1 = start2 + then + ((((x1,real_start1,real_finish1,start1,finish1):: + (x2,real_start2,real_finish2,start2,finish2)::rest_inner):: + rest_middle):: + rest_outer) + else if finish1 + 1 = start2 + then + (([(x1,real_start1,real_finish1,start1,finish1)]:: + ((x2,real_start2,real_finish2,start2,finish2)::rest_inner):: + rest_middle):: + rest_outer) + else [[(x1,real_start1,real_finish1,start1,finish1)]]::rest + | _ -> [[[(x1,real_start1,real_finish1,start1,finish1)]]]) + (* rest must be [] *) + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Entry point *) + +let plus ast = + match close (rule ast) with + Closed l -> find_neighbors l + | _ -> failwith "impossible" diff --git a/parsing_cocci/plus.mli b/parsing_cocci/plus.mli new file mode 100644 index 0000000..512f516 --- /dev/null +++ b/parsing_cocci/plus.mli @@ -0,0 +1,3 @@ +val plus : + Ast_cocci.rule -> + (Ast_cocci.anything * int * int * int * int) list list list diff --git a/parsing_cocci/pretty_print_cocci.ml b/parsing_cocci/pretty_print_cocci.ml new file mode 100644 index 0000000..308a25e --- /dev/null +++ b/parsing_cocci/pretty_print_cocci.ml @@ -0,0 +1,855 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Format +module Ast = Ast_cocci + +let print_plus_flag = ref true +let print_minus_flag = ref true +let print_newlines_disj = ref true + +let start_block str = + force_newline(); print_string " "; open_box 0 + +let end_block str = + close_box(); force_newline () + +let print_string_box s = print_string s; open_box 0 + + +let print_option = Common.do_option +let print_between = Common.print_between + +(* --------------------------------------------------------------------- *) +(* Modified code *) + +(* avoid polyvariance problems *) +let anything : (Ast.anything -> unit) ref = ref (function _ -> ()) + +let rec print_anything str = function + [] -> () + | stream -> + start_block(); + print_between force_newline + (function x -> + print_string str; open_box 0; print_anything_list x; close_box()) + stream; + end_block() + +and print_anything_list = function + [] -> () + | [x] -> !anything x + | bef::((aft::_) as rest) -> + !anything bef; + let space = + (match bef with + Ast.Rule_elemTag(_) | Ast.AssignOpTag(_) | Ast.BinaryOpTag(_) + | Ast.ArithOpTag(_) | Ast.LogicalOpTag(_) + | Ast.Token("if",_) | Ast.Token("while",_) -> true | _ -> false) or + (match aft with + Ast.Rule_elemTag(_) | Ast.AssignOpTag(_) | Ast.BinaryOpTag(_) + | Ast.ArithOpTag(_) | Ast.LogicalOpTag(_) | Ast.Token("{",_) -> true + | _ -> false) in + if space then print_string " "; + print_anything_list rest + +let print_around printer term = function + Ast.NOTHING -> printer term + | Ast.BEFORE(bef) -> print_anything "<<< " bef; printer term + | Ast.AFTER(aft) -> printer term; print_anything ">>> " aft + | Ast.BEFOREAFTER(bef,aft) -> + print_anything "<<< " bef; printer term; print_anything ">>> " aft + +let print_string_befaft fn x info = + List.iter (function s -> print_string s; force_newline()) + info.Ast.strbef; + fn x; + List.iter (function s -> force_newline(); print_string s) + info.Ast.straft + +let print_meta (r,x) = print_string r; print_string ":"; print_string x + +let print_pos = function + Ast.MetaPos(name,_,_,_,_) -> + let name = Ast.unwrap_mcode name in + print_string "@"; print_meta name + | _ -> () + +let mcode fn = function + (x, _, Ast.MINUS(_,plus_stream), pos) -> + if !print_minus_flag + then print_string (if !Flag.sgrep_mode2 then "*" else "-"); + fn x; print_pos pos; + if !print_plus_flag + then print_anything ">>> " plus_stream + | (x, _, Ast.CONTEXT(_,plus_streams), pos) -> + if !print_plus_flag + then + let fn x = fn x; print_pos pos in + print_around fn x plus_streams + else (fn x; print_pos pos) + | (x, info, Ast.PLUS, pos) -> + let fn x = fn x; print_pos pos in + print_string_befaft fn x info + +let print_mcodekind = function + Ast.MINUS(_,plus_stream) -> + print_string "MINUS"; + print_anything ">>> " plus_stream + | Ast.CONTEXT(_,plus_streams) -> + print_around (function _ -> print_string "CONTEXT") () plus_streams + | Ast.PLUS -> print_string "PLUS" + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Dots *) + +let dots between fn d = + match Ast.unwrap d with + Ast.DOTS(l) -> print_between between fn l + | Ast.CIRCLES(l) -> print_between between fn l + | Ast.STARS(l) -> print_between between fn l + +let nest_dots multi fn f d = + let mo s = if multi then "<+"^s else "<"^s in + let mc s = if multi then s^"+>" else s^">" in + match Ast.unwrap d with + Ast.DOTS(l) -> + print_string (mo "..."); f(); start_block(); + print_between force_newline fn l; + end_block(); print_string (mc "...") + | Ast.CIRCLES(l) -> + print_string (mo "ooo"); f(); start_block(); + print_between force_newline fn l; + end_block(); print_string (mc "ooo") + | Ast.STARS(l) -> + print_string (mo "***"); f(); start_block(); + print_between force_newline fn l; + end_block(); print_string (mc "***") + +(* --------------------------------------------------------------------- *) + +let print_type keep info = function + None -> () + (* print_string "/* "; + print_string "keep:"; print_unitary keep; + print_string " inherited:"; print_bool inherited; + print_string " */"*) + | Some ty -> () + (*; + print_string "/* "; + print_between (function _ -> print_string ", ") Type_cocci.typeC ty;(* + print_string "keep:"; print_unitary keep; + print_string " inherited:"; print_bool inherited;*) + print_string " */"*) + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +let rec ident i = + match Ast.unwrap i with + Ast.Id(name) -> mcode print_string name + | Ast.MetaId(name,_,keep,inherited) -> mcode print_meta name + | Ast.MetaFunc(name,_,_,_) -> mcode print_meta name + | Ast.MetaLocalFunc(name,_,_,_) -> mcode print_meta name + | Ast.OptIdent(id) -> print_string "?"; ident id + | Ast.UniqueIdent(id) -> print_string "!"; ident id + +and print_unitary = function + Type_cocci.Unitary -> print_string "unitary" + | Type_cocci.Nonunitary -> print_string "nonunitary" + | Type_cocci.Saved -> print_string "saved" + +(* --------------------------------------------------------------------- *) +(* Expression *) + +let print_disj_list fn l = + if !print_newlines_disj + then (force_newline(); print_string "("; force_newline()) + else print_string "("; + print_between + (function _ -> + if !print_newlines_disj + then (force_newline(); print_string "|"; force_newline()) + else print_string " | ") + fn l; + if !print_newlines_disj + then (force_newline(); print_string ")"; force_newline()) + else print_string ")" + +let rec expression e = + match Ast.unwrap e with + Ast.Ident(id) -> ident id + | Ast.Constant(const) -> mcode constant const + | Ast.FunCall(fn,lp,args,rp) -> + expression fn; mcode print_string_box lp; + dots (function _ -> ()) expression args; + close_box(); mcode print_string rp + | Ast.Assignment(left,op,right,simple) -> + expression left; print_string " "; mcode assignOp op; + print_string " "; expression right + | Ast.CondExpr(exp1,why,exp2,colon,exp3) -> + expression exp1; print_string " "; mcode print_string why; + print_option (function e -> print_string " "; expression e) exp2; + print_string " "; mcode print_string colon; expression exp3 + | Ast.Postfix(exp,op) -> expression exp; mcode fixOp op + | Ast.Infix(exp,op) -> mcode fixOp op; expression exp + | Ast.Unary(exp,op) -> mcode unaryOp op; expression exp + | Ast.Binary(left,op,right) -> + expression left; print_string " "; mcode binaryOp op; print_string " "; + expression right + | Ast.Nested(left,op,right) -> + expression left; print_string " "; mcode binaryOp op; print_string " "; + expression right + | Ast.Paren(lp,exp,rp) -> + mcode print_string_box lp; expression exp; close_box(); + mcode print_string rp + | Ast.ArrayAccess(exp1,lb,exp2,rb) -> + expression exp1; mcode print_string_box lb; expression exp2; close_box(); + mcode print_string rb + | Ast.RecordAccess(exp,pt,field) -> + expression exp; mcode print_string pt; ident field + | Ast.RecordPtAccess(exp,ar,field) -> + expression exp; mcode print_string ar; ident field + | Ast.Cast(lp,ty,rp,exp) -> + mcode print_string_box lp; fullType ty; close_box(); + mcode print_string rp; expression exp + | Ast.SizeOfExpr(sizeof,exp) -> + mcode print_string sizeof; expression exp + | Ast.SizeOfType(sizeof,lp,ty,rp) -> + mcode print_string sizeof; + mcode print_string_box lp; fullType ty; close_box(); + mcode print_string rp + | Ast.TypeExp(ty) -> fullType ty + + | Ast.MetaErr(name,_,_,_) -> mcode print_meta name + | Ast.MetaExpr(name,_,keep,ty,form,inherited) -> + mcode print_meta name; print_type keep inherited ty + | Ast.MetaExprList(name,_,_,_) -> mcode print_meta name + | Ast.EComma(cm) -> mcode print_string cm; print_space() + | Ast.DisjExpr(exp_list) -> print_disj_list expression exp_list + | Ast.NestExpr(expr_dots,Some whencode,multi) -> + nest_dots multi expression + (function _ -> print_string " when != "; expression whencode) + expr_dots + | Ast.NestExpr(expr_dots,None,multi) -> + nest_dots multi expression (function _ -> ()) expr_dots + | Ast.Edots(dots,Some whencode) + | Ast.Ecircles(dots,Some whencode) + | Ast.Estars(dots,Some whencode) -> + mcode print_string dots; print_string " when != "; expression whencode + | Ast.Edots(dots,None) + | Ast.Ecircles(dots,None) + | Ast.Estars(dots,None) -> mcode print_string dots + | Ast.OptExp(exp) -> print_string "?"; expression exp + | Ast.UniqueExp(exp) -> print_string "!"; expression exp + +and unaryOp = function + Ast.GetRef -> print_string "&" + | Ast.DeRef -> print_string "*" + | Ast.UnPlus -> print_string "+" + | Ast.UnMinus -> print_string "-" + | Ast.Tilde -> print_string "~" + | Ast.Not -> print_string "!" + +and assignOp = function + Ast.SimpleAssign -> print_string "=" + | Ast.OpAssign(aop) -> arithOp aop; print_string "=" + +and fixOp = function + Ast.Dec -> print_string "--" + | Ast.Inc -> print_string "++" + +and binaryOp = function + Ast.Arith(aop) -> arithOp aop + | Ast.Logical(lop) -> logicalOp lop + +and arithOp = function + Ast.Plus -> print_string "+" + | Ast.Minus -> print_string "-" + | Ast.Mul -> print_string "*" + | Ast.Div -> print_string "/" + | Ast.Mod -> print_string "%" + | Ast.DecLeft -> print_string "<<" + | Ast.DecRight -> print_string ">>" + | Ast.And -> print_string "&" + | Ast.Or -> print_string "|" + | Ast.Xor -> print_string "^" + +and logicalOp = function + Ast.Inf -> print_string "<" + | Ast.Sup -> print_string ">" + | Ast.InfEq -> print_string "<=" + | Ast.SupEq -> print_string ">=" + | Ast.Eq -> print_string "==" + | Ast.NotEq -> print_string "!=" + | Ast.AndLog -> print_string "&&" + | Ast.OrLog -> print_string "||" + +and constant = function + Ast.String(s) -> print_string "\""; print_string s; print_string "\"" + | Ast.Char(s) -> print_string "'"; print_string s; print_string "'" + | Ast.Int(s) -> print_string s + | Ast.Float(s) -> print_string s + +(* --------------------------------------------------------------------- *) +(* Declarations *) + +and storage = function + Ast.Static -> print_string "static " + | Ast.Auto -> print_string "auto " + | Ast.Register -> print_string "register " + | Ast.Extern -> print_string "extern " + +(* --------------------------------------------------------------------- *) +(* Types *) + +and fullType ft = + match Ast.unwrap ft with + Ast.Type(cv,ty) -> + print_option (function x -> mcode const_vol x; print_string " ") cv; + typeC ty + | Ast.DisjType(decls) -> print_disj_list fullType decls + | Ast.OptType(ty) -> print_string "?"; fullType ty + | Ast.UniqueType(ty) -> print_string "!"; fullType ty + +and print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2) fn = + fullType ty; mcode print_string lp1; mcode print_string star; fn(); + mcode print_string rp1; mcode print_string lp1; + parameter_list params; mcode print_string rp2 + +and print_function_type (ty,lp1,params,rp1) fn = + print_option fullType ty; fn(); mcode print_string lp1; + parameter_list params; mcode print_string rp1 + +and print_fninfo = function + Ast.FStorage(stg) -> mcode storage stg + | Ast.FType(ty) -> fullType ty + | Ast.FInline(inline) -> mcode print_string inline; print_string " " + | Ast.FAttr(attr) -> mcode print_string attr; print_string " " + +and typeC ty = + match Ast.unwrap ty with + Ast.BaseType(ty,sgn) -> print_option (mcode sign) sgn; mcode baseType ty + | Ast.ImplicitInt(sgn) -> mcode sign sgn + | Ast.Pointer(ty,star) -> fullType ty; mcode print_string star + | Ast.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2) + (function _ -> ()) + | Ast.FunctionType (_,ty,lp1,params,rp1) -> + print_function_type (ty,lp1,params,rp1) (function _ -> ()) + | Ast.Array(ty,lb,size,rb) -> + fullType ty; mcode print_string lb; print_option expression size; + mcode print_string rb + | Ast.StructUnionName(kind,name) -> + mcode structUnion kind; + print_option (function x -> ident x; print_string " ") name + | Ast.StructUnionDef(ty,lb,decls,rb) -> + fullType ty; mcode print_string lb; + dots force_newline declaration decls; + mcode print_string rb + | Ast.TypeName(name) -> mcode print_string name; print_string " " + | Ast.MetaType(name,_,_) -> + mcode print_meta name; print_string " " + +and baseType = function + Ast.VoidType -> print_string "void " + | Ast.CharType -> print_string "char " + | Ast.ShortType -> print_string "short " + | Ast.IntType -> print_string "int " + | Ast.DoubleType -> print_string "double " + | Ast.FloatType -> print_string "float " + | Ast.LongType -> print_string "long " + +and structUnion = function + Ast.Struct -> print_string "struct " + | Ast.Union -> print_string "union " + +and sign = function + Ast.Signed -> print_string "signed " + | Ast.Unsigned -> print_string "unsigned " + +and const_vol = function + Ast.Const -> print_string "const" + | Ast.Volatile -> print_string "volatile" + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +and print_named_type ty id = + match Ast.unwrap ty with + Ast.Type(None,ty1) -> + (match Ast.unwrap ty1 with + Ast.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2) + (function _ -> print_string " "; ident id) + | Ast.FunctionType(_,ty,lp1,params,rp1) -> + print_function_type (ty,lp1,params,rp1) + (function _ -> print_string " "; ident id) + | Ast.Array(ty,lb,size,rb) -> + let rec loop ty k = + match Ast.unwrap ty with + Ast.Array(ty,lb,size,rb) -> + (match Ast.unwrap ty with + Ast.Type(None,ty) -> + loop ty + (function _ -> + k (); + mcode print_string lb; + print_option expression size; + mcode print_string rb) + | _ -> failwith "complex array types not supported") + | _ -> typeC ty; ident id; k () in + loop ty1 (function _ -> ()) + | _ -> fullType ty; ident id) + | _ -> fullType ty; ident id + +and declaration d = + match Ast.unwrap d with + Ast.Init(stg,ty,id,eq,ini,sem) -> + print_option (mcode storage) stg; print_named_type ty id; + print_string " "; mcode print_string eq; + print_string " "; initialiser ini; mcode print_string sem + | Ast.UnInit(stg,ty,id,sem) -> + print_option (mcode storage) stg; print_named_type ty id; + mcode print_string sem + | Ast.MacroDecl(name,lp,args,rp,sem) -> + ident name; mcode print_string_box lp; + dots (function _ -> ()) expression args; + close_box(); mcode print_string rp; mcode print_string sem + | Ast.TyDecl(ty,sem) -> fullType ty; mcode print_string sem + | Ast.Typedef(stg,ty,id,sem) -> + mcode print_string stg; print_string " "; fullType ty; typeC id; + mcode print_string sem + | Ast.DisjDecl(decls) -> print_disj_list declaration decls + | Ast.Ddots(dots,Some whencode) -> + mcode print_string dots; print_string " when != "; declaration whencode + | Ast.Ddots(dots,None) -> mcode print_string dots + | Ast.MetaDecl(name,_,_) -> mcode print_meta name + | Ast.OptDecl(decl) -> print_string "?"; declaration decl + | Ast.UniqueDecl(decl) -> print_string "!"; declaration decl + +(* --------------------------------------------------------------------- *) +(* Initialiser *) + +and initialiser i = + match Ast.unwrap i with + Ast.InitExpr(exp) -> expression exp + | Ast.InitList(lb,initlist,rb,whencode) -> + mcode print_string lb; open_box 0; + if not (whencode = []) + then + (print_string " WHEN != "; + print_between (function _ -> print_string " v ") + initialiser whencode; + force_newline()); + List.iter initialiser initlist; close_box(); + mcode print_string rb + | Ast.InitGccDotName(dot,name,eq,ini) -> + mcode print_string dot; ident name; print_string " "; + mcode print_string eq; print_string " "; initialiser ini + | Ast.InitGccName(name,eq,ini) -> + ident name; mcode print_string eq; initialiser ini + | Ast.InitGccIndex(lb,exp,rb,eq,ini) -> + mcode print_string lb; expression exp; mcode print_string rb; + print_string " "; mcode print_string eq; print_string " "; + initialiser ini + | Ast.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> + mcode print_string lb; expression exp1; mcode print_string dots; + expression exp2; mcode print_string rb; + print_string " "; mcode print_string eq; print_string " "; + initialiser ini + | Ast.IComma(comma) -> mcode print_string comma; force_newline() + | Ast.OptIni(ini) -> print_string "?"; initialiser ini + | Ast.UniqueIni(ini) -> print_string "!"; initialiser ini + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +and parameterTypeDef p = + match Ast.unwrap p with + Ast.VoidParam(ty) -> fullType ty + | Ast.Param(ty,Some id) -> print_named_type ty id + | Ast.Param(ty,None) -> fullType ty + | Ast.MetaParam(name,_,_) -> mcode print_meta name + | Ast.MetaParamList(name,_,_,_) -> mcode print_meta name + | Ast.PComma(cm) -> mcode print_string cm; print_space() + | Ast.Pdots(dots) -> mcode print_string dots + | Ast.Pcircles(dots) -> mcode print_string dots + | Ast.OptParam(param) -> print_string "?"; parameterTypeDef param + | Ast.UniqueParam(param) -> print_string "!"; parameterTypeDef param + +and parameter_list l = dots (function _ -> ()) parameterTypeDef l + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +let rec rule_elem arity re = + match Ast.unwrap re with + Ast.FunHeader(bef,allminus,fninfo,name,lp,params,rp) -> + mcode (function _ -> ()) ((),Ast.no_info,bef,Ast.NoMetaPos); + print_string arity; List.iter print_fninfo fninfo; + ident name; mcode print_string_box lp; + parameter_list params; close_box(); mcode print_string rp; + print_string " " + | Ast.Decl(bef,allminus,decl) -> + mcode (function _ -> ()) ((),Ast.no_info,bef,Ast.NoMetaPos); + print_string arity; + declaration decl + | Ast.SeqStart(brace) -> + print_string arity; mcode print_string brace; + if !print_newlines_disj then start_block() + | Ast.SeqEnd(brace) -> + if !print_newlines_disj then end_block(); + print_string arity; mcode print_string brace + | Ast.ExprStatement(exp,sem) -> + print_string arity; expression exp; mcode print_string sem + | Ast.IfHeader(iff,lp,exp,rp) -> + print_string arity; + mcode print_string iff; print_string " "; mcode print_string_box lp; + expression exp; close_box(); mcode print_string rp; print_string " " + | Ast.Else(els) -> + print_string arity; mcode print_string els; print_string " " + | Ast.WhileHeader(whl,lp,exp,rp) -> + print_string arity; + mcode print_string whl; print_string " "; mcode print_string_box lp; + expression exp; close_box(); mcode print_string rp; print_string " " + | Ast.DoHeader(d) -> + print_string arity; mcode print_string d; print_string " " + | Ast.WhileTail(whl,lp,exp,rp,sem) -> + print_string arity; + mcode print_string whl; print_string " "; mcode print_string_box lp; + expression exp; close_box(); mcode print_string rp; + mcode print_string sem + | Ast.ForHeader(fr,lp,e1,sem1,e2,sem2,e3,rp) -> + print_string arity; + mcode print_string fr; mcode print_string_box lp; + print_option expression e1; mcode print_string sem1; + print_option expression e2; mcode print_string sem2; + print_option expression e3; close_box(); + mcode print_string rp; print_string " " + | Ast.IteratorHeader(nm,lp,args,rp) -> + print_string arity; + ident nm; print_string " "; mcode print_string_box lp; + dots (function _ -> ()) expression args; close_box(); + mcode print_string rp; print_string " " + | Ast.SwitchHeader(switch,lp,exp,rp) -> + print_string arity; + mcode print_string switch; print_string " "; mcode print_string_box lp; + expression exp; close_box(); mcode print_string rp; print_string " " + | Ast.Break(br,sem) -> + print_string arity; mcode print_string br; mcode print_string sem + | Ast.Continue(cont,sem) -> + print_string arity; mcode print_string cont; mcode print_string sem + | Ast.Label(l,dd) -> ident l; mcode print_string dd + | Ast.Goto(goto,l,sem) -> + mcode print_string goto; ident l; mcode print_string sem + | Ast.Return(ret,sem) -> + print_string arity; mcode print_string ret; mcode print_string sem + | Ast.ReturnExpr(ret,exp,sem) -> + print_string arity; mcode print_string ret; print_string " "; + expression exp; mcode print_string sem + | Ast.MetaRuleElem(name,_,_) -> + print_string arity; mcode print_meta name + | Ast.MetaStmt(name,_,_,_) -> + print_string arity; mcode print_meta name + | Ast.MetaStmtList(name,_,_) -> + print_string arity; mcode print_meta name + | Ast.Exp(exp) -> print_string arity; expression exp + | Ast.TopExp(exp) -> print_string arity; expression exp + | Ast.Ty(ty) -> print_string arity; fullType ty + | Ast.Include(inc,s) -> + mcode print_string inc; print_string " "; mcode inc_file s + | Ast.DefineHeader(def,id,params) -> + mcode print_string def; print_string " "; ident id; + print_define_parameters params + | Ast.Default(def,colon) -> + mcode print_string def; mcode print_string colon; print_string " " + | Ast.Case(case,exp,colon) -> + mcode print_string case; print_string " "; expression exp; + mcode print_string colon; print_string " " + | Ast.DisjRuleElem(res) -> + print_string arity; + force_newline(); print_string "("; force_newline(); + print_between + (function _ -> force_newline();print_string "|"; force_newline()) + (rule_elem arity) + res; + force_newline(); print_string ")" + + +and print_define_parameters params = + match Ast.unwrap params with + Ast.NoParams -> () + | Ast.DParams(lp,params,rp) -> + mcode print_string lp; + dots (function _ -> ()) print_define_param params; mcode print_string rp + +and print_define_param param = + match Ast.unwrap param with + Ast.DParam(id) -> ident id + | Ast.DPComma(comma) -> mcode print_string comma + | Ast.DPdots(dots) -> mcode print_string dots + | Ast.DPcircles(circles) -> mcode print_string circles + | Ast.OptDParam(dp) -> print_string "?"; print_define_param dp + | Ast.UniqueDParam(dp) -> print_string "!"; print_define_param dp + +and statement arity s = + match Ast.unwrap s with + Ast.Seq(lbrace,decls,body,rbrace) -> + rule_elem arity lbrace; + dots force_newline (statement arity) decls; + dots force_newline (statement arity) body; + rule_elem arity rbrace + | Ast.IfThen(header,branch,(_,_,_,aft)) -> + rule_elem arity header; statement arity branch; + mcode (function _ -> ()) ((),Ast.no_info,aft,Ast.NoMetaPos) + | Ast.IfThenElse(header,branch1,els,branch2,(_,_,_,aft)) -> + rule_elem arity header; statement arity branch1; print_string " "; + rule_elem arity els; statement arity branch2; + mcode (function _ -> ()) ((),Ast.no_info,aft,Ast.NoMetaPos) + | Ast.While(header,body,(_,_,_,aft)) -> + rule_elem arity header; statement arity body; + mcode (function _ -> ()) ((),Ast.no_info,aft,Ast.NoMetaPos) + | Ast.Do(header,body,tail) -> + rule_elem arity header; statement arity body; + rule_elem arity tail + | Ast.For(header,body,(_,_,_,aft)) -> + rule_elem arity header; statement arity body; + mcode (function _ -> ()) ((),Ast.no_info,aft,Ast.NoMetaPos) + | Ast.Iterator(header,body,(_,_,_,aft)) -> + rule_elem arity header; statement arity body; + mcode (function _ -> ()) ((),Ast.no_info,aft,Ast.NoMetaPos) + | Ast.Switch(header,lb,cases,rb) -> + rule_elem arity header; rule_elem arity lb; + List.iter (function x -> case_line arity x; force_newline()) cases; + rule_elem arity rb + | Ast.Atomic(re) -> rule_elem arity re + | Ast.FunDecl(header,lbrace,decls,body,rbrace) -> + rule_elem arity header; rule_elem arity lbrace; + dots force_newline (statement arity) decls; + dots force_newline (statement arity) body; + rule_elem arity rbrace + | Ast.Disj([stmt_dots]) -> + print_string arity; + dots (function _ -> if !print_newlines_disj then force_newline()) + (statement arity) stmt_dots + | Ast.Disj(stmt_dots_list) -> (* ignores newline directive for readability *) + print_string arity; + force_newline(); print_string "("; force_newline(); + print_between + (function _ -> force_newline();print_string "|"; force_newline()) + (dots force_newline (statement arity)) + stmt_dots_list; + force_newline(); print_string ")" + | Ast.Define(header,body) -> + rule_elem arity header; print_string " "; + dots force_newline (statement arity) body + | Ast.Nest(stmt_dots,whn,multi,_,_) -> + print_string arity; + nest_dots multi (statement arity) + (function _ -> + open_box 0; + print_between force_newline + (whencode (dots force_newline (statement "")) (statement "")) whn; + close_box(); force_newline()) + stmt_dots + | Ast.Dots(d,whn,_,_) | Ast.Circles(d,whn,_,_) | Ast.Stars(d,whn,_,_) -> + print_string arity; mcode print_string d; + open_box 0; + print_between force_newline + (whencode (dots force_newline (statement "")) (statement "")) whn; + close_box(); force_newline() + | Ast.OptStm(s) -> statement "?" s + | Ast.UniqueStm(s) -> statement "!" s + +and print_statement_when whencode = + print_string " WHEN != "; + open_box 0; + print_between (function _ -> print_string " &"; force_newline()) + (dots force_newline (statement "")) whencode; + close_box() + + +and whencode notfn alwaysfn = function + Ast.WhenNot a -> + print_string " WHEN != "; open_box 0; notfn a; close_box() + | Ast.WhenAlways a -> + print_string " WHEN = "; open_box 0; alwaysfn a; close_box() + | Ast.WhenModifier x -> print_string " WHEN "; print_when_modif x + +and print_when_modif = function + | Ast.WhenAny -> print_string "ANY" + | Ast.WhenStrict -> print_string "STRICT" + | Ast.WhenForall -> print_string "FORALL" + | Ast.WhenExists -> print_string "EXISTS" + +and case_line arity c = + match Ast.unwrap c with + Ast.CaseLine(header,code) -> + rule_elem arity header; print_string " "; + dots force_newline (statement arity) code + | Ast.OptCase(case) -> case_line "?" case + +(* --------------------------------------------------------------------- *) +(* CPP code *) + +and inc_file = function + Ast.Local(elems) -> + print_string "\""; + print_between (function _ -> print_string "/") inc_elem elems; + print_string "\"" + | Ast.NonLocal(elems) -> + print_string "<"; + print_between (function _ -> print_string "/") inc_elem elems; + print_string ">" + +and inc_elem = function + Ast.IncPath s -> print_string s + | Ast.IncDots -> print_string "..." + +(* for export only *) +let statement_dots l = dots force_newline (statement "") l + +let top_level t = + match Ast.unwrap t with + Ast.FILEINFO(old_file,new_file) -> + print_string "--- "; mcode print_string old_file; force_newline(); + print_string "+++ "; mcode print_string new_file + | Ast.DECL(stmt) -> statement "" stmt + | Ast.CODE(stmt_dots) -> + dots force_newline (statement "") stmt_dots + | Ast.ERRORWORDS(exps) -> + print_string "error words = ["; + print_between (function _ -> print_string ", ") expression exps; + print_string "]" + +let rule = + print_between (function _ -> force_newline(); force_newline()) top_level + +let pp_print_anything x = !anything x + +let _ = + anything := function + Ast.FullTypeTag(x) -> fullType x + | Ast.BaseTypeTag(x) -> baseType x + | Ast.StructUnionTag(x) -> structUnion x + | Ast.SignTag(x) -> sign x + | Ast.IdentTag(x) -> ident x + | Ast.ExpressionTag(x) -> expression x + | Ast.ConstantTag(x) -> constant x + | Ast.UnaryOpTag(x) -> unaryOp x + | Ast.AssignOpTag(x) -> assignOp x + | Ast.FixOpTag(x) -> fixOp x + | Ast.BinaryOpTag(x) -> binaryOp x + | Ast.ArithOpTag(x) -> arithOp x + | Ast.LogicalOpTag(x) -> logicalOp x + | Ast.InitTag(x) -> initialiser x + | Ast.DeclarationTag(x) -> declaration x + | Ast.StorageTag(x) -> storage x + | Ast.IncFileTag(x) -> inc_file x + | Ast.Rule_elemTag(x) -> rule_elem "" x + | Ast.StatementTag(x) -> statement "" x + | Ast.CaseLineTag(x) -> case_line "" x + | Ast.ConstVolTag(x) -> const_vol x + | Ast.Token(x,Some info) -> print_string_befaft print_string x info + | Ast.Token(x,None) -> print_string x + | Ast.Code(x) -> let _ = top_level x in () + | Ast.ExprDotsTag(x) -> dots (function _ -> ()) expression x + | Ast.ParamDotsTag(x) -> parameter_list x + | Ast.StmtDotsTag(x) -> dots (function _ -> ()) (statement "") x + | Ast.DeclDotsTag(x) -> dots (function _ -> ()) declaration x + | Ast.TypeCTag(x) -> typeC x + | Ast.ParamTag(x) -> parameterTypeDef x + | Ast.SgrepStartTag(x) -> print_string x + | Ast.SgrepEndTag(x) -> print_string x + +let rec dep in_and = function + Ast.Dep(s) -> print_string s + | Ast.AntiDep(s) -> print_string "!"; print_string s + | Ast.EverDep(s) -> print_string "ever "; print_string s + | Ast.NeverDep(s) -> print_string "never "; print_string s + | Ast.AndDep(s1,s2) -> + let print_and _ = dep true s1; print_string " && "; dep true s2 in + if in_and + then print_and () + else (print_string "("; print_and(); print_string ")") + | Ast.OrDep(s1,s2) -> + let print_or _ = dep false s1; print_string " || "; dep false s2 in + if not in_and + then print_or () + else (print_string "("; print_or(); print_string ")") + | Ast.NoDep -> failwith "not possible" + +let unparse z = + match z with + Ast.ScriptRule (lang,deps,bindings,code) -> + print_string "@@"; + force_newline(); + print_string ("script:" ^ lang); + (match deps with + Ast.NoDep -> () + | _ -> print_string " depends on "; dep true deps); + force_newline(); + print_string "@@"; + force_newline(); + print_string code; + force_newline() + | Ast.CocciRule (nm, (deps, drops, exists), x, _) -> + print_string "@@"; + force_newline(); + print_string nm; + (match deps with + Ast.NoDep -> () + | _ -> print_string " depends on "; dep true deps); + (* + print_string "line "; + print_int (Ast.get_line (List.hd x)); + *) + force_newline(); + print_string "@@"; + print_newlines_disj := true; + force_newline(); + force_newline(); + rule x; + force_newline() + +let rule_elem_to_string x = + print_newlines_disj := true; + Common.format_to_string (function _ -> rule_elem "" x) + +let ident_to_string x = + print_newlines_disj := true; + Common.format_to_string (function _ -> ident x) + +let unparse_to_string x = + print_newlines_disj := true; + Common.format_to_string (function _ -> unparse x) + +let print_rule_elem re = + let nl = !print_newlines_disj in + print_newlines_disj := false; + rule_elem "" re; + print_newlines_disj := nl + diff --git a/parsing_cocci/pretty_print_cocci.mli b/parsing_cocci/pretty_print_cocci.mli new file mode 100644 index 0000000..c06c941 --- /dev/null +++ b/parsing_cocci/pretty_print_cocci.mli @@ -0,0 +1,35 @@ +val unparse : Ast_cocci.rule -> unit +val unparse_to_string : Ast_cocci.rule -> string +val expression : Ast_cocci.expression -> unit +val ident : Ast_cocci.ident -> unit +val ident_to_string : Ast_cocci.ident -> string +val statement : string -> Ast_cocci.statement -> unit +val statement_dots : Ast_cocci.statement Ast_cocci.dots -> unit +val rule_elem : string -> Ast_cocci.rule_elem -> unit +val rule_elem_to_string : Ast_cocci.rule_elem -> string + +val print_mcodekind : Ast_cocci.mcodekind -> unit + +val constant : Ast_cocci.constant -> unit +val assignOp : Ast_cocci.assignOp -> unit +val fixOp : Ast_cocci.fixOp -> unit +val unaryOp : Ast_cocci.unaryOp -> unit +val binaryOp : Ast_cocci.binaryOp -> unit +val const_vol : Ast_cocci.const_vol -> unit +val sign : Ast_cocci.sign -> unit +val structUnion : Ast_cocci.structUnion -> unit +val storage : Ast_cocci.storage -> unit +val baseType : Ast_cocci.baseType -> unit +val fullType : Ast_cocci.fullType -> unit +val inc_file : Ast_cocci.inc_file -> unit + +val print_around : + ('a -> unit) -> 'a -> Ast_cocci.anything Ast_cocci.befaft -> unit +val print_anything : string -> Ast_cocci.anything list list -> unit +val pp_print_anything : Ast_cocci.anything -> unit + +val print_plus_flag : bool ref +val print_minus_flag : bool ref + +val print_rule_elem : Ast_cocci.rule_elem -> unit +val print_when_modif : Ast_cocci.when_modifier -> unit diff --git a/parsing_cocci/semantic_cocci.ml b/parsing_cocci/semantic_cocci.ml new file mode 100644 index 0000000..f02f041 --- /dev/null +++ b/parsing_cocci/semantic_cocci.ml @@ -0,0 +1,23 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +exception Semantic of string diff --git a/parsing_cocci/simple_assignments.ml b/parsing_cocci/simple_assignments.ml new file mode 100644 index 0000000..01eda01 --- /dev/null +++ b/parsing_cocci/simple_assignments.ml @@ -0,0 +1,119 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast0 = Ast0_cocci +module Ast = Ast_cocci +module V0 = Visitor_ast0 + +(* find assignments that can match an initialization *) + +let pure_mcodekind = function + Ast0.CONTEXT(mc) -> + (match !mc with + (Ast.NOTHING,_,_) -> true + | _ -> false) + | _ -> false + +let is_simple_assign left op = + (match Ast0.unwrap left with + Ast0.Ident(_) | Ast0.MetaExpr(_,_,_,_,_) -> true + | _ -> false) + && + ((Ast0.unwrap_mcode op) = Ast.SimpleAssign) + +let is_simple_ast_assign left op minus_left = + (match Ast.unwrap left with + Ast.Ident(_) -> true + | Ast.MetaExpr(name,_,_,_,_,_) -> + (match Ast0.unwrap minus_left with + Ast0.MetaExpr(name1,_,_,_,_) -> + Ast.unwrap_mcode name = Ast0.unwrap_mcode name1 + | _ -> false) + | _ -> false) + && + ((Ast.unwrap_mcode op) = Ast.SimpleAssign) + +let warning e msg = + Common.pr2 + ("the simple assignment expression on line "^ + (string_of_int (Ast0.get_line e))^ + " contains transformations\n"^ + "that prevent it from matching a declaration ("^msg^")\n"); + e + +let rebuild e1 left right op simple = + Ast0.rewrap e1 (Ast0.Assignment(left,op,right,simple)) + +let rec exp mc e1 = + match Ast0.unwrap e1 with + Ast0.Assignment(left,op,right,_) -> + if is_simple_assign left op + then + (if !Flag.sgrep_mode2 + then rebuild e1 left right op true + else + match mc with + Ast0.MINUS(mc) -> + (match !mc with + ([[Ast.ExpressionTag(e2)]],_) -> + (match Ast.unwrap e2 with + Ast.Assignment(left',op',_,_) -> + if is_simple_ast_assign left' op' left + then rebuild e1 left right op true + else warning e1 "replacement is not simple" + | _ -> warning e1 "replacement is not an assignment") + | _ -> warning e1 "multiple replacements") + | m -> + let pure = + (pure_mcodekind m) && + (pure_mcodekind (Ast0.get_mcodekind left)) && + (pure_mcodekind (Ast0.get_mcode_mcodekind op)) in + if not pure + then warning e1 "not pure" + else rebuild e1 left right op pure) + else e1 + | Ast0.DisjExpr(lp,exps,mids,rp) -> + Ast0.rewrap e1 + (Ast0.DisjExpr + (lp,List.map (function x -> exp (Ast0.get_mcodekind x) x) exps, + mids,rp)) + | Ast0.OptExp(e) -> + Ast0.rewrap e1 (Ast0.OptExp(exp (Ast0.get_mcodekind e) e)) + | Ast0.UniqueExp(e) -> + Ast0.rewrap e1 (Ast0.UniqueExp(exp (Ast0.get_mcodekind e) e)) + | _ -> e1 + +let simple_assignments l = + let mcode x = x in + let donothing r k e = k e in + let statement r k e = + match Ast0.unwrap e with + Ast0.Exp(e1) -> Ast0.rewrap e (Ast0.Exp(exp (Ast0.get_mcodekind e) e1)) + | _ -> k e in + let fn = + V0.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing donothing statement + donothing donothing in + List.map fn.V0.rebuilder_top_level l diff --git a/parsing_cocci/simple_assignments.mli b/parsing_cocci/simple_assignments.mli new file mode 100644 index 0000000..e9d4c89 --- /dev/null +++ b/parsing_cocci/simple_assignments.mli @@ -0,0 +1 @@ +val simple_assignments : Ast0_cocci.rule -> Ast0_cocci.rule diff --git a/parsing_cocci/single_statement.ml b/parsing_cocci/single_statement.ml new file mode 100644 index 0000000..d8b86c0 --- /dev/null +++ b/parsing_cocci/single_statement.ml @@ -0,0 +1,596 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* detect statements that are between dots in the minus code, because they +may need a special treatment if they are if branches *) + +module Ast0 = Ast0_cocci +module Ast = Ast_cocci +module V0 = Visitor_ast0 + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Helpers *) + +let left_dots f l = + match Ast0.undots l with + [] -> false + | x::xs -> f x + +let right_dots f l = + match List.rev (Ast0.undots l) with + [] -> false + | x::xs -> f x + +let modif_before_mcode mc = + match Ast0.get_mcode_mcodekind mc with + Ast0.MINUS mc -> true (*conservative; don't want to hunt right for + code*) + | Ast0.PLUS -> failwith "not possible" + | Ast0.CONTEXT mc -> + (match !mc with + (Ast.BEFORE _,_,_) -> true + | (Ast.BEFOREAFTER _,_,_) -> true + | _ -> false) + | Ast0.MIXED mc -> true (* don't think mcode can be mixed *) + +let modif_after_mcodekind = function + Ast0.MINUS mc -> true (*conservative; don't want to hunt right for + code*) + | Ast0.PLUS -> failwith "not possible" + | Ast0.CONTEXT mc -> + (match !mc with + (Ast.AFTER _,_,_) -> true + | (Ast.BEFOREAFTER _,_,_) -> true + | _ -> false) + | Ast0.MIXED mc -> true (* don't think mcode can be mixed *) + +let modif_after_mcode mc = modif_after_mcodekind (Ast0.get_mcode_mcodekind mc) + +let any_statements = + List.exists + (List.exists + (function + Ast.StatementTag(_) | Ast.StmtDotsTag(_) + | Ast.DeclarationTag(_) | Ast.DeclDotsTag(_) -> true | _ -> false)) + +let modif_before x = + match Ast0.get_mcodekind x with + Ast0.PLUS -> failwith "not possible" + | Ast0.MINUS mc -> + (match !mc with + (* do better for the common case of replacing a stmt by another one *) + ([[Ast.StatementTag(s)]],_) -> + (match Ast.unwrap s with + Ast.IfThen(_,_,_) -> true (* potentially dangerous *) + | _ -> false) + | (_,_) -> true) + | Ast0.CONTEXT mc | Ast0.MIXED mc -> + (match !mc with + (Ast.BEFORE _,_,_) -> true + | (Ast.BEFOREAFTER _,_,_) -> true + | _ -> false) + +let modif_after x = + match Ast0.get_mcodekind x with + Ast0.PLUS -> failwith "not possible" + | Ast0.MINUS mc -> + (match !mc with + (* do better for the common case of replacing a stmt by another one *) + ([[Ast.StatementTag(s)]],_) -> + (match Ast.unwrap s with + Ast.IfThen(_,_,_) -> true (* potentially dangerous *) + | _ -> false) + | (l,_) -> any_statements l) + | Ast0.CONTEXT mc | Ast0.MIXED mc -> + (match !mc with + (Ast.AFTER _,_,_) -> true + | (Ast.BEFOREAFTER _,_,_) -> true + | _ -> false) + +(* Identifier *) +let rec left_ident i = + modif_before i or + match Ast0.unwrap i with + Ast0.Id(name) -> modif_before_mcode name + | Ast0.MetaId(name,_,_) -> modif_before_mcode name + | Ast0.MetaFunc(name,_,_) -> modif_before_mcode name + | Ast0.MetaLocalFunc(name,_,_) -> modif_before_mcode name + | Ast0.OptIdent(id) -> left_ident id + | Ast0.UniqueIdent(id) -> left_ident id + +(* --------------------------------------------------------------------- *) +(* Expression *) + +let rec left_expression e = + modif_before e or + match Ast0.unwrap e with + Ast0.Ident(id) -> left_ident id + | Ast0.Constant(const) -> modif_before_mcode const + | Ast0.FunCall(fn,lp,args,rp) -> left_expression fn + | Ast0.Assignment(left,op,right,_) -> left_expression left + | Ast0.CondExpr(exp1,why,exp2,colon,exp3) -> left_expression exp1 + | Ast0.Postfix(exp,op) -> left_expression exp + | Ast0.Infix(exp,op) -> modif_before_mcode op + | Ast0.Unary(exp,op) -> modif_before_mcode op + | Ast0.Binary(left,op,right) -> left_expression left + | Ast0.Nested(left,op,right) -> left_expression left + | Ast0.Paren(lp,exp,rp) -> modif_before_mcode lp + | Ast0.ArrayAccess(exp1,lb,exp2,rb) -> left_expression exp1 + | Ast0.RecordAccess(exp,pt,field) -> left_expression exp + | Ast0.RecordPtAccess(exp,ar,field) -> left_expression exp + | Ast0.Cast(lp,ty,rp,exp) -> modif_before_mcode lp + | Ast0.SizeOfExpr(szf,exp) -> modif_before_mcode szf + | Ast0.SizeOfType(szf,lp,ty,rp) -> modif_before_mcode szf + | Ast0.TypeExp(ty) -> left_typeC ty + | Ast0.MetaErr(name,_,_) -> modif_before_mcode name + | Ast0.MetaExpr(name,_,ty,_,_) -> modif_before_mcode name + | Ast0.MetaExprList(name,_,_) -> modif_before_mcode name + | Ast0.EComma(cm) -> modif_before_mcode cm + | Ast0.DisjExpr(_,exp_list,_,_) -> List.exists left_expression exp_list + | Ast0.NestExpr(starter,expr_dots,ender,_,multi) -> + left_dots left_expression expr_dots + | Ast0.Edots(dots,_) | Ast0.Ecircles(dots,_) | Ast0.Estars(dots,_) -> false + | Ast0.OptExp(exp) -> left_expression exp + | Ast0.UniqueExp(exp) -> left_expression exp + +(* --------------------------------------------------------------------- *) +(* Types *) + +and left_typeC t = + modif_before t or + match Ast0.unwrap t with + Ast0.ConstVol(cv,ty) -> modif_before_mcode cv + | Ast0.BaseType(ty,Some sgn) -> modif_before_mcode sgn + | Ast0.BaseType(ty,None) -> modif_before_mcode ty + | Ast0.ImplicitInt(sgn) -> modif_before_mcode sgn + | Ast0.Pointer(ty,star) -> left_typeC ty + | Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> left_typeC ty + | Ast0.FunctionType(Some ty,lp1,params,rp1) -> left_typeC ty + | Ast0.FunctionType(None,lp1,params,rp1) -> modif_before_mcode lp1 + | Ast0.Array(ty,lb,size,rb) -> left_typeC ty + | Ast0.StructUnionName(kind,name) -> modif_before_mcode kind + | Ast0.StructUnionDef(ty,lb,decls,rb) -> left_typeC ty + | Ast0.TypeName(name) -> modif_before_mcode name + | Ast0.MetaType(name,_) -> modif_before_mcode name + | Ast0.DisjType(lp,types,mids,rp) -> List.exists left_typeC types + | Ast0.OptType(ty) -> left_typeC ty + | Ast0.UniqueType(ty) -> left_typeC ty + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +and left_declaration d = + modif_before d or + match Ast0.unwrap d with + Ast0.Init(Some stg,ty,id,eq,ini,sem) -> modif_before_mcode stg + | Ast0.Init(None,ty,id,eq,ini,sem) -> left_typeC ty + | Ast0.UnInit(Some stg,ty,id,sem) -> modif_before_mcode stg + | Ast0.UnInit(None,ty,id,sem) -> left_typeC ty + | Ast0.MacroDecl(name,lp,args,rp,sem) -> left_ident name + | Ast0.TyDecl(ty,sem) -> left_typeC ty + | Ast0.Typedef(stg,ty,id,sem) -> modif_before_mcode stg + | Ast0.DisjDecl(_,decls,_,_) -> List.exists left_declaration decls + | Ast0.Ddots(dots,_) -> false + | Ast0.OptDecl(decl) -> left_declaration decl + | Ast0.UniqueDecl(decl) -> left_declaration decl + +and right_declaration d = + modif_before d or + match Ast0.unwrap d with + Ast0.Init(_,ty,id,eq,ini,sem) -> modif_after_mcode sem + | Ast0.UnInit(_,ty,id,sem) -> modif_after_mcode sem + | Ast0.MacroDecl(name,lp,args,rp,sem) -> modif_after_mcode sem + | Ast0.TyDecl(ty,sem) -> modif_after_mcode sem + | Ast0.Typedef(stg,ty,id,sem) -> modif_after_mcode sem + | Ast0.DisjDecl(_,decls,_,_) -> List.exists right_declaration decls + | Ast0.Ddots(dots,_) -> false + | Ast0.OptDecl(decl) -> right_declaration decl + | Ast0.UniqueDecl(decl) -> right_declaration decl + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +and left_statement s = + modif_before s or + match Ast0.unwrap s with + Ast0.FunDecl(_,fninfo,name,lp,params,rp,lbrace,body,rbrace) -> + (* irrelevant *) false + | Ast0.Decl(_,decl) -> left_declaration decl + | Ast0.Seq(lbrace,body,rbrace) -> modif_before_mcode lbrace + | Ast0.ExprStatement(exp,sem) -> left_expression exp + | Ast0.IfThen(iff,lp,exp,rp,branch1,(info,aft)) -> modif_before_mcode iff + | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,(info,aft)) -> + modif_before_mcode iff + | Ast0.While(whl,lp,exp,rp,body,(info,aft)) -> modif_before_mcode whl + | Ast0.Do(d,body,whl,lp,exp,rp,sem) -> modif_before_mcode d + | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,(info,aft)) -> + modif_before_mcode fr + | Ast0.Iterator(nm,lp,args,rp,body,(info,aft)) -> left_ident nm + | Ast0.Switch(switch,lp,exp,rp,lb,cases,rb) -> modif_before_mcode switch + | Ast0.Break(br,sem) -> modif_before_mcode br + | Ast0.Continue(cont,sem) -> modif_before_mcode cont + | Ast0.Label(l,dd) -> left_ident l + | Ast0.Goto(goto,l,sem) -> modif_before_mcode goto + | Ast0.Return(ret,sem) -> modif_before_mcode ret + | Ast0.ReturnExpr(ret,exp,sem) -> modif_before_mcode ret + | Ast0.MetaStmt(name,pure) -> modif_before_mcode name + | Ast0.MetaStmtList(name,_) -> modif_before_mcode name + | Ast0.Disj(_,statement_dots_list,_,_) -> + List.exists (left_dots left_statement) statement_dots_list + | Ast0.Nest(starter,stmt_dots,ender,whencode,multi) -> + left_dots left_statement stmt_dots + | Ast0.Exp(exp) -> false (* can only be replaced by an expression *) + | Ast0.TopExp(exp) -> false (* as above *) + | Ast0.Ty(ty) -> false (* can only be replaced by a type *) + | Ast0.Dots(d,whn) | Ast0.Circles(d,whn) | Ast0.Stars(d,whn) -> false + | Ast0.Include(inc,s) -> modif_before_mcode inc + | Ast0.Define(def,id,params,body) -> modif_before_mcode def + | Ast0.OptStm(re) -> left_statement re + | Ast0.UniqueStm(re) -> left_statement re + +and right_statement s = + modif_after s or + match Ast0.unwrap s with + Ast0.FunDecl(_,fninfo,name,lp,params,rp,lbrace,body,rbrace) -> + (* irrelevant *) false + | Ast0.Decl(_,decl) -> right_declaration decl + | Ast0.Seq(lbrace,body,rbrace) -> modif_after_mcode rbrace + | Ast0.ExprStatement(exp,sem) -> modif_after_mcode sem + | Ast0.IfThen(iff,lp,exp,rp,branch1,(info,aft)) -> modif_after_mcodekind aft + | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,(info,aft)) -> + modif_after_mcodekind aft + | Ast0.While(whl,lp,exp,rp,body,(info,aft)) -> modif_after_mcodekind aft + | Ast0.Do(d,body,whl,lp,exp,rp,sem) -> modif_after_mcode sem + | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,(info,aft)) -> + modif_after_mcodekind aft + | Ast0.Iterator(nm,lp,args,rp,body,(info,aft)) -> + modif_after_mcodekind aft + | Ast0.Switch(switch,lp,exp,rp,lb,cases,rb) -> modif_after_mcode rb + | Ast0.Break(br,sem) -> modif_after_mcode sem + | Ast0.Continue(cont,sem) -> modif_after_mcode sem + | Ast0.Label(l,dd) -> modif_after_mcode dd + | Ast0.Goto(goto,l,sem) -> modif_after_mcode sem + | Ast0.Return(ret,sem) -> modif_after_mcode sem + | Ast0.ReturnExpr(ret,exp,sem) -> modif_after_mcode sem + | Ast0.MetaStmt(name,pure) -> modif_after_mcode name + | Ast0.MetaStmtList(name,_) -> modif_after_mcode name + | Ast0.Disj(_,statement_dots_list,_,_) -> + List.exists (right_dots right_statement) statement_dots_list + | Ast0.Nest(starter,stmt_dots,ender,whencode,multi) -> + right_dots right_statement stmt_dots + | Ast0.Exp(exp) -> false (* can only be replaced by an expression *) + | Ast0.TopExp(exp) -> false (* as above *) + | Ast0.Ty(ty) -> false (* can only be replaced by a type *) + | Ast0.Dots(d,whn) | Ast0.Circles(d,whn) | Ast0.Stars(d,whn) -> false + | Ast0.Include(inc,s) -> modif_after_mcode s + | Ast0.Define(def,id,params,body) -> right_dots right_statement body + | Ast0.OptStm(re) -> right_statement re + | Ast0.UniqueStm(re) -> right_statement re + +(* --------------------------------------------------------------------- *) + + +(* A very coarse approximation. We would really only like to return true +if a new statement is added. For this it would be best to correlate with the +plus slice. Or at least be sure that the new stuff is on the far left or +far right. *) + +let rec adding_something s = + match Ast0.get_mcodekind s with + Ast0.MINUS(mc) -> + (match !mc with + (* do better for the common case of replacing a stmt by another one *) + ([[Ast.StatementTag(s)]],_) -> + (match Ast.unwrap s with + Ast.IfThen(_,_,_) -> true (* potentially dangerous *) + | _ -> false) + | (_,_) -> true) + | Ast0.CONTEXT(mc) -> + let (text,tinfo1,tinfo2) = !mc in + (match text with Ast.NOTHING -> false | _ -> true) + | Ast0.MIXED(_) -> + not(contains_only_minus.V0.combiner_statement s) (*&& + (left_statement s) or (right_statement s)*) + | _ -> failwith "unexpected plus code" + +(* why do we need this; MINUS should mean the same thing *) +and contains_only_minus = + let bind x y = x && y in + let option_default = true in + let mcodekind = function + Ast0.MINUS(mc) -> + (match !mc with + ([],_) -> true + | _ -> false) + | Ast0.CONTEXT(mc) -> false + | _ -> false in + let mcode (_,_,_,mc,_) = mcodekind mc in + + let donothing r k e = mcodekind (Ast0.get_mcodekind e) && k e in + + let dots r k e = + match Ast0.unwrap e with + Ast0.DOTS([]) | Ast0.CIRCLES([]) | Ast0.STARS([]) -> true + | _ -> k e in + + let expression r k e = + mcodekind (Ast0.get_mcodekind e) && + match Ast0.unwrap e with + Ast0.DisjExpr(starter,expr_list,mids,ender) -> + List.for_all r.V0.combiner_expression expr_list + | _ -> k e in + + let declaration r k e = + mcodekind (Ast0.get_mcodekind e) && + match Ast0.unwrap e with + Ast0.DisjDecl(starter,decls,mids,ender) -> + List.for_all r.V0.combiner_declaration decls + | _ -> k e in + + let typeC r k e = + mcodekind (Ast0.get_mcodekind e) && + match Ast0.unwrap e with + Ast0.DisjType(starter,types,mids,ender) -> + List.for_all r.V0.combiner_typeC types + | _ -> k e in + + let statement r k e = + mcodekind (Ast0.get_mcodekind e) && + match Ast0.unwrap e with + Ast0.Disj(starter,statement_dots_list,mids,ender) -> + List.for_all r.V0.combiner_statement_dots statement_dots_list + | _ -> k e in + + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + dots dots dots dots dots dots + donothing expression typeC donothing donothing declaration + statement donothing donothing + + +(* needs a special case when there is a Disj or an empty DOTS *) +(* ---------------------------------------------------------------------- *) + +(* +Doesn't really work: + + if (acpi_device_dir(device)) ++ { + remove_proc_entry(acpi_device_bid(device), acpi_ac_dir); ++ acpi_device_dir(device) = NULL; ++ } + +The last two + lines get associated with the end of the if, not with the +branch, so the braces get added in oddly. +*) + +let add_braces orig_s = + let s = (Iso_pattern.rebuild_mcode None).V0.rebuilder_statement orig_s in + let new_mcodekind = + match Ast0.get_mcodekind s with + Ast0.MINUS(mc) -> + let (text,tinfo) = !mc in + Ast0.MINUS(ref([Ast.mkToken "{"]::text@[[Ast.mkToken "}"]],tinfo)) + | Ast0.CONTEXT(mc) -> + let (text,tinfo1,tinfo2) = !mc in + let new_text = + match text with + Ast.BEFORE(bef) -> + Ast.BEFOREAFTER([Ast.mkToken "{"]::bef,[[Ast.mkToken "}"]]) + | Ast.AFTER(aft) -> + Ast.BEFOREAFTER([[Ast.mkToken "{"]],aft@[[Ast.mkToken "}"]]) + | Ast.BEFOREAFTER(bef,aft) -> + Ast.BEFOREAFTER([Ast.mkToken "{"]::bef,aft@[[Ast.mkToken "}"]]) + | Ast.NOTHING -> + Ast.BEFOREAFTER([[Ast.mkToken "{"]],[[Ast.mkToken "}"]]) in + Ast0.CONTEXT(ref(new_text,tinfo1,tinfo2)) + | Ast0.MIXED(mc) -> + let (text,tinfo1,tinfo2) = !mc in + let new_text = + match text with + Ast.BEFORE(bef) -> + Ast.BEFOREAFTER([Ast.mkToken "{"]::bef,[[Ast.mkToken "}"]]) + | Ast.AFTER(aft) -> + Ast.BEFOREAFTER([[Ast.mkToken "{"]],aft@[[Ast.mkToken "}"]]) + | Ast.BEFOREAFTER(bef,aft) -> + Ast.BEFOREAFTER([Ast.mkToken "{"]::bef,aft@[[Ast.mkToken "}"]]) + | Ast.NOTHING -> + Ast.BEFOREAFTER([[Ast.mkToken "{"]],[[Ast.mkToken "}"]]) in + Ast0.MIXED(ref(new_text,tinfo1,tinfo2)) + | _ -> failwith "unexpected plus code" in + Ast0.set_mcodekind s new_mcodekind; + Compute_lines.statement s + +(* ---------------------------------------------------------------------- *) + +let is_dots x = + match Ast0.unwrap x with + Ast0.Dots(_,_) | Ast0.Circles(_,_) | Ast0.Stars(_,_) + | Ast0.Nest(_,_,_,_,_) -> true + | _ -> false + +let all_minus s = + match Ast0.get_mcodekind s with + Ast0.MINUS(_) -> true + | _ -> false + +let rec unchanged_minus s = + match Ast0.get_mcodekind s with + Ast0.MINUS(mc) -> (match !mc with ([],_) -> true | _ -> false) + | _ -> false + +let rec do_branch s = + if unchanged_minus s + then + Ast0.set_dots_bef_aft s (Ast0.DroppingBetweenDots(add_braces s)) + else + match Ast0.unwrap s with + Ast0.Disj(starter,statement_dots_list,mids,ender) -> + let stmts = + List.map + (function s -> + match Ast0.unwrap s with + Ast0.DOTS([s]) -> + Ast0.rewrap s (Ast0.DOTS([do_branch s])) + | Ast0.DOTS(_) -> s + | _ -> failwith "not supported") + statement_dots_list in + Ast0.rewrap s (Ast0.Disj(starter,stmts,mids,ender)) + | _ -> s + +let rec statement dots_before dots_after s = + let do_one s = + if dots_before && dots_after + then + if unchanged_minus s + then + (let with_braces = add_braces s in + Ast0.set_dots_bef_aft s (Ast0.DroppingBetweenDots(with_braces))) + else if adding_something s + then + (let with_braces = add_braces s in + Ast0.set_dots_bef_aft s (Ast0.AddingBetweenDots(with_braces))) + else s + else s in + + match Ast0.unwrap s with + Ast0.FunDecl(x,fninfo,name,lp,params,rp,lbrace,body,rbrace) -> + (* true for close brace, because that represents any way we can + exit the function, which is not necessarily followed by an explicit + close brace. *) + Ast0.rewrap s + (Ast0.FunDecl(x,fninfo,name,lp,params,rp,lbrace, + statement_dots false true body, + rbrace)) + | Ast0.Decl(_,_) -> s + | Ast0.Seq(lbrace,body,rbrace) -> + Ast0.rewrap s + (Ast0.Seq(lbrace,statement_dots false false body,rbrace)) + | Ast0.ExprStatement(exp,sem) -> do_one s + | Ast0.IfThen(iff,lp,exp,rp,branch1,x) -> + do_one + (Ast0.rewrap s + (Ast0.IfThen(iff,lp,exp,rp,statement false false branch1,x))) + | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,x) -> + do_one + (Ast0.rewrap s + (Ast0.IfThenElse + (iff,lp,exp,rp, + statement false false branch1,els, + statement false false branch2,x))) + | Ast0.While(whl,lp,exp,rp,body,x) -> + do_one + (Ast0.rewrap s + (Ast0.While(whl,lp,exp,rp,statement false false body,x))) + | Ast0.Do(d,body,whl,lp,exp,rp,sem) -> + do_one + (Ast0.rewrap s + (Ast0.Do(d,statement false false body,whl,lp,exp,rp,sem))) + | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,x) -> + do_one + (Ast0.rewrap s + (Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp, + statement false false body,x))) + | Ast0.Iterator(nm,lp,args,rp,body,x) -> + do_one + (Ast0.rewrap s + (Ast0.Iterator(nm,lp,args,rp,statement false false body,x))) + | Ast0.Switch(switch,lp,exp,rp,lb,cases,rb) -> + do_one + (Ast0.rewrap s + (Ast0.Switch(switch,lp,exp,rp,lb, + Ast0.rewrap cases + (Ast0.DOTS(List.map case_line (Ast0.undots cases))), + rb))) + | Ast0.Break(br,sem) -> do_one s + | Ast0.Continue(cont,sem) -> do_one s + | Ast0.Label(l,dd) -> do_one s + | Ast0.Goto(goto,l,sem) -> do_one s + | Ast0.Return(ret,sem) -> do_one s + | Ast0.ReturnExpr(ret,exp,sem) -> do_one s + | Ast0.MetaStmt(name,_) -> do_one s + | Ast0.MetaStmtList(name,_) -> do_one s + | Ast0.Disj(starter,statement_dots_list,mids,ender) -> + Ast0.rewrap s + (Ast0.Disj(starter, + List.map (statement_dots dots_before dots_after) + statement_dots_list, + mids,ender)) + | Ast0.Nest(starter,stmt_dots,ender,whencode,multi) -> + Ast0.rewrap s + (Ast0.Nest + (starter,statement_dots true true stmt_dots,ender,whencode,multi)) + | Ast0.Exp(exp) -> s + | Ast0.TopExp(exp) -> s + | Ast0.Ty(ty) -> s + | Ast0.Dots(d,whn) | Ast0.Circles(d,whn) | Ast0.Stars(d,whn) -> s + | Ast0.Include(inc,string) -> s (* doesn't affect the need for braces *) + | Ast0.Define(def,id,params,body) -> s (* same as include *) + | Ast0.OptStm(re) -> + Ast0.rewrap s + (Ast0.OptStm(statement dots_before dots_after re)) + | Ast0.UniqueStm(re) -> + Ast0.rewrap s + (Ast0.UniqueStm(statement dots_before dots_after re)) + +and case_line c = + Ast0.rewrap c + (match Ast0.unwrap c with + Ast0.Default(def,colon,code) -> + Ast0.Default(def,colon,statement_dots false false code) + | Ast0.Case(case,exp,colon,code) -> + Ast0.Case(case,exp,colon,statement_dots false false code) + | Ast0.OptCase(case) -> Ast0.OptCase(case_line c)) + +and do_statement_dots dots_before dots_after = function + [] -> [] + | [x] -> [statement dots_before dots_after x] + | dots::rest when is_dots dots -> + dots::(do_statement_dots true dots_after rest) + | x::(dots::_ as rest) when is_dots dots -> + (statement dots_before true x):: + do_statement_dots false dots_after rest + | x::rest -> + (statement dots_before false x):: + do_statement_dots false dots_after rest + +and statement_dots dots_before dots_after d = + Ast0.rewrap d + (match Ast0.unwrap d with + Ast0.DOTS(l) -> + Ast0.DOTS(do_statement_dots dots_before dots_after l) + | Ast0.CIRCLES(l) -> + Ast0.CIRCLES(do_statement_dots dots_before dots_after l) + | Ast0.STARS(l) -> + Ast0.STARS(do_statement_dots dots_before dots_after l)) + +let top_level t = + Ast0.rewrap t + (match Ast0.unwrap t with + Ast0.DECL(stmt_dots) -> Ast0.DECL(statement true true stmt_dots) + | Ast0.CODE(stmt_dots) -> Ast0.CODE(statement_dots true true stmt_dots) + | t -> t) + +let single_statement l = + if !Flag_parsing_cocci.sgrep_mode then l else List.map top_level l diff --git a/parsing_cocci/single_statement.mli b/parsing_cocci/single_statement.mli new file mode 100644 index 0000000..eee3744 --- /dev/null +++ b/parsing_cocci/single_statement.mli @@ -0,0 +1 @@ +val single_statement : Ast0_cocci.rule -> Ast0_cocci.rule diff --git a/parsing_cocci/test.cocci b/parsing_cocci/test.cocci new file mode 100644 index 0000000..5683b49 --- /dev/null +++ b/parsing_cocci/test.cocci @@ -0,0 +1,54 @@ +@@ +struct SHT sht; +local function proc_info_func; +@@ + sht.proc_info = proc_info_func; + +@@ +identifier buffer, start, offset, length, inout, hostptr, hostno; +@@ + proc_info_func ( ++ struct Scsi_Host *hostptr, + char *buffer, char **start, off_t offset, int length, +- int hostno, + int inout) { + ... +- struct Scsi_Host *hostptr; + ... +- hostptr = scsi_host_hn_get(hostno); + ... +?- if (!hostptr) { ... } + ... +?- scsi_host_put(hostptr); + ... + } + +@@ +expression E; +@@ + proc_info_func(...) { + <... +( +\+- E->host_no == hostno ++ E == shpnt +| +- hostno ++ shpnt->host_no +) + ...> + } + +@@ +struct foo E; +@@ + proc_info_func(...) { + <... +( +\+- E->host_no == hostno ++ E == shpnt +| +- hostno ++ shpnt->host_no +) + ...> + } diff --git a/parsing_cocci/test2.cocci b/parsing_cocci/test2.cocci new file mode 100644 index 0000000..62ec534 --- /dev/null +++ b/parsing_cocci/test2.cocci @@ -0,0 +1,39 @@ +@@ +struct SHT sht; +local function proc_info_func; +@@ + sht.proc_info = proc_info_func; + +@@ +identifier buffer, start, offset, length, inout, hostptr, hostno; +@@ + proc_info_func ( ++ struct Scsi_Host *hostptr, + char *buffer, char **start, off_t offset, int length, +- int hostno, + int inout) { + ... +- struct Scsi_Host *hostptr; + ... +- hostptr = scsi_host_hn_get(hostno); + ... +?- if (!hostptr) { ... } + ... +?- scsi_host_put(hostptr); + ... + } + +@@ +expression E; +@@ + proc_info_func(...) { + <... +( +\+- E->host_no == hostno ++ E == shpnt +| +- hostno ++ shpnt->host_no +) + ...> + } diff --git a/parsing_cocci/test_exps.ml b/parsing_cocci/test_exps.ml new file mode 100644 index 0000000..528d7e2 --- /dev/null +++ b/parsing_cocci/test_exps.ml @@ -0,0 +1,89 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast = Ast_cocci +module Ast0 = Ast0_cocci +module V0 = Visitor_ast0 + +(* call set_test_pos on test expressions *) + +(* The goal of this is to identify test expressions in the SmPL file, so that +isomorphisms like X != NULL => X are only applied in a test expression context. + +There is a related check in cocci_vs_c3.ml that in x || ..., a match +without the || is only accepted in a test expression context. This uses +the annotations in the C file. *) + +let rec process_exp e = + let e = Ast0.set_test_pos e in + match Ast0.unwrap e with + Ast0.Paren(lp,e,rp) -> + Ast0.rewrap e (Ast0.Paren(lp,process_exp e,rp)) + | _ -> e + +let set_test_poss = + let donothing r k e = k e in + let mcode x = x in + + let expression r k e = + let e = k e in + match Ast0.unwrap e with + Ast0.CondExpr(e1,q,e2,c,e3) -> + Ast0.rewrap e (Ast0.CondExpr(process_exp e1,q,e2,c,e3)) + | Ast0.Binary(e1,op,e2) -> + (match Ast0.unwrap_mcode op with + Ast.Logical(Ast.AndLog) | Ast.Logical(Ast.OrLog) -> + Ast0.rewrap e (Ast0.Binary(process_exp e1,op,process_exp e2)) + | _ -> e) + | Ast0.Unary(e1,op) -> + (match Ast0.unwrap_mcode op with + Ast.Not -> Ast0.rewrap e (Ast0.Unary(process_exp e1,op)) + | _ -> e) + | _ -> e in + + let statement r k s = + let s = k s in + match Ast0.unwrap s with + Ast0.IfThen(i,lp,e,rp,s1,aft) -> + Ast0.rewrap s (Ast0.IfThen(i,lp,process_exp e,rp,s1,aft)) + | Ast0.IfThenElse(i,lp,e,rp,s1,e1,s2,aft) -> + Ast0.rewrap s (Ast0.IfThenElse(i,lp,process_exp e,rp,s1,e1,s2,aft)) + | Ast0.While(i,lp,e,rp,s1,aft) -> + Ast0.rewrap s (Ast0.While(i,lp,process_exp e,rp,s1,aft)) + | Ast0.Do(d,s1,w,lp,e,rp,sc) -> + Ast0.rewrap s (Ast0.Do(d,s1,w,lp,process_exp e,rp,sc)) + | Ast0.For(f,lp,e1,sc1,Some e2,sc2,e3,rp,s1,aft) -> + Ast0.rewrap s + (Ast0.For(f,lp,e1,sc1,Some (process_exp e2),sc2,e3,rp,s1,aft)) + | _ -> s in + + V0.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + donothing expression donothing donothing donothing donothing statement + donothing donothing + +let process = List.map set_test_poss.V0.rebuilder_top_level + +let process_anything = set_test_poss.V0.rebuilder_anything + diff --git a/parsing_cocci/test_exps.mli b/parsing_cocci/test_exps.mli new file mode 100644 index 0000000..29d5ced --- /dev/null +++ b/parsing_cocci/test_exps.mli @@ -0,0 +1,3 @@ +val process : Ast0_cocci.rule -> Ast0_cocci.rule + +val process_anything : Ast0_cocci.anything -> Ast0_cocci.anything diff --git a/parsing_cocci/tests/1.cocci b/parsing_cocci/tests/1.cocci new file mode 100644 index 0000000..df107fa --- /dev/null +++ b/parsing_cocci/tests/1.cocci @@ -0,0 +1,20 @@ +@@ +expression E; +@@ + +- #include + <... +( +- mem_map_reserve(E) ++ SetPageReserved(E) +| +- cs4x_mem_map_reserve(E) ++ SetPageReserved(E) +| +- mem_map_unreserve(E) ++ ClearPageReserved(E) +| +- cs4x_mem_map_unreserve(E) ++ ClearPageReserved(E) +) + ...> diff --git a/parsing_cocci/tests/10.cocci b/parsing_cocci/tests/10.cocci new file mode 100644 index 0000000..39323b9 --- /dev/null +++ b/parsing_cocci/tests/10.cocci @@ -0,0 +1,11 @@ +@@ +expression E; +@@ + +- pnp_activate_dev(E, NULL) ++ pnp_activate_dev(E) + +@@ +@@ + +error words = [pnp_activate_dev] diff --git a/parsing_cocci/tests/11.cocci b/parsing_cocci/tests/11.cocci new file mode 100644 index 0000000..e6f9358 --- /dev/null +++ b/parsing_cocci/tests/11.cocci @@ -0,0 +1,102 @@ +@@ +identifier usb; +@@ + + + +@@ +local function probe_fn; +local function disconnect_fn; +int minor; +@@ + +struct usb_driver usb = { + ooo + probe: probe_fn, + ooo + disconnect: disconnect_fn, + ooo + minor: minor, + ooo +}; + +@@ +int minor_offset; +expression E1, E2, E3, E4, E5, E6; +type T; +T moe; +identifier field; +identifier v; +expression L1, L2, L3, L; +statement loop_body; +@@ + +( + probe_fn(...) { + ... + int v; + ... WHEN != v = L ++ if (usb_register_dev(&usb, 1, &v)) { + while(L1) { + <... + v = L2; + ...> + } ++ } + ... WHEN != v = L +! moe.field = v; + ... WHEN != v = L + devfs_register(E1, E2, E3, USB_MAJOR, minor + moe.field, E4, E5, E6) + ... WHEN != v = L + } +| + probe_fn(...) { + ... + int v; + ... WHEN != v = L ++ if (usb_register_dev(&usb, 1, &v)) { + while(L1) { + <... + v = L2; + ...> + } ++ } + ... WHEN != v = L +( +! moe.field = v; + ooo WHEN != v = L + devfs_register(E1, E2, E3, USB_MAJOR, minor + v, E4, E5, E6) +) + ... WHEN != v = L + } +| + probe_fn(...) { + ... WHEN != moe.field = L ++ if (usb_register_dev(&usb, 1, &moe.field)) { + while(L1) { + <... + moe.field = L2; + ...> + } ++ } + ... WHEN != moe.field = L + devfs_register(E1, E2, E3, USB_MAJOR, minor + moe.field, E4, E5, E6) + ... WHEN != moe.field = L + } +) + +@@ +T E; +identifier f; +@@ + + disconnect_fn(...) { + *** +! devfs_unregister(E.f) ++ usb_deregister_dev(&usb, 1, E.field) + *** + } diff --git a/parsing_cocci/tests/12.cocci b/parsing_cocci/tests/12.cocci new file mode 100644 index 0000000..ee22465 --- /dev/null +++ b/parsing_cocci/tests/12.cocci @@ -0,0 +1,41 @@ +@@ +expression E1, E2, E3; +@@ + +- usb_deregister_dev(E1, E2, E3); ++ usb_deregister_dev(E2, E3); + +@@ +struct usb_driver d; +!expression fops_val; +@@ + +- d.fops = fops_val; + +@@ +struct usb_driver d; +!int minor_val; +@@ + +- d.minor = minor_val; + +@@ +struct usb_driver d; +int num_minor_val; +@@ + +- d.num_minor = num_minor_val; + +@@ +expression E1, E2, E3; +identifier ret; +statement S; +@@ + +- ret = usb_register_dev(E1, E2, E3); ++ ret = usb_register_dev(fops_val, minor_val, E2, E3); +- if (ret) { +- if (ret != -ENODEV) S +- ... +- } ++ if (ret) S diff --git a/parsing_cocci/tests/13.cocci b/parsing_cocci/tests/13.cocci new file mode 100644 index 0000000..d6bf775 --- /dev/null +++ b/parsing_cocci/tests/13.cocci @@ -0,0 +1,10 @@ +@@ +expression E; +@@ + +- printk("... %s ...", ++ printk("... %u.%u.%u.%u ...", + ..., +- in_ntoa(E), ++ NIPQUAD(E), + ...); diff --git a/parsing_cocci/tests/14.cocci b/parsing_cocci/tests/14.cocci new file mode 100644 index 0000000..61a83a9 --- /dev/null +++ b/parsing_cocci/tests/14.cocci @@ -0,0 +1,36 @@ +@@ +!type A; +type A1; +identifier X, X1; +expression Y, Z; +@@ + +( + A X; + ooo + A1 X1; +) + <... + request_irq(X->irq, Y, Z) + ... + <... + X1->irq = X->irq; + ...> + ...> + +@@ +identifier X2; +local function fn; +@@ + +( + fn(..., A1 X2, ...) { +| + fn(...) { + A1 X2; +) + <... +- synchronize_irq() ++ synchronize_irq(X2) + ...> + } diff --git a/parsing_cocci/tests/15.cocci b/parsing_cocci/tests/15.cocci new file mode 100644 index 0000000..d94db70 --- /dev/null +++ b/parsing_cocci/tests/15.cocci @@ -0,0 +1,17 @@ +@@ +{struct input_dev, struct gameport} dev; +@@ + +( +- dev.idbus ++ dev.id.bustype +| +- dev.idvendor ++ dev.id.vendor +| +- dev.idproduct ++ dev.id.product +| +- dev.idversion ++ dev.id.version +) diff --git a/parsing_cocci/tests/16.cocci b/parsing_cocci/tests/16.cocci new file mode 100644 index 0000000..ba0b708 --- /dev/null +++ b/parsing_cocci/tests/16.cocci @@ -0,0 +1,8 @@ +@@ +@@ + +--- a/drivers/scsi/... ++++ b/drivers/scsi/... + +- ATA_MAX_PRD ++ LIBATA_MAX_PRD diff --git a/parsing_cocci/tests/17.cocci b/parsing_cocci/tests/17.cocci new file mode 100644 index 0000000..e872a95 --- /dev/null +++ b/parsing_cocci/tests/17.cocci @@ -0,0 +1,17 @@ +@@ +expression X, Y; +@@ + +- bio_endio(X,Y) +( ++ bio_endio(X, bio_sectors(X) << 9, Y ? 0 : -EIO) +| ++ bio_endio(X, X->bi_size << 9, Y ? 0 : -EIO) +) + +@@ +expression X; +@@ + +- bio_io_error(X) ++ bio_io_error(X,X->bi_size) diff --git a/parsing_cocci/tests/18.cocci b/parsing_cocci/tests/18.cocci new file mode 100644 index 0000000..5eee5e3 --- /dev/null +++ b/parsing_cocci/tests/18.cocci @@ -0,0 +1,25 @@ +@@ +constant char *string; +@@ + +- devfs_mk_dir(NULL,string,NULL) ++ devfs_mk_dir(string) + +@@ +constant char *string; +identifier txt; +int E; +expression list A; +@@ + +- char txt[E]; + ... WHEN != txt +- sprintf(txt,string,A); + ... WHEN != txt +- devfs_mk_dir(NULL,txt,NULL) ++ devfs_mk_dir(string,A) + +@@ +@@ + +error words = [devfs_mk_dir] diff --git a/parsing_cocci/tests/19.cocci b/parsing_cocci/tests/19.cocci new file mode 100644 index 0000000..c237dba --- /dev/null +++ b/parsing_cocci/tests/19.cocci @@ -0,0 +1,39 @@ +@@ +struct gendisk g; +expression E; +@@ + +?- g.nr_real = E; + +@@ +struct gendisk g; +@@ + +error words = [g.nr_real] + +@@ +struct gendisk *A; +expression B, E; +struct gendisk *C; +int E1;@@ + +( + add_gendisk(C+E1); + ooo +- A[minor(B)].nr_sects = E; ++ set_capacity(C[&DEVICE_NR(B)],E); +| +- A->part[B].nr_sects = E; ++ set_capacity(A+B,E); +| + add_gendisk(C+E1); + ooo +- A[minor(B)].nr_sects ++ get_capacity(C[&DEVICE_NR(B)]) + ooo +| + ... +- A->part[B].nr_sects ++ get_capacity(A+B) + ... +) diff --git a/parsing_cocci/tests/2.cocci b/parsing_cocci/tests/2.cocci new file mode 100644 index 0000000..38d7ea0 --- /dev/null +++ b/parsing_cocci/tests/2.cocci @@ -0,0 +1,29 @@ +@@ +struct i2c_client x; +@@ + +- x.name ++ x.dev.name + +@@ +struct i2c_client *p; +expression E; +@@ + +( +- p->data = E ++ i2c_set_clientdata(p,E) +| +- p->data ++ i2c_get_clientdata(p) +) + +@@ +struct i2c_client *p; +expression E1, E2; +@@ + + p = kmalloc(E1, E2); +? if (!p) { ... } ++ memcpy(p,0,E1); + ... WHEN != memcpy(p,...) diff --git a/parsing_cocci/tests/20.cocci b/parsing_cocci/tests/20.cocci new file mode 100644 index 0000000..6402978 --- /dev/null +++ b/parsing_cocci/tests/20.cocci @@ -0,0 +1,20 @@ +@@ +expression A, B, C, D; +@@ + +- snd_pcm_lib_preallocate_pci_pages_for_all(A, B, C, D) ++ snd_pcm_lib_preallocate_pages_for_all(B, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(A), C, D) + +@@ +expression A, B, C; +@@ + +- snd_pcm_lib_preallocate_isa_pages_for_all(A, B, C) ++ snd_pcm_lib_preallocate_pages_for_all(A, SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), B, C) + +@@ +expression A, B, C, D; +@@ + +- snd_pcm_lib_preallocate_sbus_pages_for_all(A, B, C, D) ++ snd_pcm_lib_preallocate_pages_for_all(B, SNDRV_DMA_TYPE_SBUS, snd_dma_sbus_data(A), C, D) diff --git a/parsing_cocci/tests/21.cocci b/parsing_cocci/tests/21.cocci new file mode 100644 index 0000000..e1aa4dc --- /dev/null +++ b/parsing_cocci/tests/21.cocci @@ -0,0 +1,41 @@ +@@ +expression A, B, C; +@@ + +- snd_magic_cast(A, B, C) ++ B + +@@ +expression X; +@@ + +- snd_magic_kfree(X) ++ kfree(X) + +@@ +expression X, A, C; +@@ + +- X = snd_magic_kcalloc(A, 0, C) ++ X = kcalloc(1, sizeof(*X), C) + +@@ +expression X, A, B, C; +@@ + +- X = snd_magic_kcalloc(A, B, C) ++ X = kcalloc(1, sizeof(*X)+B, C) + +@@ +expression X, A, C; +@@ + +- X = snd_magic_kmalloc(A, 0, C) ++ X = kmalloc(sizeof(*X), C) + +@@ +expression X, A, B, C; +@@ + +- X = snd_magic_kmalloc(A, B, C) ++ X = kmalloc(sizeof(*X)+B, C) diff --git a/parsing_cocci/tests/22.cocci b/parsing_cocci/tests/22.cocci new file mode 100644 index 0000000..75e6776 --- /dev/null +++ b/parsing_cocci/tests/22.cocci @@ -0,0 +1,42 @@ +@@ +@@ + +--- a/drivers/usb/storage/... ++++ b/drivers/usb/storage/... + +@@ +struct us_data X; +expression Y; +@@ + +- usb_sndbulkpipe (X->pusb_dev, Y) ++ X->send_bulk_pipe + +@@ +struct us_data X; +expression Y; +@@ + +- usb_rcvbulkpipe (X->pusb_dev, Y) ++ X->recv_bulk_pipe + +@@ +struct us_data X; +expression Y; +@@ + +- usb_sndctrlpipe (X->pusb_dev, Y) ++ X->send_ctrl_pipe + +@@ +struct us_data X; +expression Y; +@@ + +- usb_rcvctrlpipe (X->pusb_dev, Y) ++ X->recv_ctrl_pipe + +@@ +@@ + +error words = [usb_sndbulkpipe, usb_rcvbulkpipe, usb_sndctrlpipe, usb_rcvctrlpipe] diff --git a/parsing_cocci/tests/23.cocci b/parsing_cocci/tests/23.cocci new file mode 100644 index 0000000..fa54529 --- /dev/null +++ b/parsing_cocci/tests/23.cocci @@ -0,0 +1,31 @@ +@@ +expression X, Y, E; +identifier field; +error err; +@@ + +- Y = init_etherdev(NULL,X); ++ Y = alloc_etherdev(X); + ... + Y.field = E; ++ if (!register_netdev(Y)) { ++ kfree(Y); ++ return err; ++ } + +@@ +error err; +@@ + + Y = alloc_etherdev(X); + <... + if (...) { + ... +- unregister_netdev(Y) + ... + return err; + } + ...> + ... + register_netdev(Y) + ... diff --git a/parsing_cocci/tests/24.cocci b/parsing_cocci/tests/24.cocci new file mode 100644 index 0000000..e69de29 diff --git a/parsing_cocci/tests/25.cocci b/parsing_cocci/tests/25.cocci new file mode 100644 index 0000000..7034129 --- /dev/null +++ b/parsing_cocci/tests/25.cocci @@ -0,0 +1,24 @@ +@@ +expression A, C, E; +mdk_rdev_t *rdev; +identifier B, D, X, Y; +@@ + +( + X = mddev_to_conf(A); + ... +- atomic_dec(&X->B[C].rdev->nr_pending) ++ rdev_dec_pending(X->B[C].rdev,A) + ... +| + ... +- atomic_dec(&rdev->nr_pending) ++ rdev_dec_pending(rdev,Y->mddev) + ... +) + +@@ +expression F; +@@ + +error words = [atomic_dec(&F->nr_pending)] diff --git a/parsing_cocci/tests/26.cocci b/parsing_cocci/tests/26.cocci new file mode 100644 index 0000000..eb9f34f --- /dev/null +++ b/parsing_cocci/tests/26.cocci @@ -0,0 +1,8 @@ +@@ +expression A, B; +statement S; +@@ + +- if (!pci_dma_supported(A,B)) S +- pci_set_dma_mask(A,B); ++ if (pci_set_dma_mask(A,B) < 0 || pci_set_consistent_dma_mask(A,B) < 0) S diff --git a/parsing_cocci/tests/27.cocci b/parsing_cocci/tests/27.cocci new file mode 100644 index 0000000..5b6a3cc --- /dev/null +++ b/parsing_cocci/tests/27.cocci @@ -0,0 +1,16 @@ +@@ +local function f; +struct IsdnCard card; +@@ + + card.irq_func = f + +@@ +fresh identifier mode_switch; +@@ + + f(... ++ , int mode_switch + ) { + ... + } diff --git a/parsing_cocci/tests/28.cocci b/parsing_cocci/tests/28.cocci new file mode 100644 index 0000000..8147834 --- /dev/null +++ b/parsing_cocci/tests/28.cocci @@ -0,0 +1,14 @@ +@@ ++struct urb u1; +struct urb u2; +expression E, E2; +@@ + + <*** + u1.transfer_flags = URB_ASYNC_UNLINK|E; + *** WHEN != u1.transfer_flags = E2; + <... +- usb_unlink_urb(u2) ++ usb_kill_urb(u2) + ...> + ***> diff --git a/parsing_cocci/tests/29.cocci b/parsing_cocci/tests/29.cocci new file mode 100644 index 0000000..4228bab --- /dev/null +++ b/parsing_cocci/tests/29.cocci @@ -0,0 +1,28 @@ +@@ +struct tty_operations t; +local function fn; +@@ + +t.write = fn; + +@@ +parameter p; +identifier x; +@@ + + fn(p, +- int x, + ...) { + <*** +- x ++ 0 + ***> + } + +@@ +expression E1, E2; +@@ + +- fn(E1, E2, ++ fn(E1, + ...) diff --git a/parsing_cocci/tests/3.cocci b/parsing_cocci/tests/3.cocci new file mode 100644 index 0000000..fc4e18d --- /dev/null +++ b/parsing_cocci/tests/3.cocci @@ -0,0 +1,44 @@ +@@ +struct Scsi_Host_Template sht; +!local function proc_info_func; +@@ + +sht.proc_info = proc_info_func; + +@@ +identifier buffer, start, offset, length, inout, hostptr, hostno; +@@ + + proc_info_func( ++ struct Scsi_Host *hostptr, + char *buffer, char **start, off_t offset, + int length, +- int hostno, + int inout) { + ... +- struct Scsi_Host *hostptr; + ... +- hostptr = scsi_host_hn_get(hostno); + ... +?- if (hostptr == NULL) { ... } + ... +?- scsi_host_put(hostptr); + ... + } + +@@ +expression E; +@@ + +proc_info_func(...) { + <... +( +- E->host_no == hostno ++ E == hostptr +| +- hostno ++ hostptr->host_no +) + ...> + } + diff --git a/parsing_cocci/tests/30.cocci b/parsing_cocci/tests/30.cocci new file mode 100644 index 0000000..6f52bd8 --- /dev/null +++ b/parsing_cocci/tests/30.cocci @@ -0,0 +1,20 @@ +@@ +expression E; +@@ + +( +- if ((E->flags & (1 << TTY_DO_WRITE_WAKEUP)) && E->ldisc.write_wakeup) +| +- if (test_bit(TTY_DO_WRITE_WAKEUP, &E->flags) && E->ldisc.write_wakeup) +) +- (E->ldisc.write_wakeup)(E); ++ tty_wakeup(E); + ooo +- wake_up_interruptible(&E->write_wait); + +@@ +expression E; +@@ + +- if (E->ldisc.flush_buffer) E->ldisc.flush_buffer(E); ++ tty_ldisc_flush(E); diff --git a/parsing_cocci/tests/4.cocci b/parsing_cocci/tests/4.cocci new file mode 100644 index 0000000..46e71b4 --- /dev/null +++ b/parsing_cocci/tests/4.cocci @@ -0,0 +1,33 @@ +@@ +struct video_device v; +local function fn; +@@ + + v.mmap = fn; + +@@ +local function fn1; +identifier dev, adr, size; +fresh identifier vma; +@@ + + fn( ++ struct vm_area_struct *vma, + struct video_device *dev, const char *adr, unsigned long size) { + <*** + fn1( ++ vma, + ...) + ***> + } + + fn1( ++ struct vm_area_struct *vma, + ...) { + <*** + remap_page_range( ++ vma, + ...) + ***> + } + diff --git a/parsing_cocci/tests/5.cocci b/parsing_cocci/tests/5.cocci new file mode 100644 index 0000000..bf545da --- /dev/null +++ b/parsing_cocci/tests/5.cocci @@ -0,0 +1,35 @@ +@@ +struct IsdnCard v; +local function fn; +@@ + +v.irq_func = &fn; + +@@ +identifier intno, dev_id, regs; +@@ + + fn(int intno, void *dev_id, struct pt_regs *regs) { + <... +( +- spin_lock(...); +| +- spin_unlock(...); +) + ...> + } + +@@ +identifier cs; +@@ + + fn(int intno, void *dev_id, struct pt_regs *regs) { + ... + struct IsdnCardState *cs = dev_id; ++ spin_lock(&cs->lock); + ... +?- if (!cs) { ... } + ... ++ spin_unlock(&cs->lock); + return; + } diff --git a/parsing_cocci/tests/6.cocci b/parsing_cocci/tests/6.cocci new file mode 100644 index 0000000..e66e6cf --- /dev/null +++ b/parsing_cocci/tests/6.cocci @@ -0,0 +1,362 @@ +@@ +?local function read_fn; +?local function write_fn; +?local function write_block_fn; +!type T; + +identifier dev; +identifier subaddr; +@@ + +- read_fn(T *dev, unsigned char subaddr) { +- ... +- not while (...) { +- ooo +- +- ooo +- +- ooo +- not } +- ... +- } + +@@ +identifier dev; +identifier subaddr; +identifier data; +@@ + +- write_fn(T *dev, unsigned char subaddr, unsigned char data) { +- ... +- not while (...) { +- +- not } +- ... +- } + +@@ +identifier dev; +identifier data; +identifier len; +@@ + +- write_block_fn(T *dev, unsigned char *data, unsigned int len) { +- +- } +- ooo> +- } +@@ +!local function attach_fn, detach_fn, command_fn; +expression E, E1, E2, E3, E4; +struct i2c_driver I; +@@ + +ooo WHEN !<= I.{attach,detach,command} = E; +struct i2c_driver i2c_driver_struct = { + E1, E2, E3, E4, attach_fn, detach_fn, command_fn +}; +ooo + +@@ +!local function init_fn, exit_fn; +@@ + +module_init(init_fn); +ooo +module_exit(exit_fn); + +@@ +!identifier i2c_driver_struct; +@@ + +init_fn(...) { + ... + i2c_register_driver(&i2c_driver_struct); + ... +} +@@ +filename A; +fresh identifier A##_probe; +fresh identifier normal_i2c, normal_i2c_range, probe, probe_range, ignore, +ignore_range, force, addr_data, client_template; +@@ + +--- a/.../A##.c ++++ b/.../A##.c + +-! #include ++ #include ++ ... ++ static unsigned short normal_i2c[] = {34>>1, I2C_CLIENT_END }; ++ static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; ++ static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; ++ static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; ++ static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; ++ static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; ++ static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; ++ ++ static struct i2c_client_address_data addr_data = { ++ normal_i2c, normal_i2c_range, ++ probe, probe_range, ++ ignore, ignore_range, ++ force ++ }; ++ static struct i2c_client client_template; + + +@@ +identifier bus; +@@ + struct T { + ... +!- struct i2c_bus *bus; ++ struct i2c_client *client; + ... ++ struct semaphore lock; + } + +@@ +expression E; +@@ + +! static struct i2c_driver i2c_driver_struct = { + E, +- I2C_DRIVERID_VIDEODECODER, +- I2C_##A/u, I2C_##A/u + 1, ++ I2C_DRIVERID_##A/u, ++ I2C_DF_NOTIFY, +- attach_fn, ++ probe_fn, + detach_fn, + command_fn + }; ++ static struct i2c_client client_template = { ++ "##A##_client", -1, 0, 0, NULL, &i2c_driver_struct ++ }; +@@ +@@ + + init_fn(...) { + ... +- C[i2c_register_driver(&i2c_driver_struct)] ++ C[i2c_add_driver(&i2c_driver_struct)] + ... + } + +@@ +@@ + + exit_fn(...) { + ... +- C[i2c_unregister_driver(&i2c_driver_struct)] ++ C[i2c_del_driver(&i2c_driver_struct)] + ... + } + +error words = [i2c_register_driver, i2c_unregister_driver] +@@ +identifier device; +identifier coder; +fresh identifier adap, addr, flags, kind; +fresh identifier client; +expression E; +error expression error_code; +@@ + +- attach_fn(struct i2c_device *device) ++ attach_fn(struct i2c_adapter *adap, int addr, unsigned long flags, int kind) + { ++ struct i2c_client *client; + ++ client = kmalloc(sizeof(*client), GFP_KERNEL); ++ if(client == NULL) return -ENOMEM; ++ client_template.adapter = adap; ++ client_template.addr = addr; ++ memcpy(client, &client_template, sizeof(*client)); + ... + <... ++ kfree(client); + return error_code; + ...> + ... ++ init_MUTEX(&coder->lock); ++ i2c_attach_client(client); ++ MOD_INC_USE_COUNT; + return E; + } + { + ooo + <... +- MOD_INC_USE_COUNT + ...> + ooo + <... +- MOD_DEC_USE_COUNT + ...> + ooo + } + { + ... +! T *coder; + ... +- device->data = coder; + ... + <... +- device->data ++ coder + ...> + } + { + ... ++ client->data = coder; + coder->bus = device->bus; + ... + } + { + ooo + <... +- device->bus ++ client + ...> + ooo + <... +- coder->bus ++ coder->client + ...> + ooo + <... +- device->addr ++ addr + ...> + ooo + } + { + <... +- device ++ client + ...> + } + +error words = [attach_fn: device->data] +@@ +identifier device; +fresh identifier client; +@@ + +( + attach_fn(struct i2c_device *device) { +| + command_fn(struct i2c_device *device, ...) { +) + <... + device_fn(device,...) + ...> + } + +@@ +@@ + +- device_fn(struct i2c_device *device, ...) { ++ device_fn(struct i2c_client *client, ...) { + <... +- device ++ client + ...> + } +@@ +fresh identifier adap; +@@ + ++ static int A##_probe(struct i2c_adapter *adap) { ++ return i2c_probe(adap, &addr_data, A##_attach); ++ } + ... +@@ +fresh identifier client; +@@ + +- detach_fn(struct i2c_device *device) ++ detach_fn(struct i2c_client *client) + { + <... +- device ++ client + ...> + } + { ++ i2c_detach_client(client); + ... ++ kfree(client); + MOD_DEC_USE_COUNT; + ... + } +@@ +identifier device; +fresh identifier client; +@@ + +- command_fn(struct i2c_device *device, ...) { ++ command_fn(struct i2c_client *client, ...) { + <... +- device ++ client + ...> + } +@@ +local function fn; +identifier client; +expression X1, Y1, X2, Y2, Z2, X3, Y3, Z3, X4, Y4, X5, Y5, Z5, X6, Y6, Z6; +@@ + +( + fn(...) { + struct i2c_client *client; +| + fn(..., struct i2c_client *client, ...) { +) + ooo + <... +- read_fn(X1,Y1) ++ i2c_smbus_read_byte(client) + ...> + ooo + <... +- write_fn(X2,Y2,Z2) ++ i2c_smbus_write_byte(client,Y2,Z2) + ...> + ooo + <... +- write_block_fn(X3,Y3,Z3) ++ i2c_master_send(client,Y3,Z3) + ...> + ooo + } + + fn(...) { + ooo + <... +- read_fn(X4,Y4) ++ i2c_smbus_read_byte(X4->client) + ...> + ooo + <... +- write_fn(X5,Y5,Z5) ++ i2c_smbus_write_byte(X5->client,Y5,Z5) + ...> + ooo + <... +- write_block_fn(X6,Y6,Z6) ++ i2c_master_send(X6->client,Y6,Z6) + ...> + ooo + } diff --git a/parsing_cocci/tests/7.cocci b/parsing_cocci/tests/7.cocci new file mode 100644 index 0000000..efc6e3d --- /dev/null +++ b/parsing_cocci/tests/7.cocci @@ -0,0 +1,7 @@ +@@ +@@ + + if (blk_queue_empty(QUEUE)) { +- CLEAR_INTR; + ... + } diff --git a/parsing_cocci/tests/8.cocci b/parsing_cocci/tests/8.cocci new file mode 100644 index 0000000..8e3587f --- /dev/null +++ b/parsing_cocci/tests/8.cocci @@ -0,0 +1,62 @@ +@@ +filename A; +@@ + +--- a/.../A##.c ++++ b/.../A##.c + ... ++ static struct request_queue A##_queue; + +@@ +local function fn; +identifier X; +@@ + + fn (..., request_queue_t *X, ...) { + <... +- QUEUE ++ X + ...> + } + +@@ +@@ + ++ #define QUEUE(&X) + <... +? QUEUE + ...> + +@@ +@@ + +- BLK_DEFAULT_QUEUE(MAJOR_NR) ++ &A##_queue + +@@ +identifier i; +expression E, Y, Z; +@@ + +( + for (i = 0; i < E; i++) { + ... ++ Y->queue = &A##_queue; + set_capacity(Y, Z); + ... + } + ... + for (i = 0; i < E; i++) { + ... + add_disk(Y); + ... + } +| ++ Y->queue = &A##_queue; + set_capacity(Y, Z); + ... + add_disk(Y); +| ++ Y->queue = &A##_queue; + add_disk(Y); +) diff --git a/parsing_cocci/tests/9.cocci b/parsing_cocci/tests/9.cocci new file mode 100644 index 0000000..bfb57ff --- /dev/null +++ b/parsing_cocci/tests/9.cocci @@ -0,0 +1,45 @@ +@@ +expression E1, E2; +expression X, Y; +@@ + +( +- E1.l1.l1l2 = E2 ++ E1.l2.l1l2 = E2 +| +- E1.l2.l2l1 = E2 ++ E1.l1.l2l1 = E2 +| +- E1.l2.l2l3 = E2 ++ E1.l3.l2l3 = E2 +| +- E1.l3.l3l4 = E2 ++ E1.lli.l3l4 = E2 +| +- E1.l3.l3l2 = E2 ++ E1.l2.l3l2 = E2 +| +- E1.lli.l4l3 = E2 ++ E1.l3.l4l3 = E2 +| +- E1.lli.l4l3_proto = E2 ++ E1.l3.l4l3_proto = E2 +| +- E1->l1.l1l2(E1, X, Y) ++ L1L2(E1, X, Y) +| +- E1->l1.l2l1(E1, X, Y) ++ L2L1(E1, X, Y) +| +- E1->l1.l2l3(E1, X, Y) ++ L2L3(E1, X, Y) +| +- E1->l1.l3l2(E1, X, Y) ++ L3L2(E1, X, Y) +| +- E1->l1.l3l4(E1, X, Y) ++ L3L4(E1, X, Y) +| +- E1->lli.l4l3(E1, X, Y) ++ L4L3(E1, X, Y) +) diff --git a/parsing_cocci/tests/Makefile b/parsing_cocci/tests/Makefile new file mode 100644 index 0000000..27cd8ae --- /dev/null +++ b/parsing_cocci/tests/Makefile @@ -0,0 +1,69 @@ +all: 1.output 2.output 3.output 4.output 5.output 6.output 7.output \ +8.output 9.output 10.output 11.output 12.output 13.output 14.output \ +15.output 16.output 17.output 18.output 19.output 20.output 21.output \ +22.output 23.output 24.output 25.output 26.output 27.output 28.output \ +29.output 30.output + +1.output: 1.cocci ../cocci_parser + ../cocci_parser 1.cocci > 1.output +2.output: 2.cocci ../cocci_parser + ../cocci_parser 2.cocci > 2.output +3.output: 3.cocci ../cocci_parser + ../cocci_parser 3.cocci > 3.output +4.output: 4.cocci ../cocci_parser + ../cocci_parser 4.cocci > 4.output +5.output: 5.cocci ../cocci_parser + ../cocci_parser 5.cocci > 5.output +6.output: 6.cocci ../cocci_parser + ../cocci_parser 6.cocci > 6.output +7.output: 7.cocci ../cocci_parser + ../cocci_parser 7.cocci > 7.output +8.output: 8.cocci ../cocci_parser + ../cocci_parser 8.cocci > 8.output +9.output: 9.cocci ../cocci_parser + ../cocci_parser 9.cocci > 9.output +10.output: 10.cocci ../cocci_parser + ../cocci_parser 10.cocci > 10.output +11.output: 11.cocci ../cocci_parser + ../cocci_parser 11.cocci > 11.output +12.output: 12.cocci ../cocci_parser + ../cocci_parser 12.cocci > 12.output +13.output: 13.cocci ../cocci_parser + ../cocci_parser 13.cocci > 13.output +14.output: 14.cocci ../cocci_parser + ../cocci_parser 14.cocci > 14.output +15.output: 15.cocci ../cocci_parser + ../cocci_parser 15.cocci > 15.output +16.output: 16.cocci ../cocci_parser + ../cocci_parser 16.cocci > 16.output +17.output: 17.cocci ../cocci_parser + ../cocci_parser 17.cocci > 17.output +18.output: 18.cocci ../cocci_parser + ../cocci_parser 18.cocci > 18.output +19.output: 19.cocci ../cocci_parser + ../cocci_parser 19.cocci > 19.output +20.output: 20.cocci ../cocci_parser + ../cocci_parser 20.cocci > 20.output +21.output: 21.cocci ../cocci_parser + ../cocci_parser 21.cocci > 21.output +22.output: 22.cocci ../cocci_parser + ../cocci_parser 22.cocci > 22.output +23.output: 23.cocci ../cocci_parser + ../cocci_parser 23.cocci > 23.output +24.output: 24.cocci ../cocci_parser + ../cocci_parser 24.cocci > 24.output +25.output: 25.cocci ../cocci_parser + ../cocci_parser 25.cocci > 25.output +26.output: 26.cocci ../cocci_parser + ../cocci_parser 26.cocci > 26.output +27.output: 27.cocci ../cocci_parser + ../cocci_parser 27.cocci > 27.output +28.output: 28.cocci ../cocci_parser + ../cocci_parser 28.cocci > 28.output +29.output: 29.cocci ../cocci_parser + ../cocci_parser 29.cocci > 29.output +30.output: 30.cocci ../cocci_parser + ../cocci_parser 30.cocci > 30.output + +clean: + /bin/rm ?.output ??.output diff --git a/parsing_cocci/tests/problems b/parsing_cocci/tests/problems new file mode 100644 index 0000000..fdf6330 --- /dev/null +++ b/parsing_cocci/tests/problems @@ -0,0 +1,61 @@ +1.cocci: ok + +2.cocci: ok + +3.cocci: ok + +4.cocci: ok + +5.cocci: ok + +6.cocci: how to specify that there is no while loop around some code? + +7.cocci: ok + +8.cocci: don't allow a metavariable to be declared as filename, don't + support filename - and + syntax + +9.cocci: ok + +10.cocci: ok + +11.cocci: don't allow structure declarations; don't allow mixing top-level + declarations and statement nests + +12.cocci: ok + +13.cocci: ok + +14.cocci: don't allow ( | ) on a function header (up to { ) + +15.cocci: ok + +16.cocci: ok + +17.cocci: don't allow ( | ) with only + fragments + +18.cocci: ok + +19.cocci: ok + +20.cocci: ok + +21.cocci: ok + +22.cocci: ok + +23.cocci: rule not yet written + +24.cocci: rule not yet written + +25.cocci: ok + +26.cocci: ok + +27.cocci: ok + +28.cocci: ok + +29.cocci: ok + +30.cocci: ok \ No newline at end of file diff --git a/parsing_cocci/top_level.ml b/parsing_cocci/top_level.ml new file mode 100644 index 0000000..c52c7a7 --- /dev/null +++ b/parsing_cocci/top_level.ml @@ -0,0 +1,98 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* Reorganize the top level of a rule to be a list of either top-level +declarations or code dots. A function declaration is always considered top +level. A statement is always considered code dots. A variable declaration +is ambiguous. We use the heuristic that if there are code dots somewhere +else, then the variable declaration is at top level, otherwise it applies +both at top level and to all code. *) + +(* This is assumed to be done before compute_lines, and thus the info on a +complex term is assumed to be Ast0.default_info *) + +module Ast0 = Ast0_cocci + +let top_dots l = + let circle x = + match Ast0.unwrap x with Ast0.Circles(_) -> true | _ -> false in + let star x = + match Ast0.unwrap x with Ast0.Stars(_) -> true | _ -> false in + if List.exists circle l + then Ast0.wrap (Ast0.CIRCLES(l)) + else if List.exists star l + then Ast0.wrap (Ast0.STARS(l)) + else Ast0.wrap (Ast0.DOTS(l)) + +let scan_code l = + let statements = ref false in + let rec loop = function + [] -> ([],[]) + | (x::xs) as all -> + (match Ast0.unwrap x with + (Ast0.OTHER(code)) -> + (match Ast0.unwrap code with + Ast0.Decl(_) -> + let (front,rest) = loop xs in + (code::front,rest) + | _ -> + statements := true; + let (front,rest) = loop xs in + (code::front,rest)) + | _ -> ([],all)) in + match loop l with + ([],_) as res -> res + | (code,rest) -> + if !statements = true + then ([Ast0.wrap(Ast0.CODE(top_dots code))],rest) + else + (List.map + (function d -> + match Ast0.unwrap d with + Ast0.Decl(bef,x) -> Ast0.wrap (Ast0.DECL(d)) + | _ -> failwith "impossible") + code, + rest) + +let rec scan_top_decl = function + [] -> ([],[]) + | ((topdecl::rest) as all) -> + (match Ast0.unwrap topdecl with + Ast0.OTHER(_) -> ([],all) + | _ -> let (front,rest) = scan_top_decl rest in (topdecl::front,rest)) + +(* for debugging *) +let l2c l = + match Ast0.unwrap l with + Ast0.DECL(_) -> "decl" + | Ast0.CODE(_) -> "code" + | Ast0.FILEINFO(_,_) -> "fileinfo" + | Ast0.ERRORWORDS(_) -> "errorwords" + | Ast0.OTHER(_) -> "other" + +let rec top_level l = + match scan_code l with + (code,[]) -> code + | (code,rest) -> + (match scan_top_decl rest with + (top_decls,[]) -> code@top_decls + | (top_decls,rest) -> code @ top_decls @ (top_level rest)) diff --git a/parsing_cocci/top_level.mli b/parsing_cocci/top_level.mli new file mode 100644 index 0000000..1829d3e --- /dev/null +++ b/parsing_cocci/top_level.mli @@ -0,0 +1 @@ +val top_level : Ast0_cocci.rule -> Ast0_cocci.rule diff --git a/parsing_cocci/type_cocci.ml b/parsing_cocci/type_cocci.ml new file mode 100644 index 0000000..c702dc5 --- /dev/null +++ b/parsing_cocci/type_cocci.ml @@ -0,0 +1,117 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* for metavariables in general, but here because needed for metatypes *) +type inherited = bool (* true if inherited *) +type keep_binding = Unitary (* need no info *) + | Nonunitary (* need an env entry *) | Saved (* need a witness *) + +type typeC = + ConstVol of const_vol * typeC + | BaseType of baseType * sign option + | Pointer of typeC + | FunctionPointer of typeC (* only return type *) + | Array of typeC (* drop size info *) + | StructUnionName of structUnion * bool (* true if a metaId *) * string + | TypeName of string + | MetaType of (string * string) * keep_binding * inherited + | Unknown (* for metavariables of type expression *^* *) + +and tagged_string = string + +and baseType = VoidType | CharType | ShortType | IntType | DoubleType +| FloatType | LongType | BoolType + +and structUnion = Struct | Union + +and sign = Signed | Unsigned + +and const_vol = Const | Volatile + +(* --------------------------------------------------------------------- *) +(* Printer *) +open Format + +let rec typeC = function + ConstVol(cv,ty) -> const_vol cv; typeC ty + | BaseType(ty,None) -> baseType ty + | BaseType(ty,Some sgn) -> sign sgn; baseType ty + | Pointer(ty) -> typeC ty; print_string "*" + | FunctionPointer(ty) -> typeC ty; print_string "(*)(...)" + | Array(ty) -> typeC ty; print_string "[] " + | StructUnionName(kind,mv,name) -> + structUnion kind; print_string name; print_string " " + | TypeName(name) -> print_string name; print_string " " + | MetaType((rule,name),keep,inherited) -> + print_string "<"; print_string name; print_string ">"; print_string " "; + (* + let print_unitary = function + Unitary -> print_string "unitary" + | Nonunitary -> print_string "nonunitary" + | Saved -> print_string "saved" in + print_string "/* "; + print_string "keep:"; print_unitary keep; + print_string " inherited:"; print_bool inherited; + print_string " */" + *) + | Unknown -> print_string "unknown " + +and baseType = function + VoidType -> print_string "void " + | CharType -> print_string "char " + | ShortType -> print_string "short " + | IntType -> print_string "int " + | DoubleType -> print_string "double " + | FloatType -> print_string "float " + | LongType -> print_string "long " + | BoolType -> print_string "bool " + +and structUnion = function + Struct -> print_string "struct " + | Union -> print_string "union " + +and sign = function + Signed -> print_string "signed " + | Unsigned -> print_string "unsigned " + +and const_vol = function + Const -> print_string "const " + | Volatile -> print_string "volatile " + +(* t1 should be less informative than t1, eg t1 = Pointer(Unknown) and t2 = +Pointer(int) *) +(* only used in iso *) +(* needs to do something for MetaType *) +let compatible t1 = function + None -> t1 = Unknown + | Some t2 -> + let rec loop = function + (Unknown,_) -> true + | (ConstVol(cv1,ty1),ConstVol(cv2,ty2)) when cv1 = cv2 -> + loop(ty1,ty2) + | (Pointer(ty1),Pointer(ty2)) -> loop(ty1,ty2) + | (FunctionPointer(ty1),_) -> false (* not enough info *) + | (_,FunctionPointer(ty2)) -> false (* not enough info *) + | (Array(ty1),Array(ty2)) -> loop(ty1,ty2) + | (_,_) -> t1=t2 in + loop (t1,t2) + diff --git a/parsing_cocci/type_cocci.mli b/parsing_cocci/type_cocci.mli new file mode 100644 index 0000000..2a8c3d2 --- /dev/null +++ b/parsing_cocci/type_cocci.mli @@ -0,0 +1,29 @@ +type inherited = bool (* true if inherited *) +type keep_binding = Unitary (* need no info *) + | Nonunitary (* need an env entry *) | Saved (* need a witness *) + +type typeC = + ConstVol of const_vol * typeC + | BaseType of baseType * sign option + | Pointer of typeC + | FunctionPointer of typeC (* only return type *) + | Array of typeC (* drop size info *) + | StructUnionName of structUnion * bool (* true if type metavar *) * string + | TypeName of string + | MetaType of (string * string) * keep_binding * inherited + | Unknown (* for metavariables of type expression *^* *) + +and tagged_string = string + +and baseType = VoidType | CharType | ShortType | IntType | DoubleType +| FloatType | LongType | BoolType + +and structUnion = Struct | Union + +and sign = Signed | Unsigned + +and const_vol = Const | Volatile + +val typeC : typeC -> unit + +val compatible : typeC -> typeC option -> bool diff --git a/parsing_cocci/type_infer.ml b/parsing_cocci/type_infer.ml new file mode 100644 index 0000000..7ae9f85 --- /dev/null +++ b/parsing_cocci/type_infer.ml @@ -0,0 +1,356 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module T = Type_cocci +module Ast = Ast_cocci +module Ast0 = Ast0_cocci +module V0 = Visitor_ast0 + +(* Type inference: +Just propagates information based on declarations. Could try to infer +more precise information about expression metavariables, but not sure it is +worth it. The most obvious goal is to distinguish between test expressions +that have pointer, integer, and boolean type when matching isomorphisms, +but perhaps other needs will become apparent. *) + +(* "functions" that return a boolean value *) +let bool_functions = ["likely";"unlikely"] + +let err wrapped ty s = + T.typeC ty; Format.print_newline(); + failwith (Printf.sprintf "line %d: %s" (Ast0.get_line wrapped) s) + +type id = Id of string | Meta of (string * string) + +let rec lub_type t1 t2 = + match (t1,t2) with + (None,None) -> None + | (None,Some t) -> t2 + | (Some t,None) -> t1 + | (Some t1,Some t2) -> + let rec loop = function + (T.Unknown,t2) -> t2 + | (t1,T.Unknown) -> t1 + | (T.ConstVol(cv1,ty1),T.ConstVol(cv2,ty2)) when cv1 = cv2 -> + T.ConstVol(cv1,loop(ty1,ty2)) + | (T.Pointer(ty1),T.Pointer(ty2)) -> + T.Pointer(loop(ty1,ty2)) + | (ty1,T.Pointer(ty2)) -> T.Pointer(ty2) + | (T.Pointer(ty1),ty2) -> T.Pointer(ty1) + | (T.Array(ty1),T.Array(ty2)) -> T.Array(loop(ty1,ty2)) + | (T.TypeName(s1),t2) -> t2 + | (t1,T.TypeName(s1)) -> t1 + | (t1,_) -> t1 in (* arbitrarily pick the first, assume type correct *) + Some (loop (t1,t2)) + +let lub_envs envs = + List.fold_left + (function acc -> + function env -> + List.fold_left + (function acc -> + function (var,ty) -> + let (relevant,irrelevant) = + List.partition (function (x,_) -> x = var) acc in + match relevant with + [] -> (var,ty)::acc + | [(x,ty1)] -> + (match lub_type (Some ty) (Some ty1) with + Some new_ty -> (var,new_ty)::irrelevant + | None -> irrelevant) + | _ -> failwith "bad type environment") + acc env) + [] envs + +let rec propagate_types env = + let option_default = None in + let bind x y = option_default in (* no generic way of combining types *) + + let mcode x = option_default in + + let ident r k i = + match Ast0.unwrap i with + Ast0.Id(id) -> + (try Some(List.assoc (Id(Ast0.unwrap_mcode id)) env) + with Not_found -> None) + | Ast0.MetaId(id,_,_) -> + (try Some(List.assoc (Meta(Ast0.unwrap_mcode id)) env) + with Not_found -> None) + | _ -> k i in + + let strip_cv = function + Some (T.ConstVol(_,t)) -> Some t + | t -> t in + + let expression r k e = + let res = k e in + let ty = + match Ast0.unwrap e with + Ast0.Ident(id) -> Ast0.set_type e res; res + | Ast0.Constant(const) -> + (match Ast0.unwrap_mcode const with + Ast.String(_) -> Some (T.Pointer(T.BaseType(T.CharType,None))) + | Ast.Char(_) -> Some (T.BaseType(T.CharType,None)) + | Ast.Int(_) -> Some (T.BaseType(T.IntType,None)) + | Ast.Float(_) -> Some (T.BaseType(T.FloatType,None))) + | Ast0.FunCall(fn,lp,args,rp) -> + (match Ast0.get_type fn with + Some (T.FunctionPointer(ty)) -> Some ty + | _ -> + (match Ast0.unwrap fn with + Ast0.Ident(id) -> + (match Ast0.unwrap id with + Ast0.Id(id) -> + if List.mem (Ast0.unwrap_mcode id) bool_functions + then Some(T.BaseType(T.BoolType,None)) + else None + | _ -> None) + | _ -> None)) + | Ast0.Assignment(exp1,op,exp2,_) -> + let ty = lub_type (Ast0.get_type exp1) (Ast0.get_type exp2) in + Ast0.set_type exp1 ty; Ast0.set_type exp2 ty; ty + | Ast0.CondExpr(exp1,why,Some exp2,colon,exp3) -> + let ty = lub_type (Ast0.get_type exp2) (Ast0.get_type exp3) in + Ast0.set_type exp2 ty; Ast0.set_type exp3 ty; ty + | Ast0.CondExpr(exp1,why,None,colon,exp3) -> Ast0.get_type exp3 + | Ast0.Postfix(exp,op) | Ast0.Infix(exp,op) -> (* op is dec or inc *) + Ast0.get_type exp + | Ast0.Unary(exp,op) -> + (match Ast0.unwrap_mcode op with + Ast.GetRef -> + (match Ast0.get_type exp with + None -> Some (T.Pointer(T.Unknown)) + | Some t -> Some (T.Pointer(t))) + | Ast.DeRef -> + (match Ast0.get_type exp with + Some (T.Pointer(t)) -> Some t + | _ -> None) + | Ast.UnPlus -> Ast0.get_type exp + | Ast.UnMinus -> Ast0.get_type exp + | Ast.Tilde -> Ast0.get_type exp + | Ast.Not -> Some(T.BaseType(T.BoolType,None))) + | Ast0.Nested(exp1,op,exp2) -> failwith "nested in type inf not possible" + | Ast0.Binary(exp1,op,exp2) -> + let ty1 = Ast0.get_type exp1 in + let ty2 = Ast0.get_type exp2 in + let same_type = function + (None,None) -> Some (T.BaseType(T.IntType,None)) + | (Some (T.Pointer ty1),Some ty2) -> + Some (T.Pointer ty1) + | (Some ty1,Some (T.Pointer ty2)) -> + Some (T.Pointer ty2) + | (t1,t2) -> + let ty = lub_type t1 t2 in + Ast0.set_type exp1 ty; Ast0.set_type exp2 ty; ty in + (match Ast0.unwrap_mcode op with + Ast.Arith(op) -> same_type (ty1, ty2) + | Ast.Logical(op) -> + let ty = lub_type ty1 ty2 in + Ast0.set_type exp1 ty; Ast0.set_type exp2 ty; + Some(T.BaseType(T.BoolType,None))) + | Ast0.Paren(lp,exp,rp) -> Ast0.get_type exp + | Ast0.ArrayAccess(exp1,lb,exp2,rb) -> + (match strip_cv (Ast0.get_type exp2) with + None -> Ast0.set_type exp2 (Some(T.BaseType(T.IntType,None))) + | Some(T.BaseType(T.IntType,None)) -> () + | Some (T.MetaType(_,_,_)) -> () + | Some (T.TypeName _) -> () + | Some ty -> err exp2 ty "bad type for an array index"); + (match strip_cv (Ast0.get_type exp1) with + None -> None + | Some (T.Array(ty)) -> Some ty + | Some (T.Pointer(ty)) -> Some ty + | Some (T.MetaType(_,_,_)) -> None + | Some x -> err exp1 x "ill-typed array reference") + | Ast0.RecordAccess(exp,pt,field) -> + (match strip_cv (Ast0.get_type exp) with + None -> None + | Some (T.StructUnionName(_,_,_)) -> None + | Some (T.TypeName(_)) -> None + | Some (T.MetaType(_,_,_)) -> None + | Some x -> err exp x "non-structure type in field ref") + | Ast0.RecordPtAccess(exp,ar,field) -> + (match strip_cv (Ast0.get_type exp) with + None -> None + | Some (T.Pointer(t)) -> + (match strip_cv (Some t) with + | Some (T.Unknown) -> None + | Some (T.MetaType(_,_,_)) -> None + | Some (T.TypeName(_)) -> None + | Some (T.StructUnionName(_,_,_)) -> None + | Some x -> + err exp (T.Pointer(t)) + "non-structure pointer type in field ref" + | _ -> failwith "not possible") + | Some (T.MetaType(_,_,_)) -> None + | Some (T.TypeName(_)) -> None + | Some x -> err exp x "non-structure pointer type in field ref") + | Ast0.Cast(lp,ty,rp,exp) -> Some(Ast0.ast0_type_to_type ty) + | Ast0.SizeOfExpr(szf,exp) -> Some(T.BaseType(T.IntType,None)) + | Ast0.SizeOfType(szf,lp,ty,rp) -> Some(T.BaseType(T.IntType,None)) + | Ast0.TypeExp(ty) -> None + | Ast0.MetaErr(name,_,_) -> None + | Ast0.MetaExpr(name,_,Some [ty],_,_) -> Some ty + | Ast0.MetaExpr(name,_,ty,_,_) -> None + | Ast0.MetaExprList(name,_,_) -> None + | Ast0.EComma(cm) -> None + | Ast0.DisjExpr(_,exp_list,_,_) -> + let types = List.map Ast0.get_type exp_list in + let combined = List.fold_left lub_type None types in + (match combined with + None -> None + | Some t -> + List.iter (function e -> Ast0.set_type e (Some t)) exp_list; + Some t) + | Ast0.NestExpr(starter,expr_dots,ender,None,multi) -> + let _ = r.V0.combiner_expression_dots expr_dots in None + | Ast0.NestExpr(starter,expr_dots,ender,Some e,multi) -> + let _ = r.V0.combiner_expression_dots expr_dots in + let _ = r.V0.combiner_expression e in None + | Ast0.Edots(_,None) | Ast0.Ecircles(_,None) | Ast0.Estars(_,None) -> + None + | Ast0.Edots(_,Some e) | Ast0.Ecircles(_,Some e) + | Ast0.Estars(_,Some e) -> + let _ = r.V0.combiner_expression e in None + | Ast0.OptExp(exp) -> Ast0.get_type exp + | Ast0.UniqueExp(exp) -> Ast0.get_type exp in + Ast0.set_type e ty; + ty in + + let donothing r k e = k e in + + let rec strip id = + match Ast0.unwrap id with + Ast0.Id(name) -> Id(Ast0.unwrap_mcode name) + | Ast0.MetaId(name,_,_) -> Meta(Ast0.unwrap_mcode name) + | Ast0.MetaFunc(name,_,_) -> Meta(Ast0.unwrap_mcode name) + | Ast0.MetaLocalFunc(name,_,_) -> Meta(Ast0.unwrap_mcode name) + | Ast0.OptIdent(id) -> strip id + | Ast0.UniqueIdent(id) -> strip id in + + let process_whencode notfn allfn = function + Ast0.WhenNot(x) -> let _ = notfn x in () + | Ast0.WhenAlways(x) -> let _ = allfn x in () + | Ast0.WhenModifier(_) -> () in + + (* assume that all of the declarations are at the beginning of a statement + list, which is required by C, but not actually required by the cocci + parser *) + let rec process_statement_list r acc = function + [] -> acc + | (s::ss) -> + (match Ast0.unwrap s with + Ast0.Decl(_,decl) -> + let rec process_decl decl = + match Ast0.unwrap decl with + Ast0.Init(_,ty,id,_,exp,_) -> + let _ = + (propagate_types acc).V0.combiner_initialiser exp in + [(strip id,Ast0.ast0_type_to_type ty)] + | Ast0.UnInit(_,ty,id,_) -> + [(strip id,Ast0.ast0_type_to_type ty)] + | Ast0.MacroDecl(_,_,_,_,_) -> [] + | Ast0.TyDecl(ty,_) -> [] + | Ast0.Typedef(_,_,_,_) -> [] + | Ast0.DisjDecl(_,disjs,_,_) -> + List.concat(List.map process_decl disjs) + | Ast0.Ddots(_,_) -> [] (* not in a statement list anyway *) + | Ast0.OptDecl(decl) -> process_decl decl + | Ast0.UniqueDecl(decl) -> process_decl decl in + let new_acc = (process_decl decl)@acc in + process_statement_list r new_acc ss + | Ast0.Dots(_,wc) -> + List.iter + (process_whencode r.V0.combiner_statement_dots + r.V0.combiner_statement) + wc; + process_statement_list r acc ss + | Ast0.Disj(_,statement_dots_list,_,_) -> + let new_acc = + lub_envs + (List.map + (function x -> process_statement_list r acc (Ast0.undots x)) + statement_dots_list) in + process_statement_list r new_acc ss + | _ -> + let _ = (propagate_types acc).V0.combiner_statement s in + process_statement_list r acc ss) in + + let statement_dots r k d = + match Ast0.unwrap d with + Ast0.DOTS(l) | Ast0.CIRCLES(l) | Ast0.STARS(l) -> + let _ = process_statement_list r env l in option_default in + let statement r k s = + match Ast0.unwrap s with + Ast0.FunDecl(_,fninfo,name,lp,params,rp,lbrace,body,rbrace) -> + let rec get_binding p = + match Ast0.unwrap p with + Ast0.Param(ty,Some id) -> + [(strip id,Ast0.ast0_type_to_type ty)] + | Ast0.OptParam(param) -> get_binding param + | _ -> [] in + let fenv = List.concat (List.map get_binding (Ast0.undots params)) in + (propagate_types (fenv@env)).V0.combiner_statement_dots body + | Ast0.IfThen(_,_,exp,_,_,_) | Ast0.IfThenElse(_,_,exp,_,_,_,_,_) + | Ast0.While(_,_,exp,_,_,_) | Ast0.Do(_,_,_,_,exp,_,_) + | Ast0.For(_,_,_,_,Some exp,_,_,_,_,_) | Ast0.Switch(_,_,exp,_,_,_,_) -> + let _ = k s in + let rec process_test exp = + match (Ast0.unwrap exp,Ast0.get_type exp) with + (Ast0.Edots(_,_),_) -> None + | (Ast0.NestExpr(_,_,_,_,_),_) -> None + | (Ast0.MetaExpr(_,_,_,_,_),_) -> + (* if a type is known, it is specified in the decl *) + None + | (Ast0.Paren(lp,exp,rp),None) -> process_test exp + | (_,None) -> Some (T.BaseType(T.IntType,None)) + | _ -> None in + let new_expty = process_test exp in + (match new_expty with + None -> () (* leave things as they are *) + | Some ty -> Ast0.set_type exp new_expty); + None + | _ -> k s + + and case_line r k c = + match Ast0.unwrap c with + Ast0.Default(def,colon,code) -> let _ = k c in None + | Ast0.Case(case,exp,colon,code) -> + let _ = k c in + (match Ast0.get_type exp with + None -> Ast0.set_type exp (Some (T.BaseType(T.IntType,None))) + | _ -> ()); + None + | Ast0.OptCase(case) -> k c in + + V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing statement_dots donothing donothing + ident expression donothing donothing donothing donothing statement + case_line donothing + +let type_infer code = + let prop = propagate_types [(Id("NULL"),T.Pointer(T.Unknown))] in + let fn = prop.V0.combiner_top_level in + let _ = List.map fn code in + () diff --git a/parsing_cocci/type_infer.mli b/parsing_cocci/type_infer.mli new file mode 100644 index 0000000..796c6c7 --- /dev/null +++ b/parsing_cocci/type_infer.mli @@ -0,0 +1 @@ +val type_infer : Ast0_cocci.rule -> unit diff --git a/parsing_cocci/unify_ast.ml b/parsing_cocci/unify_ast.ml new file mode 100644 index 0000000..a32476b --- /dev/null +++ b/parsing_cocci/unify_ast.ml @@ -0,0 +1,565 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* --------------------------------------------------------------------- *) +(* Given two patterns, A and B, determine whether B can match any matched +subterms of A. For simplicity, this doesn't maintain an environment; it +just assume metavariables match. Thus the result is either NO or MAYBE. *) + +module Ast = Ast_cocci +module V = Visitor_ast + +(* --------------------------------------------------------------------- *) + +type res = NO | MAYBE + +let return b = if b then MAYBE else NO + +let unify_mcode (x,_,_,_) (y,_,_,_) = x = y + +let unify_option f t1 t2 = + match (t1,t2) with + (Some t1, Some t2) -> f t1 t2 + | (None, None) -> return true + | _ -> return false + +let unify_true_option f t1 t2 = + match (t1,t2) with + (Some t1, Some t2) -> f t1 t2 + | (None, None) -> return true + | _ -> return true + +let bool_unify_option f t1 t2 = + match (t1,t2) with + (Some t1, Some t2) -> f t1 t2 + | (None, None) -> true + | _ -> false + +let conjunct_bindings b1 b2 = + match b1 with NO -> b1 | MAYBE -> b2 + +let disjunct_bindings b1 b2 = + match b1 with MAYBE -> b1 | NO -> b2 + +let disjunct_all_bindings = List.fold_left disjunct_bindings NO + +(* --------------------------------------------------------------------- *) + +(* compute the common prefix. if in at least one case, this ends with the +end of the pattern or a ..., then return true. *) + +let unify_lists fn dfn la lb = + let rec loop = function + ([],_) | (_,[]) -> return true + | (cura::resta,curb::restb) -> + (match fn cura curb with + MAYBE -> loop (resta,restb) + | NO -> if dfn cura or dfn curb then MAYBE else NO) in + loop (la,lb) + +let unify_dots fn dfn d1 d2 = + match (Ast.unwrap d1,Ast.unwrap d2) with + (Ast.DOTS(l1),Ast.DOTS(l2)) + | (Ast.CIRCLES(l1),Ast.CIRCLES(l2)) + | (Ast.STARS(l1),Ast.STARS(l2)) -> unify_lists fn dfn l1 l2 + | _ -> return false + +let edots e = + match Ast.unwrap e with + Ast.Edots(_,_) | Ast.Ecircles(_,_) | Ast.Estars(_,_) -> true + | _ -> false + +let ddots e = + match Ast.unwrap e with + Ast.Ddots(_,_) -> true + | _ -> false + +let pdots p = + match Ast.unwrap p with + Ast.Pdots(_) | Ast.Pcircles(_) -> true + | _ -> false + +let dpdots e = + match Ast.unwrap e with + Ast.DPdots(_) | Ast.DPcircles(_) -> true + | _ -> false + +let sdots s = + match Ast.unwrap s with + Ast.Dots(_,_,_,_) | Ast.Circles(_,_,_,_) | Ast.Stars(_,_,_,_) -> true + | _ -> false + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +and unify_ident i1 i2 = + match (Ast.unwrap i1,Ast.unwrap i2) with + (Ast.Id(i1),Ast.Id(i2)) -> return (unify_mcode i1 i2) + + | (Ast.MetaId(_,_,_,_),_) + | (Ast.MetaFunc(_,_,_,_),_) + | (Ast.MetaLocalFunc(_,_,_,_),_) + | (_,Ast.MetaId(_,_,_,_)) + | (_,Ast.MetaFunc(_,_,_,_)) + | (_,Ast.MetaLocalFunc(_,_,_,_)) -> return true + + | (Ast.OptIdent(_),_) + | (Ast.UniqueIdent(_),_) + | (_,Ast.OptIdent(_)) + | (_,Ast.UniqueIdent(_)) -> failwith "unsupported ident" + +(* --------------------------------------------------------------------- *) +(* Expression *) + +let rec unify_expression e1 e2 = + match (Ast.unwrap e1,Ast.unwrap e2) with + (Ast.Ident(i1),Ast.Ident(i2)) -> unify_ident i1 i2 + | (Ast.Constant(c1),Ast.Constant(c2))-> return (unify_mcode c1 c2) + | (Ast.FunCall(f1,lp1,args1,rp1),Ast.FunCall(f2,lp2,args2,rp2)) -> + conjunct_bindings + (unify_expression f1 f2) + (unify_dots unify_expression edots args1 args2) + | (Ast.Assignment(l1,op1,r1,_),Ast.Assignment(l2,op2,r2,_)) -> + if unify_mcode op1 op2 + then conjunct_bindings (unify_expression l1 l2) (unify_expression r1 r2) + else return false + | (Ast.CondExpr(tst1,q1,thn1,c1,els1),Ast.CondExpr(tst2,q2,thn2,c2,els2)) -> + conjunct_bindings (unify_expression tst1 tst2) + (conjunct_bindings (unify_option unify_expression thn1 thn2) + (unify_expression els1 els2)) + | (Ast.Postfix(e1,op1),Ast.Postfix(e2,op2)) -> + if unify_mcode op1 op2 then unify_expression e1 e2 else return false + | (Ast.Infix(e1,op1),Ast.Infix(e2,op2)) -> + if unify_mcode op1 op2 then unify_expression e1 e2 else return false + | (Ast.Unary(e1,op1),Ast.Unary(e2,op2)) -> + if unify_mcode op1 op2 then unify_expression e1 e2 else return false + | (Ast.Binary(l1,op1,r1),Ast.Binary(l2,op2,r2)) -> + if unify_mcode op1 op2 + then conjunct_bindings (unify_expression l1 l2) (unify_expression r1 r2) + else return false + | (Ast.ArrayAccess(ar1,lb1,e1,rb1),Ast.ArrayAccess(ar2,lb2,e2,rb2)) -> + conjunct_bindings (unify_expression ar1 ar2) (unify_expression e1 e2) + | (Ast.RecordAccess(e1,d1,fld1),Ast.RecordAccess(e2,d2,fld2)) -> + conjunct_bindings (unify_expression e1 e2) (unify_ident fld1 fld2) + | (Ast.RecordPtAccess(e1,pt1,fld1),Ast.RecordPtAccess(e2,pt2,fld2)) -> + conjunct_bindings (unify_expression e1 e2) (unify_ident fld1 fld2) + | (Ast.Cast(lp1,ty1,rp1,e1),Ast.Cast(lp2,ty2,rp2,e2)) -> + conjunct_bindings (unify_fullType ty1 ty2) (unify_expression e1 e2) + | (Ast.SizeOfExpr(szf1,e1),Ast.SizeOfExpr(szf2,e2)) -> + unify_expression e1 e2 + | (Ast.SizeOfType(szf1,lp1,ty1,rp1),Ast.SizeOfType(szf2,lp2,ty2,rp2)) -> + unify_fullType ty1 ty2 + | (Ast.TypeExp(ty1),Ast.TypeExp(ty2)) -> unify_fullType ty1 ty2 + | (Ast.Paren(lp1,e1,rp1),Ast.Paren(lp2,e2,rp2)) -> + unify_expression e1 e2 + + | (Ast.MetaErr(_,_,_,_),_) + | (Ast.MetaExpr(_,_,_,_,_,_),_) + | (Ast.MetaExprList(_,_,_,_),_) + | (_,Ast.MetaErr(_,_,_,_)) + | (_,Ast.MetaExpr(_,_,_,_,_,_)) + | (_,Ast.MetaExprList(_,_,_,_)) -> return true + + | (Ast.EComma(cm1),Ast.EComma(cm2)) -> return true + + | (Ast.DisjExpr(e1),_) -> + disjunct_all_bindings (List.map (function x -> unify_expression x e2) e1) + | (_,Ast.DisjExpr(e2)) -> + disjunct_all_bindings (List.map (function x -> unify_expression e1 x) e2) + | (Ast.NestExpr(e1,_,_),Ast.NestExpr(e2,_,_)) -> + unify_dots unify_expression edots e1 e2 + + (* dots can match against anything. return true to be safe. *) + | (Ast.Edots(_,_),_) | (_,Ast.Edots(_,_)) + | (Ast.Ecircles(_,_),_) | (_,Ast.Ecircles(_,_)) + | (Ast.Estars(_,_),_) | (_,Ast.Estars(_,_)) -> return true + + | (Ast.OptExp(_),_) + | (Ast.UniqueExp(_),_) + | (_,Ast.OptExp(_)) + | (_,Ast.UniqueExp(_)) -> failwith "unsupported expression" + | _ -> return false + +(* --------------------------------------------------------------------- *) +(* Types *) + +and unify_fullType ft1 ft2 = + match (Ast.unwrap ft1,Ast.unwrap ft2) with + (Ast.Type(cv1,ty1),Ast.Type(cv2,ty2)) -> + if bool_unify_option unify_mcode cv1 cv2 + then unify_typeC ty1 ty2 + else return false + | (Ast.DisjType(ft1),_) -> + disjunct_all_bindings (List.map (function x -> unify_fullType x ft2) ft1) + | (_,Ast.DisjType(ft2)) -> + disjunct_all_bindings (List.map (function x -> unify_fullType ft1 x) ft2) + + | (Ast.OptType(_),_) + | (Ast.UniqueType(_),_) + | (_,Ast.OptType(_)) + | (_,Ast.UniqueType(_)) -> failwith "unsupported type" + +and unify_typeC t1 t2 = + match (Ast.unwrap t1,Ast.unwrap t2) with + (Ast.BaseType(ty1,sgn1),Ast.BaseType(ty2,sgn2)) -> + return (unify_mcode ty1 ty2 && bool_unify_option unify_mcode sgn1 sgn2) + | (Ast.ImplicitInt(sgn1),Ast.ImplicitInt(sgn2)) -> + return (unify_mcode sgn1 sgn2) + | (Ast.Pointer(ty1,s1),Ast.Pointer(ty2,s2)) -> unify_fullType ty1 ty2 + | (Ast.FunctionPointer(tya,lp1a,stara,rp1a,lp2a,paramsa,rp2a), + Ast.FunctionPointer(tyb,lp1b,starb,rp1b,lp2b,paramsb,rp2b)) -> + if List.for_all2 unify_mcode + [lp1a;stara;rp1a;lp2a;rp2a] [lp1b;starb;rp1b;lp2b;rp2b] + then + conjunct_bindings (unify_fullType tya tyb) + (unify_dots unify_parameterTypeDef pdots paramsa paramsb) + else return false + | (Ast.FunctionType(_,tya,lp1a,paramsa,rp1a), + Ast.FunctionType(_,tyb,lp1b,paramsb,rp1b)) -> + if List.for_all2 unify_mcode [lp1a;rp1a] [lp1b;rp1b] + then + conjunct_bindings (unify_option unify_fullType tya tyb) + (unify_dots unify_parameterTypeDef pdots paramsa paramsb) + else return false + | (Ast.FunctionType _ , _) -> failwith "not supported" + | (Ast.Array(ty1,lb1,e1,rb1),Ast.Array(ty2,lb2,e2,rb2)) -> + conjunct_bindings + (unify_fullType ty1 ty2) (unify_option unify_expression e1 e2) + | (Ast.StructUnionName(s1,Some ts1),Ast.StructUnionName(s2,Some ts2)) -> + if unify_mcode s1 s2 then unify_ident ts1 ts2 else return false + | (Ast.StructUnionName(s1,None),Ast.StructUnionName(s2,None)) -> + return true + | (Ast.StructUnionDef(ty1,lb1,decls1,rb1), + Ast.StructUnionDef(ty2,lb2,decls2,rb2)) -> + conjunct_bindings (unify_fullType ty1 ty2) + (unify_dots unify_declaration ddots decls1 decls2) + | (Ast.TypeName(t1),Ast.TypeName(t2)) -> return (unify_mcode t1 t2) + + | (Ast.MetaType(_,_,_),_) + | (_,Ast.MetaType(_,_,_)) -> return true + | _ -> return false + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +and unify_declaration d1 d2 = + match (Ast.unwrap d1,Ast.unwrap d2) with + (Ast.Init(stg1,ft1,id1,eq1,i1,s1),Ast.Init(stg2,ft2,id2,eq2,i2,s2)) -> + if bool_unify_option unify_mcode stg1 stg2 + then + conjunct_bindings (unify_fullType ft1 ft2) + (conjunct_bindings (unify_ident id1 id2) (unify_initialiser i1 i2)) + else return false + | (Ast.UnInit(stg1,ft1,id1,s1),Ast.UnInit(stg2,ft2,id2,s2)) -> + if bool_unify_option unify_mcode stg1 stg2 + then conjunct_bindings (unify_fullType ft1 ft2) (unify_ident id1 id2) + else return false + | (Ast.MacroDecl(n1,lp1,args1,rp1,sem1), + Ast.MacroDecl(n2,lp2,args2,rp2,sem2)) -> + conjunct_bindings (unify_ident n1 n2) + (unify_dots unify_expression edots args1 args2) + | (Ast.TyDecl(ft1,s1),Ast.TyDecl(ft2,s2)) -> unify_fullType ft1 ft2 + | (Ast.Typedef(stg1,ft1,id1,s1),Ast.Typedef(stg2,ft2,id2,s2)) -> + conjunct_bindings (unify_fullType ft1 ft2) (unify_typeC id1 id2) + | (Ast.DisjDecl(d1),_) -> + disjunct_all_bindings + (List.map (function x -> unify_declaration x d2) d1) + | (_,Ast.DisjDecl(d2)) -> + disjunct_all_bindings + (List.map (function x -> unify_declaration d1 x) d2) + (* dots can match against anything. return true to be safe. *) + | (Ast.Ddots(_,_),_) | (_,Ast.Ddots(_,_)) -> return true + + | (Ast.OptDecl(_),_) + | (Ast.UniqueDecl(_),_) + | (_,Ast.OptDecl(_)) + | (_,Ast.UniqueDecl(_)) -> failwith "unsupported decl" + | _ -> return false + +(* --------------------------------------------------------------------- *) +(* Initializer *) + +and unify_initialiser i1 i2 = + match (Ast.unwrap i1,Ast.unwrap i2) with + (Ast.InitExpr(expa),Ast.InitExpr(expb)) -> + unify_expression expa expb + | (Ast.InitList(_,initlista,_,whena), + Ast.InitList(_,initlistb,_,whenb)) -> + (* ignore whencode - returns true safely *) + unify_lists unify_initialiser (function _ -> false) initlista initlistb + | (Ast.InitGccDotName(_,namea,_,inia), + Ast.InitGccDotName(_,nameb,_,inib)) -> + conjunct_bindings + (unify_ident namea nameb) (unify_initialiser inia inib) + | (Ast.InitGccName(namea,_,inia),Ast.InitGccName(nameb,_,inib)) -> + conjunct_bindings (unify_ident namea nameb) (unify_initialiser inia inib) + | (Ast.InitGccIndex(_,expa,_,_,inia), + Ast.InitGccIndex(_,expb,_,_,inib)) -> + conjunct_bindings + (unify_expression expa expb) (unify_initialiser inia inib) + | (Ast.InitGccRange(_,exp1a,_,exp2a,_,_,inia), + Ast.InitGccRange(_,exp1b,_,exp2b,_,_,inib)) -> + conjunct_bindings (unify_expression exp1a exp1b) + (conjunct_bindings (unify_expression exp2a exp2b) + (unify_initialiser inia inib)) + + | (Ast.OptIni(_),_) + | (Ast.UniqueIni(_),_) + | (_,Ast.OptIni(_)) + | (_,Ast.UniqueIni(_)) -> failwith "unsupported decl" + | _ -> return false + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +and unify_parameterTypeDef p1 p2 = + match (Ast.unwrap p1,Ast.unwrap p2) with + (Ast.VoidParam(ft1),Ast.VoidParam(ft2)) -> unify_fullType ft1 ft2 + | (Ast.Param(ft1,i1),Ast.Param(ft2,i2)) -> + conjunct_bindings (unify_fullType ft1 ft2) + (unify_option unify_ident i1 i2) + + | (Ast.MetaParam(_,_,_),_) + | (Ast.MetaParamList(_,_,_,_),_) + | (_,Ast.MetaParam(_,_,_)) + | (_,Ast.MetaParamList(_,_,_,_)) -> return true + + | (Ast.PComma(_),Ast.PComma(_)) -> return true + + (* dots can match against anything. return true to be safe. *) + | (Ast.Pdots(_),_) | (_,Ast.Pdots(_)) + | (Ast.Pcircles(_),_) | (_,Ast.Pcircles(_)) -> return true + + | (Ast.OptParam(_),_) + | (Ast.UniqueParam(_),_) + | (_,Ast.OptParam(_)) + | (_,Ast.UniqueParam(_)) -> failwith "unsupported parameter" + | _ -> return false + +(* --------------------------------------------------------------------- *) +(* Define parameter *) + +and unify_define_parameters p1 p2 = + match (Ast.unwrap p1,Ast.unwrap p2) with + (Ast.NoParams,Ast.NoParams) -> return true + | (Ast.DParams(lp1,params1,rp1),Ast.DParams(lp2,params2,rp2)) -> + unify_dots unify_define_param dpdots params1 params2 + | _ -> return false + +and unify_define_param p1 p2 = + match (Ast.unwrap p1,Ast.unwrap p2) with + (Ast.DParam(i1),Ast.DParam(i2)) -> + (unify_ident i1 i2) + | (Ast.DPComma(_),Ast.DPComma(_)) -> return true + + (* dots can match against anything. return true to be safe. *) + | (Ast.DPdots(_),_) | (_,Ast.DPdots(_)) + | (Ast.DPcircles(_),_) | (_,Ast.DPcircles(_)) -> return true + + | (Ast.OptDParam(_),_) + | (Ast.UniqueDParam(_),_) + | (_,Ast.OptDParam(_)) + | (_,Ast.UniqueDParam(_)) -> failwith "unsupported parameter" + | _ -> return false + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +and unify_rule_elem re1 re2 = + match (Ast.unwrap re1,Ast.unwrap re2) with + (Ast.FunHeader(_,_,fi1,nm1,lp1,params1,rp1), + Ast.FunHeader(_,_,fi2,nm2,lp2,params2,rp2)) -> + conjunct_bindings (unify_fninfo fi1 fi2) + (conjunct_bindings (unify_ident nm1 nm2) + (unify_dots unify_parameterTypeDef pdots params1 params2)) + | (Ast.Decl(_,_,d1),Ast.Decl(_,_,d2)) -> unify_declaration d1 d2 + + | (Ast.SeqStart(lb1),Ast.SeqStart(lb2)) -> return true + | (Ast.SeqEnd(rb1),Ast.SeqEnd(rb2)) -> return true + + | (Ast.ExprStatement(e1,s1),Ast.ExprStatement(e2,s2)) -> + unify_expression e1 e2 + | (Ast.IfHeader(if1,lp1,e1,rp1),Ast.IfHeader(if2,lp2,e2,rp2)) -> + unify_expression e1 e2 + | (Ast.Else(e1),Ast.Else(e2)) -> return true + | (Ast.WhileHeader(wh1,lp1,e1,rp1),Ast.WhileHeader(wh2,lp2,e2,rp2)) -> + unify_expression e1 e2 + | (Ast.DoHeader(d1),Ast.DoHeader(d2)) -> return true + | (Ast.WhileTail(wh1,lp1,e1,rp1,s1),Ast.WhileTail(wh2,lp2,e2,rp2,s2)) -> + unify_expression e1 e2 + | (Ast.ForHeader(fr1,lp1,e11,s11,e21,s21,e31,rp1), + Ast.ForHeader(fr2,lp2,e12,s12,e22,s22,e32,rp2)) -> + conjunct_bindings + (unify_option unify_expression e11 e12) + (conjunct_bindings + (unify_option unify_expression e21 e22) + (unify_option unify_expression e31 e32)) + | (Ast.IteratorHeader(nm1,lp1,args1,rp1), + Ast.IteratorHeader(nm2,lp2,args2,rp2)) -> + conjunct_bindings (unify_ident nm1 nm2) + (unify_dots unify_expression edots args1 args2) + | (Ast.DefineHeader(_,n1,p1),Ast.DefineHeader(_,n2,p2)) -> + conjunct_bindings (unify_ident n1 n2) + (unify_define_parameters p1 p2) + | (Ast.Break(r1,s1),Ast.Break(r2,s2)) -> return true + | (Ast.Continue(r1,s1),Ast.Continue(r2,s2)) -> return true + | (Ast.Label(l1,dd1),Ast.Label(l2,dd2)) -> unify_ident l1 l2 + | (Ast.Goto(g1,l1,dd1),Ast.Goto(g2,l2,dd2)) -> unify_ident l1 l2 + | (Ast.Return(r1,s1),Ast.Return(r2,s2)) -> return true + | (Ast.ReturnExpr(r1,e1,s1),Ast.ReturnExpr(r2,e2,s2)) -> + unify_expression e1 e2 + + | (Ast.DisjRuleElem(res1),_) -> + disjunct_all_bindings + (List.map (function x -> unify_rule_elem x re2) res1) + | (_,Ast.DisjRuleElem(res2)) -> + disjunct_all_bindings + (List.map (function x -> unify_rule_elem re1 x) res2) + + | (Ast.MetaRuleElem(_,_,_),_) + | (Ast.MetaStmt(_,_,_,_),_) + | (Ast.MetaStmtList(_,_,_),_) + | (_,Ast.MetaRuleElem(_,_,_)) + | (_,Ast.MetaStmt(_,_,_,_)) + | (_,Ast.MetaStmtList(_,_,_)) -> return true + + (* can match a rule_elem in different parts *) + | (Ast.Exp(e1),Ast.Exp(e2)) -> return true + | (Ast.Exp(e1),_) -> subexp (unify_expression e1) re2 + | (_,Ast.Exp(e2)) -> subexp (unify_expression e2) re1 + + | (Ast.TopExp(e1),Ast.TopExp(e2)) -> unify_expression e1 e2 + + (* can match a rule_elem in different parts *) + | (Ast.Ty(t1),Ast.Ty(t2)) -> return true + | (Ast.Ty(t1),_) -> subtype (unify_fullType t1) re2 + | (_,Ast.Ty(t2)) -> subtype (unify_fullType t2) re1 + | _ -> return false + +and unify_fninfo patterninfo cinfo = + let patterninfo = List.sort compare patterninfo in + let cinfo = List.sort compare cinfo in + let rec loop = function + (Ast.FStorage(sta)::resta,Ast.FStorage(stb)::restb) -> + if unify_mcode sta stb then loop (resta,restb) else return false + | (Ast.FType(tya)::resta,Ast.FType(tyb)::restb) -> + conjunct_bindings (unify_fullType tya tyb) (loop (resta,restb)) + | (Ast.FInline(ia)::resta,Ast.FInline(ib)::restb) -> + if unify_mcode ia ib then loop (resta,restb) else return false + | (Ast.FAttr(ia)::resta,Ast.FAttr(ib)::restb) -> + if unify_mcode ia ib then loop (resta,restb) else return false + | (x::resta,((y::_) as restb)) -> + (match compare x y with + -1 -> return false + | 1 -> loop (resta,restb) + | _ -> failwith "not possible") + | _ -> return false in + loop (patterninfo,cinfo) + +and subexp f = + let bind = conjunct_bindings in + let option_default = return false in + let mcode r e = option_default in + let expr r k e = conjunct_bindings (f e) (k e) in + let donothing r k e = k e in + let recursor = V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + donothing expr donothing donothing donothing donothing donothing + donothing donothing donothing donothing donothing in + recursor.V.combiner_rule_elem + +and subtype f = + let bind = conjunct_bindings in + let option_default = return false in + let mcode r e = option_default in + let fullType r k e = conjunct_bindings (f e) (k e) in + let donothing r k e = k e in + let recursor = V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing + donothing donothing fullType donothing donothing donothing donothing + donothing donothing donothing donothing donothing in + recursor.V.combiner_rule_elem + +let rec unify_statement s1 s2 = + match (Ast.unwrap s1,Ast.unwrap s2) with + (Ast.Seq(lb1,d1,s1,rb1),Ast.Seq(lb2,d2,s2,rb2)) -> + conjunct_bindings (unify_rule_elem lb1 lb2) + (conjunct_bindings + (unify_dots unify_statement sdots s1 s2) + (conjunct_bindings + (unify_dots unify_statement sdots d1 d2) + (unify_rule_elem rb1 rb2))) + | (Ast.IfThen(h1,thn1,_),Ast.IfThen(h2,thn2,_)) -> + conjunct_bindings (unify_rule_elem h1 h2) (unify_statement thn1 thn2) + | (Ast.IfThenElse(h1,thn1,e1,els1,_),Ast.IfThenElse(h2,thn2,e2,els2,_)) -> + conjunct_bindings (unify_rule_elem h1 h2) + (conjunct_bindings (unify_statement thn1 thn2) + (conjunct_bindings (unify_rule_elem e1 e2) + (unify_statement els1 els2))) + | (Ast.While(h1,s1,_),Ast.While(h2,s2,_)) -> + conjunct_bindings (unify_rule_elem h1 h2) (unify_statement s1 s2) + | (Ast.Do(h1,s1,t1),Ast.Do(h2,s2,t2)) -> + conjunct_bindings (unify_rule_elem h1 h2) + (conjunct_bindings (unify_statement s1 s2) (unify_rule_elem t1 t2)) + | (Ast.For(h1,s1,_),Ast.For(h2,s2,_)) -> + conjunct_bindings (unify_rule_elem h1 h2) (unify_statement s1 s2) + | (Ast.Atomic(re1),Ast.Atomic(re2)) -> unify_rule_elem re1 re2 + | (Ast.Disj(s1),_) -> + let s2 = Ast.rewrap s2 (Ast.DOTS[s2]) in + disjunct_all_bindings + (List.map + (function x -> unify_dots unify_statement sdots x s2) + s1) + | (_,Ast.Disj(s2)) -> + let s1 = Ast.rewrap s1 (Ast.DOTS[s1]) in + disjunct_all_bindings + (List.map + (function x -> unify_dots unify_statement sdots s1 x) + s2) + | (Ast.Nest(s1,_,_,_,_),Ast.Nest(s2,_,_,_,_)) -> + unify_dots unify_statement sdots s1 s2 + | (Ast.FunDecl(h1,lb1,d1,s1,rb1),Ast.FunDecl(h2,lb2,d2,s2,rb2)) -> + conjunct_bindings (unify_rule_elem h1 h2) + (conjunct_bindings (unify_rule_elem lb1 lb2) + (conjunct_bindings (unify_dots unify_statement sdots d1 d2) + (conjunct_bindings (unify_dots unify_statement sdots s1 s2) + (unify_rule_elem rb1 rb2)))) + | (Ast.Define(h1,s1),Ast.Define(h2,s2)) -> + conjunct_bindings (unify_rule_elem h1 h2) + (unify_dots unify_statement sdots s1 s2) + (* dots can match against anything. return true to be safe. *) + | (Ast.Dots(_,_,_,_),_) | (_,Ast.Dots(_,_,_,_)) + | (Ast.Circles(_,_,_,_),_) | (_,Ast.Circles(_,_,_,_)) + | (Ast.Stars(_,_,_,_),_) | (_,Ast.Stars(_,_,_,_)) -> return true + | (Ast.OptStm(_),_) + | (Ast.UniqueStm(_),_) + | (_,Ast.OptStm(_)) + | (_,Ast.UniqueStm(_)) -> failwith "unsupported statement" + | _ -> return false + +let unify_statement_dots = unify_dots unify_statement sdots diff --git a/parsing_cocci/unify_ast.mli b/parsing_cocci/unify_ast.mli new file mode 100644 index 0000000..95a7d6f --- /dev/null +++ b/parsing_cocci/unify_ast.mli @@ -0,0 +1,5 @@ +type res = NO | MAYBE + +val unify_statement_dots : + Ast_cocci.statement Ast_cocci.dots -> + Ast_cocci.statement Ast_cocci.dots -> res diff --git a/parsing_cocci/unitary_ast0.ml b/parsing_cocci/unitary_ast0.ml new file mode 100644 index 0000000..1110f58 --- /dev/null +++ b/parsing_cocci/unitary_ast0.ml @@ -0,0 +1,284 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +(* find unitary metavariables *) +module Ast0 = Ast0_cocci +module Ast = Ast_cocci +module V0 = Visitor_ast0 + +let set_minus s minus = List.filter (function n -> not (List.mem n minus)) s + +let rec nub = function + [] -> [] + | (x::xs) when (List.mem x xs) -> nub xs + | (x::xs) -> x::(nub xs) + +(* ----------------------------------------------------------------------- *) +(* Find the variables that occur free and occur free in a unitary way *) + +(* take everything *) +let minus_checker name = let id = Ast0.unwrap_mcode name in [id] + +(* take only what is in the plus code *) +let plus_checker (nm,_,_,mc,_) = + match mc with Ast0.PLUS -> [nm] | _ -> [] + +let get_free checker t = + let bind x y = x @ y in + let option_default = [] in + let donothing r k e = k e in + let mcode _ = option_default in + + (* considers a single list *) + let collect_unitary_nonunitary free_usage = + let free_usage = List.sort compare free_usage in + let rec loop1 todrop = function + [] -> [] + | (x::xs) as all -> if x = todrop then loop1 todrop xs else all in + let rec loop2 = function + [] -> ([],[]) + | [x] -> ([x],[]) + | x::y::xs -> + if x = y + then + let (unitary,non_unitary) = loop2(loop1 x xs) in + (unitary,x::non_unitary) + else + let (unitary,non_unitary) = loop2 (y::xs) in + (x::unitary,non_unitary) in + loop2 free_usage in + + (* considers a list of lists *) + let detect_unitary_frees l = + let (unitary,nonunitary) = + List.split (List.map collect_unitary_nonunitary l) in + let unitary = nub (List.concat unitary) in + let nonunitary = nub (List.concat nonunitary) in + let unitary = + List.filter (function x -> not (List.mem x nonunitary)) unitary in + unitary@nonunitary@nonunitary in + + let whencode afn bfn = function + Ast0.WhenNot(a) -> afn a + | Ast0.WhenAlways(b) -> bfn b + | Ast0.WhenModifier(_) -> option_default in + + let ident r k i = + match Ast0.unwrap i with + Ast0.MetaId(name,_,_) | Ast0.MetaFunc(name,_,_) + | Ast0.MetaLocalFunc(name,_,_) -> checker name + | _ -> k i in + + let expression r k e = + match Ast0.unwrap e with + Ast0.MetaErr(name,_,_) | Ast0.MetaExpr(name,_,_,_,_) + | Ast0.MetaExprList(name,_,_) -> checker name + | Ast0.DisjExpr(starter,expr_list,mids,ender) -> + detect_unitary_frees(List.map r.V0.combiner_expression expr_list) + | _ -> k e in + + let typeC r k t = + match Ast0.unwrap t with + Ast0.MetaType(name,_) -> checker name + | Ast0.DisjType(starter,types,mids,ender) -> + detect_unitary_frees(List.map r.V0.combiner_typeC types) + | _ -> k t in + + let parameter r k p = + match Ast0.unwrap p with + Ast0.MetaParam(name,_) | Ast0.MetaParamList(name,_,_) -> checker name + | _ -> k p in + + let declaration r k d = + match Ast0.unwrap d with + Ast0.DisjDecl(starter,decls,mids,ender) -> + detect_unitary_frees(List.map r.V0.combiner_declaration decls) + | _ -> k d in + + let statement r k s = + match Ast0.unwrap s with + Ast0.MetaStmt(name,_) | Ast0.MetaStmtList(name,_) -> checker name + | Ast0.Disj(starter,stmt_list,mids,ender) -> + detect_unitary_frees(List.map r.V0.combiner_statement_dots stmt_list) + | Ast0.Nest(starter,stmt_dots,ender,whn,multi) -> + bind (r.V0.combiner_statement_dots stmt_dots) + (detect_unitary_frees + (List.map + (whencode r.V0.combiner_statement_dots r.V0.combiner_statement) + whn)) + | Ast0.Dots(d,whn) | Ast0.Circles(d,whn) | Ast0.Stars(d,whn) -> + detect_unitary_frees + (List.map + (whencode r.V0.combiner_statement_dots r.V0.combiner_statement) + whn) + | _ -> k s in + + let res = V0.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + ident expression typeC donothing parameter declaration statement + donothing donothing in + + collect_unitary_nonunitary + (List.concat (List.map res.V0.combiner_top_level t)) + +(* ----------------------------------------------------------------------- *) +(* update the variables that are unitary *) + +let update_unitary unitary = + let donothing r k e = k e in + let mcode x = x in + + let is_unitary name = + match (List.mem (Ast0.unwrap_mcode name) unitary, + Ast0.get_mcode_mcodekind name) with + (true,Ast0.CONTEXT(mc)) -> Ast0.PureContext + | (true,_) -> Ast0.Pure + | (false,Ast0.CONTEXT(mc)) -> Ast0.Context + | (false,_) -> Ast0.Impure in + + let ident r k i = + match Ast0.unwrap i with + Ast0.MetaId(name,constraints,_) -> + Ast0.rewrap i (Ast0.MetaId(name,constraints,is_unitary name)) + | Ast0.MetaFunc(name,constraints,_) -> + Ast0.rewrap i (Ast0.MetaFunc(name,constraints,is_unitary name)) + | Ast0.MetaLocalFunc(name,constraints,_) -> + Ast0.rewrap i (Ast0.MetaLocalFunc(name,constraints,is_unitary name)) + | _ -> k i in + + let expression r k e = + match Ast0.unwrap e with + Ast0.MetaErr(name,constraints,_) -> + Ast0.rewrap e (Ast0.MetaErr(name,constraints,is_unitary name)) + | Ast0.MetaExpr(name,constraints,ty,form,_) -> + Ast0.rewrap e (Ast0.MetaExpr(name,constraints,ty,form,is_unitary name)) + | Ast0.MetaExprList(name,lenname,_) -> + Ast0.rewrap e (Ast0.MetaExprList(name,lenname,is_unitary name)) + | _ -> k e in + + let typeC r k t = + match Ast0.unwrap t with + Ast0.MetaType(name,_) -> + Ast0.rewrap t (Ast0.MetaType(name,is_unitary name)) + | _ -> k t in + + let parameter r k p = + match Ast0.unwrap p with + Ast0.MetaParam(name,_) -> + Ast0.rewrap p (Ast0.MetaParam(name,is_unitary name)) + | Ast0.MetaParamList(name,lenname,_) -> + Ast0.rewrap p (Ast0.MetaParamList(name,lenname,is_unitary name)) + | _ -> k p in + + let statement r k s = + match Ast0.unwrap s with + Ast0.MetaStmt(name,_) -> + Ast0.rewrap s (Ast0.MetaStmt(name,is_unitary name)) + | Ast0.MetaStmtList(name,_) -> + Ast0.rewrap s (Ast0.MetaStmtList(name,is_unitary name)) + | _ -> k s in + + let res = V0.rebuilder + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + donothing donothing donothing donothing donothing donothing + ident expression typeC donothing parameter donothing statement + donothing donothing in + + List.map res.V0.rebuilder_top_level + +(* ----------------------------------------------------------------------- *) + +let rec split3 = function + [] -> ([],[],[]) + | (a,b,c)::xs -> let (l1,l2,l3) = split3 xs in (a::l1,b::l2,c::l3) + +let rec combine3 = function + ([],[],[]) -> [] + | (a::l1,b::l2,c::l3) -> (a,b,c) :: combine3 (l1,l2,l3) + | _ -> failwith "not possible" + +(* ----------------------------------------------------------------------- *) +(* process all rules *) + +let do_unitary rules = + let rec loop = function + [] -> ([],[]) + | (r::rules) -> + match r with + Ast0.ScriptRule (a,b,c,d) -> + let (x,rules) = loop rules in + (x, r::rules) + | Ast0.CocciRule ((minus,metavars,chosen_isos),((plus,_) as plusz)) -> + let mm1 = List.map Ast.get_meta_name metavars in + let (used_after, rest) = loop rules in + let (m_unitary, m_nonunitary) = get_free minus_checker minus in + let (p_unitary, p_nonunitary) = get_free plus_checker plus in + let p_free = + if !Flag.sgrep_mode2 then [] + else p_unitary @ p_nonunitary in + let (in_p, m_unitary) = + List.partition (function x -> List.mem x p_free) m_unitary in + let m_nonunitary = in_p @ m_nonunitary in + let (m_unitary, not_local) = + List.partition (function x -> List.mem x mm1) m_unitary in + let m_unitary = + List.filter (function x -> not (List.mem x used_after)) + m_unitary in + let rebuilt = update_unitary m_unitary minus in + (set_minus (m_nonunitary @ used_after) mm1, + (Ast0.CocciRule + ((rebuilt, metavars, chosen_isos),plusz))::rest) in + let (_,rules) = loop rules in + rules + +(* +let do_unitary minus plus = + let (minus,metavars,chosen_isos) = split3 minus in + let (plus,_) = List.split plus in + let rec loop = function + ([],[],[]) -> ([],[]) + | (mm1::metavars,m1::minus,p1::plus) -> + let mm1 = List.map Ast.get_meta_name mm1 in + let (used_after,rest) = loop (metavars,minus,plus) in + let (m_unitary,m_nonunitary) = get_free minus_checker m1 in + let (p_unitary,p_nonunitary) = get_free plus_checker p1 in + let p_free = + if !Flag.sgrep_mode2 + then [] + else p_unitary @ p_nonunitary in + let (in_p,m_unitary) = + List.partition (function x -> List.mem x p_free) m_unitary in + let m_nonunitary = in_p@m_nonunitary in + let (m_unitary,not_local) = + List.partition (function x -> List.mem x mm1) m_unitary in + let m_unitary = + List.filter (function x -> not(List.mem x used_after)) m_unitary in + let rebuilt = update_unitary m_unitary m1 in + (set_minus (m_nonunitary @ used_after) mm1, + rebuilt::rest) + | _ -> failwith "not possible" in + let (_,rules) = loop (metavars,minus,plus) in + combine3 (rules,metavars,chosen_isos) +*) diff --git a/parsing_cocci/unitary_ast0.mli b/parsing_cocci/unitary_ast0.mli new file mode 100644 index 0000000..ec03073 --- /dev/null +++ b/parsing_cocci/unitary_ast0.mli @@ -0,0 +1,12 @@ +(* 'iso is the return type of parse_iso, which currently is +(Ast_cocci.metavar list * Ast0_cocci.anything list list) list *) + +(* +val do_unitary : + (Ast0_cocci.rule * Ast_cocci.metavar list * 'iso) list -> + (Ast0_cocci.rule * Ast_cocci.metavar list) list -> + (Ast0_cocci.rule * Ast_cocci.metavar list * 'iso) list +*) + +val do_unitary : + Ast0_cocci.parsed_rule list -> Ast0_cocci.parsed_rule list diff --git a/parsing_cocci/unparse_ast0.ml b/parsing_cocci/unparse_ast0.ml new file mode 100644 index 0000000..80ece57 --- /dev/null +++ b/parsing_cocci/unparse_ast0.ml @@ -0,0 +1,651 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Format +module Ast0 = Ast0_cocci +module U = Pretty_print_cocci + +let quiet = ref true (* true = no decoration on - context, etc *) + +let start_block str = + force_newline(); print_string " "; open_box 0 + +let end_block str = + close_box(); force_newline () + +let print_option = Common.do_option +let print_between = Common.print_between + +(* --------------------------------------------------------------------- *) +(* Positions *) + +let meta_pos = function + Ast0.MetaPos(name,_,_) -> + print_string "@"; + let (_,name) = Ast0.unwrap_mcode name in + print_string name + | Ast0.NoMetaPos -> () + +(* --------------------------------------------------------------------- *) +(* Modified code *) + +let mcodekind brackets fn x info = function + Ast0.MINUS(plus_stream) -> + let (lb,rb) = + if !quiet + then ("","") + else + match brackets with + Some x -> ("[","]^"^(string_of_int x)) + | None -> ("","") in + let (plus_stream,_) = !plus_stream in + if !quiet + then fn x + else (print_string "-"; + print_string lb; fn x; print_string rb); + U.print_anything ">>> " plus_stream + | Ast0.CONTEXT(plus_streams) -> + let (lb,rb) = + if !quiet + then ("","") + else + match brackets with + Some x -> ("[",("]^"^(string_of_int x))) | None -> ("","") in + let (plus_streams,t1,t2) = !plus_streams in + U.print_around + (function x -> + print_string lb; fn x; print_string rb) + x plus_streams + | Ast0.PLUS -> + List.iter (function s -> print_string s; force_newline()) + info.Ast0.strings_before; + fn x; + List.iter (function s -> force_newline(); print_string s) + info.Ast0.strings_after + | Ast0.MIXED(plus_streams) -> + let (lb,rb) = + if !quiet + then ("","") + else + let n = + match brackets with Some x -> "^"^(string_of_int x) | None -> "" in + ("§","½"^n) in + let (plus_streams,_,_) = !plus_streams in + U.print_around (function x -> print_string lb; fn x; print_string rb) + x plus_streams + +let mcode fn (x,_,info,mc,pos) = + let fn x = fn x; meta_pos !pos in + mcodekind (Some info.Ast0.line_start)(*None*) fn x info mc + +let print_context x fn = + mcodekind (Some (Ast0.get_line x)) fn () (Ast0.get_info x) + (Ast0.get_mcodekind x) + +let print_meta (_,name) = print_string name + +(* --------------------------------------------------------------------- *) +(* --------------------------------------------------------------------- *) +(* Dots *) + +let dots between fn d = + print_context d + (function _ -> + match Ast0.unwrap d with + Ast0.DOTS(l) -> print_between between fn l + | Ast0.CIRCLES(l) -> print_between between fn l + | Ast0.STARS(l) -> print_between between fn l) + +(* --------------------------------------------------------------------- *) + +let print_types = function + None -> () + | Some ty -> + print_string "/* "; + Format.print_flush(); + print_between (function _ -> print_string ", ") Type_cocci.typeC ty; + Format.print_flush(); + print_string " */" + +(* --------------------------------------------------------------------- *) +(* Identifier *) + +let rec ident i = + print_context i + (function _ -> + match Ast0.unwrap i with + Ast0.Id(name) -> mcode print_string name + | Ast0.MetaId(name,_,_) -> mcode print_meta name + | Ast0.MetaFunc(name,_,_) -> mcode print_meta name + | Ast0.MetaLocalFunc(name,_,_) -> mcode print_meta name + | Ast0.OptIdent(id) -> print_string "?"; ident id + | Ast0.UniqueIdent(id) -> print_string "!"; ident id) + +(* --------------------------------------------------------------------- *) +(* Expression *) + +let print_string_box s = print_string s; open_box 0 + +let rec expression e = + print_option Type_cocci.typeC (Ast0.get_type e); + print_context e + (function _ -> + match Ast0.unwrap e with + Ast0.Ident(id) -> ident id + | Ast0.Constant(const) -> mcode U.constant const + | Ast0.FunCall(fn,lp,args,rp) -> + expression fn; mcode print_string_box lp; + let _ = dots (function _ -> ()) expression args in + close_box(); mcode print_string rp + | Ast0.Assignment(left,op,right,_) -> + expression left; print_string " "; mcode U.assignOp op; + print_string " "; expression right + | Ast0.CondExpr(exp1,why,exp2,colon,exp3) -> + expression exp1; print_string " "; mcode print_string why; + print_option (function e -> print_string " "; expression e) exp2; + print_string " "; mcode print_string colon; expression exp3 + | Ast0.Postfix(exp,op) -> expression exp; mcode U.fixOp op + | Ast0.Infix(exp,op) -> mcode U.fixOp op; expression exp + | Ast0.Unary(exp,op) -> mcode U.unaryOp op; expression exp + | Ast0.Binary(left,op,right) -> + print_string "("; + expression left; print_string " "; mcode U.binaryOp op; + print_string " "; expression right; + print_string ")" + | Ast0.Nested(left,op,right) -> + print_string "("; + expression left; print_string " "; mcode U.binaryOp op; + print_string " "; expression right; + print_string ")" + | Ast0.Paren(lp,exp,rp) -> + mcode print_string_box lp; expression exp; close_box(); + mcode print_string rp + | Ast0.ArrayAccess(exp1,lb,exp2,rb) -> + expression exp1; mcode print_string_box lb; expression exp2; + close_box(); mcode print_string rb + | Ast0.RecordAccess(exp,pt,field) -> + expression exp; mcode print_string pt; ident field + | Ast0.RecordPtAccess(exp,ar,field) -> + expression exp; mcode print_string ar; ident field + | Ast0.Cast(lp,ty,rp,exp) -> + mcode print_string_box lp; typeC ty; close_box(); + mcode print_string rp; expression exp + | Ast0.SizeOfExpr(szf,exp) -> + mcode print_string szf; expression exp + | Ast0.SizeOfType(szf,lp,ty,rp) -> + mcode print_string szf; + mcode print_string_box lp; typeC ty; close_box(); + mcode print_string rp + | Ast0.TypeExp(ty) -> typeC ty + | Ast0.MetaErr(name,_,_) -> mcode print_meta name + | Ast0.MetaExpr(name,_,ty,_,_) -> + mcode print_meta name; print_types ty + | Ast0.MetaExprList(name,_,_) -> mcode print_meta name + | Ast0.EComma(cm) -> mcode print_string cm; print_space() + | Ast0.DisjExpr(_,exp_list,_,_) -> + print_string "\n("; force_newline(); + print_between + (function _ -> print_string "\n|"; force_newline()) + expression exp_list; + print_string "\n)" + | Ast0.NestExpr(starter,expr_dots,ender,None,multi) -> + mcode print_string starter; + start_block(); dots force_newline expression expr_dots; end_block(); + mcode print_string ender + | Ast0.NestExpr(starter,expr_dots,ender,Some whencode,multi) -> + mcode print_string starter; print_string " WHEN != "; + expression whencode; + start_block(); dots force_newline expression expr_dots; end_block(); + mcode print_string ender + | Ast0.Edots(dots,Some whencode) + | Ast0.Ecircles(dots,Some whencode) + | Ast0.Estars(dots,Some whencode) -> + mcode print_string dots; print_string " WHEN != "; + expression whencode + | Ast0.Edots(dots,None) + | Ast0.Ecircles(dots,None) + | Ast0.Estars(dots,None) -> mcode print_string dots + | Ast0.OptExp(exp) -> print_string "?"; expression exp + | Ast0.UniqueExp(exp) -> print_string "!"; expression exp) + +and expression_dots x = dots (function _ -> ()) expression x + +(* --------------------------------------------------------------------- *) +(* Types *) + +and print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2) fn = + typeC ty; mcode print_string lp1; mcode print_string star; fn(); + mcode print_string rp1; mcode print_string lp2; + parameter_list params; mcode print_string rp2 + +and print_function_type (ty,lp1,params,rp1) fn = + print_option typeC ty; fn(); mcode print_string lp1; + parameter_list params; mcode print_string rp1 + +and typeC t = + print_context t + (function _ -> + match Ast0.unwrap t with + Ast0.ConstVol(cv,ty) -> + mcode U.const_vol cv; print_string " "; typeC ty + | Ast0.BaseType(ty,sgn) -> + print_option (mcode U.sign) sgn; mcode U.baseType ty + | Ast0.ImplicitInt(sgn) -> mcode U.sign sgn + | Ast0.Pointer(ty,star) -> typeC ty; mcode print_string star + | Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2) + (function _ -> ()) + | Ast0.FunctionType(ty,lp1,params,rp1) -> + print_function_type (ty,lp1,params,rp1) (function _ -> ()) + | Ast0.Array(ty,lb,size,rb) -> + typeC ty; mcode print_string lb; print_option expression size; + mcode print_string rb + | Ast0.StructUnionName(kind,name) -> + mcode U.structUnion kind; + print_option (function x -> ident x; print_string " ") name + | Ast0.StructUnionDef(ty,lb,decls,rb) -> + typeC ty; mcode print_string lb; + dots force_newline declaration decls; + mcode print_string rb + | Ast0.TypeName(name)-> mcode print_string name; print_string " " + | Ast0.MetaType(name,_)-> mcode print_meta name; print_string " " + | Ast0.DisjType(lp,types,mids,rp) -> + print_string "\n"; mcode print_string lp; force_newline(); + print_between + (function _ -> print_string "\n|"; force_newline()) + typeC types; + print_string "\n"; mcode print_string rp + | Ast0.OptType(ty) -> print_string "?"; typeC ty + | Ast0.UniqueType(ty) -> print_string "!"; typeC ty) + +(* --------------------------------------------------------------------- *) +(* Variable declaration *) +(* Even if the Cocci program specifies a list of declarations, they are + split out into multiple declarations of a single variable each. *) + +and print_named_type ty id = + match Ast0.unwrap ty with + Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + print_function_pointer (ty,lp1,star,rp1,lp2,params,rp2) + (function _ -> print_string " "; ident id) + | Ast0.FunctionType(ty,lp1,params,rp1) -> + print_function_type (ty,lp1,params,rp1) + (function _ -> print_string " "; ident id) + | Ast0.Array(ty,lb,size,rb) -> + let rec loop ty k = + match Ast0.unwrap ty with + Ast0.Array(ty,lb,size,rb) -> + loop ty + (function _ -> + k (); + mcode print_string lb; + print_option expression size; + mcode print_string rb) + | _ -> typeC ty; ident id; k () in + loop ty (function _ -> ()) + | _ -> typeC ty; ident id + +and declaration d = + print_context d + (function _ -> + match Ast0.unwrap d with + Ast0.Init(stg,ty,id,eq,ini,sem) -> + print_option (mcode U.storage) stg; + print_named_type ty id; + print_string " "; + mcode print_string eq; print_string " "; initialiser ini; + mcode print_string sem + | Ast0.UnInit(stg,ty,id,sem) -> + print_option (mcode U.storage) stg; print_named_type ty id; + mcode print_string sem + | Ast0.MacroDecl(name,lp,args,rp,sem) -> + ident name; mcode print_string_box lp; + let _ = dots (function _ -> ()) expression args in + close_box(); mcode print_string rp; mcode print_string sem + | Ast0.TyDecl(ty,sem) -> typeC ty; mcode print_string sem + | Ast0.Typedef(stg,ty,id,sem) -> + mcode print_string stg; typeC ty; typeC id; + mcode print_string sem + | Ast0.DisjDecl(_,decls,_,_) -> + print_string "\n("; force_newline(); + print_between + (function _ -> print_string "\n|"; force_newline()) + declaration decls; + print_string "\n)" + | Ast0.Ddots(dots,Some whencode) -> + mcode print_string dots; print_string " when != "; + declaration whencode + | Ast0.Ddots(dots,None) -> mcode print_string dots + | Ast0.OptDecl(decl) -> print_string "?"; declaration decl + | Ast0.UniqueDecl(decl) -> print_string "!"; declaration decl) + +and declaration_dots l = dots (function _ -> ()) declaration l + +(* --------------------------------------------------------------------- *) +(* Initialiser *) + +and initialiser i = + print_context i + (function _ -> + match Ast0.unwrap i with + Ast0.InitExpr(exp) -> expression exp + | Ast0.InitList(lb,initlist,rb) -> + mcode print_string lb; open_box 0; + let _ = dots (function _ -> ()) initialiser initlist in + close_box(); mcode print_string rb + | Ast0.InitGccDotName(dot,name,eq,ini) -> + mcode print_string dot; ident name; print_string " "; + mcode print_string eq; print_string " "; initialiser ini + | Ast0.InitGccName(name,eq,ini) -> + ident name; mcode print_string eq; initialiser ini + | Ast0.InitGccIndex(lb,exp,rb,eq,ini) -> + mcode print_string lb; expression exp; mcode print_string rb; + print_string " "; mcode print_string eq; print_string " "; + initialiser ini + | Ast0.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> + mcode print_string lb; expression exp1; mcode print_string dots; + expression exp2; mcode print_string rb; + print_string " "; mcode print_string eq; print_string " "; + initialiser ini + | Ast0.IComma(cm) -> mcode print_string cm; force_newline() + | Ast0.Idots(d,Some whencode) -> + mcode print_string d; print_string " WHEN != "; + initialiser whencode + | Ast0.Idots(d,None) -> mcode print_string d + | Ast0.OptIni(ini) -> print_string "?"; initialiser ini + | Ast0.UniqueIni(ini) -> print_string "!"; initialiser ini) + +and initialiser_list l = dots (function _ -> ()) initialiser l + +(* --------------------------------------------------------------------- *) +(* Parameter *) + +and parameterTypeDef p = + print_context p + (function _ -> + match Ast0.unwrap p with + Ast0.VoidParam(ty) -> typeC ty + | Ast0.Param(ty,Some id) -> print_named_type ty id + | Ast0.Param(ty,None) -> typeC ty + | Ast0.MetaParam(name,_) -> mcode print_meta name + | Ast0.MetaParamList(name,_,_) -> mcode print_meta name + | Ast0.PComma(cm) -> mcode print_string cm; print_space() + | Ast0.Pdots(dots) -> mcode print_string dots + | Ast0.Pcircles(dots) -> mcode print_string dots + | Ast0.OptParam(param) -> print_string "?"; parameterTypeDef param + | Ast0.UniqueParam(param) -> print_string "!"; parameterTypeDef param) + +and parameter_list l = dots (function _ -> ()) parameterTypeDef l + +(* --------------------------------------------------------------------- *) +(* Top-level code *) + +and statement arity s = + print_context s + (function _ -> + match Ast0.unwrap s with + Ast0.FunDecl(_,fninfo,name,lp,params,rp,lbrace,body,rbrace) -> + print_string arity; + List.iter print_fninfo fninfo; + ident name; mcode print_string_box lp; + parameter_list params; close_box(); mcode print_string rp; + print_string " "; + print_string arity; mcode print_string lbrace; start_block(); + dots force_newline (statement arity) body; + end_block(); print_string arity; mcode print_string rbrace + | Ast0.Decl(_,decl) -> print_string arity; declaration decl + | Ast0.Seq(lbrace,body,rbrace) -> + print_string arity; mcode print_string lbrace; start_block(); + dots force_newline (statement arity) body; + end_block(); print_string arity; mcode print_string rbrace + | Ast0.ExprStatement(exp,sem) -> + print_string arity; expression exp; mcode print_string sem + | Ast0.IfThen(iff,lp,exp,rp,branch1,(info,aft)) -> + print_string arity; + mcode print_string iff; print_string " "; mcode print_string_box lp; + expression exp; close_box(); mcode print_string rp; print_string " "; + statement arity branch1; + mcode (function _ -> ()) ((),(),info,aft,ref Ast0.NoMetaPos) + | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,(info,aft)) -> + print_string arity; + mcode print_string iff; print_string " "; mcode print_string_box lp; + expression exp; close_box(); mcode print_string rp; print_string " "; + statement arity branch1; + print_string arity; mcode print_string els; print_string " "; + statement arity branch2; + mcode (function _ -> ()) ((),(),info,aft,ref Ast0.NoMetaPos) + | Ast0.While(whl,lp,exp,rp,body,(info,aft)) -> + print_string arity; + mcode print_string whl; print_string " "; mcode print_string_box lp; + expression exp; close_box(); mcode print_string rp; print_string " "; + statement arity body; + mcode (function _ -> ()) ((),(),info,aft,ref Ast0.NoMetaPos) + | Ast0.Do(d,body,whl,lp,exp,rp,sem) -> + print_string arity; mcode print_string d; print_string " "; + statement arity body; + print_string arity; + mcode print_string whl; print_string " "; mcode print_string_box lp; + expression exp; close_box(); mcode print_string rp; + mcode print_string sem + | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,(info,aft)) -> + print_string arity; + mcode print_string fr; mcode print_string_box lp; + print_option expression e1; mcode print_string sem1; + print_option expression e2; mcode print_string sem2; + print_option expression e3; close_box(); + mcode print_string rp; print_string " "; statement arity body; + mcode (function _ -> ()) ((),(),info,aft,ref Ast0.NoMetaPos) + | Ast0.Iterator(nm,lp,args,rp,body,(info,aft)) -> + print_string arity; + ident nm; print_string " "; mcode print_string_box lp; + let _ = dots (function _ -> ()) expression args in + close_box(); mcode print_string rp; print_string " "; + statement arity body; + mcode (function _ -> ()) ((),(),info,aft,ref Ast0.NoMetaPos) + | Ast0.Switch(switch,lp,exp,rp,lb,cases,rb) -> + print_string arity; + mcode print_string switch; print_string " "; + mcode print_string_box lp; expression exp; close_box(); + mcode print_string rp; print_string " "; mcode print_string lb; + dots force_newline (case_line arity) cases; + mcode print_string rb + | Ast0.Break(br,sem) -> + print_string arity; mcode print_string br; mcode print_string sem + | Ast0.Continue(cont,sem) -> + print_string arity; mcode print_string cont; mcode print_string sem + | Ast0.Label(l,dd) -> ident l; print_string ":" + | Ast0.Goto(goto,l,sem) -> + mcode print_string goto; ident l; mcode print_string sem + | Ast0.Return(ret,sem) -> + print_string arity; mcode print_string ret; mcode print_string sem + | Ast0.ReturnExpr(ret,exp,sem) -> + print_string arity; mcode print_string ret; print_string " "; + expression exp; mcode print_string sem + | Ast0.MetaStmt(name,pure) -> + print_string arity; mcode print_meta name;(* + print_string "^"; + (match pure with + Ast0.Pure -> print_string "pure" + | Ast0.Impure -> print_string "impure" + | Ast0.Context -> print_string "context" + | Ast0.PureContext -> print_string "pure_context")*) + | Ast0.MetaStmtList(name,_) -> + print_string arity; mcode print_meta name + | Ast0.Disj(_,statement_dots_list,_,_) -> + print_string arity; + print_string "\n("; force_newline(); + print_between + (function _ -> print_string "\n|"; force_newline()) + (dots force_newline (statement arity)) + statement_dots_list; + print_string "\n)" + | Ast0.Nest(starter,stmt_dots,ender,whn,multi) -> + print_string arity; + mcode print_string starter; + open_box 0; + List.iter + (whencode (dots force_newline (statement "")) (statement "")) + whn; + close_box(); + start_block(); + dots force_newline (statement arity) stmt_dots; + end_block(); + mcode print_string ender + | Ast0.Exp(exp) -> print_string arity; expression exp + | Ast0.TopExp(exp) -> print_string arity; expression exp + | Ast0.Ty(ty) -> print_string arity; typeC ty + | Ast0.Dots(d,whn) | Ast0.Circles(d,whn) | Ast0.Stars(d,whn) -> + print_string arity; mcode print_string d; + List.iter + (whencode (dots force_newline (statement "")) (statement "")) + whn + | Ast0.Include(inc,s) -> + mcode print_string inc; print_string " "; mcode U.inc_file s + | Ast0.Define(def,id,params,body) -> + mcode print_string def; print_string " "; ident id; + print_define_parameters params; + print_string " "; + dots force_newline (statement arity) body + | Ast0.OptStm(re) -> statement "?" re + | Ast0.UniqueStm(re) -> statement "!" re) + +and print_define_parameters params = + match Ast0.unwrap params with + Ast0.NoParams -> () + | Ast0.DParams(lp,params,rp) -> + mcode print_string lp; + dots (function _ -> ()) print_define_param params; mcode print_string rp + +and print_define_param param = + match Ast0.unwrap param with + Ast0.DParam(id) -> ident id + | Ast0.DPComma(comma) -> mcode print_string comma + | Ast0.DPdots(dots) -> mcode print_string dots + | Ast0.DPcircles(circles) -> mcode print_string circles + | Ast0.OptDParam(dp) -> print_string "?"; print_define_param dp + | Ast0.UniqueDParam(dp) -> print_string "!"; print_define_param dp + +and print_fninfo = function + Ast0.FStorage(stg) -> mcode U.storage stg + | Ast0.FType(ty) -> typeC ty + | Ast0.FInline(inline) -> mcode print_string inline + | Ast0.FAttr(attr) -> mcode print_string attr + +and whencode notfn alwaysfn = function + Ast0.WhenNot a -> + print_string " WHEN != "; open_box 0; notfn a; close_box() + | Ast0.WhenAlways a -> + print_string " WHEN = "; open_box 0; alwaysfn a; close_box() + | Ast0.WhenModifier x -> print_string " WHEN "; U.print_when_modif x + +and case_line arity c = + print_context c + (function _ -> + match Ast0.unwrap c with + Ast0.Default(def,colon,code) -> + print_string arity; + mcode print_string def; mcode print_string colon; print_string " "; + dots force_newline (statement arity) code + | Ast0.Case(case,exp,colon,code) -> + print_string arity; + mcode print_string case; print_string " "; expression exp; + mcode print_string colon; print_string " "; + dots force_newline (statement arity) code + | Ast0.OptCase(case) -> case_line "?" case) + +and statement_dots l = dots (function _ -> ()) (statement "") l +and case_dots l = dots (function _ -> ()) (case_line "") l + +(* --------------------------------------------------------------------- *) +(* Top level code *) + +let top_level t = + print_context t + (function _ -> + match Ast0.unwrap t with + Ast0.FILEINFO(old_file,new_file) -> + print_string "--- "; mcode print_string old_file; force_newline(); + print_string "+++ "; mcode print_string new_file + | Ast0.DECL(stmt) -> statement "" stmt + | Ast0.CODE(stmt_dots) -> + dots force_newline (statement "") stmt_dots + | Ast0.ERRORWORDS(exps) -> + print_string "error words = ["; + print_between (function _ -> print_string ", ") expression exps; + print_string "]" + | Ast0.OTHER(s) -> + print_string "OTHER("; statement "" s; print_string ")") + +let rule = + print_between (function _ -> force_newline(); force_newline()) top_level + +let unparse_anything x = + let q = !quiet in + quiet := true; + (match x with + Ast0.DotsExprTag(d) -> + print_string "ExpDots:"; force_newline(); + expression_dots d + | Ast0.DotsParamTag(d) -> + parameter_list d + | Ast0.DotsInitTag(d) -> + initialiser_list d + | Ast0.DotsStmtTag(d) -> + print_string "StmDots:"; force_newline(); + statement_dots d + | Ast0.DotsDeclTag(d) -> + declaration_dots d + | Ast0.DotsCaseTag(d) -> + case_dots d + | Ast0.IdentTag(d) -> + ident d + | Ast0.ExprTag(d) | Ast0.ArgExprTag(d) | Ast0.TestExprTag(d) -> + print_string "Exp:"; force_newline(); + expression d + | Ast0.TypeCTag(d) -> + typeC d + | Ast0.ParamTag(d) -> + parameterTypeDef d + | Ast0.InitTag(d) -> + initialiser d + | Ast0.DeclTag(d) -> + declaration d + | Ast0.StmtTag(d) -> + print_string "Stm:"; force_newline(); + statement "" d + | Ast0.CaseLineTag(d) -> + case_line "" d + | Ast0.TopTag(d) -> + top_level d + | Ast0.IsoWhenTag(x) -> U.print_when_modif x + | Ast0.MetaPosTag(var) -> meta_pos var); + quiet := q; + print_newline() + +let unparse x = + print_string "\n@@\n@@"; + force_newline(); + force_newline(); + rule x; + print_newline() + +let unparse_to_string x = Common.format_to_string (function _ -> unparse x) diff --git a/parsing_cocci/unparse_ast0.mli b/parsing_cocci/unparse_ast0.mli new file mode 100644 index 0000000..6f66fc0 --- /dev/null +++ b/parsing_cocci/unparse_ast0.mli @@ -0,0 +1,13 @@ +val expression_dots : Ast0_cocci.expression Ast0_cocci.dots -> unit +val parameter_list : Ast0_cocci.parameterTypeDef Ast0_cocci.dots -> unit +val statement_dots : Ast0_cocci.statement Ast0_cocci.dots -> unit +val ident : Ast0_cocci.ident -> unit +val expression : Ast0_cocci.expression -> unit +val typeC : Ast0_cocci.typeC -> unit +val parameterTypeDef : Ast0_cocci.parameterTypeDef -> unit +val declaration : Ast0_cocci.declaration -> unit +val statement : string -> Ast0_cocci.statement -> unit +val top_level : Ast0_cocci.top_level -> unit + +val unparse : Ast0_cocci.rule -> unit +val unparse_anything : Ast0_cocci.anything -> unit diff --git a/parsing_cocci/visitor_ast.ml b/parsing_cocci/visitor_ast.ml new file mode 100644 index 0000000..6338874 --- /dev/null +++ b/parsing_cocci/visitor_ast.ml @@ -0,0 +1,1048 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast = Ast_cocci + +(* --------------------------------------------------------------------- *) +(* Generic traversal: combiner *) +(* parameters: + combining function + treatment of: mcode, identifiers, expressions, fullTypes, types, + declarations, statements, toplevels + default value for options *) + +type 'a combiner = + {combiner_ident : Ast.ident -> 'a; + combiner_expression : Ast.expression -> 'a; + combiner_fullType : Ast.fullType -> 'a; + combiner_typeC : Ast.typeC -> 'a; + combiner_declaration : Ast.declaration -> 'a; + combiner_initialiser : Ast.initialiser -> 'a; + combiner_parameter : Ast.parameterTypeDef -> 'a; + combiner_parameter_list : Ast.parameter_list -> 'a; + combiner_rule_elem : Ast.rule_elem -> 'a; + combiner_statement : Ast.statement -> 'a; + combiner_case_line : Ast.case_line -> 'a; + combiner_top_level : Ast.top_level -> 'a; + combiner_anything : Ast.anything -> 'a; + combiner_expression_dots : Ast.expression Ast.dots -> 'a; + combiner_statement_dots : Ast.statement Ast.dots -> 'a; + combiner_declaration_dots : Ast.declaration Ast.dots -> 'a} + +type ('mc,'a) cmcode = 'a combiner -> 'mc Ast_cocci.mcode -> 'a +type ('cd,'a) ccode = 'a combiner -> ('cd -> 'a) -> 'cd -> 'a + + +let combiner bind option_default + meta_mcodefn string_mcodefn const_mcodefn assign_mcodefn fix_mcodefn + unary_mcodefn binary_mcodefn + cv_mcodefn base_mcodefn sign_mcodefn struct_mcodefn storage_mcodefn + inc_file_mcodefn + expdotsfn paramdotsfn stmtdotsfn decldotsfn + identfn exprfn ftfn tyfn initfn paramfn declfn rulefn stmtfn casefn + topfn anyfn = + let multibind l = + let rec loop = function + [] -> option_default + | [x] -> x + | x::xs -> bind x (loop xs) in + loop l in + let get_option f = function + Some x -> f x + | None -> option_default in + + let rec meta_mcode x = meta_mcodefn all_functions x + and string_mcode x = string_mcodefn all_functions x + and const_mcode x = const_mcodefn all_functions x + and assign_mcode x = assign_mcodefn all_functions x + and fix_mcode x = fix_mcodefn all_functions x + and unary_mcode x = unary_mcodefn all_functions x + and binary_mcode x = binary_mcodefn all_functions x + and cv_mcode x = cv_mcodefn all_functions x + and base_mcode x = base_mcodefn all_functions x + and sign_mcode x = sign_mcodefn all_functions x + and struct_mcode x = struct_mcodefn all_functions x + and storage_mcode x = storage_mcodefn all_functions x + and inc_file_mcode x = inc_file_mcodefn all_functions x + + and expression_dots d = + let k d = + match Ast.unwrap d with + Ast.DOTS(l) | Ast.CIRCLES(l) | Ast.STARS(l) -> + multibind (List.map expression l) in + expdotsfn all_functions k d + + and parameter_dots d = + let k d = + match Ast.unwrap d with + Ast.DOTS(l) | Ast.CIRCLES(l) | Ast.STARS(l) -> + multibind (List.map parameterTypeDef l) in + paramdotsfn all_functions k d + + and statement_dots d = + let k d = + match Ast.unwrap d with + Ast.DOTS(l) | Ast.CIRCLES(l) | Ast.STARS(l) -> + multibind (List.map statement l) in + stmtdotsfn all_functions k d + + and declaration_dots d = + let k d = + match Ast.unwrap d with + Ast.DOTS(l) | Ast.CIRCLES(l) | Ast.STARS(l) -> + multibind (List.map declaration l) in + decldotsfn all_functions k d + + and ident i = + let k i = + match Ast.unwrap i with + Ast.Id(name) -> string_mcode name + | Ast.MetaId(name,_,_,_) -> meta_mcode name + | Ast.MetaFunc(name,_,_,_) -> meta_mcode name + | Ast.MetaLocalFunc(name,_,_,_) -> meta_mcode name + | Ast.OptIdent(id) -> ident id + | Ast.UniqueIdent(id) -> ident id in + identfn all_functions k i + + and expression e = + let k e = + match Ast.unwrap e with + Ast.Ident(id) -> ident id + | Ast.Constant(const) -> const_mcode const + | Ast.FunCall(fn,lp,args,rp) -> + multibind [expression fn; string_mcode lp; expression_dots args; + string_mcode rp] + | Ast.Assignment(left,op,right,simple) -> + multibind [expression left; assign_mcode op; expression right] + | Ast.CondExpr(exp1,why,exp2,colon,exp3) -> + multibind [expression exp1; string_mcode why; + get_option expression exp2; string_mcode colon; + expression exp3] + | Ast.Postfix(exp,op) -> bind (expression exp) (fix_mcode op) + | Ast.Infix(exp,op) -> bind (fix_mcode op) (expression exp) + | Ast.Unary(exp,op) -> bind (unary_mcode op) (expression exp) + | Ast.Binary(left,op,right) -> + multibind [expression left; binary_mcode op; expression right] + | Ast.Nested(left,op,right) -> + multibind [expression left; binary_mcode op; expression right] + | Ast.Paren(lp,exp,rp) -> + multibind [string_mcode lp; expression exp; string_mcode rp] + | Ast.ArrayAccess(exp1,lb,exp2,rb) -> + multibind + [expression exp1; string_mcode lb; expression exp2; + string_mcode rb] + | Ast.RecordAccess(exp,pt,field) -> + multibind [expression exp; string_mcode pt; ident field] + | Ast.RecordPtAccess(exp,ar,field) -> + multibind [expression exp; string_mcode ar; ident field] + | Ast.Cast(lp,ty,rp,exp) -> + multibind + [string_mcode lp; fullType ty; string_mcode rp; expression exp] + | Ast.SizeOfExpr(szf,exp) -> + multibind [string_mcode szf; expression exp] + | Ast.SizeOfType(szf,lp,ty,rp) -> + multibind + [string_mcode szf; string_mcode lp; fullType ty; string_mcode rp] + | Ast.TypeExp(ty) -> fullType ty + | Ast.MetaErr(name,_,_,_) + | Ast.MetaExpr(name,_,_,_,_,_) + | Ast.MetaExprList(name,_,_,_) -> meta_mcode name + | Ast.EComma(cm) -> string_mcode cm + | Ast.DisjExpr(exp_list) -> multibind (List.map expression exp_list) + | Ast.NestExpr(expr_dots,whencode,multi) -> + bind (expression_dots expr_dots) (get_option expression whencode) + | Ast.Edots(dots,whencode) | Ast.Ecircles(dots,whencode) + | Ast.Estars(dots,whencode) -> + bind (string_mcode dots) (get_option expression whencode) + | Ast.OptExp(exp) | Ast.UniqueExp(exp) -> + expression exp in + exprfn all_functions k e + + and fullType ft = + let k ft = + match Ast.unwrap ft with + Ast.Type(cv,ty) -> bind (get_option cv_mcode cv) (typeC ty) + | Ast.DisjType(types) -> multibind (List.map fullType types) + | Ast.OptType(ty) -> fullType ty + | Ast.UniqueType(ty) -> fullType ty in + ftfn all_functions k ft + + and function_pointer (ty,lp1,star,rp1,lp2,params,rp2) extra = + (* have to put the treatment of the identifier into the right position *) + multibind + ([fullType ty; string_mcode lp1; string_mcode star] @ extra @ + [string_mcode rp1; + string_mcode lp2; parameter_dots params; string_mcode rp2]) + + and function_type (ty,lp1,params,rp1) extra = + (* have to put the treatment of the identifier into the right position *) + multibind + ([get_option fullType ty] @ extra @ + [string_mcode lp1; parameter_dots params; string_mcode rp1]) + + and array_type (ty,lb,size,rb) extra = + multibind + ([fullType ty] @ extra @ + [string_mcode lb; get_option expression size; string_mcode rb]) + + and typeC ty = + let k ty = + match Ast.unwrap ty with + Ast.BaseType(ty,sgn) -> + bind (get_option sign_mcode sgn) (base_mcode ty) + | Ast.ImplicitInt(sgn) -> sign_mcode sgn + | Ast.Pointer(ty,star) -> + bind (fullType ty) (string_mcode star) + | Ast.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + function_pointer (ty,lp1,star,rp1,lp2,params,rp2) [] + | Ast.FunctionType (_,ty,lp1,params,rp1) -> + function_type (ty,lp1,params,rp1) [] + | Ast.Array(ty,lb,size,rb) -> array_type (ty,lb,size,rb) [] + | Ast.StructUnionName(kind,name) -> + bind (struct_mcode kind) (get_option ident name) + | Ast.StructUnionDef(ty,lb,decls,rb) -> + multibind + [fullType ty; string_mcode lb; declaration_dots decls; + string_mcode rb] + | Ast.TypeName(name) -> string_mcode name + | Ast.MetaType(name,_,_) -> meta_mcode name in + tyfn all_functions k ty + + and named_type ty id = + match Ast.unwrap ty with + Ast.Type(None,ty1) -> + (match Ast.unwrap ty1 with + Ast.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + function_pointer (ty,lp1,star,rp1,lp2,params,rp2) [ident id] + | Ast.FunctionType(_,ty,lp1,params,rp1) -> + function_type (ty,lp1,params,rp1) [ident id] + | Ast.Array(ty,lb,size,rb) -> array_type (ty,lb,size,rb) [ident id] + | _ -> bind (fullType ty) (ident id)) + | _ -> bind (fullType ty) (ident id) + + and declaration d = + let k d = + match Ast.unwrap d with + Ast.Init(stg,ty,id,eq,ini,sem) -> + bind (get_option storage_mcode stg) + (bind (named_type ty id) + (multibind + [string_mcode eq; initialiser ini; string_mcode sem])) + | Ast.UnInit(stg,ty,id,sem) -> + bind (get_option storage_mcode stg) + (bind (named_type ty id) (string_mcode sem)) + | Ast.MacroDecl(name,lp,args,rp,sem) -> + multibind + [ident name; string_mcode lp; expression_dots args; + string_mcode rp; string_mcode sem] + | Ast.TyDecl(ty,sem) -> bind (fullType ty) (string_mcode sem) + | Ast.Typedef(stg,ty,id,sem) -> + bind (string_mcode stg) + (bind (fullType ty) (bind (typeC id) (string_mcode sem))) + | Ast.DisjDecl(decls) -> multibind (List.map declaration decls) + | Ast.Ddots(dots,whencode) -> + bind (string_mcode dots) (get_option declaration whencode) + | Ast.MetaDecl(name,_,_) -> meta_mcode name + | Ast.OptDecl(decl) -> declaration decl + | Ast.UniqueDecl(decl) -> declaration decl in + declfn all_functions k d + + and initialiser i = + let k i = + match Ast.unwrap i with + Ast.InitExpr(exp) -> expression exp + | Ast.InitList(lb,initlist,rb,whencode) -> + multibind + [string_mcode lb; + multibind (List.map initialiser initlist); + string_mcode rb; + multibind (List.map initialiser whencode)] + | Ast.InitGccDotName(dot,name,eq,ini) -> + multibind + [string_mcode dot; ident name; string_mcode eq; initialiser ini] + | Ast.InitGccName(name,eq,ini) -> + multibind [ident name; string_mcode eq; initialiser ini] + | Ast.InitGccIndex(lb,exp,rb,eq,ini) -> + multibind + [string_mcode lb; expression exp; string_mcode rb; + string_mcode eq; initialiser ini] + | Ast.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> + multibind + [string_mcode lb; expression exp1; string_mcode dots; + expression exp2; string_mcode rb; string_mcode eq; + initialiser ini] + | Ast.IComma(cm) -> string_mcode cm + | Ast.OptIni(i) -> initialiser i + | Ast.UniqueIni(i) -> initialiser i in + initfn all_functions k i + + and parameterTypeDef p = + let k p = + match Ast.unwrap p with + Ast.VoidParam(ty) -> fullType ty + | Ast.Param(ty,Some id) -> named_type ty id + | Ast.Param(ty,None) -> fullType ty + | Ast.MetaParam(name,_,_) -> meta_mcode name + | Ast.MetaParamList(name,_,_,_) -> meta_mcode name + | Ast.PComma(cm) -> string_mcode cm + | Ast.Pdots(dots) -> string_mcode dots + | Ast.Pcircles(dots) -> string_mcode dots + | Ast.OptParam(param) -> parameterTypeDef param + | Ast.UniqueParam(param) -> parameterTypeDef param in + paramfn all_functions k p + + and rule_elem re = + let k re = + match Ast.unwrap re with + Ast.FunHeader(_,_,fi,name,lp,params,rp) -> + multibind + ((List.map fninfo fi) @ + [ident name;string_mcode lp;parameter_dots params; + string_mcode rp]) + | Ast.Decl(_,_,decl) -> declaration decl + | Ast.SeqStart(brace) -> string_mcode brace + | Ast.SeqEnd(brace) -> string_mcode brace + | Ast.ExprStatement(exp,sem) -> + bind (expression exp) (string_mcode sem) + | Ast.IfHeader(iff,lp,exp,rp) -> + multibind [string_mcode iff; string_mcode lp; expression exp; + string_mcode rp] + | Ast.Else(els) -> string_mcode els + | Ast.WhileHeader(whl,lp,exp,rp) -> + multibind [string_mcode whl; string_mcode lp; expression exp; + string_mcode rp] + | Ast.DoHeader(d) -> string_mcode d + | Ast.WhileTail(whl,lp,exp,rp,sem) -> + multibind [string_mcode whl; string_mcode lp; expression exp; + string_mcode rp; string_mcode sem] + | Ast.ForHeader(fr,lp,e1,sem1,e2,sem2,e3,rp) -> + multibind [string_mcode fr; string_mcode lp; + get_option expression e1; string_mcode sem1; + get_option expression e2; string_mcode sem2; + get_option expression e3; string_mcode rp] + | Ast.IteratorHeader(nm,lp,args,rp) -> + multibind [ident nm; string_mcode lp; + expression_dots args; string_mcode rp] + | Ast.SwitchHeader(switch,lp,exp,rp) -> + multibind [string_mcode switch; string_mcode lp; expression exp; + string_mcode rp] + | Ast.Break(br,sem) -> bind (string_mcode br) (string_mcode sem) + | Ast.Continue(cont,sem) -> bind (string_mcode cont) (string_mcode sem) + | Ast.Label(l,dd) -> bind (ident l) (string_mcode dd) + | Ast.Goto(goto,l,sem) -> + bind (string_mcode goto) (bind (ident l) (string_mcode sem)) + | Ast.Return(ret,sem) -> bind (string_mcode ret) (string_mcode sem) + | Ast.ReturnExpr(ret,exp,sem) -> + multibind [string_mcode ret; expression exp; string_mcode sem] + | Ast.MetaStmt(name,_,_,_) -> meta_mcode name + | Ast.MetaStmtList(name,_,_) -> meta_mcode name + | Ast.MetaRuleElem(name,_,_) -> meta_mcode name + | Ast.Exp(exp) -> expression exp + | Ast.TopExp(exp) -> expression exp + | Ast.Ty(ty) -> fullType ty + | Ast.Include(inc,name) -> bind (string_mcode inc) (inc_file_mcode name) + | Ast.DefineHeader(def,id,params) -> + multibind [string_mcode def; ident id; define_parameters params] + | Ast.Default(def,colon) -> bind (string_mcode def) (string_mcode colon) + | Ast.Case(case,exp,colon) -> + multibind [string_mcode case; expression exp; string_mcode colon] + | Ast.DisjRuleElem(res) -> multibind (List.map rule_elem res) in + rulefn all_functions k re + + (* not parameterizable for now... *) + and define_parameters p = + let k p = + match Ast.unwrap p with + Ast.NoParams -> option_default + | Ast.DParams(lp,params,rp) -> + multibind + [string_mcode lp; define_param_dots params; string_mcode rp] in + k p + + and define_param_dots d = + let k d = + match Ast.unwrap d with + Ast.DOTS(l) | Ast.CIRCLES(l) | Ast.STARS(l) -> + multibind (List.map define_param l) in + k d + + and define_param p = + let k p = + match Ast.unwrap p with + Ast.DParam(id) -> ident id + | Ast.DPComma(comma) -> string_mcode comma + | Ast.DPdots(d) -> string_mcode d + | Ast.DPcircles(c) -> string_mcode c + | Ast.OptDParam(dp) -> define_param dp + | Ast.UniqueDParam(dp) -> define_param dp in + k p + + (* discard the result, because the statement is assumed to be already + represented elsewhere in the code *) + and process_bef_aft s = + match Ast.get_dots_bef_aft s with + Ast.NoDots -> () + | Ast.DroppingBetweenDots(stm,ind) -> let _ = statement stm in () + | Ast.AddingBetweenDots(stm,ind) -> let _ = statement stm in () + + and statement s = + process_bef_aft s; + let k s = + match Ast.unwrap s with + Ast.Seq(lbrace,decls,body,rbrace) -> + multibind [rule_elem lbrace; statement_dots decls; + statement_dots body; rule_elem rbrace] + | Ast.IfThen(header,branch,_) -> + multibind [rule_elem header; statement branch] + | Ast.IfThenElse(header,branch1,els,branch2,_) -> + multibind [rule_elem header; statement branch1; rule_elem els; + statement branch2] + | Ast.While(header,body,_) -> + multibind [rule_elem header; statement body] + | Ast.Do(header,body,tail) -> + multibind [rule_elem header; statement body; rule_elem tail] + | Ast.For(header,body,_) -> multibind [rule_elem header; statement body] + | Ast.Iterator(header,body,_) -> + multibind [rule_elem header; statement body] + | Ast.Switch(header,lb,cases,rb) -> + multibind [rule_elem header;rule_elem lb; + multibind (List.map case_line cases); + rule_elem rb] + | Ast.Atomic(re) -> rule_elem re + | Ast.Disj(stmt_dots_list) -> + multibind (List.map statement_dots stmt_dots_list) + | Ast.Nest(stmt_dots,whn,_,_,_) -> + bind (statement_dots stmt_dots) + (multibind (List.map (whencode statement_dots statement) whn)) + | Ast.FunDecl(header,lbrace,decls,body,rbrace) -> + multibind [rule_elem header; rule_elem lbrace; + statement_dots decls; statement_dots body; + rule_elem rbrace] + | Ast.Define(header,body) -> + bind (rule_elem header) (statement_dots body) + | Ast.Dots(d,whn,_,_) | Ast.Circles(d,whn,_,_) | Ast.Stars(d,whn,_,_) -> + bind (string_mcode d) + (multibind (List.map (whencode statement_dots statement) whn)) + | Ast.OptStm(stmt) | Ast.UniqueStm(stmt) -> + statement stmt in + stmtfn all_functions k s + + and fninfo = function + Ast.FStorage(stg) -> storage_mcode stg + | Ast.FType(ty) -> fullType ty + | Ast.FInline(inline) -> string_mcode inline + | Ast.FAttr(attr) -> string_mcode attr + + and whencode notfn alwaysfn = function + Ast.WhenNot a -> notfn a + | Ast.WhenAlways a -> alwaysfn a + | Ast.WhenModifier(_) -> option_default + + and case_line c = + let k c = + match Ast.unwrap c with + Ast.CaseLine(header,code) -> + bind (rule_elem header) (statement_dots code) + | Ast.OptCase(case) -> case_line case in + casefn all_functions k c + + and top_level t = + let k t = + match Ast.unwrap t with + Ast.FILEINFO(old_file,new_file) -> + bind (string_mcode old_file) (string_mcode new_file) + | Ast.DECL(stmt) -> statement stmt + | Ast.CODE(stmt_dots) -> statement_dots stmt_dots + | Ast.ERRORWORDS(exps) -> multibind (List.map expression exps) in + topfn all_functions k t + + and anything a = + let k = function + (*in many cases below, the thing is not even mcode, so we do nothing*) + Ast.FullTypeTag(ft) -> fullType ft + | Ast.BaseTypeTag(bt) -> option_default + | Ast.StructUnionTag(su) -> option_default + | Ast.SignTag(sgn) -> option_default + | Ast.IdentTag(id) -> ident id + | Ast.ExpressionTag(exp) -> expression exp + | Ast.ConstantTag(cst) -> option_default + | Ast.UnaryOpTag(unop) -> option_default + | Ast.AssignOpTag(asgnop) -> option_default + | Ast.FixOpTag(fixop) -> option_default + | Ast.BinaryOpTag(binop) -> option_default + | Ast.ArithOpTag(arithop) -> option_default + | Ast.LogicalOpTag(logop) -> option_default + | Ast.DeclarationTag(decl) -> declaration decl + | Ast.InitTag(ini) -> initialiser ini + | Ast.StorageTag(stg) -> option_default + | Ast.IncFileTag(stg) -> option_default + | Ast.Rule_elemTag(rule) -> rule_elem rule + | Ast.StatementTag(rule) -> statement rule + | Ast.CaseLineTag(case) -> case_line case + | Ast.ConstVolTag(cv) -> option_default + | Ast.Token(tok,info) -> option_default + | Ast.Code(cd) -> top_level cd + | Ast.ExprDotsTag(ed) -> expression_dots ed + | Ast.ParamDotsTag(pd) -> parameter_dots pd + | Ast.StmtDotsTag(sd) -> statement_dots sd + | Ast.DeclDotsTag(sd) -> declaration_dots sd + | Ast.TypeCTag(ty) -> typeC ty + | Ast.ParamTag(param) -> parameterTypeDef param + | Ast.SgrepStartTag(tok) -> option_default + | Ast.SgrepEndTag(tok) -> option_default in + anyfn all_functions k a + + and all_functions = + {combiner_ident = ident; + combiner_expression = expression; + combiner_fullType = fullType; + combiner_typeC = typeC; + combiner_declaration = declaration; + combiner_initialiser = initialiser; + combiner_parameter = parameterTypeDef; + combiner_parameter_list = parameter_dots; + combiner_rule_elem = rule_elem; + combiner_statement = statement; + combiner_case_line = case_line; + combiner_top_level = top_level; + combiner_anything = anything; + combiner_expression_dots = expression_dots; + combiner_statement_dots = statement_dots; + combiner_declaration_dots = declaration_dots} in + all_functions + +(* ---------------------------------------------------------------------- *) + +type 'a inout = 'a -> 'a (* for specifying the type of rebuilder *) + +type rebuilder = + {rebuilder_ident : Ast.ident inout; + rebuilder_expression : Ast.expression inout; + rebuilder_fullType : Ast.fullType inout; + rebuilder_typeC : Ast.typeC inout; + rebuilder_declaration : Ast.declaration inout; + rebuilder_initialiser : Ast.initialiser inout; + rebuilder_parameter : Ast.parameterTypeDef inout; + rebuilder_parameter_list : Ast.parameter_list inout; + rebuilder_statement : Ast.statement inout; + rebuilder_case_line : Ast.case_line inout; + rebuilder_rule_elem : Ast.rule_elem inout; + rebuilder_top_level : Ast.top_level inout; + rebuilder_expression_dots : Ast.expression Ast.dots inout; + rebuilder_statement_dots : Ast.statement Ast.dots inout; + rebuilder_declaration_dots : Ast.declaration Ast.dots inout; + rebuilder_define_param_dots : Ast.define_param Ast.dots inout; + rebuilder_define_param : Ast.define_param inout; + rebuilder_define_parameters : Ast.define_parameters inout; + rebuilder_anything : Ast.anything inout} + +type 'mc rmcode = 'mc Ast.mcode inout +type 'cd rcode = rebuilder -> ('cd inout) -> 'cd inout + + +let rebuilder + meta_mcode string_mcode const_mcode assign_mcode fix_mcode unary_mcode + binary_mcode cv_mcode base_mcode sign_mcode struct_mcode storage_mcode + inc_file_mcode + expdotsfn paramdotsfn stmtdotsfn decldotsfn + identfn exprfn ftfn tyfn initfn paramfn declfn rulefn stmtfn casefn + topfn anyfn = + let get_option f = function + Some x -> Some (f x) + | None -> None in + let rec expression_dots d = + let k d = + Ast.rewrap d + (match Ast.unwrap d with + Ast.DOTS(l) -> Ast.DOTS(List.map expression l) + | Ast.CIRCLES(l) -> Ast.CIRCLES(List.map expression l) + | Ast.STARS(l) -> Ast.STARS(List.map expression l)) in + expdotsfn all_functions k d + + and parameter_dots d = + let k d = + Ast.rewrap d + (match Ast.unwrap d with + Ast.DOTS(l) -> Ast.DOTS(List.map parameterTypeDef l) + | Ast.CIRCLES(l) -> Ast.CIRCLES(List.map parameterTypeDef l) + | Ast.STARS(l) -> Ast.STARS(List.map parameterTypeDef l)) in + paramdotsfn all_functions k d + + and statement_dots d = + let k d = + Ast.rewrap d + (match Ast.unwrap d with + Ast.DOTS(l) -> Ast.DOTS(List.map statement l) + | Ast.CIRCLES(l) -> Ast.CIRCLES(List.map statement l) + | Ast.STARS(l) -> Ast.STARS(List.map statement l)) in + stmtdotsfn all_functions k d + + and declaration_dots d = + let k d = + Ast.rewrap d + (match Ast.unwrap d with + Ast.DOTS(l) -> Ast.DOTS(List.map declaration l) + | Ast.CIRCLES(l) -> Ast.CIRCLES(List.map declaration l) + | Ast.STARS(l) -> Ast.STARS(List.map declaration l)) in + decldotsfn all_functions k d + + and ident i = + let k i = + Ast.rewrap i + (match Ast.unwrap i with + Ast.Id(name) -> Ast.Id(string_mcode name) + | Ast.MetaId(name,constraints,keep,inherited) -> + Ast.MetaId(meta_mcode name,constraints,keep,inherited) + | Ast.MetaFunc(name,constraints,keep,inherited) -> + Ast.MetaFunc(meta_mcode name,constraints,keep,inherited) + | Ast.MetaLocalFunc(name,constraints,keep,inherited) -> + Ast.MetaLocalFunc(meta_mcode name,constraints,keep,inherited) + | Ast.OptIdent(id) -> Ast.OptIdent(ident id) + | Ast.UniqueIdent(id) -> Ast.UniqueIdent(ident id)) in + identfn all_functions k i + + and expression e = + let k e = + Ast.rewrap e + (match Ast.unwrap e with + Ast.Ident(id) -> Ast.Ident(ident id) + | Ast.Constant(const) -> Ast.Constant(const_mcode const) + | Ast.FunCall(fn,lp,args,rp) -> + Ast.FunCall(expression fn, string_mcode lp, expression_dots args, + string_mcode rp) + | Ast.Assignment(left,op,right,simple) -> + Ast.Assignment(expression left, assign_mcode op, expression right, + simple) + | Ast.CondExpr(exp1,why,exp2,colon,exp3) -> + Ast.CondExpr(expression exp1, string_mcode why, + get_option expression exp2, string_mcode colon, + expression exp3) + | Ast.Postfix(exp,op) -> Ast.Postfix(expression exp,fix_mcode op) + | Ast.Infix(exp,op) -> Ast.Infix(expression exp,fix_mcode op) + | Ast.Unary(exp,op) -> Ast.Unary(expression exp,unary_mcode op) + | Ast.Binary(left,op,right) -> + Ast.Binary(expression left, binary_mcode op, expression right) + | Ast.Nested(left,op,right) -> + Ast.Nested(expression left, binary_mcode op, expression right) + | Ast.Paren(lp,exp,rp) -> + Ast.Paren(string_mcode lp, expression exp, string_mcode rp) + | Ast.ArrayAccess(exp1,lb,exp2,rb) -> + Ast.ArrayAccess(expression exp1, string_mcode lb, expression exp2, + string_mcode rb) + | Ast.RecordAccess(exp,pt,field) -> + Ast.RecordAccess(expression exp, string_mcode pt, ident field) + | Ast.RecordPtAccess(exp,ar,field) -> + Ast.RecordPtAccess(expression exp, string_mcode ar, ident field) + | Ast.Cast(lp,ty,rp,exp) -> + Ast.Cast(string_mcode lp, fullType ty, string_mcode rp, + expression exp) + | Ast.SizeOfExpr(szf,exp) -> + Ast.SizeOfExpr(string_mcode szf, expression exp) + | Ast.SizeOfType(szf,lp,ty,rp) -> + Ast.SizeOfType(string_mcode szf,string_mcode lp, fullType ty, + string_mcode rp) + | Ast.TypeExp(ty) -> Ast.TypeExp(fullType ty) + | Ast.MetaErr(name,constraints,keep,inherited) -> + Ast.MetaErr(meta_mcode name,constraints,keep,inherited) + | Ast.MetaExpr(name,constraints,keep,ty,form,inherited) -> + Ast.MetaExpr(meta_mcode name,constraints,keep,ty,form,inherited) + | Ast.MetaExprList(name,lenname_inh,keep,inherited) -> + Ast.MetaExprList(meta_mcode name,lenname_inh,keep,inherited) + | Ast.EComma(cm) -> Ast.EComma(string_mcode cm) + | Ast.DisjExpr(exp_list) -> Ast.DisjExpr(List.map expression exp_list) + | Ast.NestExpr(expr_dots,whencode,multi) -> + Ast.NestExpr(expression_dots expr_dots, + get_option expression whencode,multi) + | Ast.Edots(dots,whencode) -> + Ast.Edots(string_mcode dots,get_option expression whencode) + | Ast.Ecircles(dots,whencode) -> + Ast.Ecircles(string_mcode dots,get_option expression whencode) + | Ast.Estars(dots,whencode) -> + Ast.Estars(string_mcode dots,get_option expression whencode) + | Ast.OptExp(exp) -> Ast.OptExp(expression exp) + | Ast.UniqueExp(exp) -> Ast.UniqueExp(expression exp)) in + exprfn all_functions k e + + and fullType ft = + let k ft = + Ast.rewrap ft + (match Ast.unwrap ft with + Ast.Type(cv,ty) -> Ast.Type (get_option cv_mcode cv, typeC ty) + | Ast.DisjType(types) -> Ast.DisjType(List.map fullType types) + | Ast.OptType(ty) -> Ast.OptType(fullType ty) + | Ast.UniqueType(ty) -> Ast.UniqueType(fullType ty)) in + ftfn all_functions k ft + + and typeC ty = + let k ty = + Ast.rewrap ty + (match Ast.unwrap ty with + Ast.BaseType(ty,sgn) -> + Ast.BaseType (base_mcode ty,get_option sign_mcode sgn) + | Ast.ImplicitInt(sgn) -> Ast.ImplicitInt (sign_mcode sgn) + | Ast.Pointer(ty,star) -> + Ast.Pointer (fullType ty, string_mcode star) + | Ast.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + Ast.FunctionPointer(fullType ty,string_mcode lp1,string_mcode star, + string_mcode rp1,string_mcode lp2, + parameter_dots params, + string_mcode rp2) + | Ast.FunctionType(allminus,ty,lp,params,rp) -> + Ast.FunctionType(allminus,get_option fullType ty,string_mcode lp, + parameter_dots params,string_mcode rp) + | Ast.Array(ty,lb,size,rb) -> + Ast.Array(fullType ty, string_mcode lb, + get_option expression size, string_mcode rb) + | Ast.StructUnionName(kind,name) -> + Ast.StructUnionName (struct_mcode kind, get_option ident name) + | Ast.StructUnionDef(ty,lb,decls,rb) -> + Ast.StructUnionDef (fullType ty, + string_mcode lb, declaration_dots decls, + string_mcode rb) + | Ast.TypeName(name) -> Ast.TypeName(string_mcode name) + | Ast.MetaType(name,keep,inherited) -> + Ast.MetaType(meta_mcode name,keep,inherited)) in + tyfn all_functions k ty + + and declaration d = + let k d = + Ast.rewrap d + (match Ast.unwrap d with + Ast.Init(stg,ty,id,eq,ini,sem) -> + Ast.Init(get_option storage_mcode stg, fullType ty, ident id, + string_mcode eq, initialiser ini, string_mcode sem) + | Ast.UnInit(stg,ty,id,sem) -> + Ast.UnInit(get_option storage_mcode stg, fullType ty, ident id, + string_mcode sem) + | Ast.MacroDecl(name,lp,args,rp,sem) -> + Ast.MacroDecl(ident name, string_mcode lp, expression_dots args, + string_mcode rp,string_mcode sem) + | Ast.TyDecl(ty,sem) -> Ast.TyDecl(fullType ty, string_mcode sem) + | Ast.Typedef(stg,ty,id,sem) -> + Ast.Typedef(string_mcode stg, fullType ty, typeC id, + string_mcode sem) + | Ast.DisjDecl(decls) -> Ast.DisjDecl(List.map declaration decls) + | Ast.Ddots(dots,whencode) -> + Ast.Ddots(string_mcode dots, get_option declaration whencode) + | Ast.MetaDecl(name,keep,inherited) -> + Ast.MetaDecl(meta_mcode name,keep,inherited) + | Ast.OptDecl(decl) -> Ast.OptDecl(declaration decl) + | Ast.UniqueDecl(decl) -> Ast.UniqueDecl(declaration decl)) in + declfn all_functions k d + + and initialiser i = + let k i = + Ast.rewrap i + (match Ast.unwrap i with + Ast.InitExpr(exp) -> Ast.InitExpr(expression exp) + | Ast.InitList(lb,initlist,rb,whencode) -> + Ast.InitList(string_mcode lb, List.map initialiser initlist, + string_mcode rb, List.map initialiser whencode) + | Ast.InitGccDotName(dot,name,eq,ini) -> + Ast.InitGccDotName + (string_mcode dot, ident name, string_mcode eq, initialiser ini) + | Ast.InitGccName(name,eq,ini) -> + Ast.InitGccName(ident name, string_mcode eq, initialiser ini) + | Ast.InitGccIndex(lb,exp,rb,eq,ini) -> + Ast.InitGccIndex + (string_mcode lb, expression exp, string_mcode rb, + string_mcode eq, initialiser ini) + | Ast.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> + Ast.InitGccRange + (string_mcode lb, expression exp1, string_mcode dots, + expression exp2, string_mcode rb, string_mcode eq, + initialiser ini) + | Ast.IComma(cm) -> Ast.IComma(string_mcode cm) + | Ast.OptIni(i) -> Ast.OptIni(initialiser i) + | Ast.UniqueIni(i) -> Ast.UniqueIni(initialiser i)) in + initfn all_functions k i + + and parameterTypeDef p = + let k p = + Ast.rewrap p + (match Ast.unwrap p with + Ast.VoidParam(ty) -> Ast.VoidParam(fullType ty) + | Ast.Param(ty,id) -> Ast.Param(fullType ty, get_option ident id) + | Ast.MetaParam(name,keep,inherited) -> + Ast.MetaParam(meta_mcode name,keep,inherited) + | Ast.MetaParamList(name,lenname_inh,keep,inherited) -> + Ast.MetaParamList(meta_mcode name,lenname_inh,keep,inherited) + | Ast.PComma(cm) -> Ast.PComma(string_mcode cm) + | Ast.Pdots(dots) -> Ast.Pdots(string_mcode dots) + | Ast.Pcircles(dots) -> Ast.Pcircles(string_mcode dots) + | Ast.OptParam(param) -> Ast.OptParam(parameterTypeDef param) + | Ast.UniqueParam(param) -> Ast.UniqueParam(parameterTypeDef param)) in + paramfn all_functions k p + + and rule_elem re = + let k re = + Ast.rewrap re + (match Ast.unwrap re with + Ast.FunHeader(bef,allminus,fi,name,lp,params,rp) -> + Ast.FunHeader(bef,allminus,List.map fninfo fi,ident name, + string_mcode lp, parameter_dots params, + string_mcode rp) + | Ast.Decl(bef,allminus,decl) -> + Ast.Decl(bef,allminus,declaration decl) + | Ast.SeqStart(brace) -> Ast.SeqStart(string_mcode brace) + | Ast.SeqEnd(brace) -> Ast.SeqEnd(string_mcode brace) + | Ast.ExprStatement(exp,sem) -> + Ast.ExprStatement (expression exp, string_mcode sem) + | Ast.IfHeader(iff,lp,exp,rp) -> + Ast.IfHeader(string_mcode iff, string_mcode lp, expression exp, + string_mcode rp) + | Ast.Else(els) -> Ast.Else(string_mcode els) + | Ast.WhileHeader(whl,lp,exp,rp) -> + Ast.WhileHeader(string_mcode whl, string_mcode lp, expression exp, + string_mcode rp) + | Ast.DoHeader(d) -> Ast.DoHeader(string_mcode d) + | Ast.WhileTail(whl,lp,exp,rp,sem) -> + Ast.WhileTail(string_mcode whl, string_mcode lp, expression exp, + string_mcode rp, string_mcode sem) + | Ast.ForHeader(fr,lp,e1,sem1,e2,sem2,e3,rp) -> + Ast.ForHeader(string_mcode fr, string_mcode lp, + get_option expression e1, string_mcode sem1, + get_option expression e2, string_mcode sem2, + get_option expression e3, string_mcode rp) + | Ast.IteratorHeader(whl,lp,args,rp) -> + Ast.IteratorHeader(ident whl, string_mcode lp, + expression_dots args, string_mcode rp) + | Ast.SwitchHeader(switch,lp,exp,rp) -> + Ast.SwitchHeader(string_mcode switch, string_mcode lp, + expression exp, string_mcode rp) + | Ast.Break(br,sem) -> + Ast.Break(string_mcode br, string_mcode sem) + | Ast.Continue(cont,sem) -> + Ast.Continue(string_mcode cont, string_mcode sem) + | Ast.Label(l,dd) -> Ast.Label(ident l, string_mcode dd) + | Ast.Goto(goto,l,sem) -> + Ast.Goto(string_mcode goto,ident l,string_mcode sem) + | Ast.Return(ret,sem) -> + Ast.Return(string_mcode ret, string_mcode sem) + | Ast.ReturnExpr(ret,exp,sem) -> + Ast.ReturnExpr(string_mcode ret, expression exp, string_mcode sem) + | Ast.MetaStmt(name,keep,seqible,inherited) -> + Ast.MetaStmt(meta_mcode name,keep,seqible,inherited) + | Ast.MetaStmtList(name,keep,inherited) -> + Ast.MetaStmtList(meta_mcode name,keep,inherited) + | Ast.MetaRuleElem(name,keep,inherited) -> + Ast.MetaRuleElem(meta_mcode name,keep,inherited) + | Ast.Exp(exp) -> Ast.Exp(expression exp) + | Ast.TopExp(exp) -> Ast.TopExp(expression exp) + | Ast.Ty(ty) -> Ast.Ty(fullType ty) + | Ast.Include(inc,name) -> + Ast.Include(string_mcode inc,inc_file_mcode name) + | Ast.DefineHeader(def,id,params) -> + Ast.DefineHeader(string_mcode def,ident id, + define_parameters params) + | Ast.Default(def,colon) -> + Ast.Default(string_mcode def,string_mcode colon) + | Ast.Case(case,exp,colon) -> + Ast.Case(string_mcode case,expression exp,string_mcode colon) + | Ast.DisjRuleElem(res) -> Ast.DisjRuleElem(List.map rule_elem res)) in + rulefn all_functions k re + + (* not parameterizable for now... *) + and define_parameters p = + let k p = + Ast.rewrap p + (match Ast.unwrap p with + Ast.NoParams -> Ast.NoParams + | Ast.DParams(lp,params,rp) -> + Ast.DParams(string_mcode lp,define_param_dots params, + string_mcode rp)) in + k p + + and define_param_dots d = + let k d = + Ast.rewrap d + (match Ast.unwrap d with + Ast.DOTS(l) -> Ast.DOTS(List.map define_param l) + | Ast.CIRCLES(l) -> Ast.CIRCLES(List.map define_param l) + | Ast.STARS(l) -> Ast.STARS(List.map define_param l)) in + k d + + and define_param p = + let k p = + Ast.rewrap p + (match Ast.unwrap p with + Ast.DParam(id) -> Ast.DParam(ident id) + | Ast.DPComma(comma) -> Ast.DPComma(string_mcode comma) + | Ast.DPdots(d) -> Ast.DPdots(string_mcode d) + | Ast.DPcircles(c) -> Ast.DPcircles(string_mcode c) + | Ast.OptDParam(dp) -> Ast.OptDParam(define_param dp) + | Ast.UniqueDParam(dp) -> Ast.UniqueDParam(define_param dp)) in + k p + + and process_bef_aft s = + Ast.set_dots_bef_aft + (match Ast.get_dots_bef_aft s with + Ast.NoDots -> Ast.NoDots + | Ast.DroppingBetweenDots(stm,ind) -> + Ast.DroppingBetweenDots(statement stm,ind) + | Ast.AddingBetweenDots(stm,ind) -> + Ast.AddingBetweenDots(statement stm,ind)) + s + + and statement s = + let k s = + Ast.rewrap s + (match Ast.unwrap s with + Ast.Seq(lbrace,decls,body,rbrace) -> + Ast.Seq(rule_elem lbrace, statement_dots decls, + statement_dots body, rule_elem rbrace) + | Ast.IfThen(header,branch,aft) -> + Ast.IfThen(rule_elem header, statement branch,aft) + | Ast.IfThenElse(header,branch1,els,branch2,aft) -> + Ast.IfThenElse(rule_elem header, statement branch1, rule_elem els, + statement branch2, aft) + | Ast.While(header,body,aft) -> + Ast.While(rule_elem header, statement body, aft) + | Ast.Do(header,body,tail) -> + Ast.Do(rule_elem header, statement body, rule_elem tail) + | Ast.For(header,body,aft) -> + Ast.For(rule_elem header, statement body, aft) + | Ast.Iterator(header,body,aft) -> + Ast.Iterator(rule_elem header, statement body, aft) + | Ast.Switch(header,lb,cases,rb) -> + Ast.Switch(rule_elem header,rule_elem lb, + List.map case_line cases,rule_elem rb) + | Ast.Atomic(re) -> Ast.Atomic(rule_elem re) + | Ast.Disj(stmt_dots_list) -> + Ast.Disj (List.map statement_dots stmt_dots_list) + | Ast.Nest(stmt_dots,whn,multi,bef,aft) -> + Ast.Nest(statement_dots stmt_dots, + List.map (whencode statement_dots statement) whn, + multi,bef,aft) + | Ast.FunDecl(header,lbrace,decls,body,rbrace) -> + Ast.FunDecl(rule_elem header,rule_elem lbrace, + statement_dots decls, + statement_dots body, rule_elem rbrace) + | Ast.Define(header,body) -> + Ast.Define(rule_elem header,statement_dots body) + | Ast.Dots(d,whn,bef,aft) -> + Ast.Dots(string_mcode d, + List.map (whencode statement_dots statement) whn,bef,aft) + | Ast.Circles(d,whn,bef,aft) -> + Ast.Circles(string_mcode d, + List.map (whencode statement_dots statement) whn, + bef,aft) + | Ast.Stars(d,whn,bef,aft) -> + Ast.Stars(string_mcode d, + List.map (whencode statement_dots statement) whn,bef,aft) + | Ast.OptStm(stmt) -> Ast.OptStm(statement stmt) + | Ast.UniqueStm(stmt) -> Ast.UniqueStm(statement stmt)) in + let s = stmtfn all_functions k s in + (* better to do this after, in case there is an equality test on the whole + statement, eg in free_vars. equality test would require that this + subterm not already be changed *) + process_bef_aft s + + and fninfo = function + Ast.FStorage(stg) -> Ast.FStorage(storage_mcode stg) + | Ast.FType(ty) -> Ast.FType(fullType ty) + | Ast.FInline(inline) -> Ast.FInline(string_mcode inline) + | Ast.FAttr(attr) -> Ast.FAttr(string_mcode attr) + + and whencode notfn alwaysfn = function + Ast.WhenNot a -> Ast.WhenNot (notfn a) + | Ast.WhenAlways a -> Ast.WhenAlways (alwaysfn a) + | Ast.WhenModifier(x) -> Ast.WhenModifier(x) + + and case_line c = + let k c = + Ast.rewrap c + (match Ast.unwrap c with + Ast.CaseLine(header,code) -> + Ast.CaseLine(rule_elem header,statement_dots code) + | Ast.OptCase(case) -> Ast.OptCase(case_line case)) in + casefn all_functions k c + + and top_level t = + let k t = + Ast.rewrap t + (match Ast.unwrap t with + Ast.FILEINFO(old_file,new_file) -> + Ast.FILEINFO (string_mcode old_file, string_mcode new_file) + | Ast.DECL(stmt) -> Ast.DECL(statement stmt) + | Ast.CODE(stmt_dots) -> Ast.CODE(statement_dots stmt_dots) + | Ast.ERRORWORDS(exps) -> Ast.ERRORWORDS (List.map expression exps)) in + topfn all_functions k t + + and anything a = + let k = function + (*in many cases below, the thing is not even mcode, so we do nothing*) + Ast.FullTypeTag(ft) -> Ast.FullTypeTag(fullType ft) + | Ast.BaseTypeTag(bt) as x -> x + | Ast.StructUnionTag(su) as x -> x + | Ast.SignTag(sgn) as x -> x + | Ast.IdentTag(id) -> Ast.IdentTag(ident id) + | Ast.ExpressionTag(exp) -> Ast.ExpressionTag(expression exp) + | Ast.ConstantTag(cst) as x -> x + | Ast.UnaryOpTag(unop) as x -> x + | Ast.AssignOpTag(asgnop) as x -> x + | Ast.FixOpTag(fixop) as x -> x + | Ast.BinaryOpTag(binop) as x -> x + | Ast.ArithOpTag(arithop) as x -> x + | Ast.LogicalOpTag(logop) as x -> x + | Ast.InitTag(decl) -> Ast.InitTag(initialiser decl) + | Ast.DeclarationTag(decl) -> Ast.DeclarationTag(declaration decl) + | Ast.StorageTag(stg) as x -> x + | Ast.IncFileTag(stg) as x -> x + | Ast.Rule_elemTag(rule) -> Ast.Rule_elemTag(rule_elem rule) + | Ast.StatementTag(rule) -> Ast.StatementTag(statement rule) + | Ast.CaseLineTag(case) -> Ast.CaseLineTag(case_line case) + | Ast.ConstVolTag(cv) as x -> x + | Ast.Token(tok,info) as x -> x + | Ast.Code(cd) -> Ast.Code(top_level cd) + | Ast.ExprDotsTag(ed) -> Ast.ExprDotsTag(expression_dots ed) + | Ast.ParamDotsTag(pd) -> Ast.ParamDotsTag(parameter_dots pd) + | Ast.StmtDotsTag(sd) -> Ast.StmtDotsTag(statement_dots sd) + | Ast.DeclDotsTag(sd) -> Ast.DeclDotsTag(declaration_dots sd) + | Ast.TypeCTag(ty) -> Ast.TypeCTag(typeC ty) + | Ast.ParamTag(param) -> Ast.ParamTag(parameterTypeDef param) + | Ast.SgrepStartTag(tok) as x -> x + | Ast.SgrepEndTag(tok) as x -> x in + anyfn all_functions k a + + and all_functions = + {rebuilder_ident = ident; + rebuilder_expression = expression; + rebuilder_fullType= fullType; + rebuilder_typeC = typeC; + rebuilder_declaration = declaration; + rebuilder_initialiser = initialiser; + rebuilder_parameter = parameterTypeDef; + rebuilder_parameter_list = parameter_dots; + rebuilder_rule_elem = rule_elem; + rebuilder_statement = statement; + rebuilder_case_line = case_line; + rebuilder_top_level = top_level; + rebuilder_expression_dots = expression_dots; + rebuilder_statement_dots = statement_dots; + rebuilder_declaration_dots = declaration_dots; + rebuilder_define_param_dots = define_param_dots; + rebuilder_define_param = define_param; + rebuilder_define_parameters = define_parameters; + rebuilder_anything = anything} in + all_functions + diff --git a/parsing_cocci/visitor_ast.mli b/parsing_cocci/visitor_ast.mli new file mode 100644 index 0000000..e1d561a --- /dev/null +++ b/parsing_cocci/visitor_ast.mli @@ -0,0 +1,114 @@ +type 'a combiner = + {combiner_ident : Ast_cocci.ident -> 'a; + combiner_expression : Ast_cocci.expression -> 'a; + combiner_fullType : Ast_cocci.fullType -> 'a; + combiner_typeC : Ast_cocci.typeC -> 'a; + combiner_declaration : Ast_cocci.declaration -> 'a; + combiner_initialiser : Ast_cocci.initialiser -> 'a; + combiner_parameter : Ast_cocci.parameterTypeDef -> 'a; + combiner_parameter_list : Ast_cocci.parameter_list -> 'a; + combiner_rule_elem : Ast_cocci.rule_elem -> 'a; + combiner_statement : Ast_cocci.statement -> 'a; + combiner_case_line : Ast_cocci.case_line -> 'a; + combiner_top_level : Ast_cocci.top_level -> 'a; + combiner_anything : Ast_cocci.anything -> 'a; + combiner_expression_dots : + Ast_cocci.expression Ast_cocci.dots -> 'a; + combiner_statement_dots : + Ast_cocci.statement Ast_cocci.dots -> 'a; + combiner_declaration_dots : + Ast_cocci.declaration Ast_cocci.dots -> 'a} + +type ('mc,'a) cmcode = 'a combiner -> 'mc Ast_cocci.mcode -> 'a +type ('cd,'a) ccode = 'a combiner -> ('cd -> 'a) -> 'cd -> 'a + +val combiner : + ('a -> 'a -> 'a) -> 'a -> + (((string*string),'a) cmcode) -> + ((string,'a) cmcode) -> + ((Ast_cocci.constant,'a) cmcode) -> + ((Ast_cocci.assignOp,'a) cmcode) -> + ((Ast_cocci.fixOp,'a) cmcode) -> + ((Ast_cocci.unaryOp,'a) cmcode) -> + ((Ast_cocci.binaryOp,'a) cmcode) -> + ((Ast_cocci.const_vol,'a) cmcode) -> + ((Ast_cocci.baseType,'a) cmcode) -> + ((Ast_cocci.sign,'a) cmcode) -> + ((Ast_cocci.structUnion,'a) cmcode) -> + ((Ast_cocci.storage,'a) cmcode) -> + ((Ast_cocci.inc_file,'a) cmcode) -> + ((Ast_cocci.expression Ast_cocci.dots,'a) ccode) -> + ((Ast_cocci.parameterTypeDef Ast_cocci.dots,'a) ccode) -> + ((Ast_cocci.statement Ast_cocci.dots,'a) ccode) -> + ((Ast_cocci.declaration Ast_cocci.dots,'a) ccode) -> + ((Ast_cocci.ident,'a) ccode) -> + ((Ast_cocci.expression,'a) ccode) -> + ((Ast_cocci.fullType,'a) ccode) -> + ((Ast_cocci.typeC,'a) ccode) -> + ((Ast_cocci.initialiser,'a) ccode) -> + ((Ast_cocci.parameterTypeDef,'a) ccode) -> + ((Ast_cocci.declaration,'a) ccode) -> + ((Ast_cocci.rule_elem,'a) ccode) -> + ((Ast_cocci.statement,'a) ccode) -> + ((Ast_cocci.case_line,'a) ccode) -> + ((Ast_cocci.top_level,'a) ccode) -> + ((Ast_cocci.anything,'a) ccode) -> + 'a combiner + +type 'a inout = 'a -> 'a (* for specifying the type of rebuilder *) + +type rebuilder = + {rebuilder_ident : Ast_cocci.ident inout; + rebuilder_expression : Ast_cocci.expression inout; + rebuilder_fullType : Ast_cocci.fullType inout; + rebuilder_typeC : Ast_cocci.typeC inout; + rebuilder_declaration : Ast_cocci.declaration inout; + rebuilder_initialiser : Ast_cocci.initialiser inout; + rebuilder_parameter : Ast_cocci.parameterTypeDef inout; + rebuilder_parameter_list : Ast_cocci.parameter_list inout; + rebuilder_statement : Ast_cocci.statement inout; + rebuilder_case_line : Ast_cocci.case_line inout; + rebuilder_rule_elem : Ast_cocci.rule_elem inout; + rebuilder_top_level : Ast_cocci.top_level inout; + rebuilder_expression_dots : Ast_cocci.expression Ast_cocci.dots inout; + rebuilder_statement_dots : Ast_cocci.statement Ast_cocci.dots inout; + rebuilder_declaration_dots : Ast_cocci.declaration Ast_cocci.dots inout; + rebuilder_define_param_dots: Ast_cocci.define_param Ast_cocci.dots inout; + rebuilder_define_param : Ast_cocci.define_param inout; + rebuilder_define_parameters : Ast_cocci.define_parameters inout; + rebuilder_anything : Ast_cocci.anything inout} + +type 'mc rmcode = 'mc Ast_cocci.mcode inout +type 'cd rcode = rebuilder -> ('cd inout) -> 'cd inout + +val rebuilder : + ((string*string) rmcode) -> + (string rmcode) -> + (Ast_cocci.constant rmcode) -> + (Ast_cocci.assignOp rmcode) -> + (Ast_cocci.fixOp rmcode) -> + (Ast_cocci.unaryOp rmcode) -> + (Ast_cocci.binaryOp rmcode) -> + (Ast_cocci.const_vol rmcode) -> + (Ast_cocci.baseType rmcode) -> + (Ast_cocci.sign rmcode) -> + (Ast_cocci.structUnion rmcode) -> + (Ast_cocci.storage rmcode) -> + (Ast_cocci.inc_file rmcode) -> + (Ast_cocci.expression Ast_cocci.dots rcode) -> + (Ast_cocci.parameterTypeDef Ast_cocci.dots rcode) -> + (Ast_cocci.statement Ast_cocci.dots rcode) -> + (Ast_cocci.declaration Ast_cocci.dots rcode) -> + (Ast_cocci.ident rcode) -> + (Ast_cocci.expression rcode) -> + (Ast_cocci.fullType rcode) -> + (Ast_cocci.typeC rcode) -> + (Ast_cocci.initialiser rcode) -> + (Ast_cocci.parameterTypeDef rcode) -> + (Ast_cocci.declaration rcode) -> + (Ast_cocci.rule_elem rcode) -> + (Ast_cocci.statement rcode) -> + (Ast_cocci.case_line rcode) -> + (Ast_cocci.top_level rcode) -> + (Ast_cocci.anything rcode) -> + rebuilder diff --git a/parsing_cocci/visitor_ast0.ml b/parsing_cocci/visitor_ast0.ml new file mode 100644 index 0000000..6a70898 --- /dev/null +++ b/parsing_cocci/visitor_ast0.ml @@ -0,0 +1,1028 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast = Ast_cocci +module Ast0 = Ast0_cocci + +(* --------------------------------------------------------------------- *) +(* Generic traversal: combiner *) +(* parameters: + combining function + treatment of: mcode, identifiers, expressions, typeCs, types, + declarations, statements, toplevels + default value for options *) + +type 'a combiner = + {combiner_ident : Ast0.ident -> 'a; + combiner_expression : Ast0.expression -> 'a; + combiner_typeC : Ast0.typeC -> 'a; + combiner_declaration : Ast0.declaration -> 'a; + combiner_initialiser : Ast0.initialiser -> 'a; + combiner_initialiser_list : Ast0.initialiser_list -> 'a; + combiner_parameter : Ast0.parameterTypeDef -> 'a; + combiner_parameter_list : Ast0.parameter_list -> 'a; + combiner_statement : Ast0.statement -> 'a; + combiner_case_line : Ast0.case_line -> 'a; + combiner_top_level : Ast0.top_level -> 'a; + combiner_expression_dots : + Ast0.expression Ast0.dots -> 'a; + combiner_statement_dots : + Ast0.statement Ast0.dots -> 'a; + combiner_declaration_dots : + Ast0.declaration Ast0.dots -> 'a; + combiner_case_line_dots : + Ast0.case_line Ast0.dots -> 'a; + combiner_anything : Ast0.anything -> 'a} + + +type ('mc,'a) cmcode = 'mc Ast0.mcode -> 'a +type ('cd,'a) ccode = 'a combiner -> ('cd -> 'a) -> 'cd -> 'a + +let combiner bind option_default + meta_mcode string_mcode const_mcode assign_mcode fix_mcode unary_mcode + binary_mcode cv_mcode base_mcode sign_mcode struct_mcode storage_mcode + inc_mcode + dotsexprfn dotsinitfn dotsparamfn dotsstmtfn dotsdeclfn dotscasefn + identfn exprfn + tyfn initfn paramfn declfn stmtfn casefn topfn = + let multibind l = + let rec loop = function + [] -> option_default + | [x] -> x + | x::xs -> bind x (loop xs) in + loop l in + let get_option f = function + Some x -> f x + | None -> option_default in + let rec expression_dots d = + let k d = + match Ast0.unwrap d with + Ast0.DOTS(l) | Ast0.CIRCLES(l) | Ast0.STARS(l) -> + multibind (List.map expression l) in + dotsexprfn all_functions k d + and initialiser_dots d = + let k d = + match Ast0.unwrap d with + Ast0.DOTS(l) | Ast0.CIRCLES(l) | Ast0.STARS(l) -> + multibind (List.map initialiser l) in + dotsinitfn all_functions k d + and parameter_dots d = + let k d = + match Ast0.unwrap d with + Ast0.DOTS(l) | Ast0.CIRCLES(l) | Ast0.STARS(l) -> + multibind (List.map parameterTypeDef l) in + dotsparamfn all_functions k d + and statement_dots d = + let k d = + match Ast0.unwrap d with + Ast0.DOTS(l) | Ast0.CIRCLES(l) | Ast0.STARS(l) -> + multibind (List.map statement l) in + dotsstmtfn all_functions k d + and declaration_dots d = + let k d = + match Ast0.unwrap d with + Ast0.DOTS(l) | Ast0.CIRCLES(l) | Ast0.STARS(l) -> + multibind (List.map declaration l) in + dotsdeclfn all_functions k d + and case_line_dots d = + let k d = + match Ast0.unwrap d with + Ast0.DOTS(l) | Ast0.CIRCLES(l) | Ast0.STARS(l) -> + multibind (List.map case_line l) in + dotscasefn all_functions k d + and ident i = + let k i = + match Ast0.unwrap i with + Ast0.Id(name) -> string_mcode name + | Ast0.MetaId(name,_,_) -> meta_mcode name + | Ast0.MetaFunc(name,_,_) -> meta_mcode name + | Ast0.MetaLocalFunc(name,_,_) -> meta_mcode name + | Ast0.OptIdent(id) -> ident id + | Ast0.UniqueIdent(id) -> ident id in + identfn all_functions k i + and expression e = + let k e = + match Ast0.unwrap e with + Ast0.Ident(id) -> ident id + | Ast0.Constant(const) -> const_mcode const + | Ast0.FunCall(fn,lp,args,rp) -> + multibind + [expression fn; string_mcode lp; expression_dots args; + string_mcode rp] + | Ast0.Assignment(left,op,right,_) -> + multibind [expression left; assign_mcode op; expression right] + | Ast0.CondExpr(exp1,why,exp2,colon,exp3) -> + multibind + [expression exp1; string_mcode why; get_option expression exp2; + string_mcode colon; expression exp3] + | Ast0.Postfix(exp,op) -> bind (expression exp) (fix_mcode op) + | Ast0.Infix(exp,op) -> bind (fix_mcode op) (expression exp) + | Ast0.Unary(exp,op) -> bind (unary_mcode op) (expression exp) + | Ast0.Binary(left,op,right) -> + multibind [expression left; binary_mcode op; expression right] + | Ast0.Nested(left,op,right) -> + multibind [expression left; binary_mcode op; expression right] + | Ast0.Paren(lp,exp,rp) -> + multibind [string_mcode lp; expression exp; string_mcode rp] + | Ast0.ArrayAccess(exp1,lb,exp2,rb) -> + multibind + [expression exp1; string_mcode lb; expression exp2; + string_mcode rb] + | Ast0.RecordAccess(exp,pt,field) -> + multibind [expression exp; string_mcode pt; ident field] + | Ast0.RecordPtAccess(exp,ar,field) -> + multibind [expression exp; string_mcode ar; ident field] + | Ast0.Cast(lp,ty,rp,exp) -> + multibind + [string_mcode lp; typeC ty; string_mcode rp; expression exp] + | Ast0.SizeOfExpr(szf,exp) -> + multibind [string_mcode szf; expression exp] + | Ast0.SizeOfType(szf,lp,ty,rp) -> + multibind + [string_mcode szf; string_mcode lp; typeC ty; string_mcode rp] + | Ast0.TypeExp(ty) -> typeC ty + | Ast0.MetaErr(name,_,_) + | Ast0.MetaExpr(name,_,_,_,_) + | Ast0.MetaExprList(name,_,_) -> meta_mcode name + | Ast0.EComma(cm) -> string_mcode cm + | Ast0.DisjExpr(starter,expr_list,mids,ender) -> + (match expr_list with + [] -> failwith "bad disjunction" + | x::xs -> + bind (string_mcode starter) + (bind (expression x) + (bind + (multibind + (List.map2 + (function mid -> + function x -> + bind (string_mcode mid) (expression x)) + mids xs)) + (string_mcode ender)))) + | Ast0.NestExpr(starter,expr_dots,ender,whencode,multi) -> + bind (string_mcode starter) + (bind (expression_dots expr_dots) + (bind (string_mcode ender) (get_option expression whencode))) + | Ast0.Edots(dots,whencode) | Ast0.Ecircles(dots,whencode) + | Ast0.Estars(dots,whencode) -> + bind (string_mcode dots) (get_option expression whencode) + | Ast0.OptExp(exp) -> expression exp + | Ast0.UniqueExp(exp) -> expression exp in + exprfn all_functions k e + and function_pointer (ty,lp1,star,rp1,lp2,params,rp2) extra = + (* have to put the treatment of the identifier into the right position *) + multibind + ([typeC ty; string_mcode lp1; string_mcode star] @ extra @ + [string_mcode rp1; + string_mcode lp2; parameter_dots params; string_mcode rp2]) + and function_type (ty,lp1,params,rp1) extra = + (* have to put the treatment of the identifier into the right position *) + multibind ([get_option typeC ty] @ extra @ + [string_mcode lp1; parameter_dots params; string_mcode rp1]) + and array_type (ty,lb,size,rb) extra = + multibind + ([typeC ty] @ extra @ + [string_mcode lb; get_option expression size; string_mcode rb]) + and typeC t = + let k t = + match Ast0.unwrap t with + Ast0.ConstVol(cv,ty) -> bind (cv_mcode cv) (typeC ty) + | Ast0.BaseType(ty,sign) -> + bind (get_option sign_mcode sign) (base_mcode ty) + | Ast0.ImplicitInt(sign) -> (sign_mcode sign) + | Ast0.Pointer(ty,star) -> bind (typeC ty) (string_mcode star) + | Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + function_pointer (ty,lp1,star,rp1,lp2,params,rp2) [] + | Ast0.FunctionType(ty,lp1,params,rp1) -> + function_type (ty,lp1,params,rp1) [] + | Ast0.Array(ty,lb,size,rb) -> + array_type (ty,lb,size,rb) [] + | Ast0.StructUnionName(kind,name) -> + bind (struct_mcode kind) (get_option ident name) + | Ast0.StructUnionDef(ty,lb,decls,rb) -> + multibind + [typeC ty;string_mcode lb;declaration_dots decls;string_mcode rb] + | Ast0.TypeName(name) -> string_mcode name + | Ast0.MetaType(name,_) -> meta_mcode name + | Ast0.DisjType(starter,types,mids,ender) -> + (match types with + [] -> failwith "bad disjunction" + | x::xs -> + bind (string_mcode starter) + (bind (typeC x) + (bind + (multibind + (List.map2 + (function mid -> + function x -> + bind (string_mcode mid) (typeC x)) + mids xs)) + (string_mcode ender)))) + | Ast0.OptType(ty) -> typeC ty + | Ast0.UniqueType(ty) -> typeC ty in + tyfn all_functions k t + and named_type ty id = + match Ast0.unwrap ty with + Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + function_pointer (ty,lp1,star,rp1,lp2,params,rp2) [ident id] + | Ast0.FunctionType(ty,lp1,params,rp1) -> + function_type (ty,lp1,params,rp1) [ident id] + | Ast0.Array(ty,lb,size,rb) -> + array_type (ty,lb,size,rb) [ident id] + | _ -> bind (typeC ty) (ident id) + and declaration d = + let k d = + match Ast0.unwrap d with + Ast0.Init(stg,ty,id,eq,ini,sem) -> + bind (get_option storage_mcode stg) + (bind (named_type ty id) + (multibind + [string_mcode eq; initialiser ini; string_mcode sem])) + | Ast0.UnInit(stg,ty,id,sem) -> + bind (get_option storage_mcode stg) + (bind (named_type ty id) (string_mcode sem)) + | Ast0.MacroDecl(name,lp,args,rp,sem) -> + multibind + [ident name; string_mcode lp; expression_dots args; + string_mcode rp; string_mcode sem] + | Ast0.TyDecl(ty,sem) -> bind (typeC ty) (string_mcode sem) + | Ast0.Typedef(stg,ty,id,sem) -> + bind (string_mcode stg) + (bind (typeC ty) (bind (typeC id) (string_mcode sem))) + | Ast0.DisjDecl(starter,decls,mids,ender) -> + (match decls with + [] -> failwith "bad disjunction" + | x::xs -> + bind (string_mcode starter) + (bind (declaration x) + (bind + (multibind + (List.map2 + (function mid -> + function x -> + bind (string_mcode mid) (declaration x)) + mids xs)) + (string_mcode ender)))) + | Ast0.Ddots(dots,whencode) -> + bind (string_mcode dots) (get_option declaration whencode) + | Ast0.OptDecl(decl) -> declaration decl + | Ast0.UniqueDecl(decl) -> declaration decl in + declfn all_functions k d + and initialiser i = + let k i = + match Ast0.unwrap i with + Ast0.InitExpr(exp) -> expression exp + | Ast0.InitList(lb,initlist,rb) -> + multibind + [string_mcode lb; initialiser_dots initlist; string_mcode rb] + | Ast0.InitGccDotName(dot,name,eq,ini) -> + multibind + [string_mcode dot; ident name; string_mcode eq; initialiser ini] + | Ast0.InitGccName(name,eq,ini) -> + multibind [ident name; string_mcode eq; initialiser ini] + | Ast0.InitGccIndex(lb,exp,rb,eq,ini) -> + multibind + [string_mcode lb; expression exp; string_mcode rb; + string_mcode eq; initialiser ini] + | Ast0.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> + multibind + [string_mcode lb; expression exp1; string_mcode dots; + expression exp2; string_mcode rb; string_mcode eq; + initialiser ini] + | Ast0.IComma(cm) -> string_mcode cm + | Ast0.Idots(dots,whencode) -> + bind (string_mcode dots) (get_option initialiser whencode) + | Ast0.OptIni(i) -> initialiser i + | Ast0.UniqueIni(i) -> initialiser i in + initfn all_functions k i + and parameterTypeDef p = + let k p = + match Ast0.unwrap p with + Ast0.VoidParam(ty) -> typeC ty + | Ast0.Param(ty,Some id) -> named_type ty id + | Ast0.Param(ty,None) -> typeC ty + | Ast0.MetaParam(name,_) -> meta_mcode name + | Ast0.MetaParamList(name,_,_) -> meta_mcode name + | Ast0.PComma(cm) -> string_mcode cm + | Ast0.Pdots(dots) -> string_mcode dots + | Ast0.Pcircles(dots) -> string_mcode dots + | Ast0.OptParam(param) -> parameterTypeDef param + | Ast0.UniqueParam(param) -> parameterTypeDef param in + paramfn all_functions k p + + (* discard the result, because the statement is assumed to be already + represented elsewhere in the code *) + and process_bef_aft s = + match Ast0.get_dots_bef_aft s with + Ast0.NoDots -> () + | Ast0.DroppingBetweenDots(stm) -> let _ = statement stm in () + | Ast0.AddingBetweenDots(stm) -> let _ = statement stm in () + + and statement s = + process_bef_aft s; + let k s = + match Ast0.unwrap s with + Ast0.FunDecl(_,fi,name,lp,params,rp,lbrace,body,rbrace) -> + multibind + ((List.map fninfo fi) @ + [ident name; string_mcode lp; + parameter_dots params; string_mcode rp; string_mcode lbrace; + statement_dots body; string_mcode rbrace]) + | Ast0.Decl(_,decl) -> declaration decl + | Ast0.Seq(lbrace,body,rbrace) -> + multibind + [string_mcode lbrace; statement_dots body; string_mcode rbrace] + | Ast0.ExprStatement(exp,sem) -> + bind (expression exp) (string_mcode sem) + | Ast0.IfThen(iff,lp,exp,rp,branch1,_) -> + multibind + [string_mcode iff; string_mcode lp; expression exp; + string_mcode rp; statement branch1] + | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,_) -> + multibind + [string_mcode iff; string_mcode lp; expression exp; + string_mcode rp; statement branch1; string_mcode els; + statement branch2] + | Ast0.While(whl,lp,exp,rp,body,_) -> + multibind + [string_mcode whl; string_mcode lp; expression exp; + string_mcode rp; statement body] + | Ast0.Do(d,body,whl,lp,exp,rp,sem) -> + multibind + [string_mcode d; statement body; string_mcode whl; + string_mcode lp; expression exp; string_mcode rp; + string_mcode sem] + | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,_) -> + multibind + [string_mcode fr; string_mcode lp; get_option expression e1; + string_mcode sem1; get_option expression e2; string_mcode sem2; + get_option expression e3; + string_mcode rp; statement body] + | Ast0.Iterator(nm,lp,args,rp,body,_) -> + multibind + [ident nm; string_mcode lp; expression_dots args; + string_mcode rp; statement body] + | Ast0.Switch(switch,lp,exp,rp,lb,cases,rb) -> + multibind + [string_mcode switch; string_mcode lp; expression exp; + string_mcode rp; string_mcode lb; case_line_dots cases; + string_mcode rb] + | Ast0.Break(br,sem) -> bind (string_mcode br) (string_mcode sem) + | Ast0.Continue(cont,sem) -> bind (string_mcode cont) (string_mcode sem) + | Ast0.Label(l,dd) -> bind (ident l) (string_mcode dd) + | Ast0.Goto(goto,l,sem) -> + bind (string_mcode goto) (bind (ident l) (string_mcode sem)) + | Ast0.Return(ret,sem) -> bind (string_mcode ret) (string_mcode sem) + | Ast0.ReturnExpr(ret,exp,sem) -> + multibind [string_mcode ret; expression exp; string_mcode sem] + | Ast0.MetaStmt(name,_) -> meta_mcode name + | Ast0.MetaStmtList(name,_) -> meta_mcode name + | Ast0.Disj(starter,statement_dots_list,mids,ender) -> + (match statement_dots_list with + [] -> failwith "bad disjunction" + | x::xs -> + bind (string_mcode starter) + (bind (statement_dots x) + (bind + (multibind + (List.map2 + (function mid -> + function x -> + bind (string_mcode mid) (statement_dots x)) + mids xs)) + (string_mcode ender)))) + | Ast0.Nest(starter,stmt_dots,ender,whn,multi) -> + bind (string_mcode starter) + (bind (statement_dots stmt_dots) + (bind (string_mcode ender) + (multibind + (List.map (whencode statement_dots statement) whn)))) + | Ast0.Exp(exp) -> expression exp + | Ast0.TopExp(exp) -> expression exp + | Ast0.Ty(ty) -> typeC ty + | Ast0.Dots(d,whn) | Ast0.Circles(d,whn) | Ast0.Stars(d,whn) -> + bind (string_mcode d) + (multibind (List.map (whencode statement_dots statement) whn)) + | Ast0.Include(inc,name) -> bind (string_mcode inc) (inc_mcode name) + | Ast0.Define(def,id,params,body) -> + multibind [string_mcode def; ident id; define_parameters params; + statement_dots body] + | Ast0.OptStm(re) -> statement re + | Ast0.UniqueStm(re) -> statement re in + stmtfn all_functions k s + + (* not parameterizable for now... *) + and define_parameters p = + let k p = + match Ast0.unwrap p with + Ast0.NoParams -> option_default + | Ast0.DParams(lp,params,rp) -> + multibind + [string_mcode lp; define_param_dots params; string_mcode rp] in + k p + + and define_param_dots d = + let k d = + match Ast0.unwrap d with + Ast0.DOTS(l) | Ast0.CIRCLES(l) | Ast0.STARS(l) -> + multibind (List.map define_param l) in + k d + + and define_param p = + let k p = + match Ast0.unwrap p with + Ast0.DParam(id) -> ident id + | Ast0.DPComma(comma) -> string_mcode comma + | Ast0.DPdots(d) -> string_mcode d + | Ast0.DPcircles(c) -> string_mcode c + | Ast0.OptDParam(dp) -> define_param dp + | Ast0.UniqueDParam(dp) -> define_param dp in + k p + + and fninfo = function + Ast0.FStorage(stg) -> storage_mcode stg + | Ast0.FType(ty) -> typeC ty + | Ast0.FInline(inline) -> string_mcode inline + | Ast0.FAttr(init) -> string_mcode init + + and whencode notfn alwaysfn = function + Ast0.WhenNot a -> notfn a + | Ast0.WhenAlways a -> alwaysfn a + | Ast0.WhenModifier(_) -> option_default + + and case_line c = + let k c = + match Ast0.unwrap c with + Ast0.Default(def,colon,code) -> + multibind [string_mcode def;string_mcode colon;statement_dots code] + | Ast0.Case(case,exp,colon,code) -> + multibind [string_mcode case;expression exp;string_mcode colon; + statement_dots code] + | Ast0.OptCase(case) -> case_line case in + casefn all_functions k c + + and anything a = (* for compile_iso, not parameterisable *) + let k = function + Ast0.DotsExprTag(exprs) -> expression_dots exprs + | Ast0.DotsInitTag(inits) -> initialiser_dots inits + | Ast0.DotsParamTag(params) -> parameter_dots params + | Ast0.DotsStmtTag(stmts) -> statement_dots stmts + | Ast0.DotsDeclTag(decls) -> declaration_dots decls + | Ast0.DotsCaseTag(cases) -> case_line_dots cases + | Ast0.IdentTag(id) -> ident id + | Ast0.ExprTag(exp) -> expression exp + | Ast0.ArgExprTag(exp) -> expression exp + | Ast0.TestExprTag(exp) -> expression exp + | Ast0.TypeCTag(ty) -> typeC ty + | Ast0.ParamTag(param) -> parameterTypeDef param + | Ast0.InitTag(init) -> initialiser init + | Ast0.DeclTag(decl) -> declaration decl + | Ast0.StmtTag(stmt) -> statement stmt + | Ast0.CaseLineTag(c) -> case_line c + | Ast0.TopTag(top) -> top_level top + | Ast0.IsoWhenTag(_) -> option_default + | Ast0.MetaPosTag(var) -> failwith "not supported" in + k a + + and top_level t = + let k t = + match Ast0.unwrap t with + Ast0.FILEINFO(old_file,new_file) -> + bind (string_mcode old_file) (string_mcode new_file) + | Ast0.DECL(stmt_dots) -> statement stmt_dots + | Ast0.CODE(stmt_dots) -> statement_dots stmt_dots + | Ast0.ERRORWORDS(exps) -> multibind (List.map expression exps) + | Ast0.OTHER(_) -> failwith "unexpected code" in + topfn all_functions k t + and all_functions = + {combiner_ident = ident; + combiner_expression = expression; + combiner_typeC = typeC; + combiner_declaration = declaration; + combiner_initialiser = initialiser; + combiner_initialiser_list = initialiser_dots; + combiner_parameter = parameterTypeDef; + combiner_parameter_list = parameter_dots; + combiner_statement = statement; + combiner_case_line = case_line; + combiner_top_level = top_level; + combiner_expression_dots = expression_dots; + combiner_statement_dots = statement_dots; + combiner_declaration_dots = declaration_dots; + combiner_case_line_dots = case_line_dots; + combiner_anything = anything} in + all_functions + +(* --------------------------------------------------------------------- *) +(* Generic traversal: rebuilder *) + +type 'a inout = 'a -> 'a (* for specifying the type of rebuilder *) + +type rebuilder = + {rebuilder_ident : Ast0.ident inout; + rebuilder_expression : Ast0.expression inout; + rebuilder_typeC : Ast0.typeC inout; + rebuilder_declaration : Ast0.declaration inout; + rebuilder_initialiser : Ast0.initialiser inout; + rebuilder_initialiser_list : Ast0.initialiser_list inout; + rebuilder_parameter : Ast0.parameterTypeDef inout; + rebuilder_parameter_list : Ast0.parameter_list inout; + rebuilder_statement : Ast0.statement inout; + rebuilder_case_line : Ast0.case_line inout; + rebuilder_top_level : Ast0.top_level inout; + rebuilder_expression_dots : + Ast0.expression Ast0.dots -> + Ast0.expression Ast0.dots; + rebuilder_statement_dots : + Ast0.statement Ast0.dots -> + Ast0.statement Ast0.dots; + rebuilder_declaration_dots : + Ast0.declaration Ast0.dots -> + Ast0.declaration Ast0.dots; + rebuilder_case_line_dots : + Ast0.case_line Ast0.dots -> + Ast0.case_line Ast0.dots; + rebuilder_anything : + Ast0.anything -> Ast0.anything} + +type 'mc rmcode = 'mc Ast0.mcode inout +type 'cd rcode = rebuilder -> ('cd inout) -> 'cd inout + +let rebuilder = fun + meta_mcode string_mcode const_mcode assign_mcode fix_mcode unary_mcode + binary_mcode cv_mcode base_mcode sign_mcode struct_mcode storage_mcode + inc_mcode + dotsexprfn dotsinitfn dotsparamfn dotsstmtfn dotsdeclfn dotscasefn + identfn exprfn tyfn initfn paramfn declfn stmtfn casefn topfn -> + let get_option f = function + Some x -> Some (f x) + | None -> None in + let rec expression_dots d = + let k d = + Ast0.rewrap d + (match Ast0.unwrap d with + Ast0.DOTS(l) -> Ast0.DOTS(List.map expression l) + | Ast0.CIRCLES(l) -> Ast0.CIRCLES(List.map expression l) + | Ast0.STARS(l) -> Ast0.STARS(List.map expression l)) in + dotsexprfn all_functions k d + and initialiser_list i = + let k i = + Ast0.rewrap i + (match Ast0.unwrap i with + Ast0.DOTS(l) -> Ast0.DOTS(List.map initialiser l) + | Ast0.CIRCLES(l) -> Ast0.CIRCLES(List.map initialiser l) + | Ast0.STARS(l) -> Ast0.STARS(List.map initialiser l)) in + dotsinitfn all_functions k i + and parameter_list d = + let k d = + Ast0.rewrap d + (match Ast0.unwrap d with + Ast0.DOTS(l) -> Ast0.DOTS(List.map parameterTypeDef l) + | Ast0.CIRCLES(l) -> Ast0.CIRCLES(List.map parameterTypeDef l) + | Ast0.STARS(l) -> Ast0.STARS(List.map parameterTypeDef l)) in + dotsparamfn all_functions k d + and statement_dots d = + let k d = + Ast0.rewrap d + (match Ast0.unwrap d with + Ast0.DOTS(l) -> Ast0.DOTS(List.map statement l) + | Ast0.CIRCLES(l) -> Ast0.CIRCLES(List.map statement l) + | Ast0.STARS(l) -> Ast0.STARS(List.map statement l)) in + dotsstmtfn all_functions k d + and declaration_dots d = + let k d = + Ast0.rewrap d + (match Ast0.unwrap d with + Ast0.DOTS(l) -> Ast0.DOTS(List.map declaration l) + | Ast0.CIRCLES(l) -> Ast0.CIRCLES(List.map declaration l) + | Ast0.STARS(l) -> Ast0.STARS(List.map declaration l)) in + dotsdeclfn all_functions k d + and case_line_dots d = + let k d = + Ast0.rewrap d + (match Ast0.unwrap d with + Ast0.DOTS(l) -> Ast0.DOTS(List.map case_line l) + | Ast0.CIRCLES(l) -> Ast0.CIRCLES(List.map case_line l) + | Ast0.STARS(l) -> Ast0.STARS(List.map case_line l)) in + dotscasefn all_functions k d + and ident i = + let k i = + Ast0.rewrap i + (match Ast0.unwrap i with + Ast0.Id(name) -> Ast0.Id(string_mcode name) + | Ast0.MetaId(name,constraints,pure) -> + Ast0.MetaId(meta_mcode name,constraints,pure) + | Ast0.MetaFunc(name,constraints,pure) -> + Ast0.MetaFunc(meta_mcode name,constraints,pure) + | Ast0.MetaLocalFunc(name,constraints,pure) -> + Ast0.MetaLocalFunc(meta_mcode name,constraints,pure) + | Ast0.OptIdent(id) -> Ast0.OptIdent(ident id) + | Ast0.UniqueIdent(id) -> Ast0.UniqueIdent(ident id)) in + identfn all_functions k i + and expression e = + let k e = + Ast0.rewrap e + (match Ast0.unwrap e with + Ast0.Ident(id) -> Ast0.Ident(ident id) + | Ast0.Constant(const) -> Ast0.Constant(const_mcode const) + | Ast0.FunCall(fn,lp,args,rp) -> + Ast0.FunCall(expression fn,string_mcode lp,expression_dots args, + string_mcode rp) + | Ast0.Assignment(left,op,right,simple) -> + Ast0.Assignment(expression left,assign_mcode op,expression right, + simple) + | Ast0.CondExpr(exp1,why,exp2,colon,exp3) -> + Ast0.CondExpr(expression exp1, string_mcode why, + get_option expression exp2, string_mcode colon, + expression exp3) + | Ast0.Postfix(exp,op) -> Ast0.Postfix(expression exp, fix_mcode op) + | Ast0.Infix(exp,op) -> Ast0.Infix(expression exp, fix_mcode op) + | Ast0.Unary(exp,op) -> Ast0.Unary(expression exp, unary_mcode op) + | Ast0.Binary(left,op,right) -> + Ast0.Binary(expression left, binary_mcode op, expression right) + | Ast0.Nested(left,op,right) -> + Ast0.Nested(expression left, binary_mcode op, expression right) + | Ast0.Paren(lp,exp,rp) -> + Ast0.Paren(string_mcode lp, expression exp, string_mcode rp) + | Ast0.ArrayAccess(exp1,lb,exp2,rb) -> + Ast0.ArrayAccess(expression exp1,string_mcode lb,expression exp2, + string_mcode rb) + | Ast0.RecordAccess(exp,pt,field) -> + Ast0.RecordAccess(expression exp, string_mcode pt, ident field) + | Ast0.RecordPtAccess(exp,ar,field) -> + Ast0.RecordPtAccess(expression exp, string_mcode ar, ident field) + | Ast0.Cast(lp,ty,rp,exp) -> + Ast0.Cast(string_mcode lp, typeC ty, string_mcode rp, + expression exp) + | Ast0.SizeOfExpr(szf,exp) -> + Ast0.SizeOfExpr(string_mcode szf, expression exp) + | Ast0.SizeOfType(szf,lp,ty,rp) -> + Ast0.SizeOfType(string_mcode szf,string_mcode lp, typeC ty, + string_mcode rp) + | Ast0.TypeExp(ty) -> Ast0.TypeExp(typeC ty) + | Ast0.MetaErr(name,constraints,pure) -> + Ast0.MetaErr(meta_mcode name,constraints,pure) + | Ast0.MetaExpr(name,constraints,ty,form,pure) -> + Ast0.MetaExpr(meta_mcode name,constraints,ty,form,pure) + | Ast0.MetaExprList(name,lenname,pure) -> + Ast0.MetaExprList(meta_mcode name,lenname,pure) + | Ast0.EComma(cm) -> Ast0.EComma(string_mcode cm) + | Ast0.DisjExpr(starter,expr_list,mids,ender) -> + Ast0.DisjExpr(string_mcode starter,List.map expression expr_list, + List.map string_mcode mids,string_mcode ender) + | Ast0.NestExpr(starter,expr_dots,ender,whencode,multi) -> + Ast0.NestExpr(string_mcode starter,expression_dots expr_dots, + string_mcode ender, get_option expression whencode, + multi) + | Ast0.Edots(dots,whencode) -> + Ast0.Edots(string_mcode dots, get_option expression whencode) + | Ast0.Ecircles(dots,whencode) -> + Ast0.Ecircles(string_mcode dots, get_option expression whencode) + | Ast0.Estars(dots,whencode) -> + Ast0.Estars(string_mcode dots, get_option expression whencode) + | Ast0.OptExp(exp) -> Ast0.OptExp(expression exp) + | Ast0.UniqueExp(exp) -> Ast0.UniqueExp(expression exp)) in + exprfn all_functions k e + and typeC t = + let k t = + Ast0.rewrap t + (match Ast0.unwrap t with + Ast0.ConstVol(cv,ty) -> Ast0.ConstVol(cv_mcode cv,typeC ty) + | Ast0.BaseType(ty,sign) -> + Ast0.BaseType(base_mcode ty, get_option sign_mcode sign) + | Ast0.ImplicitInt(sign) -> Ast0.ImplicitInt(sign_mcode sign) + | Ast0.Pointer(ty,star) -> + Ast0.Pointer(typeC ty, string_mcode star) + | Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) -> + Ast0.FunctionPointer(typeC ty,string_mcode lp1,string_mcode star, + string_mcode rp1,string_mcode lp2, + parameter_list params, + string_mcode rp2) + | Ast0.FunctionType(ty,lp1,params,rp1) -> + Ast0.FunctionType(get_option typeC ty, + string_mcode lp1,parameter_list params, + string_mcode rp1) + | Ast0.Array(ty,lb,size,rb) -> + Ast0.Array(typeC ty, string_mcode lb, + get_option expression size, string_mcode rb) + | Ast0.StructUnionName(kind,name) -> + Ast0.StructUnionName (struct_mcode kind, get_option ident name) + | Ast0.StructUnionDef(ty,lb,decls,rb) -> + Ast0.StructUnionDef (typeC ty, + string_mcode lb, declaration_dots decls, + string_mcode rb) + | Ast0.TypeName(name) -> Ast0.TypeName(string_mcode name) + | Ast0.MetaType(name,pure) -> + Ast0.MetaType(meta_mcode name,pure) + | Ast0.DisjType(starter,types,mids,ender) -> + Ast0.DisjType(string_mcode starter,List.map typeC types, + List.map string_mcode mids,string_mcode ender) + | Ast0.OptType(ty) -> Ast0.OptType(typeC ty) + | Ast0.UniqueType(ty) -> Ast0.UniqueType(typeC ty)) in + tyfn all_functions k t + and declaration d = + let k d = + Ast0.rewrap d + (match Ast0.unwrap d with + Ast0.Init(stg,ty,id,eq,ini,sem) -> + Ast0.Init(get_option storage_mcode stg, + typeC ty, ident id, string_mcode eq, initialiser ini, + string_mcode sem) + | Ast0.UnInit(stg,ty,id,sem) -> + Ast0.UnInit(get_option storage_mcode stg, + typeC ty, ident id, string_mcode sem) + | Ast0.MacroDecl(name,lp,args,rp,sem) -> + Ast0.MacroDecl(ident name,string_mcode lp, + expression_dots args, + string_mcode rp,string_mcode sem) + | Ast0.TyDecl(ty,sem) -> Ast0.TyDecl(typeC ty, string_mcode sem) + | Ast0.Typedef(stg,ty,id,sem) -> + Ast0.Typedef(string_mcode stg, typeC ty, typeC id, + string_mcode sem) + | Ast0.DisjDecl(starter,decls,mids,ender) -> + Ast0.DisjDecl(string_mcode starter,List.map declaration decls, + List.map string_mcode mids,string_mcode ender) + | Ast0.Ddots(dots,whencode) -> + Ast0.Ddots(string_mcode dots, get_option declaration whencode) + | Ast0.OptDecl(decl) -> Ast0.OptDecl(declaration decl) + | Ast0.UniqueDecl(decl) -> Ast0.UniqueDecl(declaration decl)) in + declfn all_functions k d + and initialiser i = + let k i = + Ast0.rewrap i + (match Ast0.unwrap i with + Ast0.InitExpr(exp) -> Ast0.InitExpr(expression exp) + | Ast0.InitList(lb,initlist,rb) -> + Ast0.InitList(string_mcode lb, initialiser_list initlist, + string_mcode rb) + | Ast0.InitGccDotName(dot,name,eq,ini) -> + Ast0.InitGccDotName + (string_mcode dot, ident name, string_mcode eq, initialiser ini) + | Ast0.InitGccName(name,eq,ini) -> + Ast0.InitGccName(ident name, string_mcode eq, initialiser ini) + | Ast0.InitGccIndex(lb,exp,rb,eq,ini) -> + Ast0.InitGccIndex + (string_mcode lb, expression exp, string_mcode rb, + string_mcode eq, initialiser ini) + | Ast0.InitGccRange(lb,exp1,dots,exp2,rb,eq,ini) -> + Ast0.InitGccRange + (string_mcode lb, expression exp1, string_mcode dots, + expression exp2, string_mcode rb, string_mcode eq, + initialiser ini) + | Ast0.IComma(cm) -> Ast0.IComma(string_mcode cm) + | Ast0.Idots(d,whencode) -> + Ast0.Idots(string_mcode d, get_option initialiser whencode) + | Ast0.OptIni(i) -> Ast0.OptIni(initialiser i) + | Ast0.UniqueIni(i) -> Ast0.UniqueIni(initialiser i)) in + initfn all_functions k i + and parameterTypeDef p = + let k p = + Ast0.rewrap p + (match Ast0.unwrap p with + Ast0.VoidParam(ty) -> Ast0.VoidParam(typeC ty) + | Ast0.Param(ty,id) -> Ast0.Param(typeC ty, get_option ident id) + | Ast0.MetaParam(name,pure) -> + Ast0.MetaParam(meta_mcode name,pure) + | Ast0.MetaParamList(name,lenname,pure) -> + Ast0.MetaParamList(meta_mcode name,lenname,pure) + | Ast0.PComma(cm) -> Ast0.PComma(string_mcode cm) + | Ast0.Pdots(dots) -> Ast0.Pdots(string_mcode dots) + | Ast0.Pcircles(dots) -> Ast0.Pcircles(string_mcode dots) + | Ast0.OptParam(param) -> Ast0.OptParam(parameterTypeDef param) + | Ast0.UniqueParam(param) -> + Ast0.UniqueParam(parameterTypeDef param)) in + paramfn all_functions k p + (* not done for combiner, because the statement is assumed to be already + represented elsewhere in the code *) + and process_bef_aft s = + Ast0.set_dots_bef_aft s + (match Ast0.get_dots_bef_aft s with + Ast0.NoDots -> Ast0.NoDots + | Ast0.DroppingBetweenDots(stm) -> + Ast0.DroppingBetweenDots(statement stm) + | Ast0.AddingBetweenDots(stm) -> + Ast0.AddingBetweenDots(statement stm)) + + and statement s = + let k s = + Ast0.rewrap s + (match Ast0.unwrap s with + Ast0.FunDecl(bef,fi,name,lp,params,rp,lbrace,body,rbrace) -> + Ast0.FunDecl(bef,List.map fninfo fi, ident name, + string_mcode lp, parameter_list params, + string_mcode rp, string_mcode lbrace, + statement_dots body, string_mcode rbrace) + | Ast0.Decl(bef,decl) -> Ast0.Decl(bef,declaration decl) + | Ast0.Seq(lbrace,body,rbrace) -> + Ast0.Seq(string_mcode lbrace, statement_dots body, + string_mcode rbrace) + | Ast0.ExprStatement(exp,sem) -> + Ast0.ExprStatement(expression exp, string_mcode sem) + | Ast0.IfThen(iff,lp,exp,rp,branch1,aft) -> + Ast0.IfThen(string_mcode iff, string_mcode lp, expression exp, + string_mcode rp, statement branch1,aft) + | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,aft) -> + Ast0.IfThenElse(string_mcode iff,string_mcode lp,expression exp, + string_mcode rp, statement branch1, string_mcode els, + statement branch2,aft) + | Ast0.While(whl,lp,exp,rp,body,aft) -> + Ast0.While(string_mcode whl, string_mcode lp, expression exp, + string_mcode rp, statement body, aft) + | Ast0.Do(d,body,whl,lp,exp,rp,sem) -> + Ast0.Do(string_mcode d, statement body, string_mcode whl, + string_mcode lp, expression exp, string_mcode rp, + string_mcode sem) + | Ast0.For(fr,lp,e1,sem1,e2,sem2,e3,rp,body,aft) -> + Ast0.For(string_mcode fr, string_mcode lp, + get_option expression e1, string_mcode sem1, + get_option expression e2, string_mcode sem2, + get_option expression e3, + string_mcode rp, statement body, aft) + | Ast0.Iterator(nm,lp,args,rp,body,aft) -> + Ast0.Iterator(ident nm, string_mcode lp, + expression_dots args, + string_mcode rp, statement body, aft) + | Ast0.Switch(switch,lp,exp,rp,lb,cases,rb) -> + Ast0.Switch(string_mcode switch,string_mcode lp,expression exp, + string_mcode rp,string_mcode lb, + case_line_dots cases, string_mcode rb) + | Ast0.Break(br,sem) -> + Ast0.Break(string_mcode br,string_mcode sem) + | Ast0.Continue(cont,sem) -> + Ast0.Continue(string_mcode cont,string_mcode sem) + | Ast0.Label(l,dd) -> Ast0.Label(ident l,string_mcode dd) + | Ast0.Goto(goto,l,sem) -> + Ast0.Goto(string_mcode goto,ident l,string_mcode sem) + | Ast0.Return(ret,sem) -> + Ast0.Return(string_mcode ret,string_mcode sem) + | Ast0.ReturnExpr(ret,exp,sem) -> + Ast0.ReturnExpr(string_mcode ret,expression exp,string_mcode sem) + | Ast0.MetaStmt(name,pure) -> + Ast0.MetaStmt(meta_mcode name,pure) + | Ast0.MetaStmtList(name,pure) -> + Ast0.MetaStmtList(meta_mcode name,pure) + | Ast0.Disj(starter,statement_dots_list,mids,ender) -> + Ast0.Disj(string_mcode starter, + List.map statement_dots statement_dots_list, + List.map string_mcode mids, + string_mcode ender) + | Ast0.Nest(starter,stmt_dots,ender,whn,multi) -> + Ast0.Nest(string_mcode starter,statement_dots stmt_dots, + string_mcode ender, + List.map (whencode statement_dots statement) whn, + multi) + | Ast0.Exp(exp) -> Ast0.Exp(expression exp) + | Ast0.TopExp(exp) -> Ast0.TopExp(expression exp) + | Ast0.Ty(ty) -> Ast0.Ty(typeC ty) + | Ast0.Dots(d,whn) -> + Ast0.Dots(string_mcode d, + List.map (whencode statement_dots statement) whn) + | Ast0.Circles(d,whn) -> + Ast0.Circles(string_mcode d, + List.map (whencode statement_dots statement) whn) + | Ast0.Stars(d,whn) -> + Ast0.Stars(string_mcode d, + List.map (whencode statement_dots statement) whn) + | Ast0.Include(inc,name) -> + Ast0.Include(string_mcode inc,inc_mcode name) + | Ast0.Define(def,id,params,body) -> + Ast0.Define(string_mcode def,ident id, + define_parameters params, + statement_dots body) + | Ast0.OptStm(re) -> Ast0.OptStm(statement re) + | Ast0.UniqueStm(re) -> Ast0.UniqueStm(statement re)) in + let s = stmtfn all_functions k s in + process_bef_aft s + + (* not parameterizable for now... *) + and define_parameters p = + let k p = + Ast0.rewrap p + (match Ast0.unwrap p with + Ast0.NoParams -> Ast0.NoParams + | Ast0.DParams(lp,params,rp) -> + Ast0.DParams(string_mcode lp,define_param_dots params, + string_mcode rp))in + k p + + and define_param_dots d = + let k d = + Ast0.rewrap d + (match Ast0.unwrap d with + Ast0.DOTS(l) -> Ast0.DOTS(List.map define_param l) + | Ast0.CIRCLES(l) -> Ast0.CIRCLES(List.map define_param l) + | Ast0.STARS(l) -> Ast0.STARS(List.map define_param l)) in + k d + + and define_param p = + let k p = + Ast0.rewrap p + (match Ast0.unwrap p with + Ast0.DParam(id) -> Ast0.DParam(ident id) + | Ast0.DPComma(comma) -> Ast0.DPComma(string_mcode comma) + | Ast0.DPdots(d) -> Ast0.DPdots(string_mcode d) + | Ast0.DPcircles(c) -> Ast0.DPcircles(string_mcode c) + | Ast0.OptDParam(dp) -> Ast0.OptDParam(define_param dp) + | Ast0.UniqueDParam(dp) -> Ast0.UniqueDParam(define_param dp)) in + k p + + and fninfo = function + Ast0.FStorage(stg) -> Ast0.FStorage(storage_mcode stg) + | Ast0.FType(ty) -> Ast0.FType(typeC ty) + | Ast0.FInline(inline) -> Ast0.FInline(string_mcode inline) + | Ast0.FAttr(init) -> Ast0.FAttr(string_mcode init) + + and whencode notfn alwaysfn = function + Ast0.WhenNot a -> Ast0.WhenNot (notfn a) + | Ast0.WhenAlways a -> Ast0.WhenAlways (alwaysfn a) + | Ast0.WhenModifier(x) -> Ast0.WhenModifier(x) + + and case_line c = + let k c = + Ast0.rewrap c + (match Ast0.unwrap c with + Ast0.Default(def,colon,code) -> + Ast0.Default(string_mcode def,string_mcode colon, + statement_dots code) + | Ast0.Case(case,exp,colon,code) -> + Ast0.Case(string_mcode case,expression exp,string_mcode colon, + statement_dots code) + | Ast0.OptCase(case) -> Ast0.OptCase(case_line case)) in + casefn all_functions k c + + and top_level t = + let k t = + Ast0.rewrap t + (match Ast0.unwrap t with + Ast0.FILEINFO(old_file,new_file) -> + Ast0.FILEINFO(string_mcode old_file, string_mcode new_file) + | Ast0.DECL(statement_dots) -> + Ast0.DECL(statement statement_dots) + | Ast0.CODE(stmt_dots) -> Ast0.CODE(statement_dots stmt_dots) + | Ast0.ERRORWORDS(exps) -> Ast0.ERRORWORDS(List.map expression exps) + | Ast0.OTHER(_) -> failwith "unexpected code") in + topfn all_functions k t + + and anything a = (* for compile_iso, not parameterisable *) + let k = function + Ast0.DotsExprTag(exprs) -> Ast0.DotsExprTag(expression_dots exprs) + | Ast0.DotsInitTag(inits) -> Ast0.DotsInitTag(initialiser_list inits) + | Ast0.DotsParamTag(params) -> Ast0.DotsParamTag(parameter_list params) + | Ast0.DotsStmtTag(stmts) -> Ast0.DotsStmtTag(statement_dots stmts) + | Ast0.DotsDeclTag(decls) -> Ast0.DotsDeclTag(declaration_dots decls) + | Ast0.DotsCaseTag(cases) -> Ast0.DotsCaseTag(case_line_dots cases) + | Ast0.IdentTag(id) -> Ast0.IdentTag(ident id) + | Ast0.ExprTag(exp) -> Ast0.ExprTag(expression exp) + | Ast0.ArgExprTag(exp) -> Ast0.ArgExprTag(expression exp) + | Ast0.TestExprTag(exp) -> Ast0.TestExprTag(expression exp) + | Ast0.TypeCTag(ty) -> Ast0.TypeCTag(typeC ty) + | Ast0.ParamTag(param) -> Ast0.ParamTag(parameterTypeDef param) + | Ast0.InitTag(init) -> Ast0.InitTag(initialiser init) + | Ast0.DeclTag(decl) -> Ast0.DeclTag(declaration decl) + | Ast0.StmtTag(stmt) -> Ast0.StmtTag(statement stmt) + | Ast0.CaseLineTag(c) -> Ast0.CaseLineTag(case_line c) + | Ast0.TopTag(top) -> Ast0.TopTag(top_level top) + | Ast0.IsoWhenTag(x) -> Ast0.IsoWhenTag(x) + | Ast0.MetaPosTag(var) -> failwith "not supported" in + k a + + (* not done for combiner, because the statement is assumed to be already + represented elsewhere in the code *) + + and all_functions = + {rebuilder_ident = ident; + rebuilder_expression = expression; + rebuilder_typeC = typeC; + rebuilder_declaration = declaration; + rebuilder_initialiser = initialiser; + rebuilder_initialiser_list = initialiser_list; + rebuilder_parameter = parameterTypeDef; + rebuilder_parameter_list = parameter_list; + rebuilder_statement = statement; + rebuilder_case_line = case_line; + rebuilder_top_level = top_level; + rebuilder_expression_dots = expression_dots; + rebuilder_statement_dots = statement_dots; + rebuilder_declaration_dots = declaration_dots; + rebuilder_case_line_dots = case_line_dots; + rebuilder_anything = anything} in + all_functions diff --git a/parsing_cocci/visitor_ast0.mli b/parsing_cocci/visitor_ast0.mli new file mode 100644 index 0000000..47cb8ed --- /dev/null +++ b/parsing_cocci/visitor_ast0.mli @@ -0,0 +1,121 @@ + +(* --------------------------------------------------------------------- *) + +type 'a combiner = + {combiner_ident : Ast0_cocci.ident -> 'a; + combiner_expression : Ast0_cocci.expression -> 'a; + combiner_typeC : Ast0_cocci.typeC -> 'a; + combiner_declaration : Ast0_cocci.declaration -> 'a; + combiner_initialiser : Ast0_cocci.initialiser -> 'a; + combiner_initialiser_list : Ast0_cocci.initialiser_list -> 'a; + combiner_parameter : Ast0_cocci.parameterTypeDef -> 'a; + combiner_parameter_list : Ast0_cocci.parameter_list -> 'a; + combiner_statement : Ast0_cocci.statement -> 'a; + combiner_case_line : Ast0_cocci.case_line -> 'a; + combiner_top_level : Ast0_cocci.top_level -> 'a; + combiner_expression_dots : + Ast0_cocci.expression Ast0_cocci.dots -> 'a; + combiner_statement_dots : + Ast0_cocci.statement Ast0_cocci.dots -> 'a; + combiner_declaration_dots : + Ast0_cocci.declaration Ast0_cocci.dots -> 'a; + combiner_case_line_dots : + Ast0_cocci.case_line Ast0_cocci.dots -> 'a; + combiner_anything : Ast0_cocci.anything -> 'a} + +type ('mc,'a) cmcode = 'mc Ast0_cocci.mcode -> 'a +type ('cd,'a) ccode = 'a combiner -> ('cd -> 'a) -> 'cd -> 'a + +val combiner : + ('a -> 'a -> 'a) -> 'a -> + ((string*string,'a) cmcode) -> + ((string,'a) cmcode) -> + ((Ast_cocci.constant,'a) cmcode) -> + ((Ast_cocci.assignOp,'a) cmcode) -> + ((Ast_cocci.fixOp,'a) cmcode) -> + ((Ast_cocci.unaryOp,'a) cmcode) -> + ((Ast_cocci.binaryOp,'a) cmcode) -> + ((Ast_cocci.const_vol,'a) cmcode) -> + ((Ast_cocci.baseType,'a) cmcode) -> + ((Ast_cocci.sign,'a) cmcode) -> + ((Ast_cocci.structUnion,'a) cmcode) -> + ((Ast_cocci.storage,'a) cmcode) -> + ((Ast_cocci.inc_file,'a) cmcode) -> + ((Ast0_cocci.expression Ast0_cocci.dots,'a) ccode) -> + ((Ast0_cocci.initialiser Ast0_cocci.dots,'a) ccode) -> + ((Ast0_cocci.parameterTypeDef Ast0_cocci.dots,'a) ccode) -> + ((Ast0_cocci.statement Ast0_cocci.dots,'a) ccode) -> + ((Ast0_cocci.declaration Ast0_cocci.dots,'a) ccode) -> + ((Ast0_cocci.case_line Ast0_cocci.dots,'a) ccode) -> + ((Ast0_cocci.ident,'a) ccode) -> + ((Ast0_cocci.expression,'a) ccode) -> + ((Ast0_cocci.typeC,'a) ccode) -> + ((Ast0_cocci.initialiser,'a) ccode) -> + ((Ast0_cocci.parameterTypeDef,'a) ccode) -> + ((Ast0_cocci.declaration,'a) ccode) -> + ((Ast0_cocci.statement,'a) ccode) -> + ((Ast0_cocci.case_line,'a) ccode) -> + ((Ast0_cocci.top_level,'a) ccode) -> + 'a combiner + +type 'a inout = 'a -> 'a (* for specifying the type of rebuilder *) + +type rebuilder = + {rebuilder_ident : Ast0_cocci.ident inout; + rebuilder_expression : Ast0_cocci.expression inout; + rebuilder_typeC : Ast0_cocci.typeC inout; + rebuilder_declaration : Ast0_cocci.declaration inout; + rebuilder_initialiser : Ast0_cocci.initialiser inout; + rebuilder_initialiser_list : Ast0_cocci.initialiser_list inout; + rebuilder_parameter : Ast0_cocci.parameterTypeDef inout; + rebuilder_parameter_list : Ast0_cocci.parameter_list inout; + rebuilder_statement : Ast0_cocci.statement inout; + rebuilder_case_line : Ast0_cocci.case_line inout; + rebuilder_top_level : Ast0_cocci.top_level inout; + rebuilder_expression_dots : + Ast0_cocci.expression Ast0_cocci.dots -> + Ast0_cocci.expression Ast0_cocci.dots; + rebuilder_statement_dots : + Ast0_cocci.statement Ast0_cocci.dots -> + Ast0_cocci.statement Ast0_cocci.dots; + rebuilder_declaration_dots : + Ast0_cocci.declaration Ast0_cocci.dots -> + Ast0_cocci.declaration Ast0_cocci.dots; + rebuilder_case_line_dots : + Ast0_cocci.case_line Ast0_cocci.dots -> + Ast0_cocci.case_line Ast0_cocci.dots; + rebuilder_anything : Ast0_cocci.anything -> Ast0_cocci.anything} + +type 'mc rmcode = 'mc Ast0_cocci.mcode inout +type 'cd rcode = rebuilder -> ('cd inout) -> 'cd inout + +val rebuilder : + ((string*string) rmcode) -> + (string rmcode) -> + (Ast_cocci.constant rmcode) -> + (Ast_cocci.assignOp rmcode) -> + (Ast_cocci.fixOp rmcode) -> + (Ast_cocci.unaryOp rmcode) -> + (Ast_cocci.binaryOp rmcode) -> + (Ast_cocci.const_vol rmcode) -> + (Ast_cocci.baseType rmcode) -> + (Ast_cocci.sign rmcode) -> + (Ast_cocci.structUnion rmcode) -> + (Ast_cocci.storage rmcode) -> + (Ast_cocci.inc_file rmcode) -> + (Ast0_cocci.expression Ast0_cocci.dots rcode) -> + (Ast0_cocci.initialiser Ast0_cocci.dots rcode) -> + (Ast0_cocci.parameterTypeDef Ast0_cocci.dots rcode) -> + (Ast0_cocci.statement Ast0_cocci.dots rcode) -> + (Ast0_cocci.declaration Ast0_cocci.dots rcode) -> + (Ast0_cocci.case_line Ast0_cocci.dots rcode) -> + (Ast0_cocci.ident rcode) -> + (Ast0_cocci.expression rcode) -> + (Ast0_cocci.typeC rcode) -> + (Ast0_cocci.initialiser rcode) -> + (Ast0_cocci.parameterTypeDef rcode) -> + (Ast0_cocci.declaration rcode) -> + (Ast0_cocci.statement rcode) -> + (Ast0_cocci.case_line rcode) -> + (Ast0_cocci.top_level rcode) -> + rebuilder diff --git a/popl/Makefile b/popl/Makefile new file mode 100644 index 0000000..f73dc3b --- /dev/null +++ b/popl/Makefile @@ -0,0 +1,102 @@ +# Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +# Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +# This file is part of Coccinelle. +# +# Coccinelle is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, according to version 2 of the License. +# +# Coccinelle is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Coccinelle. If not, see . +# +# The authors reserve the right to distribute this or future versions of +# Coccinelle under other licenses. + + +#note: if you add a file (a .mli or .ml), dont forget to do a make depend + +TARGET = popl + +SRC = ast_popl.ml asttopopl.ml insert_quantifiers.ml insert_befaft.ml \ +pretty_print_popl.ml popltoctl.ml popl.ml flag_popl.ml + +SYSLIBS=str.cma unix.cma +LIBS=../commons/commons.cma ../globals/globals.cma + +INCLUDE_PATH = -I ../commons -I ../globals \ + -I ../ctl -I ../parsing_c -I ../parsing_cocci -I ../engine + +#The Caml compilers. +#for warning: -w A +#for profiling: -p -inline 0 with OCAMLOPT +CAMLC =ocamlc$(OPTBIN) -dtypes -g +CAMLOPT=ocamlopt$(OPTBIN) $(OPTFLAGS) +CAMLLEX = ocamllex$(OPTBIN) +CAMLYACC= ocamlyacc +CAMLDEP = ocamldep$(OPTBIN) +CAMLMKTOP=ocamlmktop -g -custom + + + +LIB=$(TARGET).cma +OPTLIB=$(LIB:.cma=.cmxa) + +OBJS = $(SRC:.ml=.cmo) +OPTOBJS = $(SRC:.ml=.cmx) + +all: $(LIB) +all.opt: $(OPTLIB) + +$(TARGET).top: $(LIB) + $(CAMLMKTOP) -o $(TARGET).top $(SYSLIBS) $(LIBS) $(OBJS) + +$(LIB): $(OBJS) + $(CAMLC) -a -o $(LIB) $(OBJS) + +clean:: + rm -f $(LIB) $(TARGET).top + + +$(OPTLIB): $(OPTOBJS) + $(CAMLOPT) -a -o $(OPTLIB) $(OPTOBJS) + +# clean rule for LIB.opt +clean:: + rm -f $(OPTLIB) $(LIB:.cma=.a) + + +.SUFFIXES: +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(CAMLC) $(INCLUDE_PATH) -c $< + +.mli.cmi: + $(CAMLC) $(INCLUDE_PATH) -c $< + +.ml.cmx: + $(CAMLOPT) $(INCLUDE_PATH) -c $< + + + + +# clean rule for others files +clean:: + rm -f *.cm[iox] *.o *.annot + rm -f *~ .*~ #*# + +depend: + $(CAMLDEP) $(INCLUDE_PATH) *.mli *.ml > .depend + +#clean:: +# rm -f .depend + +.depend: + $(CAMLDEP) $(INCLUDE_PATH) *.mli *.ml > .depend + +-include .depend diff --git a/popl/ast_popl.ml b/popl/ast_popl.ml new file mode 100644 index 0000000..1f315e9 --- /dev/null +++ b/popl/ast_popl.ml @@ -0,0 +1,38 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +type sequence = + Seq of element * sequence + | Empty + | SExists of Ast_cocci.meta_name * sequence + +and element = + Term of Ast_cocci.rule_elem + | Or of sequence * sequence + | DInfo of dots * element list (* before *) * element list (* after *) + | EExists of Ast_cocci.meta_name * element + +and dots = + Dots + | Nest of sequence + | When of dots * sequence + | DExists of Ast_cocci.meta_name * dots diff --git a/popl/asttopopl.ml b/popl/asttopopl.ml new file mode 100644 index 0000000..4aae802 --- /dev/null +++ b/popl/asttopopl.ml @@ -0,0 +1,74 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast = Ast_cocci +module Past = Ast_popl + +(* --------------------------------------------------------------------- *) + +let rec stm s = + match Ast.unwrap s with + Ast.Atomic(ast) -> + (match Ast.unwrap ast with + Ast.ExprStatement(_,_) -> Past.Term ast + | Ast.Exp(_) -> Past.Term ast + | Ast.Decl(_,_,_) -> Past.Term ast + | _ -> failwith "complex statements not supported") + | Ast.Disj(stm1::stm2::stmts) -> + List.fold_left + (function prev -> + function cur -> + Past.Or(Past.Seq(prev,Past.Empty),stm_list cur)) + (Past.Or(stm_list stm1,stm_list stm2)) stmts + | Ast.Dots(dots,whencodes,_,_) -> + (match whencodes with + [Ast.WhenNot(a)] -> Past.DInfo(Past.When(Past.Dots,stm_list a),[],[]) + | _ -> failwith "only one when != supported") + | Ast.Nest(stmt_dots,whencodes,false,_,_) -> + let nest = Past.Nest(stm_list stmt_dots) in + (match whencodes with + [Ast.WhenNot(a)] -> Past.DInfo(Past.When(nest,stm_list a),[],[]) + | _ -> failwith "only when != supported") + | Ast.While(header,body,(_,_,_,aft)) | Ast.For(header,body,(_,_,_,aft)) -> + (* only allowed if only the header is significant *) + (match (Ast.unwrap body,aft) with + (Ast.Atomic(re),Ast.CONTEXT(_,Ast.NOTHING)) -> + (match Ast.unwrap re with + Ast.MetaStmt(_,Type_cocci.Unitary,_,false) -> Past.Term header + | _ -> failwith "unsupported statement1") + | _ -> failwith "unsupported statement2") + | _ -> + Pretty_print_cocci.statement "" s; + failwith "unsupported statement3" + +and stm_list s = + match Ast.unwrap s with + Ast.DOTS(d) -> + List.fold_right + (function cur -> function rest -> Past.Seq(stm cur, rest)) + d Past.Empty + | _ -> failwith "only DOTS handled" + +let top s = + match Ast.unwrap s with + Ast.CODE(stmt_dots) -> stm_list stmt_dots + | _ -> failwith "only CODE handled" diff --git a/popl/asttopopl.mli b/popl/asttopopl.mli new file mode 100644 index 0000000..5d8e4b1 --- /dev/null +++ b/popl/asttopopl.mli @@ -0,0 +1 @@ +val top : Ast_cocci.top_level -> Ast_popl.sequence diff --git a/popl/insert_befaft.ml b/popl/insert_befaft.ml new file mode 100644 index 0000000..8d6d340 --- /dev/null +++ b/popl/insert_befaft.ml @@ -0,0 +1,113 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Past = Ast_popl + +(* --------------------------------------------------------------------- *) + +let rec get_before a = function + Past.Seq(elem,seq) -> + let (elem,ea) = get_before_element a elem in + let (seq,sla) = get_before ea seq in + (Past.Seq(elem,seq),sla) + | Past.Empty -> (Past.Empty,a) + | Past.SExists(var,seq) -> failwith "not possible" + +and get_before_element a = function + Past.Term(term) as s -> (s,[s]) + | Past.Or(seq1,seq2) -> + let (seq1,seq1a) = get_before a seq1 in + let (seq2,seq2a) = get_before a seq2 in + (Past.Or(seq1,seq2),Common.union_set seq1a seq2a) + | Past.DInfo(dots,_,seq_aft) -> + let dots = get_before_dots a dots in + (Past.DInfo(dots,a,seq_aft),a) + | Past.EExists(var,seq) -> failwith "not possible" + +and get_before_dots a = function + Past.Dots -> Past.Dots + | Past.Nest(seq) -> + let (seq,_) = get_before a seq in + Past.Nest(seq) + | Past.When(dots,seq) -> + let dots = get_before_dots a dots in + let (seq,_) = get_before [] seq in + Past.When(dots,seq) + | Past.DExists(var,dots) -> failwith "not possible" + +(* --------------------------------------------------------------------- *) + +let rec get_after a = function + Past.Seq(elem,seq) -> + let (seq,sla) = get_after a seq in + let (elem,ea) = get_after_element sla elem in + (Past.Seq(elem,seq),ea) + | Past.Empty -> (Past.Empty,a) + | Past.SExists(var,seq) -> failwith "not possible" + +and get_after_element a = function + Past.Term(term) as s -> (s,[s]) + | Past.Or(seq1,seq2) -> + let (seq1,seq1a) = get_after a seq1 in + let (seq2,seq2a) = get_after a seq2 in + (Past.Or(seq1,seq2),Common.union_set seq1a seq2a) + | Past.DInfo(dots,seq_bef,_) -> + let dots = get_after_dots a dots in + (Past.DInfo(dots,seq_bef,a),a) + | Past.EExists(var,seq) -> failwith "not possible" + +and get_after_dots a = function + Past.Dots -> Past.Dots + | Past.Nest(seq) -> + let (seq,_) = get_after (Common.union_set (get_first [] seq) a) seq in + Past.Nest(seq) + | Past.When(dots,seq) -> + let dots = get_after_dots a dots in + let (seq,_) = get_after [] seq in + Past.When(dots,seq) + | Past.DExists(var,dots) -> failwith "not possible" + +(* --------------------------------------------------------------------- *) +(* like get_after, but just returns the a component; doesn't modify the term *) + +and get_first a = function + Past.Seq(elem,seq) -> + let sla = get_first a seq in + let ea = get_first_element sla elem in + ea + | Past.Empty -> a + | Past.SExists(var,seq) -> failwith "not possible" + +and get_first_element a = function + Past.Term(term) as s -> [s] + | Past.Or(seq1,seq2) -> + Common.union_set (get_first a seq1) (get_first a seq2) + | Past.DInfo(dots,_,_) -> a + | Past.EExists(var,seq) -> failwith "not possible" + +(* --------------------------------------------------------------------- *) +(* Entry point *) + +let insert_befaft sl = + let (sl,_) = get_before [] sl in + let (sl,_) = get_after [] sl in + sl diff --git a/popl/insert_befaft.mli b/popl/insert_befaft.mli new file mode 100644 index 0000000..eea1354 --- /dev/null +++ b/popl/insert_befaft.mli @@ -0,0 +1 @@ +val insert_befaft : Ast_popl.sequence -> Ast_popl.sequence diff --git a/popl/insert_quantifiers.ml b/popl/insert_quantifiers.ml new file mode 100644 index 0000000..356fbad --- /dev/null +++ b/popl/insert_quantifiers.ml @@ -0,0 +1,95 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast = Ast_cocci +module Past = Ast_popl + +(* --------------------------------------------------------------------- *) + +let rec fvs_sequence = function + Past.Seq(elem,seq) -> + Common.union_set (fvs_element elem) (fvs_sequence seq) + | Past.Empty -> [] + | Past.SExists(var,seq) -> failwith "not possible" + +and fvs_element = function + Past.Term(term) -> Ast.get_fvs term + | Past.Or(seq1,seq2) -> + Common.union_set (fvs_sequence seq1) (fvs_sequence seq2) + | Past.DInfo(dots,seq_bef,seq_aft) -> + List.fold_left + (function prev -> + function cur -> + Common.union_set (fvs_element cur) prev) + (fvs_dots dots) seq_bef + | Past.EExists(var,seq) -> failwith "not possible" + +and fvs_dots = function + Past.Dots -> [] + | Past.Nest(seq) -> fvs_sequence seq + | Past.When(dots,seq) -> Common.union_set (fvs_dots dots) (fvs_sequence seq) + | Past.DExists(var,dots) -> failwith "not possible" + +(* --------------------------------------------------------------------- *) + +let rec quant_sequence bound = function + Past.Seq(elem,seq) -> + let fe = fvs_element elem in + let fs = fvs_sequence seq in + let inter = Common.inter_set fe fs in + let free = Common.minus_set inter bound in + let new_bound = free @ bound in + List.fold_right (function cur -> function rest -> Past.SExists(cur,rest)) + free (Past.Seq(quant_element new_bound elem, + quant_sequence new_bound seq)) + | Past.Empty -> Past.Empty + | Past.SExists(var,seq) -> failwith "not possible" + +and quant_element bound = function + Past.Term(term) as x -> + let free = Common.minus_set (fvs_element x) bound in + List.fold_right (function cur -> function rest -> Past.EExists(cur,rest)) + free x + | Past.Or(seq1,seq2) -> + Past.Or(quant_sequence bound seq1,quant_sequence bound seq2) + | Past.DInfo(dots,seq_bef,seq_aft) -> + Past.DInfo(quant_dots bound dots,seq_bef, + List.map (quant_element bound) seq_aft) + | Past.EExists(var,seq) -> failwith "not possible" + +and quant_dots bound = function + Past.Dots -> Past.Dots + | Past.Nest(seq) -> Past.Nest(quant_sequence bound seq) + | Past.When(dots,seq) -> + let fd = fvs_dots dots in + let fs = fvs_sequence seq in + let inter = Common.inter_set fd fs in + let free = Common.minus_set inter bound in + let new_bound = free @ bound in + List.fold_right (function cur -> function rest -> Past.DExists(cur,rest)) + free (Past.When(quant_dots new_bound dots, + quant_sequence new_bound seq)) + | Past.DExists(var,dots) -> failwith "not possible" + +(* --------------------------------------------------------------------- *) + +let insert_quantifiers x = quant_sequence [] x diff --git a/popl/insert_quantifiers.mli b/popl/insert_quantifiers.mli new file mode 100644 index 0000000..b8eef27 --- /dev/null +++ b/popl/insert_quantifiers.mli @@ -0,0 +1 @@ +val insert_quantifiers : Ast_popl.sequence -> Ast_popl.sequence diff --git a/popl/popl.ml b/popl/popl.ml new file mode 100644 index 0000000..fca3ede --- /dev/null +++ b/popl/popl.ml @@ -0,0 +1,39 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +type cocci_predicate = Lib_engine.predicate * Ast_cocci.meta_name Ast_ctl.modif +type formula = + (cocci_predicate,Ast_cocci.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl + +let poplz (name,_,ast) = + match ast with + [ast] -> + let ast = Asttopopl.top ast in + let ba = Insert_befaft.insert_befaft ast in + let qt = Insert_quantifiers.insert_quantifiers ba in + [Popltoctl.toctl qt] + | _ -> failwith "only one rule allowed" + +let popl r = + match r with + Ast_cocci.CocciRule (a,b,c) -> poplz (a,b,c) + | _ -> [] diff --git a/popl/popl.mli b/popl/popl.mli new file mode 100644 index 0000000..4a7fd49 --- /dev/null +++ b/popl/popl.mli @@ -0,0 +1,5 @@ +type cocci_predicate = Lib_engine.predicate * Ast_cocci.meta_name Ast_ctl.modif +type formula = + (cocci_predicate,Ast_cocci.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl + +val popl : Ast_cocci.rule -> formula list diff --git a/popl/popltoctl.ml b/popl/popltoctl.ml new file mode 100644 index 0000000..fe5660c --- /dev/null +++ b/popl/popltoctl.ml @@ -0,0 +1,202 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Past = Ast_popl +module Ast = Ast_cocci +module V = Visitor_ast +module CTL = Ast_ctl + +(* --------------------------------------------------------------------- *) +(* result type *) + +type cocci_predicate = Lib_engine.predicate * Ast.meta_name Ast_ctl.modif +type formula = + (cocci_predicate,Ast_cocci.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl + +(* --------------------------------------------------------------------- *) + +let contains_modif = + let bind x y = x or y in + let option_default = false in + let mcode r (_,_,kind,_) = + match kind with + Ast.MINUS(_,_) -> true + | Ast.PLUS -> failwith "not possible" + | Ast.CONTEXT(_,info) -> not (info = Ast.NOTHING) in + let do_nothing r k e = k e in + let rule_elem r k re = + let res = k re in + match Ast.unwrap re with + Ast.FunHeader(bef,_,fninfo,name,lp,params,rp) -> + bind (mcode r ((),(),bef,Ast.NoMetaPos)) res + | Ast.Decl(bef,_,decl) -> bind (mcode r ((),(),bef,Ast.NoMetaPos)) res + | _ -> res in + let recursor = + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + do_nothing do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing + do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in + recursor.V.combiner_rule_elem + +let ctl_exists v x keep_wit = CTL.Exists(v,x,keep_wit) + +let predmaker guard term = + let pos = ("","_p") in + ctl_exists true pos + (if guard && contains_modif term + then + let v = ("","_v") in + ctl_exists true v + (CTL.Pred (Lib_engine.Match(term),CTL.Modif v)) + else CTL.Pred (Lib_engine.Match(term),CTL.Control)) + +(* --------------------------------------------------------------------- *) + +let is_true = function CTL.True -> true | _ -> false + +let is_false = function CTL.False -> true | _ -> false + +let ctl_true = CTL.True + +let ctl_false = CTL.False + +let ctl_and x y = + if is_true x then y + else if is_true y then x else CTL.And(CTL.STRICT,x,y) + +let ctl_or x y = + if is_false x then y + else if is_false y then x else CTL.Or(x,y) + +let ctl_seqor x y = CTL.SeqOr(x,y) + +let ctl_not x = CTL.Not(x) + +let ctl_ax x = + if is_true x then CTL.True + else CTL.AX(CTL.FORWARD,CTL.STRICT,x) + +let after = CTL.Pred(Lib_engine.After, CTL.Control) +let exit = CTL.Pred(Lib_engine.Exit, CTL.Control) +let truepred = CTL.Pred(Lib_engine.TrueBranch, CTL.Control) +let retpred = CTL.Pred(Lib_engine.Return, CTL.Control) + +let string2var x = ("",x) + +let labelctr = ref 0 +let get_label_ctr _ = + let cur = !labelctr in + labelctr := cur + 1; + string2var (Printf.sprintf "l%d" cur) + +let ctl_au x seq_after y = + let lv = get_label_ctr() in + let labelpred = CTL.Pred(Lib_engine.Label lv,CTL.Control) in + let preflabelpred = CTL.Pred(Lib_engine.PrefixLabel lv,CTL.Control) in + let matchgoto = CTL.Pred(Lib_engine.Goto,CTL.Control) in + let matchbreak = + predmaker false + (Ast.make_term + (Ast.Break(Ast.make_mcode "break",Ast.make_mcode ";"))) in + let matchcontinue = + predmaker false + (Ast.make_term + (Ast.Continue(Ast.make_mcode "continue",Ast.make_mcode ";"))) in + let stop_early = + ctl_or after + (ctl_and (ctl_and truepred labelpred) + (CTL.AU + (CTL.FORWARD,CTL.STRICT,preflabelpred, + ctl_and preflabelpred + (ctl_or retpred + (ctl_and (ctl_or (ctl_or matchgoto matchbreak) matchcontinue) + (CTL.AG + (CTL.FORWARD,CTL.STRICT, + ctl_not seq_after))))))) in + CTL.AU(CTL.FORWARD,CTL.STRICT,x,ctl_or y stop_early) + +let ctl_uncheck x = CTL.Uncheck(x) + +(* --------------------------------------------------------------------- *) + +let rec ctl_seq keep_wit a = function + Past.Seq(elem,seq) -> + ctl_element keep_wit (ctl_seq keep_wit a seq) elem + | Past.Empty -> a + | Past.SExists(var,seq) -> ctl_exists keep_wit var (ctl_seq keep_wit a seq) + +and ctl_element keep_wit a = function + Past.Term(term) -> ctl_and (predmaker keep_wit term) (ctl_ax a) + | Past.Or(seq1,seq2) -> + ctl_seqor (ctl_seq keep_wit a seq1) (ctl_seq keep_wit a seq2) + | Past.DInfo(dots,seq_bef,seq_aft) -> + let shortest l = + List.fold_left ctl_or ctl_false + (List.map (ctl_element false ctl_true) l) in + let s = shortest (Common.union_set seq_bef seq_aft) in + ctl_au (ctl_and (guard_ctl_dots keep_wit dots) (ctl_not s)) + (shortest seq_aft) a + | Past.EExists(var,elem) -> + ctl_exists keep_wit var (ctl_element keep_wit a elem) + +(* --------------------------------------------------------------------- *) + +and guard_ctl_seq keep_wit = function + Past.Seq(elem,Past.Empty) -> guard_ctl_element keep_wit elem + | Past.Seq(elem,seq) -> + ctl_element keep_wit (guard_ctl_seq keep_wit seq) elem + | Past.Empty -> ctl_true + | Past.SExists(var,seq) -> + ctl_exists keep_wit var (guard_ctl_seq keep_wit seq) + +and guard_ctl_element keep_wit = function + Past.Term(term) -> predmaker keep_wit term + | Past.Or(seq1,seq2) -> + ctl_seqor (guard_ctl_seq keep_wit seq1) (guard_ctl_seq keep_wit seq2) + | Past.DInfo(dots,seq_bef,seq_aft) -> + let shortest l = + List.fold_left ctl_or ctl_false + (List.map (ctl_element false ctl_true) l) in + let s = shortest (Common.union_set seq_bef seq_aft) in + let aft = ctl_or s exit in + ctl_au (ctl_and (guard_ctl_dots keep_wit dots) (ctl_not s)) + (shortest seq_aft) aft + | Past.EExists(var,elem) -> + ctl_exists keep_wit var (guard_ctl_element keep_wit elem) + +and guard_ctl_dots keep_wit = function + Past.Dots -> ctl_true + | Past.Nest(_) when not keep_wit -> ctl_true + | Past.Nest(seq) -> + ctl_or (guard_ctl_seq true seq) (ctl_not (guard_ctl_seq false seq)) + | Past.When(dots,seq) -> + ctl_and + (guard_ctl_dots keep_wit dots) + (ctl_not (ctl_seq false ctl_true seq)) + | Past.DExists(var,dots) -> + ctl_exists keep_wit var (guard_ctl_dots keep_wit dots) + +(* --------------------------------------------------------------------- *) + +let toctl sl = ctl_seq true ctl_true sl diff --git a/popl/popltoctl.mli b/popl/popltoctl.mli new file mode 100644 index 0000000..b1285d1 --- /dev/null +++ b/popl/popltoctl.mli @@ -0,0 +1,5 @@ +type cocci_predicate = Lib_engine.predicate * Ast_cocci.meta_name Ast_ctl.modif +type formula = + (cocci_predicate,Ast_cocci.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl + +val toctl : Ast_popl.sequence -> formula diff --git a/popl/pretty_print_popl.ml b/popl/pretty_print_popl.ml new file mode 100644 index 0000000..b3ca128 --- /dev/null +++ b/popl/pretty_print_popl.ml @@ -0,0 +1,76 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Format +module Past = Ast_popl + +let start_block str = + force_newline(); print_string " "; open_box 0 + +let end_block str = + close_box(); force_newline () + +(* --------------------------------------------------------------------- *) + +let rec print_sequence = function + Past.Seq(e,seq) -> print_element e; force_newline(); print_sequence seq + | Past.Empty -> () + | Past.SExists((_,v),seq) -> print_string "exists "; print_string v; + print_string " ."; force_newline(); print_sequence seq + +and print_element = function + Past.Term(term) -> Pretty_print_cocci.rule_elem "" term + | Past.Or(seq1,seq2) -> + force_newline(); print_string "("; force_newline(); print_sequence seq1; + print_string "|"; force_newline(); print_sequence seq2; print_string ")" + | Past.DInfo(dots,bef,aft) -> + start_block(); + List.iter + (function b -> print_string ">>>"; print_element b; force_newline()) + bef; + print_dots dots; + List.iter + (function b -> force_newline(); print_string "<<<"; print_element b) + aft; + end_block() + | Past.EExists((_,v),elem) -> print_string "exists "; print_string v; + print_string " ."; force_newline(); print_element elem + +and print_dots = function + Past.Dots -> print_string "..." + | Past.Nest(seq)-> print_string "<..."; start_block(); print_sequence seq; + end_block(); print_string "...>" + | Past.When(dots,seq) -> print_dots dots; print_string " when != "; + open_box 0; print_sequence seq; close_box() + | Past.DExists((_,v),dots) -> print_string "exists "; print_string v; + print_string " ."; force_newline(); print_dots dots + +(* --------------------------------------------------------------------- *) + +let pretty_print_e e = + print_element e; + print_newline() + +let pretty_print sl = + print_sequence sl; + print_newline() + diff --git a/popl/pretty_print_popl.mli b/popl/pretty_print_popl.mli new file mode 100644 index 0000000..5b3399a --- /dev/null +++ b/popl/pretty_print_popl.mli @@ -0,0 +1,2 @@ +val pretty_print : Ast_popl.sequence -> unit +val pretty_print_e : Ast_popl.element -> unit diff --git a/popl09/.depend b/popl09/.depend new file mode 100644 index 0000000..687e676 --- /dev/null +++ b/popl09/.depend @@ -0,0 +1,33 @@ +asttopopl.cmi: ast_popl.cmo ../parsing_cocci/ast_cocci.cmi +insert_quantifiers.cmi: ast_popl.cmo +popl.cmi: ../ctl/wrapper_ctl.cmi ../engine/lib_engine.cmo ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi +popltoctl.cmi: ../ctl/wrapper_ctl.cmi ../engine/lib_engine.cmo ast_popl.cmo \ + ../ctl/ast_ctl.cmo ../parsing_cocci/ast_cocci.cmi +pretty_print_popl.cmi: ast_popl.cmo +ast_popl.cmo: ../parsing_cocci/ast_cocci.cmi +ast_popl.cmx: ../parsing_cocci/ast_cocci.cmx +asttopopl.cmo: ../parsing_cocci/pretty_print_cocci.cmi ast_popl.cmo \ + ../parsing_cocci/ast_cocci.cmi asttopopl.cmi +asttopopl.cmx: ../parsing_cocci/pretty_print_cocci.cmx ast_popl.cmx \ + ../parsing_cocci/ast_cocci.cmx asttopopl.cmi +insert_quantifiers.cmo: ../commons/common.cmi ast_popl.cmo \ + ../parsing_cocci/ast_cocci.cmi insert_quantifiers.cmi +insert_quantifiers.cmx: ../commons/common.cmx ast_popl.cmx \ + ../parsing_cocci/ast_cocci.cmx insert_quantifiers.cmi +popl.cmo: ../ctl/wrapper_ctl.cmi popltoctl.cmi ../engine/lib_engine.cmo \ + insert_quantifiers.cmi asttopopl.cmi ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi popl.cmi +popl.cmx: ../ctl/wrapper_ctl.cmx popltoctl.cmx ../engine/lib_engine.cmx \ + insert_quantifiers.cmx asttopopl.cmx ../ctl/ast_ctl.cmx \ + ../parsing_cocci/ast_cocci.cmx popl.cmi +popltoctl.cmo: ../ctl/wrapper_ctl.cmi ../parsing_cocci/visitor_ast.cmi \ + ../engine/lib_engine.cmo flag_popl.cmo ast_popl.cmo ../ctl/ast_ctl.cmo \ + ../parsing_cocci/ast_cocci.cmi popltoctl.cmi +popltoctl.cmx: ../ctl/wrapper_ctl.cmx ../parsing_cocci/visitor_ast.cmx \ + ../engine/lib_engine.cmx flag_popl.cmx ast_popl.cmx ../ctl/ast_ctl.cmx \ + ../parsing_cocci/ast_cocci.cmx popltoctl.cmi +pretty_print_popl.cmo: ../parsing_cocci/pretty_print_cocci.cmi ast_popl.cmo \ + ../parsing_cocci/ast_cocci.cmi pretty_print_popl.cmi +pretty_print_popl.cmx: ../parsing_cocci/pretty_print_cocci.cmx ast_popl.cmx \ + ../parsing_cocci/ast_cocci.cmx pretty_print_popl.cmi diff --git a/popl09/Makefile b/popl09/Makefile new file mode 100644 index 0000000..96ec617 --- /dev/null +++ b/popl09/Makefile @@ -0,0 +1,101 @@ +# Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +# Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +# This file is part of Coccinelle. +# +# Coccinelle is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, according to version 2 of the License. +# +# Coccinelle is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Coccinelle. If not, see . +# +# The authors reserve the right to distribute this or future versions of +# Coccinelle under other licenses. + + +#note: if you add a file (a .mli or .ml), dont forget to do a make depend + +TARGET = popl + +SRC = ast_popl.ml asttopopl.ml insert_quantifiers.ml \ +pretty_print_popl.ml flag_popl.ml popltoctl.ml popl.ml + +SYSLIBS=str.cma unix.cma +LIBS=../commons/commons.cma ../globals/globals.cma + +INCLUDES = -I ../commons -I ../globals \ + -I ../ctl -I ../parsing_c -I ../parsing_cocci -I ../engine + +#The Caml compilers. +#for warning: -w A +#for profiling: -p -inline 0 with OCAMLOPT +OCAMLCFLAGS ?= -g -dtypes +OCAMLC =ocamlc$(OPTBIN) $(OCAMLCFLAGS) $(INCLUDES) +OCAMLOPT = ocamlopt$(OPTBIN) $(OPTFLAGS) $(INCLUDES) +OCAMLDEP = ocamldep$(OPTBIN) $(INCLUDES) +OCAMLMKTOP=ocamlmktop -g -custom + + + +LIB=$(TARGET).cma +OPTLIB=$(LIB:.cma=.cmxa) + +OBJS = $(SRC:.ml=.cmo) +OPTOBJS = $(SRC:.ml=.cmx) + +all: $(LIB) +all.opt: $(OPTLIB) + +$(TARGET).top: $(LIB) + $(OCAMLMKTOP) -o $(TARGET).top $(SYSLIBS) $(LIBS) $(OBJS) + +$(LIB): $(OBJS) + $(OCAMLC) -a -o $(LIB) $(OBJS) + +clean:: + rm -f $(LIB) $(TARGET).top + + +$(OPTLIB): $(OPTOBJS) + $(OCAMLOPT) -a -o $(OPTLIB) $(OPTOBJS) + +# clean rule for LIB.opt +clean:: + rm -f $(OPTLIB) $(LIB:.cma=.a) + + +.SUFFIXES: +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) -c $< + +.mli.cmi: + $(OCAMLC) -c $< + +.ml.cmx: + $(OCAMLOPT) -c $< + + + + +# clean rule for others files +clean:: + rm -f *.cm[iox] *.o *.annot + rm -f *~ .*~ #*# + +depend: + $(OCAMLDEP) *.mli *.ml > .depend + +#clean:: +# rm -f .depend + +.depend: + $(OCAMLDEP) $(INCLUDE_PATH) *.mli *.ml > .depend + +-include .depend diff --git a/popl09/ast_popl.ml b/popl09/ast_popl.ml new file mode 100644 index 0000000..b05a619 --- /dev/null +++ b/popl09/ast_popl.ml @@ -0,0 +1,48 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +type sequence = + Seq of element * sequence + | Empty + | SExists of Ast_cocci.meta_name * sequence + +and term = + Atomic of Ast_cocci.rule_elem + | IfThen of term * term * Ast_cocci.end_info + | TExists of Ast_cocci.meta_name * term + +and element = + Term of term * dots_bef_aft + | Or of sequence * sequence + | DInfo of dots + | EExists of Ast_cocci.meta_name * element + +and dots = + Dots + | Nest of sequence + | When of dots * sequence + +and dots_bef_aft = + NoDots + | AddingBetweenDots of term * int (*index of let var*) + | DroppingBetweenDots of term * int (*index of let var*) + diff --git a/popl09/asttopopl.ml b/popl09/asttopopl.ml new file mode 100644 index 0000000..ed339e2 --- /dev/null +++ b/popl09/asttopopl.ml @@ -0,0 +1,98 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast = Ast_cocci +module Past = Ast_popl + +(* --------------------------------------------------------------------- *) + +let term s inif = + let fail _ = + Pretty_print_cocci.statement "" s; + Format.print_newline(); + failwith "complex statements not supported" in + match Ast.unwrap s with + Ast.Atomic(ast) -> + (match Ast.unwrap ast with + Ast.ExprStatement(_,_) -> Past.Atomic ast + | Ast.Exp(_) -> Past.Atomic ast + | Ast.Decl(_,_,_) -> Past.Atomic ast + | Ast.ReturnExpr(_,_,_) -> Past.Atomic ast + | Ast.MetaStmt(_,_,_,_) when inif -> Past.Atomic ast + | Ast.DisjRuleElem(_) -> Past.Atomic ast + | _ -> fail()) + | _ -> fail() + +let rec stm s = + match Ast.unwrap s with + Ast.Atomic(ast) -> Past.Term(term s false,dots_bef_aft s false) + | Ast.IfThen(header,body,aft) -> + Past.Term( + Past.IfThen(Past.Atomic header,term body true,aft), + dots_bef_aft s true) + | Ast.Disj(stm1::stm2::stmts) -> + List.fold_left + (function prev -> + function cur -> + Past.Or(Past.Seq(prev,Past.Empty),stm_list cur)) + (Past.Or(stm_list stm1,stm_list stm2)) stmts + | Ast.Dots(dots,whencodes,_,_) -> + Past.DInfo + (List.fold_left + (function prev -> + function + Ast.WhenNot(a) -> Past.When(prev,stm_list a) + | _ -> failwith "only when != supported") + Past.Dots whencodes) + | Ast.Nest(stmt_dots,whencodes,false,_,_) -> + let nest = Past.Nest(stm_list stmt_dots) in + Past.DInfo + (List.fold_left + (function prev -> + function + Ast.WhenNot(a) -> Past.When(prev,stm_list a) + | _ -> failwith "only when != supported") + nest whencodes) + | _ -> + Pretty_print_cocci.statement "" s; + failwith "unsupported statement3" + +and dots_bef_aft s inif = + match Ast.get_dots_bef_aft s with + Ast.AddingBetweenDots (brace_term,n) -> + Past.AddingBetweenDots (term brace_term inif,n) + | Ast.DroppingBetweenDots (brace_term,n) -> + Past.DroppingBetweenDots (term brace_term inif,n) + | Ast.NoDots -> Past.NoDots + +and stm_list s = + match Ast.unwrap s with + Ast.DOTS(d) -> + List.fold_right + (function cur -> function rest -> Past.Seq(stm cur, rest)) + d Past.Empty + | _ -> failwith "only DOTS handled" + +let top s = + match Ast.unwrap s with + Ast.CODE(stmt_dots) -> stm_list stmt_dots + | _ -> failwith "only CODE handled" diff --git a/popl09/asttopopl.mli b/popl09/asttopopl.mli new file mode 100644 index 0000000..5d8e4b1 --- /dev/null +++ b/popl09/asttopopl.mli @@ -0,0 +1 @@ +val top : Ast_cocci.top_level -> Ast_popl.sequence diff --git a/popl09/flag_popl.ml b/popl09/flag_popl.ml new file mode 100644 index 0000000..75f7906 --- /dev/null +++ b/popl09/flag_popl.ml @@ -0,0 +1,24 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +let mark_all = ref false +let keep_all_wits = ref false diff --git a/popl09/insert_quantifiers.ml b/popl09/insert_quantifiers.ml new file mode 100644 index 0000000..4dc4ea0 --- /dev/null +++ b/popl09/insert_quantifiers.ml @@ -0,0 +1,113 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Ast = Ast_cocci +module Past = Ast_popl + +(* --------------------------------------------------------------------- *) + +let rec fvs_sequence = function + Past.Seq(elem,seq) -> + Common.union_set (fvs_element elem) (fvs_sequence seq) + | Past.Empty -> [] + | Past.SExists(var,seq) -> failwith "not possible" + +and fvs_term = function + Past.Atomic(term) -> Ast.get_fvs term + | Past.IfThen(test,thn,(afvs,_,_,_)) -> + Common.union_set afvs + (Common.union_set (fvs_term test) (fvs_term thn)) + | Past.TExists(var,term) -> failwith "not possible" + +and fvs_element = function + Past.Term(term,_) -> fvs_term term + | Past.Or(seq1,seq2) -> + Common.union_set (fvs_sequence seq1) (fvs_sequence seq2) + | Past.DInfo(dots) -> fvs_dots dots + | Past.EExists(var,seq) -> failwith "not possible" + +and fvs_dots = function + Past.Dots -> [] + | Past.Nest(seq) -> fvs_sequence seq + | Past.When(dots,seq) -> Common.union_set (fvs_dots dots) (fvs_sequence seq) + +(* --------------------------------------------------------------------- *) + +let inter_set l1 l2 = List.filter (function l1e -> List.mem l1e l2) l1 + +let minus_set l1 l2 = List.filter (function l1e -> not (List.mem l1e l2)) l1 + +let rec quant_sequence bound = function + Past.Seq(elem,seq) -> + let fe = fvs_element elem in + let fs = fvs_sequence seq in + let inter = inter_set fe fs in + let free = minus_set inter bound in + let new_bound = free @ bound in + List.fold_right (function cur -> function rest -> Past.SExists(cur,rest)) + free (Past.Seq(quant_element new_bound elem, + quant_sequence new_bound seq)) + | Past.Empty -> Past.Empty + | Past.SExists(var,seq) -> failwith "not possible" + +and quant_term bound = function + (Past.Atomic(term)) as x -> + let free = minus_set (Ast.get_fvs term) bound in + List.fold_right (function cur -> function rest -> Past.TExists(cur,rest)) + free x + | Past.IfThen(test,thn,((afvs,_,_,_) as aft)) -> + let fts = fvs_term test in + let fth = fvs_term thn in + let inter = inter_set fts fth in + let free = minus_set inter bound in + let new_bound = free @ bound in + List.fold_right (function cur -> function rest -> Past.TExists(cur,rest)) + free (Past.IfThen(quant_term new_bound test, + quant_term new_bound thn, + aft)) + | Past.TExists(var,term) -> failwith "not possible" + +and quant_element bound = function + Past.Term(term,ba) -> + Past.Term(quant_term bound term,dots_bef_aft bound ba) + | Past.Or(seq1,seq2) -> + Past.Or(quant_sequence bound seq1,quant_sequence bound seq2) + | Past.DInfo(dots) -> + Past.DInfo(quant_dots bound dots) + | Past.EExists(var,seq) -> failwith "not possible" + +and dots_bef_aft bound = function + Past.AddingBetweenDots (brace_term,n) -> + Past.AddingBetweenDots (quant_term bound brace_term,n) + | Past.DroppingBetweenDots (brace_term,n) -> + Past.DroppingBetweenDots (quant_term bound brace_term,n) + | Past.NoDots -> Past.NoDots + +and quant_dots bound = function + Past.Dots -> Past.Dots + | Past.Nest(seq) -> Past.Nest(quant_sequence bound seq) + | Past.When(dots,seq) -> + Past.When(quant_dots bound dots, quant_sequence bound seq) + +(* --------------------------------------------------------------------- *) + +let insert_quantifiers x = quant_sequence [] x diff --git a/popl09/insert_quantifiers.mli b/popl09/insert_quantifiers.mli new file mode 100644 index 0000000..b8eef27 --- /dev/null +++ b/popl09/insert_quantifiers.mli @@ -0,0 +1 @@ +val insert_quantifiers : Ast_popl.sequence -> Ast_popl.sequence diff --git a/popl09/popl.ml b/popl09/popl.ml new file mode 100644 index 0000000..dd9d2ca --- /dev/null +++ b/popl09/popl.ml @@ -0,0 +1,38 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +type cocci_predicate = Lib_engine.predicate * Ast_cocci.meta_name Ast_ctl.modif +type formula = + (cocci_predicate,Ast_cocci.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl + +let poplz (name,_,ast) = + match ast with + [ast] -> + let ast = Asttopopl.top ast in + let qt = Insert_quantifiers.insert_quantifiers ast in + [Popltoctl.toctl qt] + | _ -> failwith "only one rule allowed" + +let popl r = + match r with + Ast_cocci.CocciRule (a,b,c,_) -> poplz (a,b,c) + | _ -> [] diff --git a/popl09/popl.mli b/popl09/popl.mli new file mode 100644 index 0000000..4a7fd49 --- /dev/null +++ b/popl09/popl.mli @@ -0,0 +1,5 @@ +type cocci_predicate = Lib_engine.predicate * Ast_cocci.meta_name Ast_ctl.modif +type formula = + (cocci_predicate,Ast_cocci.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl + +val popl : Ast_cocci.rule -> formula list diff --git a/popl09/popltoctl.ml b/popl09/popltoctl.ml new file mode 100644 index 0000000..ef7a92f --- /dev/null +++ b/popl09/popltoctl.ml @@ -0,0 +1,238 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +module Past = Ast_popl +module Ast = Ast_cocci +module V = Visitor_ast +module CTL = Ast_ctl + +(* --------------------------------------------------------------------- *) +(* result type *) + +type cocci_predicate = Lib_engine.predicate * Ast.meta_name Ast_ctl.modif +type formula = + (cocci_predicate,Ast_cocci.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl + +(* --------------------------------------------------------------------- *) + +let contains_modif = + let bind x y = x or y in + let option_default = false in + let mcode r (_,_,kind,_) = + match kind with + Ast.MINUS(_,_) -> true + | Ast.PLUS -> failwith "not possible" + | Ast.CONTEXT(_,info) -> not (info = Ast.NOTHING) in + let do_nothing r k e = k e in + let rule_elem r k re = + let res = k re in + match Ast.unwrap re with + Ast.FunHeader(bef,_,fninfo,name,lp,params,rp) -> + bind (mcode r ((),(),bef,Ast.NoMetaPos)) res + | Ast.Decl(bef,_,decl) -> bind (mcode r ((),(),bef,Ast.NoMetaPos)) res + | _ -> res in + let recursor = + V.combiner bind option_default + mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode + mcode + do_nothing do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing + do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in + recursor.V.combiner_rule_elem + +let ctl_exists keep_wit v x = + CTL.Exists(!Flag_popl.keep_all_wits or keep_wit,v,x) + +let predmaker keep_wit term = + if (!Flag_popl.keep_all_wits or keep_wit) && + (!Flag_popl.mark_all or contains_modif term) + then + let v = ("","_v") in + ctl_exists true v + (CTL.Pred (Lib_engine.Match(term),CTL.Modif v)) + else CTL.Pred (Lib_engine.Match(term),CTL.Control) + +(* --------------------------------------------------------------------- *) + +let is_true = function CTL.True -> true | _ -> false + +let is_false = function CTL.False -> true | _ -> false + +let ctl_true = CTL.True + +let ctl_false = CTL.False + +let ctl_and x y = + if is_true x then y + else if is_true y then x else CTL.And(CTL.STRICT,x,y) + +let ctl_or x y = + if is_false x then y + else if is_false y then x else CTL.Or(x,y) + +let ctl_seqor x y = CTL.SeqOr(x,y) + +let ctl_not x = CTL.Not(x) + +let ctl_ax x = + if is_true x then CTL.True + else CTL.AX(CTL.FORWARD,CTL.STRICT,x) + +let ctl_ex x = + if is_true x then CTL.True + else CTL.EX(CTL.FORWARD,x) + +let ctl_back_ex x = + if is_true x then CTL.True + else CTL.EX(CTL.BACKWARD,x) + +let after = CTL.Pred(Lib_engine.After, CTL.Control) +let fall = CTL.Pred(Lib_engine.FallThrough, CTL.Control) +let exit = CTL.Pred(Lib_engine.Exit, CTL.Control) +let truepred = CTL.Pred(Lib_engine.TrueBranch, CTL.Control) +let falsepred = CTL.Pred(Lib_engine.FalseBranch, CTL.Control) +let retpred = CTL.Pred(Lib_engine.Return, CTL.Control) + +let string2var x = ("",x) + +let labelctr = ref 0 +let get_label_ctr _ = + let cur = !labelctr in + labelctr := cur + 1; + string2var (Printf.sprintf "l%d" cur) + +let ctl_au x y = CTL.AU(CTL.FORWARD,CTL.STRICT,x,y) + +let ctl_uncheck x = CTL.Uncheck(x) + +let make_meta_rule_elem d = + let nm = "_S" in + Ast.make_meta_rule_elem nm d ([],[],[]) + +(* --------------------------------------------------------------------- *) + +let rec ctl_seq keep_wit a = function + Past.Seq(elem,seq) -> + ctl_element keep_wit (ctl_seq keep_wit a seq) elem + | Past.Empty -> a + | Past.SExists(var,seq) -> ctl_exists keep_wit var (ctl_seq keep_wit a seq) + +and ctl_term keep_wit a = function + Past.Atomic(term) -> ctl_and (predmaker keep_wit term) (ctl_ax a) + | Past.IfThen(test,thn,(_,_,_,aft)) -> ifthen keep_wit (Some a) test thn aft + | Past.TExists(var,term) -> + ctl_exists keep_wit var (ctl_term keep_wit a term) + +and ctl_element keep_wit a = function + Past.Term(term,ba) -> + do_between_dots keep_wit ba (ctl_term keep_wit a term) a + | Past.Or(seq1,seq2) -> + ctl_seqor (ctl_seq keep_wit a seq1) (ctl_seq keep_wit a seq2) + | Past.DInfo(dots) -> ctl_au (guard_ctl_dots keep_wit a dots) a + | Past.EExists(var,elem) -> + ctl_exists keep_wit var (ctl_element keep_wit a elem) + +(* --------------------------------------------------------------------- *) + +and guard_ctl_seq keep_wit a = function + Past.Seq(elem,Past.Empty) -> guard_ctl_element keep_wit a elem + | Past.Seq(elem,seq) -> + ctl_element keep_wit (guard_ctl_seq keep_wit a seq) elem + | Past.Empty -> ctl_true + | Past.SExists(var,seq) -> + ctl_exists keep_wit var (guard_ctl_seq keep_wit a seq) + +and guard_ctl_term keep_wit = function + Past.Atomic(term) -> predmaker keep_wit term + | Past.IfThen(test,thn,(_,_,_,aft)) -> ifthen keep_wit None test thn aft + | Past.TExists(var,term) -> + ctl_exists keep_wit var (guard_ctl_term keep_wit term) + +and guard_ctl_element keep_wit a = function + Past.Term(term,_) -> guard_ctl_term keep_wit term + | Past.Or(seq1,seq2) -> + ctl_seqor + (guard_ctl_seq keep_wit a seq1) (guard_ctl_seq keep_wit a seq2) + | Past.DInfo(dots) -> ctl_au (guard_ctl_dots keep_wit a dots) a + | Past.EExists(var,elem) -> + ctl_exists keep_wit var (guard_ctl_element keep_wit a elem) + +and guard_ctl_dots keep_wit a = function + Past.Dots -> ctl_true +(* | Past.Nest(_) when not keep_wit -> ctl_true + a possible optimization, but irrelevant to popl example *) + | Past.Nest(seq) -> + ctl_or + (guard_ctl_seq true a seq) + (ctl_not (guard_ctl_seq false a seq)) + | Past.When(dots,seq) -> + ctl_and + (guard_ctl_dots keep_wit a dots) + (ctl_not (guard_ctl_seq false a seq)) + +(* --------------------------------------------------------------------- *) + +and ifthen keep_wit a test thn aft = +(* "if (test) thn; after" becomes: + if(test) & AX((TrueBranch & AX thn) v FallThrough v (After & AXAX after)) + & EX After + (* doesn't work for C code if (x) return 1; else return 2; *) +*) + let end_code = + match (aft,a) with + (Ast.CONTEXT(_,Ast.NOTHING),None) -> ctl_true + | (Ast.CONTEXT(_,Ast.NOTHING),Some a) -> ctl_ax (ctl_ax a) + | (_,None) -> failwith "not possible" + | (_,Some a) -> + ctl_ax + (ctl_and + (predmaker keep_wit (make_meta_rule_elem aft)) + (ctl_ax a)) in + let body = + ctl_or + (ctl_and truepred + (ctl_ax + (guard_ctl_term keep_wit thn))) + (ctl_or fall + (ctl_and after end_code)) in + ctl_and (ctl_term keep_wit body test) + (match a with Some CTL.True | None -> ctl_true | Some _ -> ctl_ex after) + +and do_between_dots keep_wit ba term after = + match ba with + Past.AddingBetweenDots (brace_term,n) + | Past.DroppingBetweenDots (brace_term,n) -> + (* not sure at all what to do here for after... *) + let match_brace = ctl_term keep_wit after brace_term in + let v = Printf.sprintf "_r_%d" n in + let case1 = ctl_and (CTL.Ref v) match_brace in + let case2 = ctl_and (ctl_not (CTL.Ref v)) term in + CTL.Let + (v,ctl_or + (ctl_back_ex truepred) + (ctl_back_ex (ctl_back_ex falsepred)), + ctl_or case1 case2) + | Past.NoDots -> term + +(* --------------------------------------------------------------------- *) + +let toctl sl = ctl_seq true ctl_true sl diff --git a/popl09/popltoctl.mli b/popl09/popltoctl.mli new file mode 100644 index 0000000..b1285d1 --- /dev/null +++ b/popl09/popltoctl.mli @@ -0,0 +1,5 @@ +type cocci_predicate = Lib_engine.predicate * Ast_cocci.meta_name Ast_ctl.modif +type formula = + (cocci_predicate,Ast_cocci.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl + +val toctl : Ast_popl.sequence -> formula diff --git a/popl09/pretty_print_popl.ml b/popl09/pretty_print_popl.ml new file mode 100644 index 0000000..3bfa7b3 --- /dev/null +++ b/popl09/pretty_print_popl.ml @@ -0,0 +1,97 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Format +module Past = Ast_popl +module Ast = Ast_cocci + +let start_block str = + force_newline(); print_string " "; open_box 0 + +let end_block str = + close_box(); force_newline () + +(* --------------------------------------------------------------------- *) + +let print_around printer term = function + Ast.NOTHING -> printer term + | Ast.BEFORE(bef) -> + Pretty_print_cocci.print_anything "<<< " bef; printer term + | Ast.AFTER(aft) -> + printer term; Pretty_print_cocci.print_anything ">>> " aft + | Ast.BEFOREAFTER(bef,aft) -> + Pretty_print_cocci.print_anything "<<< " bef; printer term; + Pretty_print_cocci.print_anything ">>> " aft + +let mcode fn = function + (x, _, Ast.MINUS(_,plus_stream), pos) -> + print_string "-"; fn x; + Pretty_print_cocci.print_anything ">>> " plus_stream + | (x, _, Ast.CONTEXT(_,plus_streams), pos) -> + print_around fn x plus_streams + | (x, info, Ast.PLUS, pos) -> fn x + +(* --------------------------------------------------------------------- *) + +let rec print_sequence = function + Past.Seq(e,seq) -> print_element e; force_newline(); print_sequence seq + | Past.Empty -> () + | Past.SExists((_,v),seq) -> print_string "exists "; print_string v; + print_string " ."; force_newline(); print_sequence seq + +and print_term = function + Past.Atomic(term) -> Pretty_print_cocci.rule_elem "" term + | Past.IfThen(test,thn,(_,_,_,aft)) -> + print_term test; print_term thn; + mcode (function _ -> ()) ((),Ast.no_info,aft,Ast.NoMetaPos) + | Past.TExists((_,v),term) -> print_string "exists "; print_string v; + print_string " ."; force_newline(); print_term term + +and print_element = function + Past.Term(term,_) -> print_term term + | Past.Or(seq1,seq2) -> + force_newline(); print_string "("; force_newline(); print_sequence seq1; + print_string "|"; force_newline(); print_sequence seq2; print_string ")" + | Past.DInfo(dots) -> + start_block(); + print_dots dots; + end_block() + | Past.EExists((_,v),elem) -> print_string "exists "; print_string v; + print_string " ."; force_newline(); print_element elem + +and print_dots = function + Past.Dots -> print_string "..." + | Past.Nest(seq)-> print_string "<..."; start_block(); print_sequence seq; + end_block(); print_string "...>" + | Past.When(dots,seq) -> print_dots dots; print_string " when != "; + open_box 0; print_sequence seq; close_box() + +(* --------------------------------------------------------------------- *) + +let pretty_print_e e = + print_element e; + print_newline() + +let pretty_print sl = + print_sequence sl; + print_newline() + diff --git a/popl09/pretty_print_popl.mli b/popl09/pretty_print_popl.mli new file mode 100644 index 0000000..5b3399a --- /dev/null +++ b/popl09/pretty_print_popl.mli @@ -0,0 +1,2 @@ +val pretty_print : Ast_popl.sequence -> unit +val pretty_print_e : Ast_popl.element -> unit diff --git a/prim.c b/prim.c new file mode 100644 index 0000000..e8866fe --- /dev/null +++ b/prim.c @@ -0,0 +1,7 @@ +#include "caml/mlvalues.h" + +static int x = 0; + +CAMLprim value c_counter(value nothing) { + return Val_long(x++); +} diff --git a/pycaml/Makefile b/pycaml/Makefile new file mode 100644 index 0000000..8396eff --- /dev/null +++ b/pycaml/Makefile @@ -0,0 +1,32 @@ +#pad: was called Makefile.deb-pycaml before + +OCAMLMAKEFILE = OCamlMakefile +PY_PREFIX = $(shell python getprefix.py) +PY_VERSION = $(shell python getversion.py) +CLIBS = python$(PY_VERSION) pthread dl util m c + +SOURCES = pycaml.ml pycaml_ml.c +RESULT = pycaml +THREADS = yes +NO_CUSTOM = NO_CUSTOM +CFLAGS = -fPIC + +LIBDIRS = $(PY_PREFIX)/lib/python$(PY_VERSION)/config +INCDIRS = $(PY_PREFIX)/include/python$(PY_VERSION) +OCAMLLDFLAGS = -linkall + +all.opt: native-code-library byte-code-library pycaml.customtop + cp -f dllpycaml_stubs.so ../ + +all: byte-code-library pycaml.customtop + cp -f dllpycaml_stubs.so ../ + +pycaml.customtop: pycaml.cma + ocamlmktop -o pycaml.customtop pycaml.cma + +clean:: + rm -f pycaml.customtop + +depend: # added by julia, undoubtedly wrong + +-include $(OCAMLMAKEFILE) diff --git a/pycaml/Makefile.in b/pycaml/Makefile.in new file mode 100644 index 0000000..5b74075 --- /dev/null +++ b/pycaml/Makefile.in @@ -0,0 +1,40 @@ +# +# Edit SYSLIBS to fit your system +# + +PY_PREFIX=@PY_PREFIX@ +PY_VERSION=@PY_VERSION@ +SYSLIBS=@PY_LIBS@ + +# +# The rest is automatic +# + +LIBS= pycaml_ml.o \ + -cclib -L$(PY_PREFIX)/lib/python$(PY_VERSION)/config \ + -cclib -lpython$(PY_VERSION) $(SYSLIBS) \ + unix.cma threads.cma pycaml.cmo + +all: pycamltop pycamltest ocamlobj + +pycamltop: pycaml_ml.o pycaml.cmo + ocamlmktop -thread -custom -o $@ $(LIBS) + +pycaml_ml.o: pycaml_ml.c + ocamlc -thread -ccopt -c -ccopt -g \ + -ccopt -I$(PY_PREFIX)/include/python$(PY_VERSION) $< + +pycaml.cmo: pycaml.ml + ocamlc -thread -c $< + +pycamltest: pycamltest.ml pycaml.cmo pycaml_ml.o + ocamlc -custom -thread -ccopt -g $(LIBS) pycamltest.ml -o $@ + +ocamlobj: ocamlobj.ml pycaml.cmo pycaml_ml.o + ocamlc -custom -thread -ccopt -g $(LIBS) ocamlobj.ml -o $@ + +clean: + rm -rf *.o *.cmi *.cmo pycamltop pycamltest ocamlobj + +distclean: clean + rm -rf config.cache autom4te.cache config.status Makefile \ No newline at end of file diff --git a/pycaml/OCamlMakefile b/pycaml/OCamlMakefile new file mode 100644 index 0000000..b0b9252 --- /dev/null +++ b/pycaml/OCamlMakefile @@ -0,0 +1,1231 @@ +########################################################################### +# OCamlMakefile +# Copyright (C) 1999-2007 Markus Mottl +# +# For updates see: +# http://www.ocaml.info/home/ocaml_sources.html +# +########################################################################### + +# Modified by damien for .glade.ml compilation + +# Set these variables to the names of the sources to be processed and +# the result variable. Order matters during linkage! + +ifndef SOURCES + SOURCES := foo.ml +endif +export SOURCES + +ifndef RES_CLIB_SUF + RES_CLIB_SUF := _stubs +endif +export RES_CLIB_SUF + +ifndef RESULT + RESULT := foo +endif +export RESULT := $(strip $(RESULT)) + +export LIB_PACK_NAME + +ifndef DOC_FILES + DOC_FILES := $(filter %.mli, $(SOURCES)) +endif +export DOC_FILES +FIRST_DOC_FILE := $(firstword $(DOC_FILES)) + +export BCSUFFIX +export NCSUFFIX + +ifndef TOPSUFFIX + TOPSUFFIX := .top +endif +export TOPSUFFIX + +# Eventually set include- and library-paths, libraries to link, +# additional compilation-, link- and ocamlyacc-flags +# Path- and library information needs not be written with "-I" and such... +# Define THREADS if you need it, otherwise leave it unset (same for +# USE_CAMLP4)! + +export THREADS +export VMTHREADS +export ANNOTATE +export USE_CAMLP4 + +export INCDIRS +export LIBDIRS +export EXTLIBDIRS +export RESULTDEPS +export OCAML_DEFAULT_DIRS + +export LIBS +export CLIBS +export CFRAMEWORKS + +export OCAMLFLAGS +export OCAMLNCFLAGS +export OCAMLBCFLAGS + +export OCAMLLDFLAGS +export OCAMLNLDFLAGS +export OCAMLBLDFLAGS + +export OCAMLMKLIB_FLAGS + +ifndef OCAMLCPFLAGS + OCAMLCPFLAGS := a +endif +export OCAMLCPFLAGS + +ifndef DOC_DIR + DOC_DIR := doc +endif +export DOC_DIR + +export PPFLAGS + +export LFLAGS +export YFLAGS +export IDLFLAGS + +export OCAMLDOCFLAGS + +export OCAMLFIND_INSTFLAGS + +export DVIPSFLAGS + +export STATIC + +# Add a list of optional trash files that should be deleted by "make clean" +export TRASH + +ECHO := echo + +ifdef REALLY_QUIET + export REALLY_QUIET + ECHO := true + LFLAGS := $(LFLAGS) -q + YFLAGS := $(YFLAGS) -q +endif + +#################### variables depending on your OCaml-installation + +ifdef MINGW + export MINGW + WIN32 := 1 + CFLAGS_WIN32 := -mno-cygwin +endif +ifdef MSVC + export MSVC + WIN32 := 1 + ifndef STATIC + CPPFLAGS_WIN32 := -DCAML_DLL + endif + CFLAGS_WIN32 += -nologo + EXT_OBJ := obj + EXT_LIB := lib + ifeq ($(CC),gcc) + # work around GNU Make default value + ifdef THREADS + CC := cl -MT + else + CC := cl + endif + endif + ifeq ($(CXX),g++) + # work around GNU Make default value + CXX := $(CC) + endif + CFLAG_O := -Fo +endif +ifdef WIN32 + EXT_CXX := cpp + EXE := .exe +endif + +ifndef EXT_OBJ + EXT_OBJ := o +endif +ifndef EXT_LIB + EXT_LIB := a +endif +ifndef EXT_CXX + EXT_CXX := cc +endif +ifndef EXE + EXE := # empty +endif +ifndef CFLAG_O + CFLAG_O := -o # do not delete this comment (preserves trailing whitespace)! +endif + +export CC +export CXX +export CFLAGS +export CXXFLAGS +export LDFLAGS +export CPPFLAGS + +ifndef RPATH_FLAG + ifdef ELF_RPATH_FLAG + RPATH_FLAG := $(ELF_RPATH_FLAG) + else + RPATH_FLAG := -R + endif +endif +export RPATH_FLAG + +ifndef MSVC +ifndef PIC_CFLAGS + PIC_CFLAGS := -fPIC +endif +ifndef PIC_CPPFLAGS + PIC_CPPFLAGS := -DPIC +endif +endif + +export PIC_CFLAGS +export PIC_CPPFLAGS + +BCRESULT := $(addsuffix $(BCSUFFIX), $(RESULT)) +NCRESULT := $(addsuffix $(NCSUFFIX), $(RESULT)) +TOPRESULT := $(addsuffix $(TOPSUFFIX), $(RESULT)) + +ifndef OCAMLFIND + OCAMLFIND := ocamlfind +endif +export OCAMLFIND + +ifndef OCAMLC + OCAMLC := ocamlc +endif +export OCAMLC + +ifndef OCAMLOPT + OCAMLOPT := ocamlopt +endif +export OCAMLOPT + +ifndef OCAMLMKTOP + OCAMLMKTOP := ocamlmktop +endif +export OCAMLMKTOP + +ifndef OCAMLCP + OCAMLCP := ocamlcp +endif +export OCAMLCP + +ifndef OCAMLDEP + OCAMLDEP := ocamldep +endif +export OCAMLDEP + +ifndef OCAMLLEX + OCAMLLEX := ocamllex +endif +export OCAMLLEX + +ifndef OCAMLYACC + OCAMLYACC := ocamlyacc +endif +export OCAMLYACC + +ifndef OCAMLMKLIB + OCAMLMKLIB := ocamlmklib +endif +export OCAMLMKLIB + +ifndef OCAML_GLADECC + OCAML_GLADECC := lablgladecc2 +endif +export OCAML_GLADECC + +ifndef OCAML_GLADECC_FLAGS + OCAML_GLADECC_FLAGS := +endif +export OCAML_GLADECC_FLAGS + +ifndef CAMELEON_REPORT + CAMELEON_REPORT := report +endif +export CAMELEON_REPORT + +ifndef CAMELEON_REPORT_FLAGS + CAMELEON_REPORT_FLAGS := +endif +export CAMELEON_REPORT_FLAGS + +ifndef CAMELEON_ZOGGY + CAMELEON_ZOGGY := camlp4o pa_zog.cma pr_o.cmo +endif +export CAMELEON_ZOGGY + +ifndef CAMELEON_ZOGGY_FLAGS + CAMELEON_ZOGGY_FLAGS := +endif +export CAMELEON_ZOGGY_FLAGS + +ifndef OXRIDL + OXRIDL := oxridl +endif +export OXRIDL + +ifndef CAMLIDL + CAMLIDL := camlidl +endif +export CAMLIDL + +ifndef CAMLIDLDLL + CAMLIDLDLL := camlidldll +endif +export CAMLIDLDLL + +ifndef NOIDLHEADER + MAYBE_IDL_HEADER := -header +endif +export NOIDLHEADER + +export NO_CUSTOM + +ifndef CAMLP4 + CAMLP4 := camlp4 +endif +export CAMLP4 + +ifndef REAL_OCAMLFIND + ifdef PACKS + ifndef CREATE_LIB + ifdef THREADS + PACKS += threads + endif + endif + empty := + space := $(empty) $(empty) + comma := , + ifdef PREDS + PRE_OCAML_FIND_PREDICATES := $(subst $(space),$(comma),$(PREDS)) + PRE_OCAML_FIND_PACKAGES := $(subst $(space),$(comma),$(PACKS)) + OCAML_FIND_PREDICATES := -predicates $(PRE_OCAML_FIND_PREDICATES) + # OCAML_DEP_PREDICATES := -syntax $(PRE_OCAML_FIND_PREDICATES) + OCAML_FIND_PACKAGES := $(OCAML_FIND_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) + OCAML_DEP_PACKAGES := $(OCAML_DEP_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) + else + OCAML_FIND_PACKAGES := -package $(subst $(space),$(comma),$(PACKS)) + OCAML_DEP_PACKAGES := + endif + OCAML_FIND_LINKPKG := -linkpkg + REAL_OCAMLFIND := $(OCAMLFIND) + endif +endif + +export OCAML_FIND_PACKAGES +export OCAML_DEP_PACKAGES +export OCAML_FIND_LINKPKG +export REAL_OCAMLFIND + +ifndef OCAMLDOC + OCAMLDOC := ocamldoc +endif +export OCAMLDOC + +ifndef LATEX + LATEX := latex +endif +export LATEX + +ifndef DVIPS + DVIPS := dvips +endif +export DVIPS + +ifndef PS2PDF + PS2PDF := ps2pdf +endif +export PS2PDF + +ifndef OCAMLMAKEFILE + OCAMLMAKEFILE := OCamlMakefile +endif +export OCAMLMAKEFILE + +ifndef OCAMLLIBPATH + OCAMLLIBPATH := \ + $(shell $(OCAMLC) 2>/dev/null -where || echo /usr/local/lib/ocaml) +endif +export OCAMLLIBPATH + +ifndef OCAML_LIB_INSTALL + OCAML_LIB_INSTALL := $(OCAMLLIBPATH)/contrib +endif +export OCAML_LIB_INSTALL + +########################################################################### + +#################### change following sections only if +#################### you know what you are doing! + +# delete target files when a build command fails +.PHONY: .DELETE_ON_ERROR +.DELETE_ON_ERROR: + +# for pedants using "--warn-undefined-variables" +export MAYBE_IDL +export REAL_RESULT +export CAMLIDLFLAGS +export THREAD_FLAG +export RES_CLIB +export MAKEDLL +export ANNOT_FLAG +export C_OXRIDL +export SUBPROJS +export CFLAGS_WIN32 +export CPPFLAGS_WIN32 + +INCFLAGS := + +SHELL := /bin/sh + +MLDEPDIR := ._d +BCDIDIR := ._bcdi +NCDIDIR := ._ncdi + +FILTER_EXTNS := %.mli %.ml %.mll %.mly %.idl %.oxridl %.c %.m %.$(EXT_CXX) %.rep %.zog %.glade + +FILTERED := $(filter $(FILTER_EXTNS), $(SOURCES)) +SOURCE_DIRS := $(filter-out ./, $(sort $(dir $(FILTERED)))) + +FILTERED_REP := $(filter %.rep, $(FILTERED)) +DEP_REP := $(FILTERED_REP:%.rep=$(MLDEPDIR)/%.d) +AUTO_REP := $(FILTERED_REP:.rep=.ml) + +FILTERED_ZOG := $(filter %.zog, $(FILTERED)) +DEP_ZOG := $(FILTERED_ZOG:%.zog=$(MLDEPDIR)/%.d) +AUTO_ZOG := $(FILTERED_ZOG:.zog=.ml) + +FILTERED_GLADE := $(filter %.glade, $(FILTERED)) +DEP_GLADE := $(FILTERED_GLADE:%.glade=$(MLDEPDIR)/%.d) +AUTO_GLADE := $(FILTERED_GLADE:.glade=.ml) + +FILTERED_ML := $(filter %.ml, $(FILTERED)) +DEP_ML := $(FILTERED_ML:%.ml=$(MLDEPDIR)/%.d) + +FILTERED_MLI := $(filter %.mli, $(FILTERED)) +DEP_MLI := $(FILTERED_MLI:.mli=.di) + +FILTERED_MLL := $(filter %.mll, $(FILTERED)) +DEP_MLL := $(FILTERED_MLL:%.mll=$(MLDEPDIR)/%.d) +AUTO_MLL := $(FILTERED_MLL:.mll=.ml) + +FILTERED_MLY := $(filter %.mly, $(FILTERED)) +DEP_MLY := $(FILTERED_MLY:%.mly=$(MLDEPDIR)/%.d) $(FILTERED_MLY:.mly=.di) +AUTO_MLY := $(FILTERED_MLY:.mly=.mli) $(FILTERED_MLY:.mly=.ml) + +FILTERED_IDL := $(filter %.idl, $(FILTERED)) +DEP_IDL := $(FILTERED_IDL:%.idl=$(MLDEPDIR)/%.d) $(FILTERED_IDL:.idl=.di) +C_IDL := $(FILTERED_IDL:%.idl=%_stubs.c) +ifndef NOIDLHEADER + C_IDL += $(FILTERED_IDL:.idl=.h) +endif +OBJ_C_IDL := $(FILTERED_IDL:%.idl=%_stubs.$(EXT_OBJ)) +AUTO_IDL := $(FILTERED_IDL:.idl=.mli) $(FILTERED_IDL:.idl=.ml) $(C_IDL) + +FILTERED_OXRIDL := $(filter %.oxridl, $(FILTERED)) +DEP_OXRIDL := $(FILTERED_OXRIDL:%.oxridl=$(MLDEPDIR)/%.d) $(FILTERED_OXRIDL:.oxridl=.di) +AUTO_OXRIDL := $(FILTERED_OXRIDL:.oxridl=.mli) $(FILTERED_OXRIDL:.oxridl=.ml) $(C_OXRIDL) + +FILTERED_C_CXX := $(filter %.c %.m %.$(EXT_CXX), $(FILTERED)) +OBJ_C_CXX := $(FILTERED_C_CXX:.c=.$(EXT_OBJ)) +OBJ_C_CXX := $(OBJ_C_CXX:.m=.$(EXT_OBJ)) +OBJ_C_CXX := $(OBJ_C_CXX:.$(EXT_CXX)=.$(EXT_OBJ)) + +PRE_TARGETS += $(AUTO_MLL) $(AUTO_MLY) $(AUTO_IDL) $(AUTO_OXRIDL) $(AUTO_ZOG) $(AUTO_REP) $(AUTO_GLADE) + +ALL_DEPS := $(DEP_ML) $(DEP_MLI) $(DEP_MLL) $(DEP_MLY) $(DEP_IDL) $(DEP_OXRIDL) $(DEP_ZOG) $(DEP_REP) $(DEP_GLADE) + +MLDEPS := $(filter %.d, $(ALL_DEPS)) +MLIDEPS := $(filter %.di, $(ALL_DEPS)) +BCDEPIS := $(MLIDEPS:%.di=$(BCDIDIR)/%.di) +NCDEPIS := $(MLIDEPS:%.di=$(NCDIDIR)/%.di) + +ALLML := $(filter %.mli %.ml %.mll %.mly %.idl %.oxridl %.rep %.zog %.glade, $(FILTERED)) + +IMPLO_INTF := $(ALLML:%.mli=%.mli.__) +IMPLO_INTF := $(foreach file, $(IMPLO_INTF), \ + $(basename $(file)).cmi $(basename $(file)).cmo) +IMPLO_INTF := $(filter-out %.mli.cmo, $(IMPLO_INTF)) +IMPLO_INTF := $(IMPLO_INTF:%.mli.cmi=%.cmi) + +IMPLX_INTF := $(IMPLO_INTF:.cmo=.cmx) + +INTF := $(filter %.cmi, $(IMPLO_INTF)) +IMPL_CMO := $(filter %.cmo, $(IMPLO_INTF)) +IMPL_CMX := $(IMPL_CMO:.cmo=.cmx) +IMPL_ASM := $(IMPL_CMO:.cmo=.asm) +IMPL_S := $(IMPL_CMO:.cmo=.s) + +OBJ_LINK := $(OBJ_C_IDL) $(OBJ_C_CXX) +OBJ_FILES := $(IMPL_CMO:.cmo=.$(EXT_OBJ)) $(OBJ_LINK) + +EXECS := $(addsuffix $(EXE), \ + $(sort $(TOPRESULT) $(BCRESULT) $(NCRESULT))) +ifdef WIN32 + EXECS += $(BCRESULT).dll $(NCRESULT).dll +endif + +CLIB_BASE := $(RESULT)$(RES_CLIB_SUF) +ifneq ($(strip $(OBJ_LINK)),) + RES_CLIB := lib$(CLIB_BASE).$(EXT_LIB) +endif + +ifdef WIN32 +DLLSONAME := $(CLIB_BASE).dll +else +DLLSONAME := dll$(CLIB_BASE).so +endif + +NONEXECS := $(INTF) $(IMPL_CMO) $(IMPL_CMX) $(IMPL_ASM) $(IMPL_S) \ + $(OBJ_FILES) $(PRE_TARGETS) $(BCRESULT).cma $(NCRESULT).cmxa \ + $(NCRESULT).$(EXT_LIB) $(BCRESULT).cmi $(BCRESULT).cmo \ + $(NCRESULT).cmi $(NCRESULT).cmx $(NCRESULT).o \ + $(RES_CLIB) $(IMPL_CMO:.cmo=.annot) \ + $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(LIB_PACK_NAME).cmx $(LIB_PACK_NAME).o + +ifndef STATIC + NONEXECS += $(DLLSONAME) +endif + +ifndef LIBINSTALL_FILES + LIBINSTALL_FILES := $(RESULT).mli $(RESULT).cmi $(RESULT).cma \ + $(RESULT).cmxa $(RESULT).$(EXT_LIB) $(RES_CLIB) + ifndef STATIC + ifneq ($(strip $(OBJ_LINK)),) + LIBINSTALL_FILES += $(DLLSONAME) + endif + endif +endif + +export LIBINSTALL_FILES + +ifdef WIN32 + # some extra stuff is created while linking DLLs + NONEXECS += $(BCRESULT).$(EXT_LIB) $(BCRESULT).exp $(NCRESULT).exp $(CLIB_BASE).exp $(CLIB_BASE).lib +endif + +TARGETS := $(EXECS) $(NONEXECS) + +# If there are IDL-files +ifneq ($(strip $(FILTERED_IDL)),) + MAYBE_IDL := -cclib -lcamlidl +endif + +ifdef USE_CAMLP4 + CAMLP4PATH := \ + $(shell $(CAMLP4) -where 2>/dev/null || echo /usr/local/lib/camlp4) + INCFLAGS := -I $(CAMLP4PATH) + CINCFLAGS := -I$(CAMLP4PATH) +endif + +DINCFLAGS := $(INCFLAGS) $(SOURCE_DIRS:%=-I %) $(OCAML_DEFAULT_DIRS:%=-I %) +INCFLAGS := $(DINCFLAGS) $(INCDIRS:%=-I %) +CINCFLAGS += $(SOURCE_DIRS:%=-I%) $(INCDIRS:%=-I%) $(OCAML_DEFAULT_DIRS:%=-I%) + +ifndef MSVC + CLIBFLAGS += $(SOURCE_DIRS:%=-L%) $(LIBDIRS:%=-L%) \ + $(EXTLIBDIRS:%=-L%) $(OCAML_DEFAULT_DIRS:%=-L%) + + ifeq ($(ELF_RPATH), yes) + CLIBFLAGS += $(EXTLIBDIRS:%=-Wl,$(RPATH_FLAG)%) + endif +endif + +ifndef PROFILING + INTF_OCAMLC := $(OCAMLC) +else + ifndef THREADS + INTF_OCAMLC := $(OCAMLCP) -p $(OCAMLCPFLAGS) + else + # OCaml does not support profiling byte code + # with threads (yet), therefore we force an error. + ifndef REAL_OCAMLC + $(error Profiling of multithreaded byte code not yet supported by OCaml) + endif + INTF_OCAMLC := $(OCAMLC) + endif +endif + +ifndef MSVC + COMMON_LDFLAGS := $(LDFLAGS:%=-ccopt %) $(SOURCE_DIRS:%=-ccopt -L%) \ + $(LIBDIRS:%=-ccopt -L%) $(EXTLIBDIRS:%=-ccopt -L%) \ + $(EXTLIBDIRS:%=-ccopt -Wl $(OCAML_DEFAULT_DIRS:%=-ccopt -L%)) + + ifeq ($(ELF_RPATH),yes) + COMMON_LDFLAGS += $(EXTLIBDIRS:%=-ccopt -Wl,$(RPATH_FLAG)%) + endif +else + COMMON_LDFLAGS := -ccopt "/link -NODEFAULTLIB:LIBC $(LDFLAGS:%=%) $(SOURCE_DIRS:%=-LIBPATH:%) \ + $(LIBDIRS:%=-LIBPATH:%) $(EXTLIBDIRS:%=-LIBPATH:%) \ + $(OCAML_DEFAULT_DIRS:%=-LIBPATH:%) " +endif + +CLIBS_OPTS := $(CLIBS:%=-cclib -l%) $(CFRAMEWORKS:%=-cclib '-framework %') +ifdef MSVC + ifndef STATIC + # MSVC libraries do not have 'lib' prefix + CLIBS_OPTS := $(CLIBS:%=-cclib %.lib) + endif +endif + +ifneq ($(strip $(OBJ_LINK)),) + ifdef CREATE_LIB + OBJS_LIBS := -cclib -l$(CLIB_BASE) $(CLIBS_OPTS) $(MAYBE_IDL) + else + OBJS_LIBS := $(OBJ_LINK) $(CLIBS_OPTS) $(MAYBE_IDL) + endif +else + OBJS_LIBS := $(CLIBS_OPTS) $(MAYBE_IDL) +endif + +# If we have to make byte-code +ifndef REAL_OCAMLC + BYTE_OCAML := y + + # EXTRADEPS is added dependencies we have to insert for all + # executable files we generate. Ideally it should be all of the + # libraries we use, but it's hard to find the ones that get searched on + # the path since I don't know the paths built into the compiler, so + # just include the ones with slashes in their names. + EXTRADEPS := $(addsuffix .cma,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) + SPECIAL_OCAMLFLAGS := $(OCAMLBCFLAGS) + + REAL_OCAMLC := $(INTF_OCAMLC) + + REAL_IMPL := $(IMPL_CMO) + REAL_IMPL_INTF := $(IMPLO_INTF) + IMPL_SUF := .cmo + + DEPFLAGS := + MAKE_DEPS := $(MLDEPS) $(BCDEPIS) + + ifdef CREATE_LIB + override CFLAGS := $(PIC_CFLAGS) $(CFLAGS) + override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS) + ifndef STATIC + ifneq ($(strip $(OBJ_LINK)),) + MAKEDLL := $(DLLSONAME) + ALL_LDFLAGS := -dllib $(DLLSONAME) + endif + endif + endif + + ifndef NO_CUSTOM + ifneq "$(strip $(OBJ_LINK) $(THREADS) $(MAYBE_IDL) $(CLIBS) $(CFRAMEWORKS))" "" + ALL_LDFLAGS += -custom + endif + endif + + ALL_LDFLAGS += $(INCFLAGS) $(OCAMLLDFLAGS) $(OCAMLBLDFLAGS) \ + $(COMMON_LDFLAGS) $(LIBS:%=%.cma) + CAMLIDLDLLFLAGS := + + ifdef THREADS + ifdef VMTHREADS + THREAD_FLAG := -vmthread + else + THREAD_FLAG := -thread + endif + ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) + ifndef CREATE_LIB + ifndef REAL_OCAMLFIND + ALL_LDFLAGS := unix.cma threads.cma $(ALL_LDFLAGS) + endif + endif + endif + +# we have to make native-code +else + EXTRADEPS := $(addsuffix .cmxa,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) + ifndef PROFILING + SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS) + PLDFLAGS := + else + SPECIAL_OCAMLFLAGS := -p $(OCAMLNCFLAGS) + PLDFLAGS := -p + endif + + REAL_IMPL := $(IMPL_CMX) + REAL_IMPL_INTF := $(IMPLX_INTF) + IMPL_SUF := .cmx + + override CPPFLAGS := -DNATIVE_CODE $(CPPFLAGS) + + DEPFLAGS := -native + MAKE_DEPS := $(MLDEPS) $(NCDEPIS) + + ALL_LDFLAGS := $(PLDFLAGS) $(INCFLAGS) $(OCAMLLDFLAGS) \ + $(OCAMLNLDFLAGS) $(COMMON_LDFLAGS) + CAMLIDLDLLFLAGS := -opt + + ifndef CREATE_LIB + ALL_LDFLAGS += $(LIBS:%=%.cmxa) + else + override CFLAGS := $(PIC_CFLAGS) $(CFLAGS) + override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS) + endif + + ifdef THREADS + THREAD_FLAG := -thread + ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) + ifndef CREATE_LIB + ifndef REAL_OCAMLFIND + ALL_LDFLAGS := unix.cmxa threads.cmxa $(ALL_LDFLAGS) + endif + endif + endif +endif + +export MAKE_DEPS + +ifdef ANNOTATE + ANNOT_FLAG := -dtypes +else +endif + +ALL_OCAMLCFLAGS := $(THREAD_FLAG) $(ANNOT_FLAG) $(OCAMLFLAGS) \ + $(INCFLAGS) $(SPECIAL_OCAMLFLAGS) + +ifdef make_deps + -include $(MAKE_DEPS) + PRE_TARGETS := +endif + +########################################################################### +# USER RULES + +# Call "OCamlMakefile QUIET=" to get rid of all of the @'s. +QUIET=@ + +# generates byte-code (default) +byte-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ + REAL_RESULT="$(BCRESULT)" make_deps=yes +bc: byte-code + +byte-code-nolink: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ + REAL_RESULT="$(BCRESULT)" make_deps=yes +bcnl: byte-code-nolink + +top: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(TOPRESULT) \ + REAL_RESULT="$(BCRESULT)" make_deps=yes + +# generates native-code + +native-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ + REAL_RESULT="$(NCRESULT)" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + make_deps=yes +nc: native-code + +native-code-nolink: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ + REAL_RESULT="$(NCRESULT)" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + make_deps=yes +ncnl: native-code-nolink + +# generates byte-code libraries +byte-code-library: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(BCRESULT).cma \ + REAL_RESULT="$(BCRESULT)" \ + CREATE_LIB=yes \ + make_deps=yes +bcl: byte-code-library + +# generates native-code libraries +native-code-library: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(NCRESULT).cmxa \ + REAL_RESULT="$(NCRESULT)" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + CREATE_LIB=yes \ + make_deps=yes +ncl: native-code-library + +ifdef WIN32 +# generates byte-code dll +byte-code-dll: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(BCRESULT).dll \ + REAL_RESULT="$(BCRESULT)" \ + make_deps=yes +bcd: byte-code-dll + +# generates native-code dll +native-code-dll: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(NCRESULT).dll \ + REAL_RESULT="$(NCRESULT)" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + make_deps=yes +ncd: native-code-dll +endif + +# generates byte-code with debugging information +debug-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ + REAL_RESULT="$(BCRESULT)" make_deps=yes \ + OCAMLFLAGS="-g $(OCAMLFLAGS)" \ + OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" +dc: debug-code + +debug-code-nolink: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ + REAL_RESULT="$(BCRESULT)" make_deps=yes \ + OCAMLFLAGS="-g $(OCAMLFLAGS)" \ + OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" +dcnl: debug-code-nolink + +# generates byte-code with debugging information (native code) +debug-native-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ + REAL_RESULT="$(NCRESULT)" make_deps=yes \ + REAL_OCAMLC="$(OCAMLOPT)" \ + OCAMLFLAGS="-g $(OCAMLFLAGS)" \ + OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" +dnc: debug-native-code + +debug-native-code-nolink: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ + REAL_RESULT="$(NCRESULT)" make_deps=yes \ + REAL_OCAMLC="$(OCAMLOPT)" \ + OCAMLFLAGS="-g $(OCAMLFLAGS)" \ + OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" +dncnl: debug-native-code-nolink + +# generates byte-code libraries with debugging information +debug-code-library: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(BCRESULT).cma \ + REAL_RESULT="$(BCRESULT)" make_deps=yes \ + CREATE_LIB=yes \ + OCAMLFLAGS="-g $(OCAMLFLAGS)" \ + OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" +dcl: debug-code-library + +# generates byte-code libraries with debugging information (native code) +debug-native-code-library: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(NCRESULT).cma \ + REAL_RESULT="$(NCRESULT)" make_deps=yes \ + REAL_OCAMLC="$(OCAMLOPT)" \ + CREATE_LIB=yes \ + OCAMLFLAGS="-g $(OCAMLFLAGS)" \ + OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" +dncl: debug-native-code-library + +# generates byte-code for profiling +profiling-byte-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ + REAL_RESULT="$(BCRESULT)" PROFILING="y" \ + make_deps=yes +pbc: profiling-byte-code + +# generates native-code + +profiling-native-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ + REAL_RESULT="$(NCRESULT)" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + PROFILING="y" \ + make_deps=yes +pnc: profiling-native-code + +# generates byte-code libraries +profiling-byte-code-library: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(BCRESULT).cma \ + REAL_RESULT="$(BCRESULT)" PROFILING="y" \ + CREATE_LIB=yes \ + make_deps=yes +pbcl: profiling-byte-code-library + +# generates native-code libraries +profiling-native-code-library: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(RES_CLIB) $(NCRESULT).cmxa \ + REAL_RESULT="$(NCRESULT)" PROFILING="y" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + CREATE_LIB=yes \ + make_deps=yes +pncl: profiling-native-code-library + +# packs byte-code objects +pack-byte-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT).cmo \ + REAL_RESULT="$(BCRESULT)" \ + PACK_LIB=yes make_deps=yes +pabc: pack-byte-code + +# packs native-code objects +pack-native-code: $(PRE_TARGETS) + $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ + $(NCRESULT).cmx $(NCRESULT).o \ + REAL_RESULT="$(NCRESULT)" \ + REAL_OCAMLC="$(OCAMLOPT)" \ + PACK_LIB=yes make_deps=yes +panc: pack-native-code + +# generates HTML-documentation +htdoc: $(DOC_DIR)/$(RESULT)/html/index.html + +# generates Latex-documentation +ladoc: $(DOC_DIR)/$(RESULT)/latex/doc.tex + +# generates PostScript-documentation +psdoc: $(DOC_DIR)/$(RESULT)/latex/doc.ps + +# generates PDF-documentation +pdfdoc: $(DOC_DIR)/$(RESULT)/latex/doc.pdf + +# generates all supported forms of documentation +doc: htdoc ladoc psdoc pdfdoc + +########################################################################### +# LOW LEVEL RULES + +$(REAL_RESULT): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(RESULTDEPS) + $(REAL_OCAMLFIND) $(REAL_OCAMLC) \ + $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ + $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \ + $(REAL_IMPL) + +nolink: $(REAL_IMPL_INTF) $(OBJ_LINK) + +ifdef WIN32 +$(REAL_RESULT).dll: $(REAL_IMPL_INTF) $(OBJ_LINK) + $(CAMLIDLDLL) $(CAMLIDLDLLFLAGS) $(OBJ_LINK) $(CLIBS) \ + -o $@ $(REAL_IMPL) +endif + +%$(TOPSUFFIX): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) + $(REAL_OCAMLFIND) $(OCAMLMKTOP) \ + $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ + $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \ + $(REAL_IMPL) + +.SUFFIXES: .mli .ml .cmi .cmo .cmx .cma .cmxa .$(EXT_OBJ) \ + .mly .di .d .$(EXT_LIB) .idl %.oxridl .c .m .$(EXT_CXX) .h .so \ + .rep .zog .glade + +ifndef STATIC +ifdef MINGW +$(DLLSONAME): $(OBJ_LINK) + $(CC) $(CFLAGS) $(CFLAGS_WIN32) $(OBJ_LINK) -shared -o $@ \ + -Wl,--whole-archive $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/lib%.a))) \ + $(OCAMLLIBPATH)/ocamlrun.a \ + -Wl,--export-all-symbols \ + -Wl,--no-whole-archive +else +ifdef MSVC +$(DLLSONAME): $(OBJ_LINK) + link /NOLOGO /DLL /OUT:$@ $(OBJ_LINK) \ + $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/%.lib))) \ + $(OCAMLLIBPATH)/ocamlrun.lib + +else +$(DLLSONAME): $(OBJ_LINK) + $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \ + -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) $(CFRAMEWORKS:%=-framework %) \ + $(OCAMLMKLIB_FLAGS) +endif +endif +endif + +ifndef LIB_PACK_NAME +$(RESULT).cma: $(REAL_IMPL_INTF) $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) + $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@ $(REAL_IMPL) + +$(RESULT).cmxa $(RESULT).$(EXT_LIB): $(REAL_IMPL_INTF) $(EXTRADEPS) $(RESULTDEPS) + $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@ $(REAL_IMPL) +else +ifdef BYTE_OCAML +$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo: $(REAL_IMPL_INTF) + $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmo $(OCAMLLDFLAGS) $(REAL_IMPL) +else +$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx: $(REAL_IMPL_INTF) + $(REAL_OCAMLFIND) $(OCAMLOPT) -pack -o $(LIB_PACK_NAME).cmx $(OCAMLLDFLAGS) $(REAL_IMPL) +endif + +$(RESULT).cma: $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) + $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@ $(LIB_PACK_NAME).cmo + +$(RESULT).cmxa $(RESULT).$(EXT_LIB): $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx $(EXTRADEPS) $(RESULTDEPS) + $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(filter-out -custom, $(ALL_LDFLAGS)) $(OBJS_LIBS) -o $@ $(LIB_PACK_NAME).cmx +endif + +$(RES_CLIB): $(OBJ_LINK) +ifndef MSVC + ifneq ($(strip $(OBJ_LINK)),) + $(AR) rcs $@ $(OBJ_LINK) + endif +else + ifneq ($(strip $(OBJ_LINK)),) + lib -nologo -debugtype:cv -out:$(RES_CLIB) $(OBJ_LINK) + endif +endif + +.mli.cmi: $(EXTRADEPS) + $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ + if [ -z "$$pp" ]; then \ + $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c $(THREAD_FLAG) $(ANNOT_FLAG) \ + $(OCAMLFLAGS) $(INCFLAGS) $<; \ + $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c $(THREAD_FLAG) $(ANNOT_FLAG) \ + $(OCAMLFLAGS) $(INCFLAGS) $<; \ + else \ + $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c -pp \"$$pp $(PPFLAGS)\" $(THREAD_FLAG) $(ANNOT_FLAG) \ + $(OCAMLFLAGS) $(INCFLAGS) $<; \ + $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c -pp "$$pp $(PPFLAGS)" $(THREAD_FLAG) $(ANNOT_FLAG) \ + $(OCAMLFLAGS) $(INCFLAGS) $<; \ + fi + +.ml.cmi .ml.$(EXT_OBJ) .ml.cmx .ml.cmo: $(EXTRADEPS) + $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ + if [ -z "$$pp" ]; then \ + $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c $(ALL_OCAMLCFLAGS) $<; \ + $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c $(ALL_OCAMLCFLAGS) $<; \ + else \ + $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c -pp \"$$pp $(PPFLAGS)\" $(ALL_OCAMLCFLAGS) $<; \ + $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ + -c -pp "$$pp $(PPFLAGS)" $(ALL_OCAMLCFLAGS) $<; \ + fi + +ifdef PACK_LIB +$(REAL_RESULT).cmo $(REAL_RESULT).cmx $(REAL_RESULT).o: $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) + $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack $(ALL_LDFLAGS) \ + $(OBJS_LIBS) -o $@ $(REAL_IMPL) +endif + +.PRECIOUS: %.ml +%.ml: %.mll + $(OCAMLLEX) $(LFLAGS) $< + +.PRECIOUS: %.ml %.mli +%.ml %.mli: %.mly + $(OCAMLYACC) $(YFLAGS) $< + $(QUIET)pp=`sed -n -e 's/.*(\*pp \([^*]*\) \*).*/\1/p;q' $<`; \ + if [ ! -z "$$pp" ]; then \ + mv $*.ml $*.ml.temporary; \ + echo "(*pp $$pp $(PPFLAGS)*)" > $*.ml; \ + cat $*.ml.temporary >> $*.ml; \ + rm $*.ml.temporary; \ + mv $*.mli $*.mli.temporary; \ + echo "(*pp $$pp $(PPFLAGS)*)" > $*.mli; \ + cat $*.mli.temporary >> $*.mli; \ + rm $*.mli.temporary; \ + fi + + +.PRECIOUS: %.ml +%.ml: %.rep + $(CAMELEON_REPORT) $(CAMELEON_REPORT_FLAGS) -gen $< + +.PRECIOUS: %.ml +%.ml: %.zog + $(CAMELEON_ZOGGY) $(CAMELEON_ZOGGY_FLAGS) -impl $< > $@ + +.PRECIOUS: %.ml +%.ml: %.glade + $(OCAML_GLADECC) $(OCAML_GLADECC_FLAGS) $< > $@ + +.PRECIOUS: %.ml %.mli +%.ml %.mli: %.oxridl + $(OXRIDL) $< + +.PRECIOUS: %.ml %.mli %_stubs.c %.h +%.ml %.mli %_stubs.c %.h: %.idl + $(CAMLIDL) $(MAYBE_IDL_HEADER) $(IDLFLAGS) \ + $(CAMLIDLFLAGS) $< + $(QUIET)if [ $(NOIDLHEADER) ]; then touch $*.h; fi + +.c.$(EXT_OBJ): + $(OCAMLC) -c -cc "$(CC)" -ccopt "$(CFLAGS) \ + $(CPPFLAGS) $(CPPFLAGS_WIN32) \ + $(CFLAGS_WIN32) $(CINCFLAGS) $(CFLAG_O)$@ " $< + +.m.$(EXT_OBJ): + $(CC) -c $(CFLAGS) $(CINCFLAGS) $(CPPFLAGS) \ + -I'$(OCAMLLIBPATH)' \ + $< $(CFLAG_O)$@ + +.$(EXT_CXX).$(EXT_OBJ): + $(CXX) -c $(CXXFLAGS) $(CINCFLAGS) $(CPPFLAGS) \ + -I'$(OCAMLLIBPATH)' \ + $< $(CFLAG_O)$@ + +$(MLDEPDIR)/%.d: %.ml + $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi + $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ + if [ -z "$$pp" ]; then \ + $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ + $(DINCFLAGS) $< \> $@; \ + $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ + $(DINCFLAGS) $< > $@; \ + else \ + $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ + -pp \"$$pp $(PPFLAGS)\" $(DINCFLAGS) $< \> $@; \ + $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ + -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \ + fi + +$(BCDIDIR)/%.di $(NCDIDIR)/%.di: %.mli + $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi + $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ + if [ -z "$$pp" ]; then \ + $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(DINCFLAGS) $< \> $@; \ + $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(DINCFLAGS) $< > $@; \ + else \ + $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ + -pp \"$$pp $(PPFLAGS)\" $(DINCFLAGS) $< \> $@; \ + $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ + -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \ + fi + +$(DOC_DIR)/$(RESULT)/html: + mkdir -p $@ + +$(DOC_DIR)/$(RESULT)/html/index.html: $(DOC_DIR)/$(RESULT)/html $(DOC_FILES) + rm -rf $= $min_ft_version) +no_ft="" +if test "$FT2_CONFIG" = "no" ; then + no_ft=yes +else + FT2_CFLAGS=`$FT2_CONFIG $ft_config_args --cflags` + FT2_LIBS=`$FT2_CONFIG $ft_config_args --libs` + ft_config_major_version=`$FT2_CONFIG $ft_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + ft_config_minor_version=`$FT2_CONFIG $ft_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + ft_config_micro_version=`$FT2_CONFIG $ft_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + ft_min_major_version=`echo $min_ft_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + ft_min_minor_version=`echo $min_ft_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + ft_min_micro_version=`echo $min_ft_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test x$enable_fttest = xyes ; then + ft_config_is_lt="" + if test $ft_config_major_version -lt $ft_min_major_version ; then + ft_config_is_lt=yes + else + if test $ft_config_major_version -eq $ft_min_major_version ; then + if test $ft_config_minor_version -lt $ft_min_minor_version ; then + ft_config_is_lt=yes + else + if test $ft_config_minor_version -eq $ft_min_minor_version ; then + if test $ft_config_micro_version -lt $ft_min_micro_version ; then + ft_config_is_lt=yes + fi + fi + fi + fi + fi + if test x$ft_config_is_lt = xyes ; then + no_ft=yes + else + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $FT2_CFLAGS" + LIBS="$FT2_LIBS $LIBS" +dnl +dnl Sanity checks for the results of freetype-config to some extent +dnl + AC_TRY_RUN([ +#include +#include FT_FREETYPE_H +#include +#include + +int +main() +{ + FT_Library library; + FT_Error error; + + error = FT_Init_FreeType(&library); + + if (error) + return 1; + else + { + FT_Done_FreeType(library); + return 0; + } +} +],, no_ft=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi # test $ft_config_version -lt $ft_min_version + fi # test x$enable_fttest = xyes +fi # test "$FT2_CONFIG" = "no" +if test x$no_ft = x ; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) +else + AC_MSG_RESULT(no) + if test "$FT2_CONFIG" = "no" ; then + echo "*** The freetype-config script installed by FreeType 2 could not be found." + echo "*** If FreeType 2 was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the FT2_CONFIG environment variable to the" + echo "*** full path to freetype-config." + else + if test x$ft_config_is_lt = xyes ; then + echo "*** Your installed version of the FreeType 2 library is too old." + echo "*** If you have different versions of FreeType 2, make sure that" + echo "*** correct values for --with-ft-prefix or --with-ft-exec-prefix" + echo "*** are used, or set the FT2_CONFIG environment variable to the" + echo "*** full path to freetype-config." + else + echo "*** The FreeType test program failed to run. If your system uses" + echo "*** shared libraries and they are installed outside the normal" + echo "*** system library path, make sure the variable LD_LIBRARY_PATH" + echo "*** (or whatever is appropiate for your system) is correctly set." + fi + fi + FT2_CFLAGS="" + FT2_LIBS="" + ifelse([$3], , :, [$3]) +fi +AC_SUBST(FT2_CFLAGS) +AC_SUBST(FT2_LIBS) +]) + +# libtool.m4 - Configure libtool for the host system. -*-Shell-script-*- +## Copyright 1996, 1997, 1998, 1999, 2000, 2001 +## Free Software Foundation, Inc. +## Originally by Gordon Matzigkeit , 1996 +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## As a special exception to the GNU General Public License, if you +## distribute this file as part of a program that contains a +## configuration script generated by Autoconf, you may include it under +## the same distribution terms that you use for the rest of that program. + +# serial 46 AC_PROG_LIBTOOL + +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +]) + +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.13)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +_LT_AC_PROG_ECHO_BACKSLASH +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE(libtool-lock, + [ --disable-libtool-lock avoid locking (might break parallel builds)]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_SAVE + AC_LANG_C + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_RESTORE]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one + AC_CACHE_CHECK([if libtool should supply DllMain function], lt_cv_need_dllmain, + [AC_TRY_LINK([], + [extern int __attribute__((__stdcall__)) DllMain(void*, int, void*); + DllMain (0, 0, 0);], + [lt_cv_need_dllmain=no],[lt_cv_need_dllmain=yes])]) + + case $host/$CC in + *-*-cygwin*/gcc*-mno-cygwin*|*-*-mingw*) + # old mingw systems require "-dll" to link a DLL, while more recent ones + # require "-mdll" + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -mdll" + AC_CACHE_CHECK([how to link DLLs], lt_cv_cc_dll_switch, + [AC_TRY_LINK([], [], [lt_cv_cc_dll_switch=-mdll],[lt_cv_cc_dll_switch=-dll])]) + CFLAGS="$SAVE_CFLAGS" ;; + *-*-cygwin* | *-*-pw32*) + # cygwin systems need to pass --dll to the linker, and not link + # crt.o which will require a WinMain@16 definition. + lt_cv_cc_dll_switch="-Wl,--dll -nostartfiles" ;; + esac + ;; + ]) +esac + +_LT_AC_LTCONFIG_HACK + +]) + +# AC_LIBTOOL_HEADER_ASSERT +# ------------------------ +AC_DEFUN([AC_LIBTOOL_HEADER_ASSERT], +[AC_CACHE_CHECK([whether $CC supports assert without backlinking], + [lt_cv_func_assert_works], + [case $host in + *-*-solaris*) + if test "$GCC" = yes && test "$with_gnu_ld" != yes; then + case `$CC --version 2>/dev/null` in + [[12]].*) lt_cv_func_assert_works=no ;; + *) lt_cv_func_assert_works=yes ;; + esac + fi + ;; + esac]) + +if test "x$lt_cv_func_assert_works" = xyes; then + AC_CHECK_HEADERS(assert.h) +fi +])# AC_LIBTOOL_HEADER_ASSERT + +# _LT_AC_CHECK_DLFCN +# -------------------- +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h) +])# _LT_AC_CHECK_DLFCN + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [dnl + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + lt_cv_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +solaris* | sysv5*) + symcode='[[BDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $host_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + symcode='[[ABCDGISTW]]' +fi + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. +lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_global_symbol_to_cdecl"' < "$nlist" >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[[]] = +{ +EOF + sed "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr) \&\2},/" < "$nlist" >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$no_builtin_flag" + if AC_TRY_EVAL(ac_link) && test -s conftest; then + pipe_works=yes + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AC_FD_CC + fi + else + echo "cannot find nm_test_var in $nlist" >&AC_FD_CC + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AC_FD_CC + fi + else + echo "$progname: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +global_symbol_pipe="$lt_cv_sys_global_symbol_pipe" +if test -z "$lt_cv_sys_global_symbol_pipe"; then + global_symbol_to_cdecl= + global_symbol_to_c_name_address= +else + global_symbol_to_cdecl="$lt_cv_global_symbol_to_cdecl" + global_symbol_to_c_name_address="$lt_cv_global_symbol_to_c_name_address" +fi +if test -z "$global_symbol_pipe$global_symbol_to_cdec$global_symbol_to_c_name_address"; +then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + +# _LT_AC_LIBTOOL_SYS_PATH_SEPARATOR +# --------------------------------- +AC_DEFUN([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR], +[# Find the correct PATH separator. Usually this is `:', but +# DJGPP uses `;' like DOS. +if test "X${PATH_SEPARATOR+set}" != Xset; then + UNAME=${UNAME-`uname 2>/dev/null`} + case X$UNAME in + *-DOS) lt_cv_sys_path_separator=';' ;; + *) lt_cv_sys_path_separator=':' ;; + esac + PATH_SEPARATOR=$lt_cv_sys_path_separator +fi +])# _LT_AC_LIBTOOL_SYS_PATH_SEPARATOR + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + IFS="${IFS= }"; save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +AC_DIVERT_POP +])# _LT_AC_PROG_ECHO_BACKSLASH + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ------------------------------------------------------------------ +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[if test "$cross_compiling" = yes; then : + [$4] +else + AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_unknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + +# AC_LIBTOOL_DLOPEN_SELF +# ------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + cygwin* | mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + +AC_DEFUN([_LT_AC_LTCONFIG_HACK], +[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])dnl +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +sed_quote_subst='s/\([[\\"\\`$\\\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([[\\"\\`\\\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" +need_locks="$enable_libtool_lock" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +if test x"$host" != x"$build"; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi + +# Transform linux* to *-*-linux-gnu*, to support old configure scripts. +case $host_os in +linux-gnu*) ;; +linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` +esac + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="[$]2" + +## FIXME: this should be a separate macro +## +AC_MSG_CHECKING([for objdir]) +rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + objdir=_libs +fi +rmdir .libs 2>/dev/null +AC_MSG_RESULT($objdir) +## +## END FIXME + + +## FIXME: this should be a separate macro +## +AC_ARG_WITH(pic, +[ --with-pic try to use only PIC/non-PIC objects [default=use both]], +pic_mode="$withval", pic_mode=default) +test -z "$pic_mode" && pic_mode=default + +# We assume here that the value for lt_cv_prog_cc_pic will not be cached +# in isolation, and that seeing it set (from the cache) indicates that +# the associated values are set (in the cache) correctly too. +AC_MSG_CHECKING([for $compiler option to produce PIC]) +AC_CACHE_VAL(lt_cv_prog_cc_pic, +[ lt_cv_prog_cc_pic= + lt_cv_prog_cc_shlib= + lt_cv_prog_cc_wl= + lt_cv_prog_cc_static= + lt_cv_prog_cc_no_builtin= + lt_cv_prog_cc_can_build_shared=$can_build_shared + + if test "$GCC" = yes; then + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-static' + + case $host_os in + aix*) + # Below there is a dirty hack to force normal static linking with -ldl + # The problem is because libdl dynamically linked with both libc and + # libC (AIX C++ library), which obviously doesn't included in libraries + # list by gcc. This cause undefined symbols with -static flags. + # This hack allows C programs to be linked with "-static -ldl", but + # not sure about C++ programs. + lt_cv_prog_cc_static="$lt_cv_prog_cc_static ${lt_cv_prog_cc_wl}-lC" + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_cv_prog_cc_pic='-fno-common' + ;; + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_cv_prog_cc_pic='-DDLL_EXPORT' + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_cv_prog_cc_pic=-Kconform_pic + fi + ;; + *) + lt_cv_prog_cc_pic='-fPIC' + ;; + esac + else + # PORTME Check for PIC flags for the system compiler. + case $host_os in + aix3* | aix4* | aix5*) + lt_cv_prog_cc_wl='-Wl,' + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_cv_prog_cc_static='-Bstatic' + else + lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + hpux9* | hpux10* | hpux11*) + # Is there a better lt_cv_prog_cc_static that works with the bundled CC? + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static="${lt_cv_prog_cc_wl}-a ${lt_cv_prog_cc_wl}archive" + lt_cv_prog_cc_pic='+Z' + ;; + + irix5* | irix6* | nonstopux*) + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_cv_prog_cc_pic='-DDLL_EXPORT' + ;; + + newsos6) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + ;; + + osf3* | osf4* | osf5*) + # All OSF/1 code is PIC. + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-non_shared' + ;; + + sco3.2v5*) + lt_cv_prog_cc_pic='-Kpic' + lt_cv_prog_cc_static='-dn' + lt_cv_prog_cc_shlib='-belf' + ;; + + solaris*) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Wl,' + ;; + + sunos4*) + lt_cv_prog_cc_pic='-PIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Qoption ld ' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + if test "x$host_vendor" = xsni; then + lt_cv_prog_cc_wl='-LD' + else + lt_cv_prog_cc_wl='-Wl,' + fi + ;; + + uts4*) + lt_cv_prog_cc_pic='-pic' + lt_cv_prog_cc_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_cv_prog_cc_pic='-Kconform_pic' + lt_cv_prog_cc_static='-Bstatic' + fi + ;; + + *) + lt_cv_prog_cc_can_build_shared=no + ;; + esac + fi +]) +if test -z "$lt_cv_prog_cc_pic"; then + AC_MSG_RESULT([none]) +else + AC_MSG_RESULT([$lt_cv_prog_cc_pic]) + + # Check to make sure the pic_flag actually works. + AC_MSG_CHECKING([if $compiler PIC flag $lt_cv_prog_cc_pic works]) + AC_CACHE_VAL(lt_cv_prog_cc_pic_works, [dnl + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $lt_cv_prog_cc_pic -DPIC" + AC_TRY_COMPILE([], [], [dnl + case $host_os in + hpux9* | hpux10* | hpux11*) + # On HP-UX, both CC and GCC only warn that PIC is supported... then + # they create non-PIC objects. So, if there were any warnings, we + # assume that PIC is not supported. + if test -s conftest.err; then + lt_cv_prog_cc_pic_works=no + else + lt_cv_prog_cc_pic_works=yes + fi + ;; + *) + lt_cv_prog_cc_pic_works=yes + ;; + esac + ], [dnl + lt_cv_prog_cc_pic_works=no + ]) + CFLAGS="$save_CFLAGS" + ]) + + if test "X$lt_cv_prog_cc_pic_works" = Xno; then + lt_cv_prog_cc_pic= + lt_cv_prog_cc_can_build_shared=no + else + lt_cv_prog_cc_pic=" $lt_cv_prog_cc_pic" + fi + + AC_MSG_RESULT([$lt_cv_prog_cc_pic_works]) +fi +## +## END FIXME + +# Check for any special shared library compilation flags. +if test -n "$lt_cv_prog_cc_shlib"; then + AC_MSG_WARN([\`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries]) + if echo "$old_CC $old_CFLAGS " | egrep -e "[[ ]]$lt_cv_prog_cc_shlib[[ ]]" >/dev/null; then : + else + AC_MSG_WARN([add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure]) + lt_cv_prog_cc_can_build_shared=no + fi +fi + +## FIXME: this should be a separate macro +## +AC_MSG_CHECKING([if $compiler static flag $lt_cv_prog_cc_static works]) +AC_CACHE_VAL([lt_cv_prog_cc_static_works], [dnl + lt_cv_prog_cc_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_cv_prog_cc_static" + AC_TRY_LINK([], [], [lt_cv_prog_cc_static_works=yes]) + LDFLAGS="$save_LDFLAGS" +]) + +# Belt *and* braces to stop my trousers falling down: +test "X$lt_cv_prog_cc_static_works" = Xno && lt_cv_prog_cc_static= +AC_MSG_RESULT([$lt_cv_prog_cc_static_works]) + +pic_flag="$lt_cv_prog_cc_pic" +special_shlib_compile_flags="$lt_cv_prog_cc_shlib" +wl="$lt_cv_prog_cc_wl" +link_static_flag="$lt_cv_prog_cc_static" +no_builtin_flag="$lt_cv_prog_cc_no_builtin" +can_build_shared="$lt_cv_prog_cc_can_build_shared" +## +## END FIXME + + +## FIXME: this should be a separate macro +## +# Check to see if options -o and -c are simultaneously supported by compiler +AC_MSG_CHECKING([if $compiler supports -c -o file.$ac_objext]) +AC_CACHE_VAL([lt_cv_compiler_c_o], [ +$rm -r conftest 2>/dev/null +mkdir conftest +cd conftest +echo "int some_variable = 0;" > conftest.$ac_ext +mkdir out +# According to Tom Tromey, Ian Lance Taylor reported there are C compilers +# that will create temporary files in the current directory regardless of +# the output directory. Thus, making CWD read-only will cause this test +# to fail, enabling locking or at least warning the user not to do parallel +# builds. +chmod -w . +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -o out/conftest2.$ac_objext" +compiler_c_o=no +if { (eval echo configure:__oline__: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s out/conftest.err; then + lt_cv_compiler_c_o=no + else + lt_cv_compiler_c_o=yes + fi +else + # Append any errors to the config.log. + cat out/conftest.err 1>&AC_FD_CC + lt_cv_compiler_c_o=no +fi +CFLAGS="$save_CFLAGS" +chmod u+w . +$rm conftest* out/* +rmdir out +cd .. +rmdir conftest +$rm -r conftest 2>/dev/null +]) +compiler_c_o=$lt_cv_compiler_c_o +AC_MSG_RESULT([$compiler_c_o]) + +if test x"$compiler_c_o" = x"yes"; then + # Check to see if we can write to a .lo + AC_MSG_CHECKING([if $compiler supports -c -o file.lo]) + AC_CACHE_VAL([lt_cv_compiler_o_lo], [ + lt_cv_compiler_o_lo=no + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -c -o conftest.lo" + save_objext="$ac_objext" + ac_objext=lo + AC_TRY_COMPILE([], [int some_variable = 0;], [dnl + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + lt_cv_compiler_o_lo=no + else + lt_cv_compiler_o_lo=yes + fi + ]) + ac_objext="$save_objext" + CFLAGS="$save_CFLAGS" + ]) + compiler_o_lo=$lt_cv_compiler_o_lo + AC_MSG_RESULT([$compiler_o_lo]) +else + compiler_o_lo=no +fi +## +## END FIXME + +## FIXME: this should be a separate macro +## +# Check to see if we can do hard links to lock some files if needed +hard_links="nottested" +if test "$compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([\`$CC' does not support \`-c -o', so \`make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +## +## END FIXME + +## FIXME: this should be a separate macro +## +if test "$GCC" = yes; then + # Check to see if options -fno-rtti -fno-exceptions are supported by compiler + AC_MSG_CHECKING([if $compiler supports -fno-rtti -fno-exceptions]) + echo "int some_variable = 0;" > conftest.$ac_ext + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.$ac_ext" + compiler_rtti_exceptions=no + AC_TRY_COMPILE([], [int some_variable = 0;], [dnl + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + compiler_rtti_exceptions=no + else + compiler_rtti_exceptions=yes + fi + ]) + CFLAGS="$save_CFLAGS" + AC_MSG_RESULT([$compiler_rtti_exceptions]) + + if test "$compiler_rtti_exceptions" = "yes"; then + no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' + else + no_builtin_flag=' -fno-builtin' + fi +fi +## +## END FIXME + +## FIXME: this should be a separate macro +## +# See if the linker supports building shared libraries. +AC_MSG_CHECKING([whether the linker ($LD) supports shared libraries]) + +allow_undefined_flag= +no_undefined_flag= +need_lib_prefix=unknown +need_version=unknown +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +archive_cmds= +archive_expsym_cmds= +old_archive_from_new_cmds= +old_archive_from_expsyms_cmds= +export_dynamic_flag_spec= +whole_archive_flag_spec= +thread_safe_flag_spec= +hardcode_into_libs=no +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_shlibpath_var=unsupported +runpath_var= +link_all_deplibs=unknown +always_export_symbols=no +export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' +# include_expsyms should be a list of space-separated symbols to be *always* +# included in the symbol list +include_expsyms= +# exclude_expsyms can be an egrep regular expression of symbols to exclude +# it will be wrapped by ` (' and `)$', so one must not match beginning or +# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', +# as well as any symbol that contains `d'. +exclude_expsyms="_GLOBAL_OFFSET_TABLE_" +# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out +# platforms (ab)use it in PIC code, but their linkers get confused if +# the symbol is explicitly referenced. Since portable code cannot +# rely on this symbol name, it's probably fine to never include it in +# preloaded symbol tables. +extract_expsyms_cmds= + +case $host_os in +cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; +openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX, the GNU linker is very broken + # Note:Check GNU linker on AIX 5-IA64 when/if it becomes available. + ld_shlibs=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=yes + + extract_expsyms_cmds='test -f $output_objdir/impgen.c || \ + sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //;s/^# *$//; p; }" -e d < $''0 > $output_objdir/impgen.c~ + test -f $output_objdir/impgen.exe || (cd $output_objdir && \ + if test "x$HOST_CC" != "x" ; then $HOST_CC -o impgen impgen.c ; \ + else $CC -o impgen impgen.c ; fi)~ + $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def' + + old_archive_from_expsyms_cmds='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib' + + # cygwin and mingw dlls have different entry points and sets of symbols + # to exclude. + # FIXME: what about values for MSVC? + dll_entry=__cygwin_dll_entry@12 + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~ + case $host_os in + mingw*) + # mingw values + dll_entry=_DllMainCRTStartup@12 + dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~ + ;; + esac + + # mingw and cygwin differ, and it's simplest to just exclude the union + # of the two symbol sets. + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one (in ltdll.c) + if test "x$lt_cv_need_dllmain" = "xyes"; then + ltdll_obj='$output_objdir/$soname-ltdll.'"$ac_objext " + ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $''0 > $output_objdir/$soname-ltdll.c~ + test -f $output_objdir/$soname-ltdll.$ac_objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~' + else + ltdll_obj= + ltdll_cmds= + fi + + # Extract the symbol export list from an `--export-all' def file, + # then regenerate the def file from the symbol export list, so that + # the compiled dll only exports the symbol export list. + # Be careful not to strip the DATA tag left be newer dlltools. + export_symbols_cmds="$ltdll_cmds"' + $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~ + sed -e "1,/EXPORTS/d" -e "s/ @ [[0-9]]*//" -e "s/ *;.*$//" < $output_objdir/$soname-def > $export_symbols' + + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is. + # If DATA tags from a recent dlltool are present, honour them! + archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname-def; + else + echo EXPORTS > $output_objdir/$soname-def; + _lt_hint=1; + cat $export_symbols | while read symbol; do + set dummy \$symbol; + case \[$]# in + 2) echo " \[$]2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;; + *) echo " \[$]2 @ \$_lt_hint \[$]3 ; " >> $output_objdir/$soname-def;; + esac; + _lt_hint=`expr 1 + \$_lt_hint`; + done; + fi~ + '"$ltdll_cmds"' + $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~ + $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~ + $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags' + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = yes; then + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + case $host_os in + cygwin* | mingw* | pw32*) + # dlltool doesn't understand --whole-archive et. al. + whole_archive_flag_spec= + ;; + *) + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + ;; + esac + fi +else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + hardcode_direct=yes + archive_cmds='' + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + esac + + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + shared_flag='${wl}-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall can do strange things, so it is better to + # generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib' + archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname ${wl}-h$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + hardcode_libdir_flag_spec='${wl}-bnolibpath ${wl}-blibpath:$libdir:/usr/lib:/lib' + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='${wl}-berok' + # This is a bit strange, but is similar to how AIX traditionally builds + # it's shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"' ~$AR -crlo $objdir/$libname$release.a $objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + ;; + + darwin* | rhapsody*) + case "$host_os" in + rhapsody* | darwin1.[[012]]) + allow_undefined_flag='-undefined suppress' + ;; + *) # Darwin 1.3 on + allow_undefined_flag='-flat_namespace -undefined suppress' + ;; + esac + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. Also zsh mangles + # `"' quotes if we put them in here... so don't! + archive_cmds='$nonopt $(test .$module = .yes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib $libobjs $deplibs$linker_flags -install_name $rpath/$soname $verstring' + # We need to add '_' to the symbols in $export_symbols first + #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols' + hardcode_direct=yes + hardcode_shlibpath_var=no + whole_archive_flag_spec='-all_load $convenience' + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9* | hpux10* | hpux11*) + case $host_os in + hpux9*) archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;; + *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; + esac + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_minus_L=yes # Not in the search PATH, but as the default + # location of the library. + export_dynamic_flag_spec='${wl}-E' + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + openbsd*) + hardcode_direct=yes + hardcode_shlibpath_var=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case "$host_os" in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + #Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + + sco3.2v5*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + export_dynamic_flag_spec='${wl}-Bexport' + ;; + + solaris*) + # gcc --version < 3.0 without binutils cannot create self contained + # shared libraries reliably, requiring libgcc.a to resolve some of + # the object symbols generated in some cases. Libraries that use + # assert need libgcc.a to resolve __eprintf, for example. Linking + # a copy of libgcc.a into every shared library to guarantee resolving + # such symbols causes other problems: According to Tim Van Holder + # , C++ libraries end up with a separate + # (to the application) exception stack for one thing. + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + case `$CC --version 2>/dev/null` in + [[12]].*) + cat <&2 + +*** Warning: Releases of GCC earlier than version 3.0 cannot reliably +*** create self contained shared libraries on Solaris systems, without +*** introducing a dependency on libgcc.a. Therefore, libtool is disabling +*** -no-undefined support, which will at least allow you to build shared +*** libraries. However, you may find that when you link such libraries +*** into an application without using GCC, you have to manually add +*** \`gcc --print-libgcc-file-name\` to the link command. We urge you to +*** upgrade to a newer version of GCC. Another option is to rebuild your +*** current GCC to use the GNU linker from GNU binutils 2.9.1 or newer. + +EOF + no_undefined_flag= + ;; + esac + fi + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + if test "x$host_vendor" = xsno; then + archive_cmds='$LD -G -Bsymbolic -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + else + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv5*) + no_undefined_flag=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec= + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4.2uw2*) + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=no + hardcode_shlibpath_var=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5uw7* | unixware7*) + no_undefined_flag='${wl}-z ${wl}text' + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac +fi +AC_MSG_RESULT([$ld_shlibs]) +test "$ld_shlibs" = no && can_build_shared=no +## +## END FIXME + +## FIXME: this should be a separate macro +## +# Check hardcoding attributes. +AC_MSG_CHECKING([how to hardcode library paths into programs]) +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var"; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$hardcode_shlibpath_var" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +AC_MSG_RESULT([$hardcode_action]) +## +## END FIXME + +## FIXME: this should be a separate macro +## +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi +## +## END FIXME + +reload_cmds='$LD$reload_flag -o $output$reload_objs' +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +## FIXME: this should be a separate macro +## +# PORTME Fill in your ld.so characteristics +AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}.so$major' + ;; + +aix4* | aix5*) + version_type=linux + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can + # not hardcode correct soname into executable. Probably we can + # add versioning support to collect2, so additional links can + # be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}.so$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}.so' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + export_dynamic_flag_spec=-rdynamic + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + need_version=no + need_lib_prefix=no + case $GCC,$host_os in + yes,cygwin*) + library_names_spec='$libname.dll.a' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll' + postinstall_cmds='dlpath=`bash 2>&1 -c '\''. $dir/${file}i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog .libs/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`bash 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + ;; + yes,mingw*) + library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"` + ;; + yes,pw32*) + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll' + ;; + *) + library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. + library_names_spec='${libname}${release}${versuffix}.$(test .$module = .yes && echo so || echo dylib) ${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib) ${libname}.$(test .$module = .yes && echo so || echo dylib)' + soname_spec='${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib)' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + *) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + dynamic_linker="$host_os dld.sl" + version_type=sunos + need_lib_prefix=no + need_version=no + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl' + soname_spec='${libname}${release}.sl$major' + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) version_type=irix ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux-gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so' + soname_spec='${libname}${release}.so$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case "$host_os" in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +os2*) + libname_spec='$name' + need_lib_prefix=no + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_version=no + need_lib_prefix=no + soname_spec='${libname}${release}.so' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no +## +## END FIXME + +## FIXME: this should be a separate macro +## +# Report the final consequences. +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) +## +## END FIXME + +## FIXME: this should be a separate macro +## +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) +## +## END FIXME + +## FIXME: this should be a separate macro +## +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) +## +## END FIXME + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +AC_LIBTOOL_DLOPEN_SELF + +## FIXME: this should be a separate macro +## +if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + AC_CACHE_VAL([lt_cv_archive_cmds_need_lc], + [$rm conftest* + echo 'static int dummy;' > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile); then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_cv_prog_cc_wl + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if AC_TRY_EVAL(archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi]) + AC_MSG_RESULT([$lt_cv_archive_cmds_need_lc]) + ;; + esac +fi +need_lc=${lt_cv_archive_cmds_need_lc-yes} +## +## END FIXME + +## FIXME: this should be a separate macro +## +# The second clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + : +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + test -f Makefile && make "$ltmain" +fi + +if test -f "$ltmain"; then + trap "$rm \"${ofile}T\"; exit 1" 1 2 15 + $rm -f "${ofile}T" + + echo creating $ofile + + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS \ + AR AR_FLAGS CC LD LN_S NM SHELL \ + reload_flag reload_cmds wl \ + pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ + thread_safe_flag_spec whole_archive_flag_spec libname_spec \ + library_names_spec soname_spec \ + RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ + old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds \ + postuninstall_cmds extract_expsyms_cmds old_archive_from_expsyms_cmds \ + old_striplib striplib file_magic_cmd export_symbols_cmds \ + deplibs_check_method allow_undefined_flag no_undefined_flag \ + finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \ + global_symbol_to_c_name_address \ + hardcode_libdir_flag_spec hardcode_libdir_separator \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do + + case $var in + reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + export_symbols_cmds | archive_cmds | archive_expsym_cmds | \ + extract_expsyms_cmds | old_archive_from_expsyms_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + cat <<__EOF__ > "${ofile}T" +#! $SHELL + +# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996-2000 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="sed -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +# ### BEGIN LIBTOOL CONFIG + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$need_lc + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# The default C compiler. +CC=$lt_CC + +# Is the compiler the GNU C compiler? +with_gcc=$GCC + +# The linker used to build libraries. +LD=$lt_LD + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_wl + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_pic_flag +pic_mode=$pic_mode + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_compiler_c_o + +# Can we write directly to a .lo ? +compiler_o_lo=$lt_compiler_o_lo + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_link_static_flag + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# ### END LIBTOOL CONFIG + +__EOF__ + + case $host_os in + aix3*) + cat <<\EOF >> "${ofile}T" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + case $host_os in + cygwin* | mingw* | pw32* | os2*) + cat <<'EOF' >> "${ofile}T" + # This is a source program that is used to create dlls on Windows + # Don't remove nor modify the starting and closing comments +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ + # This is a source program that is used to create import libraries + # on Windows for dlls which lack them. Don't remove nor modify the + # starting and closing comments +# /* impgen.c starts here */ +# /* Copyright (C) 1999-2000 Free Software Foundation, Inc. +# +# This file is part of GNU libtool. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# */ +# +# #include /* for printf() */ +# #include /* for open(), lseek(), read() */ +# #include /* for O_RDONLY, O_BINARY */ +# #include /* for strdup() */ +# +# /* O_BINARY isn't required (or even defined sometimes) under Unix */ +# #ifndef O_BINARY +# #define O_BINARY 0 +# #endif +# +# static unsigned int +# pe_get16 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[2]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 2); +# return b[0] + (b[1]<<8); +# } +# +# static unsigned int +# pe_get32 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[4]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 4); +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# static unsigned int +# pe_as32 (ptr) +# void *ptr; +# { +# unsigned char *b = ptr; +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# int +# main (argc, argv) +# int argc; +# char *argv[]; +# { +# int dll; +# unsigned long pe_header_offset, opthdr_ofs, num_entries, i; +# unsigned long export_rva, export_size, nsections, secptr, expptr; +# unsigned long name_rvas, nexp; +# unsigned char *expdata, *erva; +# char *filename, *dll_name; +# +# filename = argv[1]; +# +# dll = open(filename, O_RDONLY|O_BINARY); +# if (dll < 1) +# return 1; +# +# dll_name = filename; +# +# for (i=0; filename[i]; i++) +# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') +# dll_name = filename + i +1; +# +# pe_header_offset = pe_get32 (dll, 0x3c); +# opthdr_ofs = pe_header_offset + 4 + 20; +# num_entries = pe_get32 (dll, opthdr_ofs + 92); +# +# if (num_entries < 1) /* no exports */ +# return 1; +# +# export_rva = pe_get32 (dll, opthdr_ofs + 96); +# export_size = pe_get32 (dll, opthdr_ofs + 100); +# nsections = pe_get16 (dll, pe_header_offset + 4 +2); +# secptr = (pe_header_offset + 4 + 20 + +# pe_get16 (dll, pe_header_offset + 4 + 16)); +# +# expptr = 0; +# for (i = 0; i < nsections; i++) +# { +# char sname[8]; +# unsigned long secptr1 = secptr + 40 * i; +# unsigned long vaddr = pe_get32 (dll, secptr1 + 12); +# unsigned long vsize = pe_get32 (dll, secptr1 + 16); +# unsigned long fptr = pe_get32 (dll, secptr1 + 20); +# lseek(dll, secptr1, SEEK_SET); +# read(dll, sname, 8); +# if (vaddr <= export_rva && vaddr+vsize > export_rva) +# { +# expptr = fptr + (export_rva - vaddr); +# if (export_rva + export_size > vaddr + vsize) +# export_size = vsize - (export_rva - vaddr); +# break; +# } +# } +# +# expdata = (unsigned char*)malloc(export_size); +# lseek (dll, expptr, SEEK_SET); +# read (dll, expdata, export_size); +# erva = expdata - export_rva; +# +# nexp = pe_as32 (expdata+24); +# name_rvas = pe_as32 (expdata+32); +# +# printf ("EXPORTS\n"); +# for (i = 0; i> "${ofile}T" || (rm -f "${ofile}T"; exit 1) + + mv -f "${ofile}T" "$ofile" || \ + (rm -f "$ofile" && cp "${ofile}T" "$ofile" && rm -f "${ofile}T") + chmod +x "$ofile" +fi +## +## END FIXME + +])# _LT_AC_LTCONFIG_HACK + +# AC_LIBTOOL_DLOPEN - enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])]) + +# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])]) + +# AC_ENABLE_SHARED - implement the --enable-shared flag +# Usage: AC_ENABLE_SHARED[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(shared, +changequote(<<, >>)dnl +<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl +]) + +# AC_DISABLE_SHARED - set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no)]) + +# AC_ENABLE_STATIC - implement the --enable-static flag +# Usage: AC_ENABLE_STATIC[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(static, +changequote(<<, >>)dnl +<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_static=AC_ENABLE_STATIC_DEFAULT)dnl +]) + +# AC_DISABLE_STATIC - set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no)]) + + +# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag +# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(fast-install, +changequote(<<, >>)dnl +<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl +]) + +# AC_DISABLE_FAST_INSTALL - set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no)]) + +# AC_LIBTOOL_PICMODE - implement the --with-pic flag +# Usage: AC_LIBTOOL_PICMODE[(MODE)] +# Where MODE is either `yes' or `no'. If omitted, it defaults to +# `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default)]) + + +# AC_PATH_TOOL_PREFIX - find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +]) + + +# AC_PATH_MAGIC - find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])dnl +AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin:$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin:$PATH) + else + MAGIC_CMD=: + fi +fi +]) + + +# AC_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | [[A-Za-z]]:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$lt_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_PROG_LD_GNU +]) + +# AC_PROG_LD_GNU - +AC_DEFUN([AC_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + lt_cv_prog_gnu_ld=yes +else + lt_cv_prog_gnu_ld=no +fi]) +with_gnu_ld=$lt_cv_prog_gnu_ld +]) + +# AC_PROG_LD_RELOAD_FLAG - find reload flag for linker +# -- PORTME Some linkers may need a different reload flag. +AC_DEFUN([AC_PROG_LD_RELOAD_FLAG], +[AC_CACHE_CHECK([for $LD option to reload object files], lt_cv_ld_reload_flag, +[lt_cv_ld_reload_flag='-r']) +reload_flag=$lt_cv_ld_reload_flag +test -n "$reload_flag" && reload_flag=" $reload_flag" +]) + +# AC_DEPLIBS_CHECK_METHOD - how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +AC_DEFUN([AC_DEPLIBS_CHECK_METHOD], +[AC_CACHE_CHECK([how to recognise dependant libraries], +lt_cv_deplibs_check_method, +[lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix4* | aix5*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi4*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin* | mingw* | pw32*) + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library' + lt_cv_file_magic_cmd='/usr/bin/file -L' + case "$host_os" in + rhapsody* | darwin1.[[012]]) + lt_cv_file_magic_test_file=`echo /System/Library/Frameworks/System.framework/Versions/*/System | head -1` + ;; + *) # Darwin 1.3 on + lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib' + ;; + esac + ;; + +freebsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20*|hpux11*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + irix5* | nonstopux*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[[1234]] dynamic lib MIPS - version 1" + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux-gnu*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/\.]]+\.so\.[[0-9]]+\.[[0-9]]+$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/\.]]+\.so$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +openbsd*) + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object' + else + lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' + fi + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +sysv5uw[[78]]* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + esac + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +]) + + +# AC_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_REQUIRE([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR])dnl +AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/${ac_tool_prefix}nm + if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then + lt_cv_path_NM="$tmp_nm -B" + break + elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + lt_cv_path_NM="$tmp_nm -p" + break + else + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +AC_MSG_RESULT([$NM]) +]) + +# AC_CHECK_LIBM - check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32*) + # These system don't have libm + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, main, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, main, LIBM="-lm") + ;; +esac +]) + +# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl convenience library and LTDLINCL to the include flags for +# the libltdl header and adds --enable-ltdl-convenience to the +# configure arguments. Note that LIBLTDL and LTDLINCL are not +# AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not +# provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed +# with '${top_builddir}/' and LTDLINCL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +]) + +# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl installable library and LTDLINCL to the include flags for +# the libltdl header and adds --enable-ltdl-install to the configure +# arguments. Note that LIBLTDL and LTDLINCL are not AC_SUBSTed, nor is +# AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed +# libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed +# with '${top_srcdir}/' (note the single quotes!). If your package is +# not flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, main, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +]) + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) diff --git a/pycaml/aclocal.m4 b/pycaml/aclocal.m4 new file mode 100644 index 0000000..72fad3f --- /dev/null +++ b/pycaml/aclocal.m4 @@ -0,0 +1,3655 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +AC_DEFUN(AM_PATH_PYTHON, +[ +AC_ARG_WITH(python-prefix,[ --with-python-prefix=PFX Prefix where Python is installed (optional)], + python_prefix="$withval" + PYPACKAGE="" + if test -e "$python_prefix/bin/python" ; then + PYPACKAGE="$python_prefix/bin/python" + fi, + PYPACKAGE="") +] +) + +dnl AC_CHECK_FT2([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for FreeType2, and define FT2_CFLAGS and FT2_LIBS +dnl +AC_DEFUN(AC_CHECK_FT2, +[dnl +dnl Get the cflags and libraries from the freetype-config script +dnl +AC_ARG_WITH(ft-prefix, [ --with-ft-prefix=PFX Prefix where FreeType is installed (optional)], + ft_config_prefix="$withval", ft_config_prefix="") +AC_ARG_WITH(ft-exec-prefix, [ --with-ft-exec-prefix=PFX Exec prefix where FreeType is installed (optional)], + ft_config_exec_prefix="$withval", ft_config_exec_prefix="") +AC_ARG_ENABLE(freetypetest, [ --disable-freetypetest Do not try to compile and run a FreeType test], + , enable_fttest=yes) + +if test x$ft_config_exec_prefix != x ; then + ft_config_args="$ft_config_args --exec-prefix=$ft_config_exec_prefix" + if test x${FT2_CONFIG+set} != xset ; then + FT2_CONFIG=$ft_config_exec_prefix/bin/freetype-config + fi +fi +if test x$ft_config_prefix != x ; then + ft_config_args="$ft_config_args --prefix=$ft_config_prefix" + if test x${FT2_CONFIG+set} != xset ; then + FT2_CONFIG=$ft_config_prefix/bin/freetype-config + fi +fi + +AC_PATH_PROG(FT2_CONFIG, freetype-config, no) +min_ft_version=ifelse([$1], ,6.1.0,$1) + +AC_MSG_CHECKING(for FreeType - version >= $min_ft_version) +no_ft="" +if test "$FT2_CONFIG" = "no" ; then + no_ft=yes +else + FT2_CFLAGS=`$FT2_CONFIG $ft_config_args --cflags` + FT2_LIBS=`$FT2_CONFIG $ft_config_args --libs` + ft_config_major_version=`$FT2_CONFIG $ft_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + ft_config_minor_version=`$FT2_CONFIG $ft_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + ft_config_micro_version=`$FT2_CONFIG $ft_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + ft_min_major_version=`echo $min_ft_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + ft_min_minor_version=`echo $min_ft_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + ft_min_micro_version=`echo $min_ft_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test x$enable_fttest = xyes ; then + ft_config_is_lt="" + if test $ft_config_major_version -lt $ft_min_major_version ; then + ft_config_is_lt=yes + else + if test $ft_config_major_version -eq $ft_min_major_version ; then + if test $ft_config_minor_version -lt $ft_min_minor_version ; then + ft_config_is_lt=yes + else + if test $ft_config_minor_version -eq $ft_min_minor_version ; then + if test $ft_config_micro_version -lt $ft_min_micro_version ; then + ft_config_is_lt=yes + fi + fi + fi + fi + fi + if test x$ft_config_is_lt = xyes ; then + no_ft=yes + else + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $FT2_CFLAGS" + LIBS="$FT2_LIBS $LIBS" +dnl +dnl Sanity checks for the results of freetype-config to some extent +dnl + AC_TRY_RUN([ +#include +#include FT_FREETYPE_H +#include +#include + +int +main() +{ + FT_Library library; + FT_Error error; + + error = FT_Init_FreeType(&library); + + if (error) + return 1; + else + { + FT_Done_FreeType(library); + return 0; + } +} +],, no_ft=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi # test $ft_config_version -lt $ft_min_version + fi # test x$enable_fttest = xyes +fi # test "$FT2_CONFIG" = "no" +if test x$no_ft = x ; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) +else + AC_MSG_RESULT(no) + if test "$FT2_CONFIG" = "no" ; then + echo "*** The freetype-config script installed by FreeType 2 could not be found." + echo "*** If FreeType 2 was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the FT2_CONFIG environment variable to the" + echo "*** full path to freetype-config." + else + if test x$ft_config_is_lt = xyes ; then + echo "*** Your installed version of the FreeType 2 library is too old." + echo "*** If you have different versions of FreeType 2, make sure that" + echo "*** correct values for --with-ft-prefix or --with-ft-exec-prefix" + echo "*** are used, or set the FT2_CONFIG environment variable to the" + echo "*** full path to freetype-config." + else + echo "*** The FreeType test program failed to run. If your system uses" + echo "*** shared libraries and they are installed outside the normal" + echo "*** system library path, make sure the variable LD_LIBRARY_PATH" + echo "*** (or whatever is appropiate for your system) is correctly set." + fi + fi + FT2_CFLAGS="" + FT2_LIBS="" + ifelse([$3], , :, [$3]) +fi +AC_SUBST(FT2_CFLAGS) +AC_SUBST(FT2_LIBS) +]) + +# libtool.m4 - Configure libtool for the host system. -*-Shell-script-*- + +# serial 46 AC_PROG_LIBTOOL + +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +]) + +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.13)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +_LT_AC_PROG_ECHO_BACKSLASH +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE(libtool-lock, + [ --disable-libtool-lock avoid locking (might break parallel builds)]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_SAVE + AC_LANG_C + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_RESTORE]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one + AC_CACHE_CHECK([if libtool should supply DllMain function], lt_cv_need_dllmain, + [AC_TRY_LINK([], + [extern int __attribute__((__stdcall__)) DllMain(void*, int, void*); + DllMain (0, 0, 0);], + [lt_cv_need_dllmain=no],[lt_cv_need_dllmain=yes])]) + + case $host/$CC in + *-*-cygwin*/gcc*-mno-cygwin*|*-*-mingw*) + # old mingw systems require "-dll" to link a DLL, while more recent ones + # require "-mdll" + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -mdll" + AC_CACHE_CHECK([how to link DLLs], lt_cv_cc_dll_switch, + [AC_TRY_LINK([], [], [lt_cv_cc_dll_switch=-mdll],[lt_cv_cc_dll_switch=-dll])]) + CFLAGS="$SAVE_CFLAGS" ;; + *-*-cygwin* | *-*-pw32*) + # cygwin systems need to pass --dll to the linker, and not link + # crt.o which will require a WinMain@16 definition. + lt_cv_cc_dll_switch="-Wl,--dll -nostartfiles" ;; + esac + ;; + ]) +esac + +_LT_AC_LTCONFIG_HACK + +]) + +# AC_LIBTOOL_HEADER_ASSERT +# ------------------------ +AC_DEFUN([AC_LIBTOOL_HEADER_ASSERT], +[AC_CACHE_CHECK([whether $CC supports assert without backlinking], + [lt_cv_func_assert_works], + [case $host in + *-*-solaris*) + if test "$GCC" = yes && test "$with_gnu_ld" != yes; then + case `$CC --version 2>/dev/null` in + [[12]].*) lt_cv_func_assert_works=no ;; + *) lt_cv_func_assert_works=yes ;; + esac + fi + ;; + esac]) + +if test "x$lt_cv_func_assert_works" = xyes; then + AC_CHECK_HEADERS(assert.h) +fi +])# AC_LIBTOOL_HEADER_ASSERT + +# _LT_AC_CHECK_DLFCN +# -------------------- +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h) +])# _LT_AC_CHECK_DLFCN + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [dnl + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + lt_cv_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +solaris* | sysv5*) + symcode='[[BDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $host_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + symcode='[[ABCDGISTW]]' +fi + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. +lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_global_symbol_to_cdecl"' < "$nlist" >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[[]] = +{ +EOF + sed "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr) \&\2},/" < "$nlist" >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$no_builtin_flag" + if AC_TRY_EVAL(ac_link) && test -s conftest; then + pipe_works=yes + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AC_FD_CC + fi + else + echo "cannot find nm_test_var in $nlist" >&AC_FD_CC + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AC_FD_CC + fi + else + echo "$progname: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +global_symbol_pipe="$lt_cv_sys_global_symbol_pipe" +if test -z "$lt_cv_sys_global_symbol_pipe"; then + global_symbol_to_cdecl= + global_symbol_to_c_name_address= +else + global_symbol_to_cdecl="$lt_cv_global_symbol_to_cdecl" + global_symbol_to_c_name_address="$lt_cv_global_symbol_to_c_name_address" +fi +if test -z "$global_symbol_pipe$global_symbol_to_cdec$global_symbol_to_c_name_address"; +then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + +# _LT_AC_LIBTOOL_SYS_PATH_SEPARATOR +# --------------------------------- +AC_DEFUN([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR], +[# Find the correct PATH separator. Usually this is `:', but +# DJGPP uses `;' like DOS. +if test "X${PATH_SEPARATOR+set}" != Xset; then + UNAME=${UNAME-`uname 2>/dev/null`} + case X$UNAME in + *-DOS) lt_cv_sys_path_separator=';' ;; + *) lt_cv_sys_path_separator=':' ;; + esac + PATH_SEPARATOR=$lt_cv_sys_path_separator +fi +])# _LT_AC_LIBTOOL_SYS_PATH_SEPARATOR + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + IFS="${IFS= }"; save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +AC_DIVERT_POP +])# _LT_AC_PROG_ECHO_BACKSLASH + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ------------------------------------------------------------------ +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[if test "$cross_compiling" = yes; then : + [$4] +else + AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_unknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + +# AC_LIBTOOL_DLOPEN_SELF +# ------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + cygwin* | mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + +AC_DEFUN([_LT_AC_LTCONFIG_HACK], +[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])dnl +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +sed_quote_subst='s/\([[\\"\\`$\\\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([[\\"\\`\\\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" +need_locks="$enable_libtool_lock" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +if test x"$host" != x"$build"; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi + +# Transform linux* to *-*-linux-gnu*, to support old configure scripts. +case $host_os in +linux-gnu*) ;; +linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` +esac + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="[$]2" + +AC_MSG_CHECKING([for objdir]) +rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + objdir=_libs +fi +rmdir .libs 2>/dev/null +AC_MSG_RESULT($objdir) + + +AC_ARG_WITH(pic, +[ --with-pic try to use only PIC/non-PIC objects [default=use both]], +pic_mode="$withval", pic_mode=default) +test -z "$pic_mode" && pic_mode=default + +# We assume here that the value for lt_cv_prog_cc_pic will not be cached +# in isolation, and that seeing it set (from the cache) indicates that +# the associated values are set (in the cache) correctly too. +AC_MSG_CHECKING([for $compiler option to produce PIC]) +AC_CACHE_VAL(lt_cv_prog_cc_pic, +[ lt_cv_prog_cc_pic= + lt_cv_prog_cc_shlib= + lt_cv_prog_cc_wl= + lt_cv_prog_cc_static= + lt_cv_prog_cc_no_builtin= + lt_cv_prog_cc_can_build_shared=$can_build_shared + + if test "$GCC" = yes; then + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-static' + + case $host_os in + aix*) + # Below there is a dirty hack to force normal static linking with -ldl + # The problem is because libdl dynamically linked with both libc and + # libC (AIX C++ library), which obviously doesn't included in libraries + # list by gcc. This cause undefined symbols with -static flags. + # This hack allows C programs to be linked with "-static -ldl", but + # not sure about C++ programs. + lt_cv_prog_cc_static="$lt_cv_prog_cc_static ${lt_cv_prog_cc_wl}-lC" + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_cv_prog_cc_pic='-fno-common' + ;; + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_cv_prog_cc_pic='-DDLL_EXPORT' + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_cv_prog_cc_pic=-Kconform_pic + fi + ;; + *) + lt_cv_prog_cc_pic='-fPIC' + ;; + esac + else + # PORTME Check for PIC flags for the system compiler. + case $host_os in + aix3* | aix4* | aix5*) + lt_cv_prog_cc_wl='-Wl,' + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_cv_prog_cc_static='-Bstatic' + else + lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + hpux9* | hpux10* | hpux11*) + # Is there a better lt_cv_prog_cc_static that works with the bundled CC? + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static="${lt_cv_prog_cc_wl}-a ${lt_cv_prog_cc_wl}archive" + lt_cv_prog_cc_pic='+Z' + ;; + + irix5* | irix6* | nonstopux*) + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_cv_prog_cc_pic='-DDLL_EXPORT' + ;; + + newsos6) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + ;; + + osf3* | osf4* | osf5*) + # All OSF/1 code is PIC. + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-non_shared' + ;; + + sco3.2v5*) + lt_cv_prog_cc_pic='-Kpic' + lt_cv_prog_cc_static='-dn' + lt_cv_prog_cc_shlib='-belf' + ;; + + solaris*) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Wl,' + ;; + + sunos4*) + lt_cv_prog_cc_pic='-PIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Qoption ld ' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + if test "x$host_vendor" = xsni; then + lt_cv_prog_cc_wl='-LD' + else + lt_cv_prog_cc_wl='-Wl,' + fi + ;; + + uts4*) + lt_cv_prog_cc_pic='-pic' + lt_cv_prog_cc_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_cv_prog_cc_pic='-Kconform_pic' + lt_cv_prog_cc_static='-Bstatic' + fi + ;; + + *) + lt_cv_prog_cc_can_build_shared=no + ;; + esac + fi +]) +if test -z "$lt_cv_prog_cc_pic"; then + AC_MSG_RESULT([none]) +else + AC_MSG_RESULT([$lt_cv_prog_cc_pic]) + + # Check to make sure the pic_flag actually works. + AC_MSG_CHECKING([if $compiler PIC flag $lt_cv_prog_cc_pic works]) + AC_CACHE_VAL(lt_cv_prog_cc_pic_works, [dnl + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $lt_cv_prog_cc_pic -DPIC" + AC_TRY_COMPILE([], [], [dnl + case $host_os in + hpux9* | hpux10* | hpux11*) + # On HP-UX, both CC and GCC only warn that PIC is supported... then + # they create non-PIC objects. So, if there were any warnings, we + # assume that PIC is not supported. + if test -s conftest.err; then + lt_cv_prog_cc_pic_works=no + else + lt_cv_prog_cc_pic_works=yes + fi + ;; + *) + lt_cv_prog_cc_pic_works=yes + ;; + esac + ], [dnl + lt_cv_prog_cc_pic_works=no + ]) + CFLAGS="$save_CFLAGS" + ]) + + if test "X$lt_cv_prog_cc_pic_works" = Xno; then + lt_cv_prog_cc_pic= + lt_cv_prog_cc_can_build_shared=no + else + lt_cv_prog_cc_pic=" $lt_cv_prog_cc_pic" + fi + + AC_MSG_RESULT([$lt_cv_prog_cc_pic_works]) +fi + +# Check for any special shared library compilation flags. +if test -n "$lt_cv_prog_cc_shlib"; then + AC_MSG_WARN([\`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries]) + if echo "$old_CC $old_CFLAGS " | egrep -e "[[ ]]$lt_cv_prog_cc_shlib[[ ]]" >/dev/null; then : + else + AC_MSG_WARN([add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure]) + lt_cv_prog_cc_can_build_shared=no + fi +fi + +AC_MSG_CHECKING([if $compiler static flag $lt_cv_prog_cc_static works]) +AC_CACHE_VAL([lt_cv_prog_cc_static_works], [dnl + lt_cv_prog_cc_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_cv_prog_cc_static" + AC_TRY_LINK([], [], [lt_cv_prog_cc_static_works=yes]) + LDFLAGS="$save_LDFLAGS" +]) + +# Belt *and* braces to stop my trousers falling down: +test "X$lt_cv_prog_cc_static_works" = Xno && lt_cv_prog_cc_static= +AC_MSG_RESULT([$lt_cv_prog_cc_static_works]) + +pic_flag="$lt_cv_prog_cc_pic" +special_shlib_compile_flags="$lt_cv_prog_cc_shlib" +wl="$lt_cv_prog_cc_wl" +link_static_flag="$lt_cv_prog_cc_static" +no_builtin_flag="$lt_cv_prog_cc_no_builtin" +can_build_shared="$lt_cv_prog_cc_can_build_shared" + + +# Check to see if options -o and -c are simultaneously supported by compiler +AC_MSG_CHECKING([if $compiler supports -c -o file.$ac_objext]) +AC_CACHE_VAL([lt_cv_compiler_c_o], [ +$rm -r conftest 2>/dev/null +mkdir conftest +cd conftest +echo "int some_variable = 0;" > conftest.$ac_ext +mkdir out +# According to Tom Tromey, Ian Lance Taylor reported there are C compilers +# that will create temporary files in the current directory regardless of +# the output directory. Thus, making CWD read-only will cause this test +# to fail, enabling locking or at least warning the user not to do parallel +# builds. +chmod -w . +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -o out/conftest2.$ac_objext" +compiler_c_o=no +if { (eval echo configure:__oline__: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s out/conftest.err; then + lt_cv_compiler_c_o=no + else + lt_cv_compiler_c_o=yes + fi +else + # Append any errors to the config.log. + cat out/conftest.err 1>&AC_FD_CC + lt_cv_compiler_c_o=no +fi +CFLAGS="$save_CFLAGS" +chmod u+w . +$rm conftest* out/* +rmdir out +cd .. +rmdir conftest +$rm -r conftest 2>/dev/null +]) +compiler_c_o=$lt_cv_compiler_c_o +AC_MSG_RESULT([$compiler_c_o]) + +if test x"$compiler_c_o" = x"yes"; then + # Check to see if we can write to a .lo + AC_MSG_CHECKING([if $compiler supports -c -o file.lo]) + AC_CACHE_VAL([lt_cv_compiler_o_lo], [ + lt_cv_compiler_o_lo=no + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -c -o conftest.lo" + save_objext="$ac_objext" + ac_objext=lo + AC_TRY_COMPILE([], [int some_variable = 0;], [dnl + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + lt_cv_compiler_o_lo=no + else + lt_cv_compiler_o_lo=yes + fi + ]) + ac_objext="$save_objext" + CFLAGS="$save_CFLAGS" + ]) + compiler_o_lo=$lt_cv_compiler_o_lo + AC_MSG_RESULT([$compiler_o_lo]) +else + compiler_o_lo=no +fi + +# Check to see if we can do hard links to lock some files if needed +hard_links="nottested" +if test "$compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([\`$CC' does not support \`-c -o', so \`make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi + +if test "$GCC" = yes; then + # Check to see if options -fno-rtti -fno-exceptions are supported by compiler + AC_MSG_CHECKING([if $compiler supports -fno-rtti -fno-exceptions]) + echo "int some_variable = 0;" > conftest.$ac_ext + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.$ac_ext" + compiler_rtti_exceptions=no + AC_TRY_COMPILE([], [int some_variable = 0;], [dnl + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + compiler_rtti_exceptions=no + else + compiler_rtti_exceptions=yes + fi + ]) + CFLAGS="$save_CFLAGS" + AC_MSG_RESULT([$compiler_rtti_exceptions]) + + if test "$compiler_rtti_exceptions" = "yes"; then + no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' + else + no_builtin_flag=' -fno-builtin' + fi +fi + +# See if the linker supports building shared libraries. +AC_MSG_CHECKING([whether the linker ($LD) supports shared libraries]) + +allow_undefined_flag= +no_undefined_flag= +need_lib_prefix=unknown +need_version=unknown +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +archive_cmds= +archive_expsym_cmds= +old_archive_from_new_cmds= +old_archive_from_expsyms_cmds= +export_dynamic_flag_spec= +whole_archive_flag_spec= +thread_safe_flag_spec= +hardcode_into_libs=no +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_shlibpath_var=unsupported +runpath_var= +link_all_deplibs=unknown +always_export_symbols=no +export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' +# include_expsyms should be a list of space-separated symbols to be *always* +# included in the symbol list +include_expsyms= +# exclude_expsyms can be an egrep regular expression of symbols to exclude +# it will be wrapped by ` (' and `)$', so one must not match beginning or +# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', +# as well as any symbol that contains `d'. +exclude_expsyms="_GLOBAL_OFFSET_TABLE_" +# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out +# platforms (ab)use it in PIC code, but their linkers get confused if +# the symbol is explicitly referenced. Since portable code cannot +# rely on this symbol name, it's probably fine to never include it in +# preloaded symbol tables. +extract_expsyms_cmds= + +case $host_os in +cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; +openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX, the GNU linker is very broken + # Note:Check GNU linker on AIX 5-IA64 when/if it becomes available. + ld_shlibs=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=yes + + extract_expsyms_cmds='test -f $output_objdir/impgen.c || \ + sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //;s/^# *$//; p; }" -e d < $''0 > $output_objdir/impgen.c~ + test -f $output_objdir/impgen.exe || (cd $output_objdir && \ + if test "x$HOST_CC" != "x" ; then $HOST_CC -o impgen impgen.c ; \ + else $CC -o impgen impgen.c ; fi)~ + $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def' + + old_archive_from_expsyms_cmds='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib' + + # cygwin and mingw dlls have different entry points and sets of symbols + # to exclude. + # FIXME: what about values for MSVC? + dll_entry=__cygwin_dll_entry@12 + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~ + case $host_os in + mingw*) + # mingw values + dll_entry=_DllMainCRTStartup@12 + dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~ + ;; + esac + + # mingw and cygwin differ, and it's simplest to just exclude the union + # of the two symbol sets. + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one (in ltdll.c) + if test "x$lt_cv_need_dllmain" = "xyes"; then + ltdll_obj='$output_objdir/$soname-ltdll.'"$ac_objext " + ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $''0 > $output_objdir/$soname-ltdll.c~ + test -f $output_objdir/$soname-ltdll.$ac_objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~' + else + ltdll_obj= + ltdll_cmds= + fi + + # Extract the symbol export list from an `--export-all' def file, + # then regenerate the def file from the symbol export list, so that + # the compiled dll only exports the symbol export list. + # Be careful not to strip the DATA tag left be newer dlltools. + export_symbols_cmds="$ltdll_cmds"' + $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~ + sed -e "1,/EXPORTS/d" -e "s/ @ [[0-9]]*//" -e "s/ *;.*$//" < $output_objdir/$soname-def > $export_symbols' + + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is. + # If DATA tags from a recent dlltool are present, honour them! + archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname-def; + else + echo EXPORTS > $output_objdir/$soname-def; + _lt_hint=1; + cat $export_symbols | while read symbol; do + set dummy \$symbol; + case \[$]# in + 2) echo " \[$]2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;; + *) echo " \[$]2 @ \$_lt_hint \[$]3 ; " >> $output_objdir/$soname-def;; + esac; + _lt_hint=`expr 1 + \$_lt_hint`; + done; + fi~ + '"$ltdll_cmds"' + $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~ + $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~ + $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags' + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = yes; then + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + case $host_os in + cygwin* | mingw* | pw32*) + # dlltool doesn't understand --whole-archive et. al. + whole_archive_flag_spec= + ;; + *) + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + ;; + esac + fi +else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + hardcode_direct=yes + archive_cmds='' + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + esac + + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + shared_flag='${wl}-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall can do strange things, so it is better to + # generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib' + archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname ${wl}-h$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + hardcode_libdir_flag_spec='${wl}-bnolibpath ${wl}-blibpath:$libdir:/usr/lib:/lib' + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='${wl}-berok' + # This is a bit strange, but is similar to how AIX traditionally builds + # it's shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"' ~$AR -crlo $objdir/$libname$release.a $objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + ;; + + darwin* | rhapsody*) + case "$host_os" in + rhapsody* | darwin1.[[012]]) + allow_undefined_flag='-undefined suppress' + ;; + *) # Darwin 1.3 on + allow_undefined_flag='-flat_namespace -undefined suppress' + ;; + esac + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. Also zsh mangles + # `"' quotes if we put them in here... so don't! + archive_cmds='$nonopt $(test .$module = .yes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib $libobjs $deplibs$linker_flags -install_name $rpath/$soname $verstring' + # We need to add '_' to the symbols in $export_symbols first + #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols' + hardcode_direct=yes + hardcode_shlibpath_var=no + whole_archive_flag_spec='-all_load $convenience' + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9* | hpux10* | hpux11*) + case $host_os in + hpux9*) archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;; + *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; + esac + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_minus_L=yes # Not in the search PATH, but as the default + # location of the library. + export_dynamic_flag_spec='${wl}-E' + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + openbsd*) + hardcode_direct=yes + hardcode_shlibpath_var=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case "$host_os" in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + #Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + + sco3.2v5*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + export_dynamic_flag_spec='${wl}-Bexport' + ;; + + solaris*) + # gcc --version < 3.0 without binutils cannot create self contained + # shared libraries reliably, requiring libgcc.a to resolve some of + # the object symbols generated in some cases. Libraries that use + # assert need libgcc.a to resolve __eprintf, for example. Linking + # a copy of libgcc.a into every shared library to guarantee resolving + # such symbols causes other problems: According to Tim Van Holder + # , C++ libraries end up with a separate + # (to the application) exception stack for one thing. + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + case `$CC --version 2>/dev/null` in + [[12]].*) + cat <&2 + +*** Warning: Releases of GCC earlier than version 3.0 cannot reliably +*** create self contained shared libraries on Solaris systems, without +*** introducing a dependency on libgcc.a. Therefore, libtool is disabling +*** -no-undefined support, which will at least allow you to build shared +*** libraries. However, you may find that when you link such libraries +*** into an application without using GCC, you have to manually add +*** \`gcc --print-libgcc-file-name\` to the link command. We urge you to +*** upgrade to a newer version of GCC. Another option is to rebuild your +*** current GCC to use the GNU linker from GNU binutils 2.9.1 or newer. + +EOF + no_undefined_flag= + ;; + esac + fi + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + if test "x$host_vendor" = xsno; then + archive_cmds='$LD -G -Bsymbolic -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + else + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv5*) + no_undefined_flag=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec= + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4.2uw2*) + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=no + hardcode_shlibpath_var=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5uw7* | unixware7*) + no_undefined_flag='${wl}-z ${wl}text' + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac +fi +AC_MSG_RESULT([$ld_shlibs]) +test "$ld_shlibs" = no && can_build_shared=no + +# Check hardcoding attributes. +AC_MSG_CHECKING([how to hardcode library paths into programs]) +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var"; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$hardcode_shlibpath_var" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +AC_MSG_RESULT([$hardcode_action]) + +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +reload_cmds='$LD$reload_flag -o $output$reload_objs' +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +# PORTME Fill in your ld.so characteristics +AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}.so$major' + ;; + +aix4* | aix5*) + version_type=linux + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can + # not hardcode correct soname into executable. Probably we can + # add versioning support to collect2, so additional links can + # be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}.so$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}.so' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + export_dynamic_flag_spec=-rdynamic + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + need_version=no + need_lib_prefix=no + case $GCC,$host_os in + yes,cygwin*) + library_names_spec='$libname.dll.a' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll' + postinstall_cmds='dlpath=`bash 2>&1 -c '\''. $dir/${file}i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog .libs/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`bash 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + ;; + yes,mingw*) + library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"` + ;; + yes,pw32*) + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll' + ;; + *) + library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. + library_names_spec='${libname}${release}${versuffix}.$(test .$module = .yes && echo so || echo dylib) ${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib) ${libname}.$(test .$module = .yes && echo so || echo dylib)' + soname_spec='${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib)' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + *) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + dynamic_linker="$host_os dld.sl" + version_type=sunos + need_lib_prefix=no + need_version=no + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl' + soname_spec='${libname}${release}.sl$major' + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) version_type=irix ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux-gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so' + soname_spec='${libname}${release}.so$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case "$host_os" in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +os2*) + libname_spec='$name' + need_lib_prefix=no + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_version=no + need_lib_prefix=no + soname_spec='${libname}${release}.so' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +# Report the final consequences. +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +AC_LIBTOOL_DLOPEN_SELF + +if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + AC_CACHE_VAL([lt_cv_archive_cmds_need_lc], + [$rm conftest* + echo 'static int dummy;' > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile); then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_cv_prog_cc_wl + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if AC_TRY_EVAL(archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi]) + AC_MSG_RESULT([$lt_cv_archive_cmds_need_lc]) + ;; + esac +fi +need_lc=${lt_cv_archive_cmds_need_lc-yes} + +# The second clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + : +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + test -f Makefile && make "$ltmain" +fi + +if test -f "$ltmain"; then + trap "$rm \"${ofile}T\"; exit 1" 1 2 15 + $rm -f "${ofile}T" + + echo creating $ofile + + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS \ + AR AR_FLAGS CC LD LN_S NM SHELL \ + reload_flag reload_cmds wl \ + pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ + thread_safe_flag_spec whole_archive_flag_spec libname_spec \ + library_names_spec soname_spec \ + RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ + old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds \ + postuninstall_cmds extract_expsyms_cmds old_archive_from_expsyms_cmds \ + old_striplib striplib file_magic_cmd export_symbols_cmds \ + deplibs_check_method allow_undefined_flag no_undefined_flag \ + finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \ + global_symbol_to_c_name_address \ + hardcode_libdir_flag_spec hardcode_libdir_separator \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do + + case $var in + reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + export_symbols_cmds | archive_cmds | archive_expsym_cmds | \ + extract_expsyms_cmds | old_archive_from_expsyms_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + cat <<__EOF__ > "${ofile}T" +#! $SHELL + +# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996-2000 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="sed -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +# ### BEGIN LIBTOOL CONFIG + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$need_lc + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# The default C compiler. +CC=$lt_CC + +# Is the compiler the GNU C compiler? +with_gcc=$GCC + +# The linker used to build libraries. +LD=$lt_LD + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_wl + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_pic_flag +pic_mode=$pic_mode + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_compiler_c_o + +# Can we write directly to a .lo ? +compiler_o_lo=$lt_compiler_o_lo + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_link_static_flag + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# ### END LIBTOOL CONFIG + +__EOF__ + + case $host_os in + aix3*) + cat <<\EOF >> "${ofile}T" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + case $host_os in + cygwin* | mingw* | pw32* | os2*) + cat <<'EOF' >> "${ofile}T" + # This is a source program that is used to create dlls on Windows + # Don't remove nor modify the starting and closing comments +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ + # This is a source program that is used to create import libraries + # on Windows for dlls which lack them. Don't remove nor modify the + # starting and closing comments +# /* impgen.c starts here */ +# /* Copyright (C) 1999-2000 Free Software Foundation, Inc. +# +# This file is part of GNU libtool. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# */ +# +# #include /* for printf() */ +# #include /* for open(), lseek(), read() */ +# #include /* for O_RDONLY, O_BINARY */ +# #include /* for strdup() */ +# +# /* O_BINARY isn't required (or even defined sometimes) under Unix */ +# #ifndef O_BINARY +# #define O_BINARY 0 +# #endif +# +# static unsigned int +# pe_get16 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[2]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 2); +# return b[0] + (b[1]<<8); +# } +# +# static unsigned int +# pe_get32 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[4]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 4); +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# static unsigned int +# pe_as32 (ptr) +# void *ptr; +# { +# unsigned char *b = ptr; +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# int +# main (argc, argv) +# int argc; +# char *argv[]; +# { +# int dll; +# unsigned long pe_header_offset, opthdr_ofs, num_entries, i; +# unsigned long export_rva, export_size, nsections, secptr, expptr; +# unsigned long name_rvas, nexp; +# unsigned char *expdata, *erva; +# char *filename, *dll_name; +# +# filename = argv[1]; +# +# dll = open(filename, O_RDONLY|O_BINARY); +# if (dll < 1) +# return 1; +# +# dll_name = filename; +# +# for (i=0; filename[i]; i++) +# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') +# dll_name = filename + i +1; +# +# pe_header_offset = pe_get32 (dll, 0x3c); +# opthdr_ofs = pe_header_offset + 4 + 20; +# num_entries = pe_get32 (dll, opthdr_ofs + 92); +# +# if (num_entries < 1) /* no exports */ +# return 1; +# +# export_rva = pe_get32 (dll, opthdr_ofs + 96); +# export_size = pe_get32 (dll, opthdr_ofs + 100); +# nsections = pe_get16 (dll, pe_header_offset + 4 +2); +# secptr = (pe_header_offset + 4 + 20 + +# pe_get16 (dll, pe_header_offset + 4 + 16)); +# +# expptr = 0; +# for (i = 0; i < nsections; i++) +# { +# char sname[8]; +# unsigned long secptr1 = secptr + 40 * i; +# unsigned long vaddr = pe_get32 (dll, secptr1 + 12); +# unsigned long vsize = pe_get32 (dll, secptr1 + 16); +# unsigned long fptr = pe_get32 (dll, secptr1 + 20); +# lseek(dll, secptr1, SEEK_SET); +# read(dll, sname, 8); +# if (vaddr <= export_rva && vaddr+vsize > export_rva) +# { +# expptr = fptr + (export_rva - vaddr); +# if (export_rva + export_size > vaddr + vsize) +# export_size = vsize - (export_rva - vaddr); +# break; +# } +# } +# +# expdata = (unsigned char*)malloc(export_size); +# lseek (dll, expptr, SEEK_SET); +# read (dll, expdata, export_size); +# erva = expdata - export_rva; +# +# nexp = pe_as32 (expdata+24); +# name_rvas = pe_as32 (expdata+32); +# +# printf ("EXPORTS\n"); +# for (i = 0; i> "${ofile}T" || (rm -f "${ofile}T"; exit 1) + + mv -f "${ofile}T" "$ofile" || \ + (rm -f "$ofile" && cp "${ofile}T" "$ofile" && rm -f "${ofile}T") + chmod +x "$ofile" +fi + +])# _LT_AC_LTCONFIG_HACK + +# AC_LIBTOOL_DLOPEN - enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])]) + +# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])]) + +# AC_ENABLE_SHARED - implement the --enable-shared flag +# Usage: AC_ENABLE_SHARED[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(shared, +changequote(<<, >>)dnl +<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl +]) + +# AC_DISABLE_SHARED - set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no)]) + +# AC_ENABLE_STATIC - implement the --enable-static flag +# Usage: AC_ENABLE_STATIC[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(static, +changequote(<<, >>)dnl +<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_static=AC_ENABLE_STATIC_DEFAULT)dnl +]) + +# AC_DISABLE_STATIC - set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no)]) + + +# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag +# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(fast-install, +changequote(<<, >>)dnl +<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl +]) + +# AC_DISABLE_FAST_INSTALL - set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no)]) + +# AC_LIBTOOL_PICMODE - implement the --with-pic flag +# Usage: AC_LIBTOOL_PICMODE[(MODE)] +# Where MODE is either `yes' or `no'. If omitted, it defaults to +# `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default)]) + + +# AC_PATH_TOOL_PREFIX - find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +]) + + +# AC_PATH_MAGIC - find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])dnl +AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin:$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin:$PATH) + else + MAGIC_CMD=: + fi +fi +]) + + +# AC_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | [[A-Za-z]]:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$lt_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_PROG_LD_GNU +]) + +# AC_PROG_LD_GNU - +AC_DEFUN([AC_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + lt_cv_prog_gnu_ld=yes +else + lt_cv_prog_gnu_ld=no +fi]) +with_gnu_ld=$lt_cv_prog_gnu_ld +]) + +# AC_PROG_LD_RELOAD_FLAG - find reload flag for linker +# -- PORTME Some linkers may need a different reload flag. +AC_DEFUN([AC_PROG_LD_RELOAD_FLAG], +[AC_CACHE_CHECK([for $LD option to reload object files], lt_cv_ld_reload_flag, +[lt_cv_ld_reload_flag='-r']) +reload_flag=$lt_cv_ld_reload_flag +test -n "$reload_flag" && reload_flag=" $reload_flag" +]) + +# AC_DEPLIBS_CHECK_METHOD - how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +AC_DEFUN([AC_DEPLIBS_CHECK_METHOD], +[AC_CACHE_CHECK([how to recognise dependant libraries], +lt_cv_deplibs_check_method, +[lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix4* | aix5*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi4*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin* | mingw* | pw32*) + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library' + lt_cv_file_magic_cmd='/usr/bin/file -L' + case "$host_os" in + rhapsody* | darwin1.[[012]]) + lt_cv_file_magic_test_file=`echo /System/Library/Frameworks/System.framework/Versions/*/System | head -1` + ;; + *) # Darwin 1.3 on + lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib' + ;; + esac + ;; + +freebsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20*|hpux11*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + irix5* | nonstopux*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[[1234]] dynamic lib MIPS - version 1" + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux-gnu*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/\.]]+\.so\.[[0-9]]+\.[[0-9]]+$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/\.]]+\.so$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +openbsd*) + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object' + else + lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' + fi + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +sysv5uw[[78]]* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + esac + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +]) + + +# AC_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_REQUIRE([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR])dnl +AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/${ac_tool_prefix}nm + if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then + lt_cv_path_NM="$tmp_nm -B" + break + elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + lt_cv_path_NM="$tmp_nm -p" + break + else + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +AC_MSG_RESULT([$NM]) +]) + +# AC_CHECK_LIBM - check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32*) + # These system don't have libm + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, main, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, main, LIBM="-lm") + ;; +esac +]) + +# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl convenience library and LTDLINCL to the include flags for +# the libltdl header and adds --enable-ltdl-convenience to the +# configure arguments. Note that LIBLTDL and LTDLINCL are not +# AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not +# provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed +# with '${top_builddir}/' and LTDLINCL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +]) + +# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl installable library and LTDLINCL to the include flags for +# the libltdl header and adds --enable-ltdl-install to the configure +# arguments. Note that LIBLTDL and LTDLINCL are not AC_SUBSTed, nor is +# AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed +# libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed +# with '${top_srcdir}/' (note the single quotes!). If your package is +# not flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, main, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +]) + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + diff --git a/pycaml/configure b/pycaml/configure new file mode 100644 index 0000000..bf39340 --- /dev/null +++ b/pycaml/configure @@ -0,0 +1,4142 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.57. +# +# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="pycaml_ml.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP PYPACKAGE haveldd PY_LIBS PY_VERSION PY_PREFIX LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-python-prefix=PFX Prefix where Python is installed (optional) + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 +Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.57. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core core.* *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output" >&5 +echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + ''\ + '#include ' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +echo "$as_me:$LINENO: checking for main in -lpython" >&5 +echo $ECHO_N "checking for main in -lpython... $ECHO_C" >&6 +if test "${ac_cv_lib_python_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpython $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_python_main=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_python_main=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_python_main" >&5 +echo "${ECHO_T}$ac_cv_lib_python_main" >&6 +if test $ac_cv_lib_python_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPYTHON 1 +_ACEOF + + LIBS="-lpython $LIBS" + +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc in + yes:no ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; + no:yes ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + + + + + +# Check whether --with-python-prefix or --without-python-prefix was given. +if test "${with_python_prefix+set}" = set; then + withval="$with_python_prefix" + python_prefix="$withval" + PYPACKAGE="" + if test -e "$python_prefix/bin/python" ; then + PYPACKAGE="$python_prefix/bin/python" + fi +else + PYPACKAGE="" +fi; + + + +for ac_prog in python +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_path_PYPACKAGE+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $PYPACKAGE in + [\\/]* | ?:[\\/]*) + ac_cv_path_PYPACKAGE="$PYPACKAGE" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PYPACKAGE="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + ;; +esac +fi +PYPACKAGE=$ac_cv_path_PYPACKAGE + +if test -n "$PYPACKAGE"; then + echo "$as_me:$LINENO: result: $PYPACKAGE" >&5 +echo "${ECHO_T}$PYPACKAGE" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$PYPACKAGE" && break +done + + + + +PY_PREFIX=`$PYPACKAGE getprefix.py` +PY_VERSION=`$PYPACKAGE getversion.py` + + +if test `echo $PY_VERSION | tr -d .` -lt 15; then +echo "Sorry, you need to have Python 1.5+ installed - update your version!" + { { echo "$as_me:$LINENO: error: *** Python 1.5 or better required" >&5 +echo "$as_me: error: *** Python 1.5 or better required" >&2;} + { (exit 1); exit 1; }; } +fi + + +echo "$as_me:$LINENO: checking for Python header files" >&5 +echo $ECHO_N "checking for Python header files... $ECHO_C" >&6 + +PY_INCLUDE=`$PYPACKAGE -c 'import sys ; print "%s/include/python%s" % (sys.prefix, sys.version[:3])'` + + +if test -r "$PY_INCLUDE/Python.h"; then + PY_CFLAGS="-I$PY_INCLUDE" +else + { { echo "$as_me:$LINENO: error: Could not find Python.h in $PY_INCLUDE" >&5 +echo "$as_me: error: Could not find Python.h in $PY_INCLUDE" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: found" >&5 +echo "${ECHO_T}found" >&6 + + +echo "$as_me:$LINENO: checking for Python library" >&5 +echo $ECHO_N "checking for Python library... $ECHO_C" >&6 +PYLIB="" + +PY_PREFIX=`$PYPACKAGE -c 'import sys; print sys.prefix'` +PYLIBVER=`$PYPACKAGE -c 'import sys; print sys.version[:3]'` + + +py_paths="$PY_PREFIX/lib/python$PYLIBVER/config $PYPREFIX/lib" +py_suffix="$PYLIBVER.so $PYLIBVER.a .so .a" + + +for ppath in $py_paths ; do + if test -r "$ppath/libpython$PYLIBVER.so" -o \ + -r "$ppath/libpython$PYLIBVER.a"; then + PYLIB="-cclib -L$ppath -cclib -lpython$PYLIBVER" + break + fi + + if test -r "$ppath/libpython.so" -o \ + -r "$ppath/libpython.a"; then + PYLIB="-cclib -L$ppath -cclib -lpython" + break + fi +done + +if test "x$PYLIB" != x ; then + PY_LIBS="$PYLIB $PY_LIBS" + echo "$as_me:$LINENO: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + { { echo "$as_me:$LINENO: error: *** Python library not found" >&5 +echo "$as_me: error: *** Python library not found" >&2;} + { (exit 1); exit 1; }; } +fi + + +# Extract the first word of "ldd", so it can be a program name with args. +set dummy ldd; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_path_haveldd+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $haveldd in + [\\/]* | ?:[\\/]*) + ac_cv_path_haveldd="$haveldd" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_haveldd="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + ;; +esac +fi +haveldd=$ac_cv_path_haveldd + +if test -n "$haveldd"; then + echo "$as_me:$LINENO: result: $haveldd" >&5 +echo "${ECHO_T}$haveldd" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +echo "$as_me:$LINENO: checking for Python's dependencies" >&5 +echo $ECHO_N "checking for Python's dependencies... $ECHO_C" >&6 + +if test x$haveldd != x ; then + + py_deps=`ldd $PYPACKAGE | sed 's/\( *lib\([^\/]*\)\.so.*=.*$\)/-cclib\ \"-l\2\"/p; d'` + for py_lib in $py_deps ; do + if test "$py_lib" != "-lm" && test "$py_lib" != "-lc" ; then + PY_DEPS="$PY_DEPS $py_lib" + fi + done + +fi + + +if $LD -v 2>&1 &5; then + PY_LIBS="-Wl,-E $PY_LIBS $PY_DEPS" +else + PY_LIBS="$PY_LIBS $PY_DEPS" +fi + +export PY_LIBS +export PY_VERSION +export PY_PREFIX + + + + + + ac_config_files="$ac_config_files Makefile" +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then we branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +cat >confdef2opt.sed <<\_ACEOF +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g +t quote +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g +t quote +d +: quote +s,[ `~#$^&*(){}\\|;'"<>?],\\&,g +s,\[,\\&,g +s,\],\\&,g +s,\$,$$,g +p +_ACEOF +# We use echo to avoid assuming a particular line-breaking character. +# The extra dot is to prevent the shell from consuming trailing +# line-breaks from the sub-command output. A line-break within +# single-quotes doesn't work because, if this script is created in a +# platform that uses two characters for line-breaks (e.g., DOS), tr +# would break. +ac_LF_and_DOT=`echo; echo .` +DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` +rm -f confdef2opt.sed + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by $as_me, which was +generated by GNU Autoconf 2.57. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.57, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + + + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@PYPACKAGE@,$PYPACKAGE,;t t +s,@haveldd@,$haveldd,;t t +s,@PY_LIBS@,$PY_LIBS,;t t +s,@PY_VERSION@,$PY_VERSION,;t t +s,@PY_PREFIX@,$PY_PREFIX,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo $f;; + *) # Relative + if test -f "$f"; then + # Build tree + echo $f + elif test -f "$srcdir/$f"; then + # Source tree + echo $srcdir/$f + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/pycaml/configure.in b/pycaml/configure.in new file mode 100644 index 0000000..3e5a426 --- /dev/null +++ b/pycaml/configure.in @@ -0,0 +1,121 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(pycaml_ml.c) + +dnl Checks for programs. + +dnl Checks for libraries. +dnl Replace `main' with a function in -lpython: +AC_CHECK_LIB(python, main) + +dnl Checks for header files. +AC_CHECK_HEADERS(unistd.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +dnl Checks for library functions. +AC_HEADER_STDC + +dnl ******************** +dnl Check for Python. +dnl ******************** + +AM_PATH_PYTHON() + +dnl Find Python executable +AC_PATH_PROGS(PYPACKAGE, python) + +dnl Extract the version using Python, check against 1.5+ + +changequote(<<, >>) +PY_PREFIX=`$PYPACKAGE getprefix.py` +PY_VERSION=`$PYPACKAGE getversion.py` +changequote([, ]) + +if test `echo $PY_VERSION | tr -d .` -lt 15; then +echo "Sorry, you need to have Python 1.5+ installed - update your version!" + AC_MSG_ERROR([*** Python 1.5 or better required]) +fi + +dnl Find the Python.h header file + +AC_MSG_CHECKING(for Python header files) +changequote(<<, >>) +PY_INCLUDE=`$PYPACKAGE -c 'import sys ; print "%s/include/python%s" % (sys.prefix, sys.version[:3])'` +changequote([, ]) + +if test -r "$PY_INCLUDE/Python.h"; then + PY_CFLAGS="-I$PY_INCLUDE" +else + AC_MSG_ERROR([Could not find Python.h in $PY_INCLUDE]) +fi +AC_MSG_RESULT(found) + +dnl Find the Python library + +AC_MSG_CHECKING(for Python library) +PYLIB="" +changequote(<<, >>) +PY_PREFIX=`$PYPACKAGE -c 'import sys; print sys.prefix'` +PYLIBVER=`$PYPACKAGE -c 'import sys; print sys.version[:3]'` +changequote([, ]) + +py_paths="$PY_PREFIX/lib/python$PYLIBVER/config $PYPREFIX/lib" +py_suffix="$PYLIBVER.so $PYLIBVER.a .so .a" + +dnl Try for specific version first, then the generic version, then panic + +for ppath in $py_paths ; do + if test -r "$ppath/libpython$PYLIBVER.so" -o \ + -r "$ppath/libpython$PYLIBVER.a"; then + PYLIB="-cclib -L$ppath -cclib -lpython$PYLIBVER" + break + fi + + if test -r "$ppath/libpython.so" -o \ + -r "$ppath/libpython.a"; then + PYLIB="-cclib -L$ppath -cclib -lpython" + break + fi +done + +if test "x$PYLIB" != x ; then + PY_LIBS="$PYLIB $PY_LIBS" + AC_MSG_RESULT(found) +else + AC_MSG_ERROR([*** Python library not found]) +fi + +dnl Get the libraries that python depends on + +AC_PATH_PROG(haveldd, ldd) +AC_MSG_CHECKING(for Python's dependencies) + +if test x$haveldd != x ; then + changequote(<<, >>) + py_deps=`ldd $PYPACKAGE | sed 's/\( *lib\([^\/]*\)\.so.*=.*$\)/-cclib\ \"-l\2\"/p; d'` + for py_lib in $py_deps ; do + if test "$py_lib" != "-lm" && test "$py_lib" != "-lc" ; then + PY_DEPS="$PY_DEPS $py_lib" + fi + done + changequote([, ]) +fi + +dnl only GNU ld seems to know -E flag + +if $LD -v 2>&1 &5; then + PY_LIBS="-Wl,-E $PY_LIBS $PY_DEPS" +else + PY_LIBS="$PY_LIBS $PY_DEPS" +fi + +export PY_LIBS +export PY_VERSION +export PY_PREFIX + +AC_SUBST(PY_LIBS) +AC_SUBST(PY_VERSION) +AC_SUBST(PY_PREFIX) + +AC_OUTPUT(Makefile) diff --git a/pycaml/getprefix.py b/pycaml/getprefix.py new file mode 100644 index 0000000..ce18302 --- /dev/null +++ b/pycaml/getprefix.py @@ -0,0 +1,3 @@ +import sys + +print sys.exec_prefix diff --git a/pycaml/getversion.py b/pycaml/getversion.py new file mode 100644 index 0000000..594d754 --- /dev/null +++ b/pycaml/getversion.py @@ -0,0 +1,3 @@ +import sys + +print sys.version[:3] diff --git a/pycaml/license.txt b/pycaml/license.txt new file mode 100644 index 0000000..b1e3f5a --- /dev/null +++ b/pycaml/license.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/pycaml/modif-orig.txt b/pycaml/modif-orig.txt new file mode 100644 index 0000000..bc0743a --- /dev/null +++ b/pycaml/modif-orig.txt @@ -0,0 +1,107 @@ +--- a/pycaml_ml.c 2004-12-02 17:17:07.000000000 +0100 ++++ b/pycaml_ml.c 2008-03-27 12:15:23.000000000 +0100 +@@ -554,6 +554,7 @@ + extern DL_IMPORT(PyObject *) PyObject_GetAttrString(PyObject *, char *); + /* 17 */ + extern DL_IMPORT(PyObject *) PyObject_GetAttr(PyObject *, PyObject *); ++extern DL_IMPORT(PyObject *) PyObject_CallObject(PyObject *, PyObject *); + /* 18 */ + extern DL_IMPORT(int) PyObject_IsTrue(PyObject *); + extern DL_IMPORT(int) PyObject_Not(PyObject *); +@@ -654,6 +655,7 @@ + extern DL_IMPORT(PyObject *) PyTuple_New(int size); + /* 18 */ + extern DL_IMPORT(int) PyTuple_Size(PyObject *); ++extern DL_IMPORT(int) PyTuple_Check(PyObject *); + /* 40 */ + extern DL_IMPORT(PyObject *) PyTuple_GetItem(PyObject *, int); + /* 41 */ +@@ -883,6 +885,47 @@ + #endif//MAYBE_RUN + #endif//DONT_COMPILE_THIS + ++/* HST FIXUP */ ++#undef PyRun_SimpleString ++int PyRun_SimpleString(const char* command) { return PyRun_SimpleStringFlags(command, NULL); } ++ ++#undef PyRun_AnyFile ++int PyRun_AnyFile(FILE* fp, const char* filename) { return PyRun_AnyFileExFlags(fp, filename, 0, NULL); } ++ ++#undef PyRun_SimpleFile ++int PyRun_SimpleFile(FILE* fp, const char* filename) { return PyRun_SimpleFileExFlags(fp, filename, 0, NULL); } ++ ++#undef PyRun_InteractiveOne ++int PyRun_InteractiveOne(FILE* fp, const char* filename) { return PyRun_InteractiveOneFlags(fp, filename, NULL); } ++ ++#undef PyRun_InteractiveLoop ++int PyRun_InteractiveLoop(FILE* fp, const char* filename) { return PyRun_InteractiveLoopFlags(fp, filename, NULL); } ++ ++#undef PyRun_AnyFileEx ++int PyRun_AnyFileEx(FILE* fp, const char* filename, int closeit) { return PyRun_AnyFileExFlags(fp, filename, closeit, NULL); } ++ ++#undef PyRun_SimpleFileEx ++int PyRun_SimpleFileEx(FILE* fp, const char* filename, int closeit) { return PyRun_SimpleFileExFlags(fp, filename, closeit, NULL); } ++ ++#undef PyRun_String ++PyObject* PyRun_String(const char* str, int start, PyObject* globals, PyObject* locals) { return PyRun_StringFlags(str, start, globals, locals, NULL); } ++ ++#undef PyRun_File ++PyObject* PyRun_File(FILE* fp, const char* filename, int start, PyObject* globals, PyObject* locals) { return PyRun_FileExFlags(fp, filename, start, globals, locals, 0, NULL); } ++ ++#undef PyRun_FileEx ++PyObject* PyRun_FileEx(FILE* fp, const char* filename, int start, PyObject* globals, PyObject* locals, int closeit) { return PyRun_FileExFlags(fp, filename, start, globals, locals, closeit, NULL); } ++ ++#undef Py_CompileString ++PyObject* Py_CompileString(const char* str, const char* filename, int start) { return Py_CompileStringFlags(str, filename, start, NULL); } ++ ++#undef PyRange_New ++PyObject* PyRange_New(PyObject* start, PyObject* stop, PyObject* step) { return PyObject_CallFunction((PyObject*)&PyRange_Type, "lll", start, stop, step); } ++ ++#undef PyTuple_Check ++int PyTuple_Check(PyObject* op) { return PyObject_TypeCheck(op, &PyTuple_Type); } ++/* END HST FIXUP */ ++ + /* Value -> Pyobject */ + + value pywrapvalue( value cb ) { +@@ -963,6 +1006,7 @@ + { (void *)PyObject_GetAttrString, 16, "PyObject_GetAttrString" }, + /* 17 */ + { (void *)PyObject_GetAttr, 17, "PyObject_GetAttr" }, ++ { (void *)PyObject_CallObject, 17, "PyObject_CallObject" }, + /* 18 */ + { (void *)PyObject_IsTrue, 18, "PyObject_IsTrue" }, + { (void *)PyObject_Not, 18, "PyObject_Not" }, +@@ -1051,6 +1095,7 @@ + { (void *)PyTuple_New, 39, "PyTuple_New" }, + /* 18 */ + { (void *)PyTuple_Size, 18, "PyTuple_Size" }, ++ { (void *)PyTuple_Check, 18, "PyTuple_Check" }, + /* 40 */ + { (void *)PyTuple_GetItem, 40, "PyTuple_GetItem" }, + /* 41 */ +@@ -1385,3 +1430,24 @@ + + CAMLreturn(Val_unit); + } ++ ++value pycaml_setargs(value argv) { ++ CAMLparam1(argv); ++ char* cargv[1]; ++ ++ cargv[0] = String_val(argv); ++ ++ PySys_SetArgv(1, cargv); ++ ++ CAMLreturn0; ++} ++ ++value pytrue( value unit ) { ++ CAMLparam1(unit); ++ CAMLreturn(pywrap(Py_True)); ++} ++ ++value pyfalse(value unit) { ++ CAMLparam1(unit); ++ CAMLreturn(pywrap(Py_False)); ++} diff --git a/pycaml/ocamlobj.ml b/pycaml/ocamlobj.ml new file mode 100644 index 0000000..651fd1e --- /dev/null +++ b/pycaml/ocamlobj.ml @@ -0,0 +1,12 @@ +open Pycaml + +let foo_bar_print = pywrap_closure (fun x -> print_endline "hi" ; pynone ()) ;; +let sd = pyimport_getmoduledict () ;; +let mx = pymodule_new "CamlModule" ;; +let cd = pydict_new () ;; +let cx = pyclass_new (pynull (), cd, pystring_fromstring "CamlClass") ;; +let cmx = pymethod_new (foo_bar_print,(pynull ()),cx) ;; +let _ = pydict_setitemstring (cd, "CamlMethod", cmx) ;; +let _ = pydict_setitemstring (pymodule_getdict mx, "CamlClass", cx) ;; +let _ = pydict_setitemstring (sd, "CamlModule", mx) ;; +let _ = pyrun_interactiveloop (0,"-") ;; diff --git a/pycaml/pycaml.html b/pycaml/pycaml.html new file mode 100644 index 0000000..d476329 --- /dev/null +++ b/pycaml/pycaml.html @@ -0,0 +1,321 @@ + + +Module Pycaml + + +
      +

      Pycaml

      +
      +

      +

      What is Pycaml

      +A library written by
      +arty@users.sourceforge.net which follows the Python/C API as +closely as possible, while +providing equivalent functionality for objective caml. This is built +against python 2.x and Ocaml 3.04.

      It is intended to allow users to +build native ocaml libraries and use them from python, and alternately, +in order to allow ocaml users to benefit from linkable libraries provided +for python.

      +I created this library in order to take advantage of python binding for +certain native libraries from ocaml. While it is true that I could have +written new interfaces specifically for ocaml, the python interface is +sufficient for my needs, and this project was easier.

      + +Note: Unfortunately, the symbol init_exceptions exists in +both compiled ocaml code, and the python runtime. In order to proceed, you +must rename this symbol either in the ocaml distribution (in byterun/fail.c, +and byterun/startup.c), or in the python distribution, and rebuild the +software appropriately.

      + +Please edit the Makefile to put in your system's libraries used for +compiling programs embedded with python. This library compiles on most +linux boxes without modification. The python interpreter is used to determine +the path to the python library and must be in your path when you run make. +

      + +Get the distribution here:pycaml.tar.gz

      + +Because these are made to closely mirror the python API, the user should +become familiar with the python API.

      +Given Ocaml parameter passing convention, it was convenient to pass multiple +arguments as members of a tuple, but single arguments without. Consequently, +functions with arity 1, such as pytuple_new are called as

      +

      +  pytuple_new 3 ;;
      +

      +And functions with more arguments are called as

      +

      +  pydict_getitemstring (dict,"keystring") ;;
      +
      + +

      Module Pycaml

      + +

      Visible Types

      + + + + + + + + + + + + + + + + +
      typepyobject
      +The abstract type of python objects. +
      typepyobject_type =
      TupleType
      |StringType
      |IntType
      |FloatType
      |ListType
      |NoneType
      |CallableType
      |ModuleType
      |ClassType
      |TypeType
      |OtherType
      +The type representing the range of types available to python programs. +Values of this type are provided by the pytype function, and identify the +python type of opaque pyobject objects. +
      + +

      Supported Functions from the Python/C API

      +In each case, the signature of the function is unchanged from the Python/C +API except for the case of 'out' pointer to pointer parameters; +in the case of a single return, the returned value is copied, otherwise, +a tuple is created with copies of all output parameters. In the case of +zero parameter, or void return, unit is used.

      +In python API functions that take a FILE *, an int file descriptor is used +instead such as those returned by the Unix library.

      + +

      fun unit -> unit

      +py_initialize, py_finalize, pyerr_print, pyerr_clear, pyimport_cleanup +

      fun int -> unit

      +py_exit, pyerr_printex +

      fun string -> unit

      +py_setprogramname, py_setpythonhome +

      fun unit -> int

      +py_isinitialized, pyeval_getrestricted +

      fun string -> int

      +pyrun_simplestring, pyimport_importfrozenmodule, +

      fun (int * string) -> int

      +pyrun_anyfile, pyrun_simplefile, pyrun_interactiveone, pyrun_interactiveloop, +py_fdisinteractive +

      fun (int * string * int) -> int

      +pyrun_anyfileex, pyrun_simplefileex +

      fun unit -> string

      +py_getprogramname, py_getpthonhome, py_getprogramfullpath, py_getprefix, +py_getexecprefix, py_getpath, py_getversion, py_getplatform, py_getcopyright, +py_getcompiler, py_getbuildinfo +

      fun (string * int * pyobject * pyobject) -> pyobject

      +pyrun_string +

      fun (int * string * int * pyobject * pyobject) -> pyobject

      +pyrun_file +

      fun (int * string * int * pyobject * pyobject * int) -> pyobject

      +pyrun_fileex +

      fun (string * string * int) -> pyobject

      +py_compilestring +

      fun (pyobject * int * int) -> int

      +pyobject_print, pytuple_getslice, pysequence_getslice

    +

    fun pyobject -> pyobject

    +pyobject_repr, pyobject_str, pyobject_unicode, pydict_keys, pydict_values, +pydict_items, pydict_copy, pymodule_getdict, pymethod_function, pymethod_self, +pymethod_class, pymodule_getdict, pyimport_reloadmodule, pyobject_type, +pynumber_negative, pynumber_positive, pynumber_absolute, pynumber_invert, +pynumber_int, pynumber_long, pynumber_float, pysequence_tuple, pysequence_list +

    fun (pyobject * pyobject * int) -> pyobject

    +pyobject_richcompare +

    fun (pyobject * string) -> pyobject

    +pyobject_getattrstring, pydict_getitemstring, pysequence_fast, +pymapping_haskeystring, pymapping_getitemstring +

    fun (pyobject * pyobject) -> pyobject

    +pyobject_getattr, pystring_format, pydict_getitem, pyinstance_newraw, +pyeval_callobject, pyobject_getitem, pyobject_delitem, pynumber_add, +pynumber_subtract, pynumber_multiply, pynumber_divide, pynumber_remainder, +pynumber_divmod, pynumber_lshift, pynumber_rshift, pynumber_and, pynumber_xor, +pynumber_or, pynumber_inplaceadd, pynumber_inplacesubtract, pynumber_inplacemultiply, pynumber_inplacedivide, pynumber_inplaceremainder, pynumber_inplacelshift, pynumber_inplacershift, pynumber_inplaceand, pynumber_inplacexor, pynumber_inplaceor, pysequence_concat, pysequence_inplaceconcat +

    fun pyobject -> int

    +pyobject_istrue, pyobject_not, pycalable_check, pystring_size, pydict_size, +pytuple_new, pyerr_exceptionmatches, pyobject_size, pynumber_check, +pysequence_check, pysequence_size, pysequence_length, pymapping_check, +pymapping_size, pymapping_length, pyint_asint +

    fun (pyobject * pyobject) -> int

    +pyobject_compare, pyobject_hasattr, pydict_delitem, +pyerr_givenexceptionmatches, pysequence_count, pysequence_contains, +pysequence_in, pysequence_index, pymapping_haskey +

    fun (pyobject * pyobject * int) -> int

    +pyobject_richcomparebool, pysequence_delitem +

    fun (pyobject * string * pyobject) -> int

    +pyobject_setattrstring, pydict_setitemstring +

    fun (pyobject * string) -> int

    +pyobject_hasattrstring, pydict_delitemstring, pysequence_inplacerepeat +

    fun (pyobject * pyobject) -> (pyobject * pyobject)

    +pynumber_coerce, pynumber_coerceex +

    fun (pyobject * pyobject * pyobject) -> int

    +pyobject_setattr, pydict_setitem, pyobject_setitem +

    fun pyobject -> int64

    +pyobject_hash, pyint_aslong +

    fun pyobject -> string

    +pystring_asstring, pymodule_getname, pymodule_getfilename +

    fun (pyobject * pyobject) -> pyobject

    +pystring_concat, pystring_concatanddel +

    fun string -> pyobject

    +pystring_fromstring, pymodule_new, pyimport_addmodule, pyimport_importmodule, +pyimport_import +

    fun unit -> pyobject

    +pydict_new, pyerr_occurred, pyimport_getmoduledict, pyeval_getbuiltins, +pyeval_getglobals, pyeval_getlocals, pyeval_getframe +

    fun pyobject -> unit

    +pydict_clear, pyerr_setnone +

    fun (pyobject * int) -> (pyobject * pyobject * int)

    +pydict_next +

    fun int64 -> pyobject

    +pyint_fromlong +

    fun unit -> int64

    +pyint_getmax +

    fun float -> pyobject

    +pyfloat_fromdouble +

    fun pyobject -> float

    +pyfloat_asdouble +

    fun int -> pyobject

    +pytuple_new, pyint_fromint +

    fun (pyobject * int) -> pyobject

    +pytuple_getitem, pysequence_repeat, pysequence_getitem +

    fun (pyobject * int * pyobject) -> int

    +pytuple_setitem, pysequence_setitem, pymapping_setitem +

    fun (pyobject * pyobject * pyobject) -> pyobject

    +pyslice_new, pyclass_new, pyinstance_new, pymethod_new, +pyeval_callobjectwithkeywords, pynumber_power, pynumber_inplacepower +

    fun (pyobject * int) -> (int * int * int)

    +pyslice_getindices +

    fun (int * int * int * int) -> pyobject

    +pyrange_new +

    fun (pyobject * pyobject) -> unit

    +pyerr_setobject +

    fun (pyobject * string) -> unit

    +pyerr_setstring +

    fun (pyobject * pyobject * pyobject) -> (pyobject * pyobject * pyobject)

    +pyerr_fetch, pyerr_normalizeexception +

    fun (pyobject * pyobject * pyobject) -> unit

    +pyerr_restore +

    fun (pyobject * string) -> pyobject

    +pyimport_execcodemodule +

    fun (string * pyobject * string) -> pyobject

    +pyimport_execcodemoduleex +

    fun (string * pyobject * pyobject * pyobject) -> pyobject

    +pyimport_importmoduleex +

    fun pyobject -> string

    +pyobject_ascharbuffer, pyobject_asreadbuffer, pyobject_aswritebuffer +

    fun (pyobject * int * int * pyobject) -> int

    +pysequence_setslice +

    fun (pyobject * int * int) -> int

    +pysequence_delslice + +

    Unique Functions Needed for Ocaml

    +In addition to the functions in the usual library, several new functions are +provided which give specific support for ocaml.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    pytuple_toarraypyobject -> pyobject array
    +Convert a python tuple to an ocaml array containing the same items. +
    pywrap_closure(pyobject -> pyobject) -> pyobject
    +Create a python callable object from a closure. The closure receives the +argument tuple from the invocation and returns a pyobject. +
    pywrap_value'a -> pyobject
    +Create a simple void * style wrapping around an ocaml object. The object +may be retrieved with pyunwrap_value : pyobject -> 'a. Use this +to enclose an ocaml data structure in python to be used later. +
    pynullunit -> pyobject
    +Generate the null PyObject * and return it. This may sound dangerous, but +it is used by library calls to indicate errors to the python system. +
    pynoneunit -> pyobject
    +Generate a reference to the Py_None object. +
    pytuple_fromarraypyobject array -> pyobject
    +Create a pytuple (as would be used for a function call) from the given +array. This may be used to implement varargs calls on python functions, +and for other purposes. +
    pytuple_emptypyobject array -> pyobject
    +Shortcut for pytuple_new 0 +
    pytuple_fromsinglepyobject -> pyobject
    +Create a tuple with the single given object inside. Use this to create +single element tuples as for a function call with one argument. +
    pytuple1-5(pyobject * ...) -> pyobject
    +Create a python tuple that has the same contents as the given ocaml tuple. +
    pytypepyobject -> pyobject_type
    +Determine roughly which type family the given value belongs to. For example, +pytype (pystring_fromstring "hi") yields StringType. +
    + +

    Sample Application

    +This is the sample application that I developed the library with. It +illustrates a python function call, as well as a call back into ocaml. +The first form is used in cases where python libraries are to be used +from ocaml, and the second would be used to produce native libraries in +ocaml.

    + +

    +open Pycaml ;;
    +
    +let colorsys = pyimport_importmodule "colorsys"
    +let dict = pymodule_getdict colorsys
    +
    +let triplet = pytuple3 (pyfloat_fromdouble 1.0,
    +			pyfloat_fromdouble 0.5,
    +			pyfloat_fromdouble 0.2) ;;
    +
    +let rgbtoyiq = pydict_getitemstring (dict,"rgb_to_yiq")
    +let triplet = pyeval_callobject (rgbtoyiq,triplet)
    +
    +let _ = print_endline ((string_of_float
    +			  (pyfloat_asdouble (pytuple_getitem (triplet,0)))) ^ 
    +		       " " ^
    +		       (string_of_float
    +			  (pyfloat_asdouble (pytuple_getitem (triplet,1)))) ^
    +		       " " ^
    +		       (string_of_float
    +			  (pyfloat_asdouble (pytuple_getitem (triplet,2))))) ;;
    +
    +let x = pywrap_closure 
    +    (fun x -> print_string (pystring_asstring (pytuple_getitem (x,0))) ; 
    +      pynone ())
    +
    +let _ = pyeval_callobject 
    +    (x,pytuple_fromsingle (pystring_fromstring "hi there"))
    +
    + + diff --git a/pycaml/pycaml.ml b/pycaml/pycaml.ml new file mode 100644 index 0000000..5d5ff99 --- /dev/null +++ b/pycaml/pycaml.ml @@ -0,0 +1,541 @@ +(* + * (C) arty 2002 + * This software is covered under the GNU lesser general public license + *) + +open Int64 ;; + +type funcptr +type pyobject +type funcent = (funcptr * int * int) + +type pymodule_func = { pyml_name : string ; + pyml_func : (pyobject -> pyobject) ; + pyml_flags : int ; + pyml_doc : string } + +type pyobject_type = + TupleType + | StringType + | IntType + | FloatType + | ListType + | NoneType + | CallableType + | ModuleType + | ClassType + | NullType + | TypeType + | OtherType + + (* Function list *) + +external getfuncarray : unit -> funcent array = "pygetfuncarray" +let py_funcs = getfuncarray () +external pytype : pyobject -> pyobject_type = "pytype" + +external pyfuncall1 : (funcptr * int * int) -> unit -> unit = "pygencall" +external pyfuncall2 : (funcptr * int * int) -> int -> unit = "pygencall" +external pyfuncall3 : (funcptr * int * int) -> string -> unit = "pygencall" +external pyfuncall4 : (funcptr * int * int) -> unit -> int = "pygencall" +external pyfuncall5 : (funcptr * int * int) -> string -> int = "pygencall" +external pyfuncall6 : (funcptr * int * int) -> (int * string) -> int = "pygencall" +external pyfuncall7 : (funcptr * int * int) -> (int * string * int) -> int = + "pygencall" +external pyfuncall8 : (funcptr * int * int) -> unit -> string = "pygencall" +external pyfuncall9 : (funcptr * int * int) -> (string * int * pyobject * pyobject) -> pyobject = "pygencall" +external pyfuncall10 : (funcptr * int * int) -> + (int * string * int * pyobject * pyobject) -> pyobject = "pygencall" +external pyfuncall11 : (funcptr * int * int) -> + (int * string * int * pyobject * pyobject * int) -> pyobject = "pygencall" +external pyfuncall12 : (funcptr * int * int) -> + (string * string * int) -> pyobject = "pygencall" +external pyfuncall13 : (funcptr * int * int) -> + (pyobject * int * int) -> int = "pygencall" +external pyfuncall14 : (funcptr * int * int) -> pyobject -> pyobject = "pygencall" +external pyfuncall15 : (funcptr * int * int) -> (pyobject * pyobject * int) -> pyobject = "pygencall" +external pyfuncall16 : (funcptr * int * int) -> (pyobject * string) -> pyobject = "pygencall" +external pyfuncall17 : (funcptr * int * int) -> (pyobject * pyobject) -> pyobject = "pygencall" +external pyfuncall18 : (funcptr * int * int) -> pyobject -> int = "pygencall" +external pyfuncall19 : (funcptr * int * int) -> (pyobject * pyobject) -> int = "pygencall" +external pyfuncall20 : (funcptr * int * int) -> (pyobject * pyobject * int) -> int = "pygencall" +external pyfuncall21 : (funcptr * int * int) -> (pyobject * string * pyobject) -> int = "pygencall" +external pyfuncall22 : (funcptr * int * int) -> (pyobject * string) -> int = "pygencall" +external pyfuncall23 : (funcptr * int * int) -> (pyobject * pyobject) -> (pyobject * pyobject) option = "pygencall" +external pyfuncall24 : (funcptr * int * int) -> (pyobject * pyobject * pyobject) -> int = "pygencall" +external pyfuncall25 : (funcptr * int * int) -> pyobject -> int64 = "pygencall" +external pyfuncall26 : (funcptr * int * int) -> pyobject -> string = "pygencall" +external pyfuncall27 : (funcptr * int * int) -> (pyobject * pyobject) -> pyobject = "pygencall" +external pyfuncall28 : (funcptr * int * int) -> string -> pyobject = "pygencall" +external pyfuncall29 : (funcptr * int * int) -> unit -> pyobject = "pygencall" +external pyfuncall30 : (funcptr * int * int) -> pyobject -> unit = "pygencall" +external pyfuncall31 : (funcptr * int * int) -> (pyobject * int) -> + (pyobject * pyobject * int) option = "pygencall" +external pyfuncall34 : (funcptr * int * int) -> int64 -> pyobject = "pygencall" +external pyfuncall35 : (funcptr * int * int) -> unit -> int64 = "pygencall" +external pyfuncall36 : (funcptr * int * int) -> float -> pyobject = "pygencall" +external pyfuncall37 : (funcptr * int * int) -> pyobject -> float = "pygencall" +external pyfuncall39 : (funcptr * int * int) -> int -> pyobject = "pygencall" +external pyfuncall40 : (funcptr * int * int) -> (pyobject * int) -> + pyobject = "pygencall" +external pyfuncall41 : (funcptr * int * int) -> (pyobject * int * pyobject) -> + int = "pygencall" +external pyfuncall42 : (funcptr * int * int) -> (pyobject * pyobject * pyobject) -> + pyobject = "pygencall" +external pyfuncall43 : (funcptr * int * int) -> (pyobject * int) -> + (int * int * int) option = "pygencall" +external pyfuncall44 : (funcptr * int * int) -> (int * int * int * int) -> + pyobject = "pygencall" +external pyfuncall45 : (funcptr * int * int) -> (pyobject * pyobject) -> unit = + "pygencall" +external pyfuncall46 : (funcptr * int * int) -> (pyobject * string) -> unit = + "pygencall" +external pyfuncall47 : (funcptr * int * int) -> (pyobject * pyobject * pyobject) -> + (pyobject * pyobject * pyobject) = "pygencall" +external pyfuncall48 : (funcptr * int * int) -> (pyobject * pyobject * pyobject) -> + unit = "pygencall" +external pyfuncall49 : (funcptr * int * int) -> (pyobject * string) -> pyobject = + "pygencall" +external pyfuncall50 : (funcptr * int * int) -> (string * pyobject * string) -> + pyobject = "pygencall" +external pyfuncall51 : (funcptr * int * int) -> + (string * pyobject * pyobject * pyobject) -> pyobject = "pygencall" +external pyfuncall52 : (funcptr * int * int) -> pyobject -> string = "pygencall" +external pyfuncall53 : (funcptr * int * int) -> (pyobject * int * int * pyobject) -> int = "pygencall" +external pyfuncall54 : (funcptr * int * int) -> (pyobject * int * int) -> int = + "pygencall" + +let fmt1call func = pyfuncall1 func +let fmt2call func = pyfuncall2 func +let fmt3call func = pyfuncall3 func +let fmt4call func = pyfuncall4 func +let fmt5call func = pyfuncall5 func +let fmt6call func = pyfuncall6 func +let fmt7call func = pyfuncall7 func +let fmt8call func = pyfuncall8 func +let fmt9call func = pyfuncall9 func +let fmt10call func = pyfuncall10 func +let fmt11call func = pyfuncall11 func +let fmt12call func = pyfuncall12 func +let fmt13call func = pyfuncall13 func +let fmt14call func = pyfuncall14 func +let fmt15call func = pyfuncall15 func +let fmt16call func = pyfuncall16 func +let fmt17call func = pyfuncall17 func +let fmt18call func = pyfuncall18 func +let fmt19call func = pyfuncall19 func +let fmt20call func = pyfuncall20 func +let fmt21call func = pyfuncall21 func +let fmt22call func = pyfuncall22 func +let fmt23call func = pyfuncall23 func +let fmt24call func = pyfuncall24 func +let fmt25call func = pyfuncall25 func +let fmt26call func = pyfuncall26 func +let fmt27call func = pyfuncall27 func +let fmt28call func = pyfuncall28 func +let fmt29call func = pyfuncall29 func +let fmt30call func = pyfuncall30 func +let fmt31call func = pyfuncall31 func + (* 32 *) + (* 33 *) +let fmt34call func = pyfuncall34 func +let fmt35call func = pyfuncall35 func +let fmt36call func = pyfuncall36 func +let fmt37call func = pyfuncall37 func + (* 38 *) +let fmt39call func = pyfuncall39 func +let fmt40call func = pyfuncall40 func +let fmt41call func = pyfuncall41 func +let fmt42call func = pyfuncall42 func +let fmt43call func = pyfuncall43 func +let fmt44call func = pyfuncall44 func +let fmt45call func = pyfuncall45 func +let fmt46call func = pyfuncall46 func +let fmt47call func = pyfuncall47 func +let fmt48call func = pyfuncall48 func +let fmt49call func = pyfuncall49 func +let fmt50call func = pyfuncall50 func +let fmt51call func = pyfuncall51 func +let fmt52call func = pyfuncall52 func +let fmt53call func = pyfuncall53 func +let fmt54call func = pyfuncall54 func + +let py_cur_func_num = ref 0 +let pnf () = let this_func = py_funcs.(!py_cur_func_num) in +py_cur_func_num := !py_cur_func_num + 1 ; this_func + + (* 1 *) +let py_initialize = fmt1call (pnf ()) +let py_finalize = fmt1call (pnf ()) +let pyerr_print = fmt1call (pnf ()) + (* 2 *) +let py_exit = fmt2call (pnf ()) +let pyerr_printex = fmt2call (pnf ()) + (* 3 *) +let py_setprogramname = fmt3call (pnf ()) +let py_setpythonhome = fmt3call (pnf ()) + (* 4 *) +let py_isinitialized = fmt4call (pnf ()) + (* 5 *) +let pyrun_simplestring = fmt5call (pnf ()) + (* 6 *) +let pyrun_anyfile = fmt6call (pnf ()) +let pyrun_simplefile = fmt6call (pnf ()) +let pyrun_interactiveone = fmt6call (pnf ()) +let pyrun_interactiveloop = fmt6call (pnf ()) +let py_fdisinteractive = fmt6call (pnf ()) + (* 7 *) +let pyrun_anyfileex = fmt7call (pnf ()) +let pyrun_simplefileex = fmt7call (pnf ()) + (* 8 *) +let py_getprogramname = fmt8call (pnf ()) +let py_getpythonhome = fmt8call (pnf ()) +let py_getprogramfullpath = fmt8call (pnf ()) +let py_getprefix = fmt8call (pnf ()) +let py_getexecprefix = fmt8call (pnf ()) +let py_getpath = fmt8call (pnf ()) +let py_getversion = fmt8call (pnf ()) +let py_getplatform = fmt8call (pnf ()) +let py_getcopyright = fmt8call (pnf ()) +let py_getcompiler = fmt8call (pnf ()) +let py_getbuildinfo = fmt8call (pnf ()) + (* 9 *) +let pyrun_string = fmt9call (pnf ()) + (* 10 *) +let pyrun_file = fmt10call (pnf ()) + (* 11 *) +let pyrun_fileex = fmt11call (pnf ()) + (* 12 *) +let py_compilestring = fmt12call (pnf ()) + (* 13 *) +let pyobject_print = fmt13call (pnf ()) + (* 14 *) +let pyobject_repr = fmt14call (pnf ()) +let pyobject_str = fmt14call (pnf ()) +let pyobject_unicode = fmt14call (pnf ()) +(* 15 *) +let pyobject_richcompare = fmt15call (pnf ()) +(* 16 *) +let pyobject_getattrstring = fmt16call (pnf ()) +(* 17 *) +let pyobject_getattr = fmt17call (pnf ()) +let pyobject_callobject = fmt17call (pnf ()) +(* 18 *) +let pyobject_istrue = fmt18call (pnf ()) +let pyobject_not = fmt18call (pnf ()) +let pycallable_check = fmt18call (pnf ()) +(* 19 *) +let pyobject_compare = fmt19call (pnf ()) +let pyobject_hasattr = fmt19call (pnf ()) +(* 20 *) +let pyobject_richcomparebool = fmt20call (pnf ()) +(* 21 *) +let pyobject_setattrstring = fmt21call (pnf ()) +(* 22 *) +let pyobject_hasattrstring = fmt22call (pnf ()) +(* 23 *) +let pynumber_coerce = fmt23call (pnf ()) +let pynumber_coerceex = fmt23call (pnf ()) +(* 24 *) +let pyobject_setattr = fmt24call (pnf ()) +(* 25 *) +let pyobject_hash = fmt25call (pnf ()) +(* Strings *) +(* 18 *) +let pystring_size = fmt18call (pnf ()) +(* 26 *) +let pystring_asstring = fmt26call (pnf ()) +(* 27 *) +let pystring_concat = fmt27call (pnf ()) +let pystring_concatanddel = fmt27call (pnf ()) +(* 28 *) +let pystring_fromstring = fmt28call (pnf ()) +(* 17 *) +let pystring_format = fmt17call (pnf ()) + +(* Dictionaries *) +(* 29 *) +let pydict_new = fmt29call (pnf ()) +(* 17 *) +let pydict_getitem = fmt17call (pnf ()) +(* 24 *) +let pydict_setitem = fmt24call (pnf ()) +(* 19 *) +let pydict_delitem = fmt19call (pnf ()) +(* 30 *) +let pydict_clear = fmt30call (pnf ()) +(* 31 *) +let pydict_next = fmt31call (pnf ()) +(* 14 *) +let pydict_keys = fmt14call (pnf ()) +let pydict_values = fmt14call (pnf ()) +let pydict_items = fmt14call (pnf ()) +let pydict_copy = fmt14call (pnf ()) +(* 18 *) +let pydict_size = fmt18call (pnf ()) +(* 16 *) +let pydict_getitemstring = fmt16call (pnf ()) +(* 22 *) +let pydict_delitemstring = fmt22call (pnf ()) +(* 21 *) +let pydict_setitemstring = fmt21call (pnf ()) + +(* Integer *) +(* 34 *) +let pyint_fromlong = fmt34call (pnf ()) +(* 25 *) +let pyint_aslong = fmt25call (pnf ()) +(* 35 *) +let pyint_getmax = fmt35call (pnf ()) + +(* Float *) +(* 36 *) +let pyfloat_fromdouble = fmt36call (pnf ()) +(* 37 *) +let pyfloat_asdouble = fmt37call (pnf ()) + +(* Modules *) +(* 28 *) +let pymodule_new = fmt28call (pnf ()) +(* 14 *) +let pymodule_getdict = fmt14call (pnf ()) +(* 26 *) +let pymodule_getname = fmt26call (pnf ()) +let pymodule_getfilename = fmt26call (pnf ()) + +(* 39 *) +let pytuple_new = fmt39call (pnf ()) +(* 18 *) +let pytuple_size = fmt18call (pnf ()) +let pytuple_check = fmt18call (pnf ()) +(* 40 *) +let pytuple_getitem = fmt40call (pnf ()) +(* 41 *) +let pytuple_setitem = fmt41call (pnf ()) +(* 13 *) +let pytuple_getslice = fmt13call (pnf ()) + +(* 42 *) +let pyslice_new = fmt42call (pnf ()) +(* 43 *) +let pyslice_getindices = fmt43call (pnf ()) +(* 44 *) +let pyrange_new = fmt44call (pnf ()) + +(* Error handling definitions *) + +(* 30 *) +let pyerr_setnone = fmt30call (pnf ()) +(* 45 *) +let pyerr_setobject = fmt45call (pnf ()) +(* 46 *) +let pyerr_setstring = fmt46call (pnf ()) +(* 29 *) +let pyerr_occurred = fmt29call (pnf ()) +(* 1 *) +let pyerr_clear = fmt1call (pnf ()) +(* 47 *) +let pyerr_fetch = fmt47call (pnf ()) +(* 48 *) +let pyerr_restore = fmt48call (pnf ()) + +(* Error testing and normalization *) +(* 19 *) +let pyerr_givenexceptionmatches = fmt19call (pnf ()) +(* 18 *) +let pyerr_exceptionmatches = fmt18call (pnf ()) +(* 47 *) +let pyerr_normalizeexception = fmt47call (pnf ()) + +(* Classes *) +(* 42 *) +let pyclass_new = fmt42call (pnf ()) +(* 42 *) +let pyinstance_new = fmt42call (pnf ()) + +(* 17 *) +let pyinstance_newraw = fmt17call (pnf ()) +(* 42 *) +let pymethod_new = fmt42call (pnf ()) +(* 14 *) +let pymethod_function = fmt14call (pnf ()) +let pymethod_self = fmt14call (pnf ()) +let pymethod_class = fmt14call (pnf ()) + +(* Module *) +(* 28 *) +let pymodule_new = fmt28call (pnf ()) +(* 14 *) +let pymodule_getdict = fmt14call (pnf ()) +(* 26 *) +let pymodule_getname = fmt26call (pnf ()) +let pymodule_getfilename = fmt26call (pnf ()) +(* 35 *) +let pyimport_getmagicnumber = fmt35call (pnf ()) +(* 49 *) +let pyimport_execcodemodule = fmt49call (pnf ()) +(* 50 *) +let pyimport_execcodemoduleex = fmt50call (pnf ()) +(* 29 *) +let pyimport_getmoduledict = fmt29call (pnf ()) +(* 28 *) +let pyimport_addmodule = fmt28call (pnf ()) +let pyimport_importmodule = fmt28call (pnf ()) +(* 51 *) +let pyimport_importmoduleex = fmt51call (pnf ()) +(* 28 *) +let pyimport_import = fmt28call (pnf ()) +(* 14 *) +let pyimport_reloadmodule = fmt14call (pnf ()) +(* 1 *) +let pyimport_cleanup = fmt1call (pnf ()) +(* 5 *) +let pyimport_importfrozenmodule = fmt5call (pnf ()) + +(* Interface to random parts in ceval.c *) +(* 42 *) +let pyeval_callobjectwithkeywords = fmt42call (pnf ()) +(* 17 *) +let pyeval_callobject = fmt17call (pnf ()) + +(* 29 *) +let pyeval_getbuiltins = fmt29call (pnf ()) +let pyeval_getglobals = fmt29call (pnf ()) +let pyeval_getlocals = fmt29call (pnf ()) +let pyeval_getframe = fmt29call (pnf ()) +(* 4 *) +let pyeval_getrestricted = fmt4call (pnf ()) + +(* Abstract layer *) +(* 14 *) +let pyobject_type = fmt14call (pnf ()) +(* 18 *) +let pyobject_size = fmt18call (pnf ()) +(* 17 *) +let pyobject_getitem = fmt17call (pnf ()) +(* 24 *) +let pyobject_setitem = fmt24call (pnf ()) +(* 17 *) +let pyobject_delitem = fmt17call (pnf ()) +(* 52 *) +let pyobject_ascharbuffer = fmt52call (pnf ()) +let pyobject_asreadbuffer = fmt52call (pnf ()) +let pyobject_aswritebuffer = fmt52call (pnf ()) +(* 18 *) +let pynumber_check = fmt18call (pnf ()) +(* 17 *) +let pynumber_add = fmt17call (pnf ()) +let pynumber_subtract = fmt17call (pnf ()) +let pynumber_multiply = fmt17call (pnf ()) +let pynumber_divide = fmt17call (pnf ()) +let pynumber_remainder = fmt17call (pnf ()) +let pynumber_divmod = fmt17call (pnf ()) +(* 42 *) +let pynumber_power = fmt42call (pnf ()) +(* 14 *) +let pynumber_negative = fmt14call (pnf ()) +let pynumber_positive = fmt14call (pnf ()) +let pynumber_absolute = fmt14call (pnf ()) +let pynumber_invert = fmt14call (pnf ()) +(* 17 *) +let pynumber_lshift = fmt17call (pnf ()) +let pynumber_rshift = fmt17call (pnf ()) +let pynumber_and = fmt17call (pnf ()) +let pynumber_xor = fmt17call (pnf ()) +let pynumber_or = fmt17call (pnf ()) +(* 14 *) +let pynumber_int = fmt14call (pnf ()) +let pynumber_long = fmt14call (pnf ()) +let pynumber_float = fmt14call (pnf ()) +(* 17 *) +let pynumber_inplaceadd = fmt17call (pnf ()) +let pynumber_inplacesubtract = fmt17call (pnf ()) +let pynumber_inplacemultiply = fmt17call (pnf ()) +let pynumber_inplacedivide = fmt17call (pnf ()) +let pynumber_inplaceremainder = fmt17call (pnf ()) +let pynumber_inplacelshift = fmt17call (pnf ()) +let pynumber_inplacershift = fmt17call (pnf ()) +let pynumber_inplaceand = fmt17call (pnf ()) +let pynumber_inplacexor = fmt17call (pnf ()) +let pynumber_inplaceor = fmt17call (pnf ()) +(* 42 *) +let pynumber_inplacepower = fmt42call (pnf ()) +(* 18 *) +let pysequence_check = fmt18call (pnf ()) +let pysequence_size = fmt18call (pnf ()) +let pysequence_length = fmt18call (pnf ()) +(* 17 *) +let pysequence_concat = fmt17call (pnf ()) +(* 40 *) +let pysequence_repeat = fmt40call (pnf ()) +let pysequence_getitem = fmt40call (pnf ()) +(* 13 *) +let pysequence_getslice = fmt13call (pnf ()) +(* 41 *) +let pysequence_setitem = fmt41call (pnf ()) +(* 20 *) +let pysequence_delitem = fmt20call (pnf ()) +(* 53 *) +let pysequence_setslice = fmt53call (pnf ()) +(* 54 *) +let pysequence_delslice = fmt54call (pnf ()) +(* 14 *) +let pysequence_tuple = fmt14call (pnf ()) +let pysequence_list = fmt14call (pnf ()) +(* 16 *) +let pysequence_fast = fmt16call (pnf ()) +(* 19 *) +let pysequence_count = fmt19call (pnf ()) +let pysequence_contains = fmt19call (pnf ()) +let pysequence_in = fmt19call (pnf ()) +let pysequence_index = fmt19call (pnf ()) +(* 17 *) +let pysequence_inplaceconcat = fmt17call (pnf ()) +(* 22 *) +let pysequence_inplacerepeat = fmt22call (pnf ()) +(* 18 *) +let pymapping_check = fmt18call (pnf ()) +let pymapping_size = fmt18call (pnf ()) +let pymapping_length = fmt18call (pnf ()) +(* 16 *) +let pymapping_haskeystring = fmt16call (pnf ()) +(* 19 *) +let pymapping_haskey = fmt19call (pnf ()) +(* 16 *) +let pymapping_getitemstring = fmt16call (pnf ()) +(* 41 *) +let pymapping_setitemstring = fmt41call (pnf ()) + +external pynull : unit -> pyobject = "pynull" + +external pynone : unit -> pyobject = "pynone" +external pytrue : unit -> pyobject = "pytrue" +external pyfalse : unit -> pyobject = "pyfalse" + +external pytuple_fromarray : pyobject array -> pyobject = "pytuple_fromarray" +let pytuple_fromsingle elt = pytuple_fromarray [| elt |] +let pytuple_empty = pytuple_fromarray [| |] +external pytuple2 : (pyobject * pyobject) -> pyobject = + "pytuple_fromarray" +external pytuple3 : (pyobject * pyobject * pyobject) -> pyobject = + "pytuple_fromarray" +external pytuple4 : (pyobject * pyobject * pyobject * pyobject) -> + pyobject = "pytuple_fromarray" +external pytuple5 : (pyobject * pyobject * pyobject * pyobject * pyobject) -> + pyobject = "pytuple_fromarray" + +let pyint_fromint i = pyint_fromlong (Int64.of_int i) +let pyint_asint obj = Int64.to_int (pyint_aslong obj) + +external pytuple_toarray : pyobject -> pyobject array = "pytuple_toarray" + +external pywrap_closure : (pyobject -> pyobject) -> pyobject = "pywrap_closure" +external pycaml_setargs : string -> unit = "pycaml_setargs" + +external pymodule_initmodule : string -> pymodule_func array = "pymodule_initmodule" + +external pywrap_value : 'a -> pyobject = "pywrapvalue" ;; + +external pyunwrap_value : pyobject -> 'a = "pyunwrapvalue" ;; + +let _ = py_initialize () ;; diff --git a/pycaml/pycaml_ml.c b/pycaml/pycaml_ml.c new file mode 100644 index 0000000..30217f9 --- /dev/null +++ b/pycaml/pycaml_ml.c @@ -0,0 +1,1467 @@ +/* + * (C) arty 2002 + * This software is covered under the GNU lesser general public license + */ + +#include "Python.h" +#include "caml/mlvalues.h" +#include "caml/memory.h" +#include "caml/callback.h" +#include "caml/custom.h" +#include "caml/alloc.h" +#include + +#define true 1 +#define false 0 + +static void *getcustom( value v ) { return *((void **)Data_custom_val(v)); } + +static void pydecref( value v ) { + if( getcustom(v) ) { Py_DECREF((PyObject *)getcustom(v)); } +} + +static int pycompare( value v1, value v2 ) { + int result; + if( getcustom(v1) && !getcustom(v2) ) return -1; + if( getcustom(v2) && !getcustom(v1) ) return 1; + if( !getcustom(v1) && !getcustom(v2) ) return 0; + PyObject_Cmp((PyObject *)getcustom(v1), + (PyObject *)getcustom(v2),&result); + return result; +} + +static long pyhash( value v ) { + if( getcustom(v) ) return PyObject_Hash((PyObject *)getcustom(v)); + else return 0; +} + +static unsigned long pydeserialize( void *dst ) { + return 0; +} + +struct custom_operations pyops = { + "PythonObject", + pydecref, + pycompare, + pyhash, + custom_serialize_default, + pydeserialize +}; + +struct custom_operations fnops = { + "FuncPointer", + NULL, + NULL, + NULL, + NULL, + NULL +}; + +value pywrap( PyObject *obj ) { + CAMLparam0(); + CAMLlocal1(v); + if( obj ) + Py_INCREF(obj); + v = alloc_custom( &pyops, sizeof( PyObject * ), 100, 100000 ); + *((PyObject **)Data_custom_val(v)) = obj; + CAMLreturn(v); +} + +value funcwrap( void *obj ) { + CAMLparam0(); + CAMLlocal1(v); + v = alloc_custom( &fnops, sizeof( void * ), 100, 100000 ); + *((void **)Data_custom_val(v)) = obj; + CAMLreturn(v); +} + +PyObject *pyunwrap( value v ) { + return *((PyObject **)Data_custom_val(v)); +} + +static void camldestr( void *v ) { + value *valptr = (value *)v; + remove_global_root(valptr); + free( v ); +} + +PyObject *camlwrap( value val, void *aux_str, int size ) { + value *v = (value *)malloc(sizeof(value) + size); + *v = val; + memcpy((void *)v+sizeof(value),aux_str,size); + register_global_root(v); + return PyCObject_FromVoidPtr(v,camldestr); +} + +void *caml_aux( PyObject *obj ) { + value *v = (value *)PyCObject_AsVoidPtr( obj ); + return (void *)v+sizeof(value); +} + +PyObject *pycall_callback( PyObject *obj, PyObject *args ) { + value out; + value *v; + + if( !PyCObject_Check(obj) ) { + Py_INCREF(Py_None); + return Py_None; + } + v = (value *)PyCObject_AsVoidPtr( obj ); + out = callback(*v,pywrap(args)); + return pyunwrap(out); +} + +typedef void (*type_1)( void ); +typedef void (*type_2)( int ); +typedef void (*type_3)( char * ); +typedef int (*type_4)( void ); +typedef int (*type_5)( char * ); +typedef int (*type_6)( FILE *, char * ); +typedef int (*type_7)( FILE *, char *, int ); +typedef char *(*type_8)( void ); +typedef PyObject* (*type_9)(char*, int, PyObject *, PyObject *); +typedef PyObject* (*type_10)(FILE *, char*, int, PyObject *, PyObject *); +typedef PyObject* (*type_11)(FILE *, char*, int, PyObject *, PyObject *, int ); +typedef PyObject* (*type_12)(char*, char*, int); +typedef int (*type_13)(PyObject *, FILE *, int); +typedef PyObject * (*type_14)(PyObject *); +typedef PyObject * (*type_15)(PyObject *, PyObject *, int); +typedef PyObject * (*type_16)(PyObject *, char *); +typedef PyObject * (*type_17)(PyObject *, PyObject *); +typedef int (*type_18)(PyObject *); +typedef int (*type_19)(PyObject *, PyObject *); +typedef int (*type_20)(PyObject *, PyObject *, int); +typedef int (*type_21)(PyObject *, char *, PyObject *); +typedef int (*type_22)(PyObject *, char *); +typedef int (*type_23)(PyObject **, PyObject **); +typedef int (*type_24)(PyObject *, PyObject *, PyObject *); +typedef long (*type_25)(PyObject *); +typedef char *(*type_26)(PyObject *); +typedef void (*type_27)(PyObject **, PyObject *); +typedef PyObject *(*type_28)(char *); +typedef PyObject *(*type_29)(void); +typedef void (*type_30)(PyObject *); +typedef int (*type_31)(PyObject *, int *, PyObject **, PyObject **); +typedef PyObject *(*type_32)(char*, char**, int); +typedef PyObject *(*type_33)(Py_UNICODE*, int, int); +typedef PyObject *(*type_34)(long); +typedef long (*type_35)(void); +typedef PyObject *(*type_36)(double); +typedef double (*type_37)(PyObject *); +typedef PyObject *(*type_38)(PyObject*, char**); +typedef PyObject *(*type_39)(int size); +typedef PyObject *(*type_40)(PyObject *, int); +typedef int (*type_41)(PyObject *, int, PyObject *); +typedef PyObject *(*type_42)(PyObject* start, PyObject* stop, PyObject* step); +typedef int (*type_43)(PySliceObject *r, int length, int *start, int *stop, int *step); +typedef PyObject *(*type_44)(long, long, long, int); +typedef void (*type_45)(PyObject *, PyObject *); +typedef void (*type_46)(PyObject *, const char *); +typedef void (*type_47)(PyObject **, PyObject **, PyObject **); +typedef void (*type_48)(PyObject *, PyObject *, PyObject *); +typedef PyObject *(*type_49)(PyObject *, char *); +typedef PyObject *(*type_50)(char *,PyObject *,char *); +typedef PyObject *(*type_51)(char *,PyObject *,PyObject *,PyObject *); +typedef int (*type_52)(PyObject *obj,const char **buffer,int *buffer_len); +typedef int (*type_53)(PyObject *o, int i1, int i2, PyObject *v); +typedef int (*type_54)(PyObject *o, int i1, int i2); + +value pygencall( value format, value arg ) { + CAMLparam2(format,arg); + CAMLlocal1(rv); + FILE *f; + int fd; + int x; + int ret_int; + char *rvs; + int fmt = Int_val(Field(format,1)); + PyObject *ob1,*ob2,*ob3; + void *func = getcustom(Field(format,0)); + int reflect = Int_val(Field(format,2)); + + rv = Val_unit; + + switch( fmt ) { + case 1: + ((type_1)func)(); + CAMLreturn(Val_unit); + + case 2: + ((type_2)func)(Int_val(arg)); + CAMLreturn(Val_unit); + + case 3: + ((type_3)func)(String_val(arg)); + CAMLreturn(Val_unit); + + case 4: + CAMLreturn(Int_val(((type_4)func)())); + + case 5: + CAMLreturn(Int_val(((type_5)func) + (String_val(arg)))); + + case 6: + case 7: + case 10: + case 11: + fd = dup(Int_val(Field(arg,0))); + f = fdopen(fd,"r+"); + switch( fmt ) { + case 6: + rv = Val_int(((type_6)func) + (f,String_val(Field(arg,1)))); + break; + + case 7: + rv = Val_int(((type_7)func) + (f, + String_val(Field(arg,1)), + Int_val(Field(arg,2)))); + break; + + case 10: + rv = pywrap(((type_10)func) + (f, + String_val(Field(arg,1)), + Int_val(Field(arg,2)), + pyunwrap(Field(arg,3)), + pyunwrap(Field(arg,4)))); + break; + + case 11: + rv = pywrap(((type_11)func) + (f, + String_val(Field(arg,1)), + Int_val(Field(arg,2)), + pyunwrap(Field(arg,3)), + pyunwrap(Field(arg,4)), + Int_val(Field(arg,5)))); + break; + } + + fclose( f ); + CAMLreturn( rv ); + + case 8: + CAMLreturn(copy_string(((type_8)func)())); + + case 9: + CAMLreturn(pywrap(((type_9)func) + (String_val(Field(arg,0)), + Int_val(Field(arg,1)), + pyunwrap(Field(arg,2)), + pyunwrap(Field(arg,3))))); + + case 12: + CAMLreturn(pywrap(((type_12)func) + (String_val(Field(arg,0)), + String_val(Field(arg,1)), + Int_val(Field(arg,2))))); + + case 13: + fd = dup(Int_val(Field(arg,1))); + f = fdopen(fd,"r+"); + rv = Val_int(((type_13)func) + (pyunwrap(Field(arg,0)), + f, + Int_val(Field(arg,2)))); + fclose( f ); + break; + + case 14: + CAMLreturn(pywrap(((type_14)func)(pyunwrap(arg)))); + + case 15: + CAMLreturn(pywrap(((type_15)func) + (pyunwrap(Field(arg,0)), + pyunwrap(Field(arg,1)),Int_val(Field(arg,2))))); + + case 16: + CAMLreturn(pywrap(((type_16)func) + (pyunwrap(Field(arg,0)), + String_val(Field(arg,1))))); + + case 17: + CAMLreturn(pywrap(((type_17)func) + (pyunwrap(Field(arg,0)),pyunwrap(Field(arg,1))))); + + case 18: + CAMLreturn(Val_int(((type_18)func)(pyunwrap(arg)))); + + case 19: + CAMLreturn(Val_int(((type_19)func) + (pyunwrap(Field(arg,0)), + pyunwrap(Field(arg,1))))); + + case 20: + CAMLreturn(Val_int(((type_20)func) + (pyunwrap(Field(arg,0)), + pyunwrap(Field(arg,1)), + Int_val(Field(arg,2))))); + + case 21: + CAMLreturn(Val_int(((type_21)func) + (pyunwrap(Field(arg,0)), + String_val(Field(arg,1)), + pyunwrap(Field(arg,2))))); + + case 22: + CAMLreturn(Val_int(((type_22)func) + (pyunwrap(Field(arg,0)), + String_val(Field(arg,1))))); + + case 23: + ob1 = pyunwrap(Field(arg,0)); ob2 = pyunwrap(Field(arg,1)); + ret_int = ((type_23)func)( &ob1, &ob2 ); + if( ret_int == -1 ) CAMLreturn((value)1); + else { + rv = alloc_tuple(2); + Field(rv,0) = pywrap(ob1); + Field(rv,1) = pywrap(ob2); + CAMLreturn(rv); + } + + case 24: + CAMLreturn(Int_val(((type_24)func) + (pyunwrap(Field(arg,0)), + pyunwrap(Field(arg,1)), + pyunwrap(Field(arg,2))))); + + case 25: + CAMLreturn(copy_int64(((type_25)func)(pyunwrap(arg)))); + + case 26: + CAMLreturn(copy_string(((type_26)func)(pyunwrap(arg)))); + + case 27: + ob1 = pyunwrap(Field(arg,0)); + ((type_27)func)(&ob1,pyunwrap(Field(arg,1))); + CAMLreturn(pywrap(ob1)); + + case 28: + CAMLreturn(pywrap(((type_28)func)(String_val(arg)))); + + case 29: + CAMLreturn(pywrap(((type_29)func)())); + + case 30: + ((type_30)func)(pyunwrap(arg)); + CAMLreturn(Val_unit); + + case 31: + x = Int_val(Field(arg,1)); + ret_int = ((type_31)func) + (pyunwrap(Field(arg,0)), + &x, + &ob1, &ob2); + if( !ret_int ) CAMLreturn((value)1); + else { + rv = alloc_tuple(3); + Field(rv,0) = pywrap(ob1); + Field(rv,1) = pywrap(ob2); + Field(rv,2) = Val_int(x); + CAMLreturn(rv); + } + + /* case 32: string -> int */ + + /* case 33: unicode ... need to do something coherent */ + + case 34: + CAMLreturn(pywrap(((type_34)func)(Int64_val(arg)))); + + case 35: + CAMLreturn(copy_int64(((type_35)func)())); + + case 36: + CAMLreturn(pywrap(((type_36)func)(Double_val(arg)))); + + case 37: + CAMLreturn(copy_double(((type_37)func) + (pyunwrap(arg)))); + + /* case 38: string -> float */ + + case 39: + CAMLreturn(pywrap(((type_39)func)(Int_val(arg)))); + + case 40: + CAMLreturn(pywrap(((type_40)func) + (pyunwrap(Field(arg,0)), + Int_val(Field(arg,1))))); + + case 41: + CAMLreturn(Val_int(((type_41)func) + (pyunwrap(Field(arg,0)), + Int_val(Field(arg,1)), + pyunwrap(Field(arg,2))))); + + case 42: + CAMLreturn(pywrap(((type_42)func) + (pyunwrap(Field(arg,0)), + pyunwrap(Field(arg,1)), + pyunwrap(Field(arg,2))))); + + case 43: { + int start,end,step; + + ret_int = ((type_43)func) + ((PySliceObject *)pyunwrap(Field(arg,0)), + Int_val(Field(arg,1)), + &start, &end, &step); + if( !ret_int ) CAMLreturn((value)1); + else { + rv = alloc_tuple(3); + Field(rv,0) = start; + Field(rv,1) = end; + Field(rv,2) = step; + CAMLreturn(rv); + } + } + + case 44: + CAMLreturn(pywrap(((type_44)func) + (Int_val(Field(arg,0)), + Int_val(Field(arg,1)), + Int_val(Field(arg,2)), + Int_val(Field(arg,3))))); + + case 45: + ((type_45)func) + (pyunwrap(Field(arg,0)), + pyunwrap(Field(arg,1))); + CAMLreturn(Val_unit); + + case 46: + ((type_46)func) + (pyunwrap(Field(arg,0)),String_val(Field(arg,1))); + CAMLreturn(Val_unit); + + case 47: + ob1 = pyunwrap(Field(arg,0)); + ob2 = pyunwrap(Field(arg,1)); + ob3 = pyunwrap(Field(arg,2)); + ((type_47)func)(&ob1,&ob2,&ob3); + rv = alloc_tuple(3); + Field(rv,0) = pywrap(ob1); + Field(rv,1) = pywrap(ob2); + Field(rv,2) = pywrap(ob3); + CAMLreturn(rv); + + case 48: + ((type_48)func) + (pyunwrap(Field(arg,0)), + pyunwrap(Field(arg,1)), + pyunwrap(Field(arg,2))); + CAMLreturn(Val_unit); + + case 49: + CAMLreturn(pywrap(((type_49)func) + (pyunwrap(Field(arg,0)), + String_val(Field(arg,1))))); + + case 50: + CAMLreturn(pywrap(((type_50)func) + (String_val(Field(arg,0)), + pyunwrap(Field(arg,1)), + String_val(Field(arg,2))))); + + case 51: + CAMLreturn(pywrap(((type_51)func) + (String_val(Field(arg,0)), + pyunwrap(Field(arg,1)), + pyunwrap(Field(arg,2)), + pyunwrap(Field(arg,3))))); + + case 52: + ((type_52)func)(pyunwrap(arg),&rvs,&ret_int); + rv = copy_string(rvs); + CAMLreturn(rv); + + case 53: + CAMLreturn(Val_int(((type_53)func) + (pyunwrap(Field(arg,0)), + Int_val(Field(arg,1)), + Int_val(Field(arg,2)), + pyunwrap(Field(arg,3))))); + + case 54: + CAMLreturn(Val_int(((type_54)func) + (pyunwrap(Field(arg,0)), + Int_val(Field(arg,1)), + Int_val(Field(arg,2))))); + } + + CAMLreturn(rv); +} + +#ifdef DONT_COMPILE_THIS +/* 1 */ +DL_IMPORT(void) Py_Initialize(void); +DL_IMPORT(void) Py_Finalize(void); +DL_IMPORT(void) PyErr_Print(void); +/* 2 */ +DL_IMPORT(void) Py_Exit(int); +DL_IMPORT(void) PyErr_PrintEx(int); +/* 3 */ +DL_IMPORT(void) Py_SetProgramName(char *); +DL_IMPORT(void) Py_SetPythonHome(char *); +/* 4 */ +DL_IMPORT(int) Py_IsInitialized(void); +/* 5 */ +DL_IMPORT(int) PyRun_SimpleString(char *); +/* 6 */ +DL_IMPORT(int) PyRun_AnyFile(FILE *, char *); +DL_IMPORT(int) PyRun_SimpleFile(FILE *, char *); +DL_IMPORT(int) PyRun_InteractiveOne(FILE *, char *); +DL_IMPORT(int) PyRun_InteractiveLoop(FILE *, char *); +DL_IMPORT(int) Py_FdIsInteractive(FILE *, char *); +/* 7 */ +DL_IMPORT(int) PyRun_AnyFileEx(FILE *, char *, int); +DL_IMPORT(int) PyRun_SimpleFileEx(FILE *, char *, int); +/* 8 */ +DL_IMPORT(char*) Py_GetProgramName(void); +DL_IMPORT(char*) Py_GetPythonHome(void); +DL_IMPORT(char*) Py_GetProgramFullPath(void); +DL_IMPORT(char*) Py_GetPrefix(void); +DL_IMPORT(char*) Py_GetExecPrefix(void); +DL_IMPORT(char*) Py_GetPath(void); +DL_IMPORT(char*) Py_GetVersion(void); +DL_IMPORT(char*) Py_GetPlatform(void); +DL_IMPORT(char*) Py_GetCopyright(void); +DL_IMPORT(char*) Py_GetCompiler(void); +DL_IMPORT(char*) Py_GetBuildInfo(void); +/* 9 */ +DL_IMPORT(PyObject*) PyRun_String(char*, int, PyObject *, PyObject *); +/* 10 */ +DL_IMPORT(PyObject*) PyRun_File(FILE *, char*, int, PyObject *, PyObject *); +/* 11 */ +DL_IMPORT(PyObject*) PyRun_FileEx(FILE *, char*, int, PyObject *, PyObject *, int ); +/* 12 */ +DL_IMPORT(PyObject*) Py_CompileString(char*, char*, int); /* FUNCTION 30 */ + +/* Generic operations on objects */ +/* 13 */ +extern DL_IMPORT(int) PyObject_Print(PyObject *, FILE *, int); +/* 14 */ +extern DL_IMPORT(PyObject *) PyObject_Repr(PyObject *); +extern DL_IMPORT(PyObject *) PyObject_Str(PyObject *); +extern DL_IMPORT(PyObject *) PyObject_Unicode(PyObject *); +/* 15 */ +extern DL_IMPORT(PyObject *) PyObject_RichCompare(PyObject *, PyObject *, int); +/* 16 */ +extern DL_IMPORT(PyObject *) PyObject_GetAttrString(PyObject *, char *); +/* 17 */ +extern DL_IMPORT(PyObject *) PyObject_GetAttr(PyObject *, PyObject *); +extern DL_IMPORT(PyObject *) PyObject_CallObject(PyObject *, PyObject *); +/* 18 */ +extern DL_IMPORT(int) PyObject_IsTrue(PyObject *); +extern DL_IMPORT(int) PyObject_Not(PyObject *); +extern DL_IMPORT(int) PyCallable_Check(PyObject *); +/* 19 */ +extern DL_IMPORT(int) PyObject_Compare(PyObject *, PyObject *); +extern DL_IMPORT(int) PyObject_HasAttr(PyObject *, PyObject *); +/* 20 */ +extern DL_IMPORT(int) PyObject_RichCompareBool(PyObject *, PyObject *, int); +/* 21 */ +extern DL_IMPORT(int) PyObject_SetAttrString(PyObject *, char *, PyObject *); +/* 22 */ +extern DL_IMPORT(int) PyObject_HasAttrString(PyObject *, char *); +/* 23 */ +extern DL_IMPORT(int) PyNumber_Coerce(PyObject **, PyObject **); +extern DL_IMPORT(int) PyNumber_CoerceEx(PyObject **, PyObject **); +/* 24 */ +extern DL_IMPORT(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *); +/* 25 */ +extern DL_IMPORT(long) PyObject_Hash(PyObject *); + +/* Strings */ +/* 18 */ +extern DL_IMPORT(int) PyString_Size(PyObject *); +/* 26 */ +extern DL_IMPORT(char *) PyString_AsString(PyObject *); +/* 27 */ +extern DL_IMPORT(void) PyString_Concat(PyObject **, PyObject *); +extern DL_IMPORT(void) PyString_ConcatAndDel(PyObject **, PyObject *); +/* 28 */ +extern DL_IMPORT(PyObject *) PyString_FromString(const char *); +/* 17 */ +extern DL_IMPORT(PyObject *) PyString_Format(PyObject *, PyObject *); + +/* Dictionaries */ +/* 29 */ +extern DL_IMPORT(PyObject *) PyDict_New(void); +/* 17 */ +extern DL_IMPORT(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key); +/* 24 */ +extern DL_IMPORT(int) PyDict_SetItem(PyObject *mp, PyObject *key, PyObject *item); +/* 19 */ +extern DL_IMPORT(int) PyDict_DelItem(PyObject *mp, PyObject *key); +/* 30 */ +extern DL_IMPORT(void) PyDict_Clear(PyObject *mp); +/* 31 */ +extern DL_IMPORT(int) PyDict_Next + (PyObject *mp, int *pos, PyObject **key, PyObject **value); +/* 14 */ +extern DL_IMPORT(PyObject *) PyDict_Keys(PyObject *mp); +extern DL_IMPORT(PyObject *) PyDict_Values(PyObject *mp); +extern DL_IMPORT(PyObject *) PyDict_Items(PyObject *mp); +extern DL_IMPORT(PyObject *) PyDict_Copy(PyObject *mp); +/* 18 */ +extern DL_IMPORT(int) PyDict_Size(PyObject *mp); +/* 16 */ +extern DL_IMPORT(PyObject *) PyDict_GetItemString(PyObject *dp, char *key); +/* 22 */ +extern DL_IMPORT(int) PyDict_DelItemString(PyObject *dp, char *key); +/* 21 */ +extern DL_IMPORT(int) PyDict_SetItemString(PyObject *dp, char *key, PyObject *item); + +/* Integer */ +/* 32 */ +extern DL_IMPORT(PyObject *) PyInt_FromString(char*, char**, int); +/* 33 */ +extern DL_IMPORT(PyObject *) PyInt_FromUnicode(Py_UNICODE*, int, int); +/* 34 */ +extern DL_IMPORT(PyObject *) PyInt_FromLong(long); +/* 25 */ +extern DL_IMPORT(long) PyInt_AsLong(PyObject *); +/* 35 */ +extern DL_IMPORT(long) PyInt_GetMax(void); +/* Long */ +/* 34 */ +extern DL_IMPORT(PyObject *) PyLong_FromLong(long); +/* 36 */ +extern DL_IMPORT(PyObject *) PyLong_FromDouble(double); +/* 25 */ +extern DL_IMPORT(long) PyLong_AsLong(PyObject *); + +/* Float */ +/* 36 */ +extern DL_IMPORT(PyObject *) PyFloat_FromDouble(double); +/* 37 */ +extern DL_IMPORT(double) PyFloat_AsDouble(PyObject *); + +/* Modules */ +/* 28 */ +extern DL_IMPORT(PyObject *) PyModule_New(char *); +/* 14 */ +extern DL_IMPORT(PyObject *) PyModule_GetDict(PyObject *); +/* 26 */ +extern DL_IMPORT(char *) PyModule_GetName(PyObject *); +extern DL_IMPORT(char *) PyModule_GetFilename(PyObject *); + +/* 39 */ +extern DL_IMPORT(PyObject *) PyTuple_New(int size); +/* 18 */ +extern DL_IMPORT(int) PyTuple_Size(PyObject *); +extern DL_IMPORT(int) PyTuple_Check(PyObject *); +/* 40 */ +extern DL_IMPORT(PyObject *) PyTuple_GetItem(PyObject *, int); +/* 41 */ +extern DL_IMPORT(int) PyTuple_SetItem(PyObject *, int, PyObject *); +/* 13 */ +extern DL_IMPORT(PyObject *) PyTuple_GetSlice(PyObject *, int, int); + +/* 42 */ +DL_IMPORT(PyObject *) PySlice_New(PyObject* start, PyObject* stop, PyObject* step); +/* 43 */ +DL_IMPORT(int) PySlice_GetIndices(PySliceObject *r, int length, int *start, int *stop, int *step); +/* 44 */ +DL_IMPORT(PyObject *) PyRange_New(long, long, long, int); + +/* Error handling definitions */ + +/* 30 */ +DL_IMPORT(void) PyErr_SetNone(PyObject *); +/* 45 */ +DL_IMPORT(void) PyErr_SetObject(PyObject *, PyObject *); +/* 46 */ +DL_IMPORT(void) PyErr_SetString(PyObject *, const char *); +/* 29 */ +DL_IMPORT(PyObject *) PyErr_Occurred(void); +/* 1 */ +DL_IMPORT(void) PyErr_Clear(void); +/* 47 */ +DL_IMPORT(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **); +/* 48 */ +DL_IMPORT(void) PyErr_Restore(PyObject *, PyObject *, PyObject *); + +/* Error testing and normalization */ +/* 19 */ +DL_IMPORT(int) PyErr_GivenExceptionMatches(PyObject *, PyObject *); +/* 18 */ +DL_IMPORT(int) PyErr_ExceptionMatches(PyObject *); +/* 47 */ +DL_IMPORT(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**); + +/* Classes */ +/* 42 */ +extern DL_IMPORT(PyObject *) PyClass_New(PyObject *, PyObject *, PyObject *); +/* 42 */ +extern DL_IMPORT(PyObject *) PyInstance_New(PyObject *, PyObject *, + PyObject *); +/* 17 */ +extern DL_IMPORT(PyObject *) PyInstance_NewRaw(PyObject *, PyObject *); +/* 42 */ +extern DL_IMPORT(PyObject *) PyMethod_New(PyObject *, PyObject *, PyObject *); +/* 14 */ +extern DL_IMPORT(PyObject *) PyMethod_Function(PyObject *); +extern DL_IMPORT(PyObject *) PyMethod_Self(PyObject *); +extern DL_IMPORT(PyObject *) PyMethod_Class(PyObject *); + +/* Module */ +/* 28 */ +extern DL_IMPORT(PyObject *) PyModule_New(char *); +/* 14 */ +extern DL_IMPORT(PyObject *) PyModule_GetDict(PyObject *); +/* 26 */ +extern DL_IMPORT(char *) PyModule_GetName(PyObject *); +extern DL_IMPORT(char *) PyModule_GetFilename(PyObject *); +/* 35 */ +DL_IMPORT(long) PyImport_GetMagicNumber(void); +/* 49 */ +DL_IMPORT(PyObject *) PyImport_ExecCodeModule(char *name, PyObject *co); +/* 50 */ +DL_IMPORT(PyObject *) PyImport_ExecCodeModuleEx(char *name, PyObject *co, char *pathname); +/* 29 */ +DL_IMPORT(PyObject *) PyImport_GetModuleDict(void); +/* 28 */ +DL_IMPORT(PyObject *) PyImport_AddModule(char *name); +DL_IMPORT(PyObject *) PyImport_ImportModule(char *name); +/* 51 */ +DL_IMPORT(PyObject *) PyImport_ImportModuleEx(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist); +/* 28 */ +DL_IMPORT(PyObject *) PyImport_Import(PyObject *name); +/* 14 */ +DL_IMPORT(PyObject *) PyImport_ReloadModule(PyObject *m); +/* 1 */ +DL_IMPORT(void) PyImport_Cleanup(void); +/* 5 */ +DL_IMPORT(int) PyImport_ImportFrozenModule(char *); + +/* Interface to random parts in ceval.c */ +/* 42 */ +DL_IMPORT(PyObject *) PyEval_CallObjectWithKeywords(PyObject *, PyObject *, PyObject *); +/* 17 */ +DL_IMPORT(PyObject *) PyEval_CallObject(PyObject *, PyObject *); + +/* 29 */ +DL_IMPORT(PyObject *) PyEval_GetBuiltins(void); +DL_IMPORT(PyObject *) PyEval_GetGlobals(void); +DL_IMPORT(PyObject *) PyEval_GetLocals(void); +DL_IMPORT(PyObject *) PyEval_GetFrame(void); +/* 4 */ +DL_IMPORT(int) PyEval_GetRestricted(void); + +/* Abstract layer */ +/* 14 */ +DL_IMPORT(PyObject *) PyObject_Type(PyObject *o); +/* 18 */ +DL_IMPORT(int) PyObject_Size(PyObject *o); +/* 17 */ +DL_IMPORT(PyObject *) PyObject_GetItem(PyObject *o, PyObject *key); +/* 24 */ +DL_IMPORT(int) PyObject_SetItem(PyObject *o, PyObject *key, PyObject *v); +/* 17 */ +DL_IMPORT(int) PyObject_DelItem(PyObject *o, PyObject *key); +/* 52 */ +DL_IMPORT(int) PyObject_AsCharBuffer(PyObject *obj,const char **buffer,int *buffer_len); +DL_IMPORT(int) PyObject_AsReadBuffer(PyObject *obj,const void **buffer,int *buffer_len); +DL_IMPORT(int) PyObject_AsWriteBuffer(PyObject *obj,void **buffer,int *buffer_len); +/* 18 */ +DL_IMPORT(int) PyNumber_Check(PyObject *o); +/* 17 */ +DL_IMPORT(PyObject *) PyNumber_Add(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_Subtract(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_Multiply(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_Divide(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_Remainder(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_Divmod(PyObject *o1, PyObject *o2); +/* 42 */ +DL_IMPORT(PyObject *) PyNumber_Power(PyObject *o1, PyObject *o2,PyObject *o3); +/* 14 */ +DL_IMPORT(PyObject *) PyNumber_Negative(PyObject *o); +DL_IMPORT(PyObject *) PyNumber_Positive(PyObject *o); +DL_IMPORT(PyObject *) PyNumber_Absolute(PyObject *o); +DL_IMPORT(PyObject *) PyNumber_Invert(PyObject *o); +/* 17 */ +DL_IMPORT(PyObject *) PyNumber_Lshift(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_Rshift(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_And(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_Xor(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_Or(PyObject *o1, PyObject *o2); +/* 14 */ +DL_IMPORT(PyObject *) PyNumber_Int(PyObject *o); +DL_IMPORT(PyObject *) PyNumber_Long(PyObject *o); +DL_IMPORT(PyObject *) PyNumber_Float(PyObject *o); +/* 17 */ +DL_IMPORT(PyObject *) PyNumber_InPlaceAdd(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_InPlaceSubtract(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_InPlaceMultiply(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_InPlaceDivide(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_InPlaceRemainder(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_InPlaceLshift(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_InPlaceRshift(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_InPlaceAnd(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_InPlaceXor(PyObject *o1, PyObject *o2); +DL_IMPORT(PyObject *) PyNumber_InPlaceOr(PyObject *o1, PyObject *o2); +/* 42 */ +DL_IMPORT(PyObject *) PyNumber_InPlacePower(PyObject *o1, PyObject *o2,PyObject *o3); +/* 18 */ +DL_IMPORT(int) PySequence_Check(PyObject *o); +DL_IMPORT(int) PySequence_Size(PyObject *o); +DL_IMPORT(int) PySequence_Length(PyObject *o); +/* 17 */ +DL_IMPORT(PyObject *) PySequence_Concat(PyObject *o1, PyObject *o2); +/* 40 */ +DL_IMPORT(PyObject *) PySequence_Repeat(PyObject *o, int count); +DL_IMPORT(PyObject *) PySequence_GetItem(PyObject *o, int i); +/* 13 */ +DL_IMPORT(PyObject *) PySequence_GetSlice(PyObject *o, int i1, int i2); +/* 41 */ +DL_IMPORT(int) PySequence_SetItem(PyObject *o, int i, PyObject *v); +/* 20 */ +DL_IMPORT(int) PySequence_DelItem(PyObject *o, int i); +/* 53 */ +DL_IMPORT(int) PySequence_SetSlice(PyObject *o, int i1, int i2, PyObject *v); +/* 54 */ +DL_IMPORT(int) PySequence_DelSlice(PyObject *o, int i1, int i2); +/* 14 */ +DL_IMPORT(PyObject *) PySequence_Tuple(PyObject *o); +DL_IMPORT(PyObject *) PySequence_List(PyObject *o); +/* 16 */ +DL_IMPORT(PyObject *) PySequence_Fast(PyObject *o, const char* m); +/* 19 */ +DL_IMPORT(int) PySequence_Count(PyObject *o, PyObject *value); +DL_IMPORT(int) PySequence_Contains(PyObject *o, PyObject *value); +DL_IMPORT(int) PySequence_In(PyObject *o, PyObject *value); +DL_IMPORT(int) PySequence_Index(PyObject *o, PyObject *value); +/* 17 */ +DL_IMPORT(PyObject *) PySequence_InPlaceConcat(PyObject *o1, PyObject *o2); +/* 22 */ +DL_IMPORT(PyObject *) PySequence_InPlaceRepeat(PyObject *o, int count); +/* 18 */ +DL_IMPORT(int) PyMapping_Check(PyObject *o); +DL_IMPORT(int) PyMapping_Size(PyObject *o); +DL_IMPORT(int) PyMapping_Length(PyObject *o); +/* 16 */ +DL_IMPORT(int) PyMapping_HasKeyString(PyObject *o, char *key); +/* 19 */ +DL_IMPORT(int) PyMapping_HasKey(PyObject *o, PyObject *key); +/* 16 */ +DL_IMPORT(PyObject *) PyMapping_GetItemString(PyObject *o, char *key); +/* 41 */ +DL_IMPORT(int) PyMapping_SetItemString(PyObject *o, char *key, PyObject *value); + + +#ifdef MAYBE_RUN +DL_IMPORT(void) init_exceptions(void); +DL_IMPORT(void) fini_exceptions(void); +DL_IMPORT(void) _PyImport_Init(void); +DL_IMPORT(void) _PyImport_Fini(void); +DL_IMPORT(void) PyMethod_Fini(void); +DL_IMPORT(void) PyFrame_Fini(void); +DL_IMPORT(void) PyCFunction_Fini(void); +DL_IMPORT(void) PyTuple_Fini(void); +DL_IMPORT(void) PyString_Fini(void); +DL_IMPORT(void) PyInt_Fini(void); +DL_IMPORT(void) PyFloat_Fini(void); +DL_IMPORT(PyObject*) _PyBuiltin_Init(void); +DL_IMPORT(PyObject*) _PySys_Init(void); +DL_IMPORT(struct symtable *) Py_SymtableString(char*, char*, int); +DL_IMPORT(struct _node *) PyParser_SimpleParseString(char*, int); +DL_IMPORT(struct _node *) PyParser_SimpleParseFile(FILE *, char*, int); +DL_IMPORT(int) Py_AtExit(void (*func)(void)); +DL_IMPORT(void) Py_EndInterpreter(PyThreadState *); +DL_IMPORT(PyThreadState *) Py_NewInterpreter(void); +DL_IMPORT(int) (*PyOS_InputHook)(void); +DL_IMPORT(int) PyOS_CheckStack(void); +DL_IMPORT(char) *(*PyOS_ReadlineFunctionPointer)(char*); +DL_IMPORT(PyOS_sighandler_t) PyOS_getsig(int); +DL_IMPORT(PyOS_sighandler_t) PyOS_setsig(int, PyOS_sighandler_t); +DL_IMPORT(void) PyOS_FiniInterrupts(void); +DL_IMPORT(char*) PyOS_Readline(char*); +#endif//MAYBE_RUN +#endif//DONT_COMPILE_THIS + +/* HST FIXUP */ +#if (PY_MAJOR_VERSION >= 2 && PY_MINOR_VERSION > 4) +#undef PyRun_SimpleString +#define PyRun_SimpleString PyRun_SimpleString_redo +int PyRun_SimpleString_redo(const char* command) { return PyRun_SimpleStringFlags(command, NULL); } + +#undef PyRun_AnyFile +#define PyRun_AnyFile PyRun_AnyFile_redo +int PyRun_AnyFile_redo(FILE* fp, const char* filename) { return PyRun_AnyFileExFlags(fp, filename, 0, NULL); } + +#undef PyRun_SimpleFile +#define PyRun_SimpleFile PyRun_SimpleFile_redo +int PyRun_SimpleFile_redo(FILE* fp, const char* filename) { return PyRun_SimpleFileExFlags(fp, filename, 0, NULL); } + +#undef PyRun_InteractiveOne +#define PyRun_InteractiveOne PyRun_InteractiveOne_redo +int PyRun_InteractiveOne_redo(FILE* fp, const char* filename) { return PyRun_InteractiveOneFlags(fp, filename, NULL); } + +#undef PyRun_InteractiveLoop +#define PyRun_InteractiveLoop PyRun_InteractiveLoop_redo +int PyRun_InteractiveLoop_redo(FILE* fp, const char* filename) { return PyRun_InteractiveLoopFlags(fp, filename, NULL); } + +#undef PyRun_AnyFileEx +#define PyRun_AnyFileEx PyRun_AnyFileEx_redo +int PyRun_AnyFileEx_redo(FILE* fp, const char* filename, int closeit) { return PyRun_AnyFileExFlags(fp, filename, closeit, NULL); } + +#undef PyRun_SimpleFileEx +#define PyRun_SimpleFileEx PyRun_SimpleFileEx_redo +int PyRun_SimpleFileEx_redo(FILE* fp, const char* filename, int closeit) { return PyRun_SimpleFileExFlags(fp, filename, closeit, NULL); } + +#undef PyRun_String +#define PyRun_String PyRun_String_redo +PyObject* PyRun_String_redo(const char* str, int start, PyObject* globals, PyObject* locals) { return PyRun_StringFlags(str, start, globals, locals, NULL); } + +#undef PyRun_File +#define PyRun_File PyRun_File_redo +PyObject* PyRun_File_redo(FILE* fp, const char* filename, int start, PyObject* globals, PyObject* locals) { return PyRun_FileExFlags(fp, filename, start, globals, locals, 0, NULL); } + +#undef PyRun_FileEx +#define PyRun_FileEx PyRun_FileEx_redo +PyObject* PyRun_FileEx_redo(FILE* fp, const char* filename, int start, PyObject* globals, PyObject* locals, int closeit) { return PyRun_FileExFlags(fp, filename, start, globals, locals, closeit, NULL); } + +#undef Py_CompileString +#define Py_CompileString Py_CompileString_redo +PyObject* Py_CompileString_redo(const char* str, const char* filename, int start) { return Py_CompileStringFlags(str, filename, start, NULL); } + +#undef PyRange_New +#define PyRange_New PyRange_New_redo +PyObject* PyRange_New_redo(PyObject* start, PyObject* stop, PyObject* step) { return PyObject_CallFunction((PyObject*)&PyRange_Type, "lll", start, stop, step); } +#endif /* PYTHON 2.4 */ + +#undef PyTuple_Check +int PyTuple_Check(PyObject* op) { return PyObject_TypeCheck(op, &PyTuple_Type); } +/* END HST FIXUP */ + +/* Value -> Pyobject */ + +value pywrapvalue( value cb ) { + CAMLparam1(cb); + CAMLreturn(pywrap(camlwrap(cb,NULL,0))); +} + +value pyunwrapvalue( value cb ) { + CAMLparam1(cb); + value *v; + v = (value *)PyCObject_AsVoidPtr( pyunwrap(cb) ); + CAMLreturn(*v); +} + +/* Create the function table */ + +typedef struct _python_func_table { + void *func; + int format; + char *desc; +} python_func_table; + +python_func_table the_python_func_table[] = { +/* 1 */ + { (void *)Py_Initialize, 1, "Py_Initialize" }, + { (void *)Py_Finalize, 1, "Py_Finalize" }, + { (void *)PyErr_Print, 1, "PyErr_Print" }, +/* 2 */ + { (void *)Py_Exit, 2, "Py_Exit" }, + { (void *)PyErr_PrintEx, 2, "PyErr_PrintEx" }, +/* 3 */ + { (void *)Py_SetProgramName, 3, "Py_SetProgramName" }, + { (void *)Py_SetPythonHome, 3, "Py_SetPythonHome" }, +/* 4 */ + { (void *)Py_IsInitialized, 4, "Py_IsInitialized" }, +/* 5 */ + { (void *)PyRun_SimpleString, 5, "PyRun_SimpleString" }, +/* 6 */ + { (void *)PyRun_AnyFile, 6, "PyRun_AnyFile" }, + { (void *)PyRun_SimpleFile, 6, "PyRun_SimpleFile" }, + { (void *)PyRun_InteractiveOne, 6, "PyRun_InteractiveOne" }, + { (void *)PyRun_InteractiveLoop, 6, "PyRun_InteractiveLoop" }, + { (void *)Py_FdIsInteractive, 6, "Py_FdIsInteractive" }, +/* 7 */ + { (void *)PyRun_AnyFileEx, 7, "PyRun_AnyFileEx" }, + { (void *)PyRun_SimpleFileEx, 7, "PyRun_SimpleFileEx" }, +/* 8 */ + { (void *)Py_GetProgramName, 8, "Py_GetProgramName" }, + { (void *)Py_GetPythonHome, 8, "Py_GetPythonHome" }, + { (void *)Py_GetProgramFullPath, 8, "Py_GetProgramFullPath" }, + { (void *)Py_GetPrefix, 8, "Py_GetPrefix" }, + { (void *)Py_GetExecPrefix, 8, "Py_GetExecPrefix" }, + { (void *)Py_GetPath, 8, "Py_GetPath" }, + { (void *)Py_GetVersion, 8, "Py_GetVersion" }, + { (void *)Py_GetPlatform, 8, "Py_GetPlatform" }, + { (void *)Py_GetCopyright, 8, "Py_GetCopyright" }, + { (void *)Py_GetCompiler, 8, "Py_GetCompiler" }, + { (void *)Py_GetBuildInfo, 8, "Py_GetBuildInfo" }, +/* 9 */ + { (void *)PyRun_String, 9, "PyRun_String" }, +/* 10 */ + { (void *)PyRun_File, 10, "PyRun_File" }, +/* 11 */ + { (void *)PyRun_FileEx, 11, "PyRun_FileEx" }, +/* 12 */ + { (void *)Py_CompileString, 12, "Py_CompileString" }, + +/* Object */ +/* 13 */ + { (void *)PyObject_Print, 13, "PyObject_Print" }, +/* 14 */ + { (void *)PyObject_Repr, 14, "PyObject_Repr" }, + { (void *)PyObject_Str, 14, "PyObject_Str" }, + { (void *)PyObject_Unicode, 14, "PyObject_Unicode" }, +/* 15 */ + { (void *)PyObject_RichCompare, 15, "PyObject_RichCompare" }, +/* 16 */ + { (void *)PyObject_GetAttrString, 16, "PyObject_GetAttrString" }, +/* 17 */ + { (void *)PyObject_GetAttr, 17, "PyObject_GetAttr" }, + { (void *)PyObject_CallObject, 17, "PyObject_CallObject" }, +/* 18 */ + { (void *)PyObject_IsTrue, 18, "PyObject_IsTrue" }, + { (void *)PyObject_Not, 18, "PyObject_Not" }, + { (void *)PyCallable_Check, 18, "PyCallable_Check" }, +/* 19 */ + { (void *)PyObject_Compare, 19, "PyObject_Compare" }, + { (void *)PyObject_HasAttr, 19, "PyObject_HasAttr" }, +/* 20 */ + { (void *)PyObject_RichCompareBool, 20, "PyObject_RichCompareBool" }, +/* 21 */ + { (void *)PyObject_SetAttrString, 21, "PyObject_SetAttrString" }, +/* 22 */ + { (void *)PyObject_HasAttrString, 22, "PyObject_HasAttrString" }, +/* 23 */ + { (void *)PyNumber_Coerce, 23, "PyNumber_Coerce" }, + { (void *)PyNumber_CoerceEx, 23, "PyNumber_CoerceEx" }, +/* 24 */ + { (void *)PyObject_SetAttr, 24, "PyObject_SetAttr" }, +/* 25 */ + { (void *)PyObject_Hash, 25, "PyObject_Hash" }, + +/* Strings */ +/* 18 */ + { (void *)PyString_Size, 18, "PyString_Size" }, +/* 26 */ + { (void *)PyString_AsString, 26, "PyString_AsString" }, +/* 27 */ + { (void *)PyString_Concat, 27, "PyString_Concat" }, + { (void *)PyString_ConcatAndDel, 27, "PyString_ConcatAndDel" }, +/* 28 */ + { (void *)PyString_FromString, 28, "PyString_FromString" }, +/* 17 */ + { (void *)PyString_Format, 17, "PyString_Format" }, + +/* Dictionaries */ +/* 29 */ + { (void *)PyDict_New, 29, "PyDict_New" }, +/* 17 */ + { (void *)PyDict_GetItem, 17, "PyDict_GetItem" }, +/* 24 */ + { (void *)PyDict_SetItem, 24, "PyDict_SetItem" }, +/* 19 */ + { (void *)PyDict_DelItem, 19, "PyDict_DelItem" }, +/* 30 */ + { (void *)PyDict_Clear, 30, "PyDict_Clear" }, +/* 31 */ + { (void *)PyDict_Next, 31, "PyDict_Next" }, +/* 14 */ + { (void *)PyDict_Keys, 14, "PyDict_Keys" }, + { (void *)PyDict_Values, 14, "PyDict_Values" }, + { (void *)PyDict_Items, 14, "PyDict_Items" }, + { (void *)PyDict_Copy, 14, "PyDict_Copy" }, +/* 18 */ + { (void *)PyDict_Size, 18, "PyDict_Size" }, +/* 16 */ + { (void *)PyDict_GetItemString, 16, "PyDict_GetItemString" }, +/* 22 */ + { (void *)PyDict_DelItemString, 22, "PyDict_DelItemString" }, +/* 21 */ + { (void *)PyDict_SetItemString, 21, "PyDict_SetItemString" }, + +/* Integer */ +/* 34 */ + { (void *)PyInt_FromLong, 34, "PyInt_FromLong" }, +/* 25 */ + { (void *)PyInt_AsLong, 25, "PyInt_AsLong" }, +/* 35 */ + { (void *)PyInt_GetMax, 35, "PyInt_GetMax" }, + +/* Float */ +/* 36 */ + { (void *)PyFloat_FromDouble, 36, "PyFloat_FromDouble" }, +/* 37 */ + { (void *)PyFloat_AsDouble, 37, "PyFloat_AsDouble" }, + +/* Modules */ +/* 28 */ + { (void *)PyModule_New, 28, "PyModule_New" }, +/* 14 */ + { (void *)PyModule_GetDict, 14, "PyModule_GetDict" }, +/* 26 */ + { (void *)PyModule_GetName, 26, "PyModule_GetName" }, + { (void *)PyModule_GetFilename, 26, "PyModule_GetFilename" }, + +/* 39 */ + { (void *)PyTuple_New, 39, "PyTuple_New" }, +/* 18 */ + { (void *)PyTuple_Size, 18, "PyTuple_Size" }, + { (void *)PyTuple_Check, 18, "PyTuple_Check" }, +/* 40 */ + { (void *)PyTuple_GetItem, 40, "PyTuple_GetItem" }, +/* 41 */ + { (void *)PyTuple_SetItem, 41, "PyTuple_SetItem" }, +/* 13 */ + { (void *)PyTuple_GetSlice, 13, "PyTuple_GetSlice" }, + +/* 42 */ + { (void *)PySlice_New, 42, "PySlice_New" }, +/* 43 */ + { (void *)PySlice_GetIndices, 43, "PySlice_GetIndices" }, +/* 44 */ + { (void *)PyRange_New, 44, "PyRange_New" }, + +/* Error handling definitions */ + +/* 30 */ + { (void *)PyErr_SetNone, 30, "PyErr_SetNone" }, +/* 45 */ + { (void *)PyErr_SetObject, 45, "PyErr_SetObject" }, +/* 46 */ + { (void *)PyErr_SetString, 46, "PyErr_SetString" }, +/* 29 */ + { (void *)PyErr_Occurred, 29, "PyErr_Occurred" }, +/* 1 */ + { (void *)PyErr_Clear, 1, "PyErr_Clear" }, +/* 47 */ + { (void *)PyErr_Fetch, 47, "PyErr_Fetch" }, +/* 48 */ + { (void *)PyErr_Restore, 48, "PyErr_Restore" }, + +/* Error testing and normalization */ +/* 19 */ + { (void *)PyErr_GivenExceptionMatches, 19, "PyErr_GivenExceptionMatches" }, +/* 18 */ + { (void *)PyErr_ExceptionMatches, 18, "PyErr_ExceptionMatches" }, +/* 47 */ + { (void *)PyErr_NormalizeException, 47, "PyErr_NormalizeException" }, + +/* Classes */ +/* 42 */ + { (void *)PyClass_New, 42, "PyClass_New" }, +/* 42 */ + { (void *)PyInstance_New, 42, "PyInstance_New" }, + +/* 17 */ +{ (void *)PyInstance_NewRaw, 17, "PyInstance_NewRaw" }, +/* 42 */ +{ (void *)PyMethod_New, 42, "PyMethod_New" }, +/* 14 */ +{ (void *)PyMethod_Function, 14, "PyMethod_Function" }, +{ (void *)PyMethod_Self, 14, "PyMethod_Self" }, +{ (void *)PyMethod_Class, 14, "PyMethod_Class" }, + +/* Module */ +/* 28 */ +{ (void *)PyModule_New, 28, "PyModule_New" }, +/* 14 */ +{ (void *)PyModule_GetDict, 14, "PyModule_GetDict" }, +/* 26 */ +{ (void *)PyModule_GetName, 26, "PyModule_GetName" }, +{ (void *)PyModule_GetFilename, 26, "PyModule_GetFilename" }, +/* 35 */ +{ (void *)PyImport_GetMagicNumber, 35, "PyImport_GetMagicNumber" }, +/* 49 */ +{ (void *)PyImport_ExecCodeModule, 49, "PyImport_ExecCodeModule" }, +/* 50 */ +{ (void *)PyImport_ExecCodeModuleEx, 50, "PyImport_ExecCodeModuleEx" }, +/* 29 */ +{ (void *)PyImport_GetModuleDict, 29, "PyImport_GetModuleDict" }, +/* 28 */ +{ (void *)PyImport_AddModule, 28, "PyImport_AddModule" }, +{ (void *)PyImport_ImportModule, 28, "PyImport_ImportModule" }, +/* 51 */ +{ (void *)PyImport_ImportModuleEx, 51, "PyImport_ImportModuleEx" }, +/* 28 */ +{ (void *)PyImport_Import, 28, "PyImport_Import" }, +/* 14 */ +{ (void *)PyImport_ReloadModule, 14, "PyImport_ReloadModule" }, +/* 1 */ +{ (void *)PyImport_Cleanup, 1, "PyImport_Cleanup" }, +/* 5 */ +{ (void *)PyImport_ImportFrozenModule, 5, "PyImport_ImportFrozenModule" }, + +/* Interface to random parts in ceval.c */ +/* 42 */ +{ (void *)PyEval_CallObjectWithKeywords, 42, "PyEval_CallObjectWithKeywords" }, +/* 17 */ +{ (void *)PyEval_CallObject, 17, "PyEval_CallObject" }, + +/* 29 */ +{ (void *)PyEval_GetBuiltins, 29, "PyEval_GetBuiltins" }, +{ (void *)PyEval_GetGlobals, 29, "PyEval_GetGlobals" }, +{ (void *)PyEval_GetLocals, 29, "PyEval_GetLocals" }, +{ (void *)PyEval_GetFrame, 29, "PyEval_GetFrame" }, +/* 4 */ +{ (void *)PyEval_GetRestricted, 4, "PyEval_GetRestricted" }, + +/* Abstract layer */ +/* 14 */ +{ (void *)PyObject_Type, 14, "PyObject_Type" }, +/* 18 */ +{ (void *)PyObject_Size, 18, "PyObject_Size" }, +/* 17 */ +{ (void *)PyObject_GetItem, 17, "PyObject_GetItem" }, +/* 24 */ +{ (void *)PyObject_SetItem, 24, "PyObject_SetItem" }, +/* 17 */ +{ (void *)PyObject_DelItem, 17, "PyObject_DelItem" }, +/* 52 */ +{ (void *)PyObject_AsCharBuffer, 52, "PyObject_AsCharBuffer" }, +{ (void *)PyObject_AsReadBuffer, 52, "PyObject_AsReadBuffer" }, +{ (void *)PyObject_AsWriteBuffer, 52, "PyObject_AsWriteBuffer" }, +/* 18 */ +{ (void *)PyNumber_Check, 18, "PyNumber_Check" }, +/* 17 */ +{ (void *)PyNumber_Add, 17, "PyNumber_Add" }, +{ (void *)PyNumber_Subtract, 17, "PyNumber_Subtract" }, +{ (void *)PyNumber_Multiply, 17, "PyNumber_Multiply" }, +{ (void *)PyNumber_Divide, 17, "PyNumber_Divide" }, +{ (void *)PyNumber_Remainder, 17, "PyNumber_Remainder" }, +{ (void *)PyNumber_Divmod, 17, "PyNumber_Divmod" }, +/* 42 */ +{ (void *)PyNumber_Power, 42, "PyNumber_Power" }, +/* 14 */ +{ (void *)PyNumber_Negative, 14, "PyNumber_Negative" }, +{ (void *)PyNumber_Positive, 14, "PyNumber_Positive" }, +{ (void *)PyNumber_Absolute, 14, "PyNumber_Absolute" }, +{ (void *)PyNumber_Invert, 14, "PyNumber_Invert" }, +/* 17 */ +{ (void *)PyNumber_Lshift, 17, "PyNumber_Lshift" }, +{ (void *)PyNumber_Rshift, 17, "PyNumber_Rshift" }, +{ (void *)PyNumber_And, 17, "PyNumber_And" }, +{ (void *)PyNumber_Xor, 17, "PyNumber_Xor" }, +{ (void *)PyNumber_Or, 17, "PyNumber_Or" }, +/* 14 */ +{ (void *)PyNumber_Int, 14, "PyNumber_Int" }, +{ (void *)PyNumber_Long, 14, "PyNumber_Long" }, +{ (void *)PyNumber_Float, 14, "PyNumber_Float" }, +/* 17 */ +{ (void *)PyNumber_InPlaceAdd, 17, "PyNumber_InPlaceAdd" }, +{ (void *)PyNumber_InPlaceSubtract, 17, "PyNumber_InPlaceSubtract" }, +{ (void *)PyNumber_InPlaceMultiply, 17, "PyNumber_InPlaceMultiply" }, +{ (void *)PyNumber_InPlaceDivide, 17, "PyNumber_InPlaceDivide" }, +{ (void *)PyNumber_InPlaceRemainder, 17, "PyNumber_InPlaceRemainder" }, +{ (void *)PyNumber_InPlaceLshift, 17, "PyNumber_InPlaceLshift" }, +{ (void *)PyNumber_InPlaceRshift, 17, "PyNumber_InPlaceRshift" }, +{ (void *)PyNumber_InPlaceAnd, 17, "PyNumber_InPlaceAnd" }, +{ (void *)PyNumber_InPlaceXor, 17, "PyNumber_InPlaceXor" }, +{ (void *)PyNumber_InPlaceOr, 17, "PyNumber_InPlaceOr" }, +/* 42 */ +{ (void *)PyNumber_InPlacePower, 42, "PyNumber_InPlacePower" }, +/* 18 */ +{ (void *)PySequence_Check, 18, "PySequence_Check" }, +{ (void *)PySequence_Size, 18, "PySequence_Size" }, +{ (void *)PySequence_Length, 18, "PySequence_Length" }, +/* 17 */ +{ (void *)PySequence_Concat, 17, "PySequence_Concat" }, +/* 40 */ +{ (void *)PySequence_Repeat, 40, "PySequence_Repeat" }, +{ (void *)PySequence_GetItem, 40, "PySequence_GetItem" }, +/* 13 */ +{ (void *)PySequence_GetSlice, 13, "PySequence_GetSlice" }, +/* 41 */ +{ (void *)PySequence_SetItem, 41, "PySequence_SetItem" }, +/* 20 */ +{ (void *)PySequence_DelItem, 20, "PySequence_DelItem" }, +/* 53 */ +{ (void *)PySequence_SetSlice, 53, "PySequence_SetSlice" }, +/* 54 */ +{ (void *)PySequence_DelSlice, 54, "PySequence_DelSlice" }, +/* 14 */ +{ (void *)PySequence_Tuple, 14, "PySequence_Tuple" }, +{ (void *)PySequence_List, 14, "PySequence_List" }, +/* 16 */ +{ (void *)PySequence_Fast, 16, "PySequence_Fast" }, +/* 19 */ +{ (void *)PySequence_Count, 19, "PySequence_Count" }, +{ (void *)PySequence_Contains, 19, "PySequence_Contains" }, +{ (void *)PySequence_In, 19, "PySequence_In" }, +{ (void *)PySequence_Index, 19, "PySequence_Index" }, +/* 17 */ +{ (void *)PySequence_InPlaceConcat, 17, "PySequence_InPlaceConcat" }, +/* 22 */ +{ (void *)PySequence_InPlaceRepeat, 22, "PySequence_InPlaceRepeat" }, +/* 18 */ +{ (void *)PyMapping_Check, 18, "PyMapping_Check" }, +{ (void *)PyMapping_Size, 18, "PyMapping_Size" }, +{ (void *)PyMapping_Length, 18, "PyMapping_Length" }, +/* 16 */ +{ (void *)PyMapping_HasKeyString, 16, "PyMapping_HasKeyString" }, +/* 19 */ +{ (void *)PyMapping_HasKey, 19, "PyMapping_HasKey" }, +/* 16 */ +{ (void *)PyMapping_GetItemString, 16, "PyMapping_GetItemString" }, +/* 41 */ +{ (void *)PyMapping_SetItemString, 41, "PyMapping_SetItemString" }, + +/* End */ +{ NULL, 0 } +}; + +value pygetfuncarray( value unit ) { + CAMLparam1(unit); + CAMLlocal2(retv,tuplev); + int i; + int total_funcs; + + for( i = 0; the_python_func_table[i].func; i++ ) ; total_funcs = i; + + retv = alloc(total_funcs,0); + + for( i = 0; i < total_funcs; i++ ) { + tuplev = alloc_tuple( 3 ); + Store_field(tuplev,0,funcwrap((void *)the_python_func_table[i].func)); + Store_field(tuplev,1,Val_int(the_python_func_table[i].format)); + Store_field(tuplev,2,Val_int(i)); + Store_field(retv,i,tuplev); + } + + CAMLreturn(retv); +} + +enum PycamlTypeLabels { + TupleType = 0, + StringType, + IntType, + FloatType, + ListType, + NoneType, + CallableType, + ModuleType, + ClassType, + TypeType, + DictType, + NullType, + OtherType +}; + +value pytype( value obj ) { + CAMLparam1(obj); + PyObject *pobj = pyunwrap( obj ); + if( !pobj ) CAMLreturn(NullType); + else if( PyTuple_Check( pobj ) ) CAMLreturn(Val_int(TupleType)); + else if( PyString_Check( pobj ) ) CAMLreturn(Val_int(StringType)); + else if( PyInt_Check( pobj ) ) CAMLreturn(Val_int(IntType)); + else if( PyFloat_Check( pobj ) ) CAMLreturn(Val_int(FloatType)); + else if( PyList_Check( pobj ) ) CAMLreturn(Val_int(ListType)); + else if( pobj == Py_None ) CAMLreturn(Val_int(NoneType)); + else if( PyCallable_Check( pobj ) ) CAMLreturn(Val_int(CallableType)); + else if( PyModule_Check( pobj ) ) CAMLreturn(Val_int(ModuleType)); + else if( PyClass_Check( pobj ) ) CAMLreturn(Val_int(ClassType)); + else if( PyType_Check( pobj ) ) CAMLreturn(Val_int(TypeType)); + else if( PyDict_Check( pobj ) ) CAMLreturn(Val_int(DictType)); + else CAMLreturn(Val_int(OtherType)); +} + +value pynull( value unit ) { + CAMLparam1(unit); + CAMLreturn(pywrap(NULL)); +} + +value pynone( value unit ) { + CAMLparam1(unit); + CAMLreturn(pywrap(Py_None)); +} + +value pytuple_fromarray( value array ) { + CAMLparam1(array); + PyObject *tuple = PyTuple_New(Wosize_val(array)); + PyObject *elt; + int i; + int x; + + for( i = 0; i < Wosize_val(array); i++ ) { + elt = pyunwrap(Field(array,i)); + Py_INCREF(elt); /* PyTuple_SetItem will steal a reference */ + x = PyTuple_SetItem(tuple,i,elt); + } + + CAMLreturn(pywrap(tuple)); +} + +value pytuple_toarray( value array ) { + CAMLparam1(array); + PyObject *obj = pyunwrap(array); + int i; + CAMLlocal1(rv); + + rv = alloc_tuple( PySequence_Size(obj) ); + + for( i = 0; i < PySequence_Size(obj); i++ ) + Store_field(rv,i,pywrap(PySequence_GetItem(obj,i))); + + CAMLreturn(rv); +} + +value pywrap_closure( value closure ) { + CAMLparam1(closure); + PyMethodDef ml; + PyObject *obj; + PyMethodDef *ml_def; + ml.ml_name = "anonymous_closure"; + ml.ml_meth = pycall_callback; + ml.ml_flags = 1; + ml.ml_doc = "Anonymous closure"; + obj = camlwrap(closure,&ml,sizeof(ml)); + ml_def = (PyMethodDef *)caml_aux(obj); + CAMLreturn(pywrap(PyCFunction_New(ml_def,obj))); +} + +value pymodule_initmodule( value name, value funclist ) { + CAMLparam2(name,funclist); + int i; + PyMethodDef *methods = malloc( sizeof( PyMethodDef ) * + Wosize_val(funclist) ); + CAMLlocal1(item); + + PyImport_AddModule( String_val(name) ); + + for( i = 0; i < Wosize_val(funclist); i++ ) { + item = Field(funclist,i); + methods[i].ml_name = String_val(Field(item,0)); + methods[i].ml_meth = pywrap_closure(Field(item,1)); + methods[i].ml_flags = Int_val(Field(item,2)); + methods[i].ml_doc = String_val(Field(item,3)); + } + + Py_InitModule( String_val(name), methods ); + + free( methods ); + + CAMLreturn(Val_unit); +} + +value pycaml_setargs(value argv) { + CAMLparam1(argv); + char* cargv[1]; + + cargv[0] = String_val(argv); + + PySys_SetArgv(1, cargv); + + CAMLreturn0; +} + +value pytrue( value unit ) { + CAMLparam1(unit); + CAMLreturn(pywrap(Py_True)); +} + +value pyfalse(value unit) { + CAMLparam1(unit); + CAMLreturn(pywrap(Py_False)); +} diff --git a/pycaml/pycamltest.ml b/pycaml/pycamltest.ml new file mode 100644 index 0000000..8dd90ef --- /dev/null +++ b/pycaml/pycamltest.ml @@ -0,0 +1,31 @@ +(* + * (C) arty 2002 + * This software is covered under the GNU lesser general public license + *) +open Pycaml ;; + +let colorsys = pyimport_importmodule "colorsys" +let dict = pymodule_getdict colorsys + +let triplet = pytuple3 (pyfloat_fromdouble 1.0, + pyfloat_fromdouble 0.5, + pyfloat_fromdouble 0.2) ;; + +let rgbtoyiq = pydict_getitemstring (dict,"rgb_to_yiq") +let triplet = pyeval_callobject (rgbtoyiq,triplet) + +let _ = print_endline ((string_of_float + (pyfloat_asdouble (pytuple_getitem (triplet,0)))) ^ + " " ^ + (string_of_float + (pyfloat_asdouble (pytuple_getitem (triplet,1)))) ^ + " " ^ + (string_of_float + (pyfloat_asdouble (pytuple_getitem (triplet,2))))) ;; + +let x = pywrap_closure + (fun x -> print_string (pystring_asstring (pytuple_getitem (x,0))) ; + pynone ()) + +let _ = pyeval_callobject + (x,pytuple_fromsingle (pystring_fromstring "hi there")) diff --git a/pycaml/tupletest.ml b/pycaml/tupletest.ml new file mode 100644 index 0000000..41ecdc3 --- /dev/null +++ b/pycaml/tupletest.ml @@ -0,0 +1,17 @@ +open Pycaml + +let foo_bar_print = pywrap_closure + (fun x -> pytuple_fromarray (pytuple_toarray x)) ;; +let sd = pyimport_getmoduledict () ;; +let mx = pymodule_new "CamlModule" ;; +let cd = pydict_new () ;; +let cx = pyclass_new (pynull (), cd, pystring_fromstring "CamlClass") ;; +let cmx = pymethod_new (foo_bar_print,(pynull ()),cx) ;; +let _ = pydict_setitemstring (cd, "CamlMethod", cmx) ;; +let _ = pydict_setitemstring (pymodule_getdict mx, "CamlClass", cx) ;; +let _ = pydict_setitemstring (sd, "CamlModule", mx) ;; +let _ = pyrun_simplestring + ("from CamlModule import CamlClass\n" ^ + "x = CamlClass()\n" ^ + "for i in range(100000):\n" ^ + " x.CamlMethod(1,2,3,4)\n") diff --git a/python/.depend b/python/.depend new file mode 100644 index 0000000..f6f1ff2 --- /dev/null +++ b/python/.depend @@ -0,0 +1,22 @@ +no_pycocci.cmo: pycocci_aux.cmo ../commons/common.cmi ../parsing_c/ast_c.cmo +no_pycocci.cmx: pycocci_aux.cmx ../commons/common.cmx ../parsing_c/ast_c.cmx +no_pycocci_aux.cmo: ../parsing_c/pretty_print_c.cmi ../commons/common.cmi \ + ../parsing_c/ast_c.cmo +no_pycocci_aux.cmx: ../parsing_c/pretty_print_c.cmx ../commons/common.cmx \ + ../parsing_c/ast_c.cmx +pycocci.cmo: pycocci_aux.cmo ../commons/common.cmi ../parsing_c/ast_c.cmo +pycocci.cmx: pycocci_aux.cmx ../commons/common.cmx ../parsing_c/ast_c.cmx +pycocci_aux.cmo: ../parsing_c/pretty_print_c.cmi ../commons/common.cmi \ + ../parsing_c/ast_c.cmo +pycocci_aux.cmx: ../parsing_c/pretty_print_c.cmx ../commons/common.cmx \ + ../parsing_c/ast_c.cmx +yes_pycocci.cmo: pycocci_aux.cmo ../pycaml/pycaml.cmo ../globals/flag.cmo \ + ../commons/common.cmi ../parsing_c/ast_c.cmo +yes_pycocci.cmx: pycocci_aux.cmx ../pycaml/pycaml.cmx ../globals/flag.cmx \ + ../commons/common.cmx ../parsing_c/ast_c.cmx +yes_pycocci_aux.cmo: ../pycaml/pycaml.cmo ../parsing_c/pretty_print_c.cmi \ + ../commons/common.cmi ../parsing_cocci/ast_cocci.cmi \ + ../parsing_c/ast_c.cmo +yes_pycocci_aux.cmx: ../pycaml/pycaml.cmx ../parsing_c/pretty_print_c.cmx \ + ../commons/common.cmx ../parsing_cocci/ast_cocci.cmx \ + ../parsing_c/ast_c.cmx diff --git a/python/Makefile b/python/Makefile new file mode 100644 index 0000000..0fe4954 --- /dev/null +++ b/python/Makefile @@ -0,0 +1,146 @@ +# Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +# Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +# This file is part of Coccinelle. +# +# Coccinelle is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, according to version 2 of the License. +# +# Coccinelle is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Coccinelle. If not, see . +# +# The authors reserve the right to distribute this or future versions of +# Coccinelle under other licenses. + + +############################################################################# +# Configuration section +############################################################################# +-include ../Makefile.config + +############################################################################## +# Variables +############################################################################## +TARGET=coccipython + +SOURCES= pycocci_aux.ml pycocci.ml + +INCLUDEDIRS = ../commons ../commons/ocamlextra ../globals ../pycaml \ + ../parsing_c ../parsing_cocci + +SYSLIBS = str.cma unix.cma +LIBS=../commons/commons.cma ../globals/globals.cma + +# ../ctl/ctl.cma \ +# ../parsing_c/c_parser.cma ../parsing_cocci/cocci_parser.cma +#pycaml/pycaml.cma + + +############################################################################## +# Generic variables +############################################################################## + +INCLUDES=$(INCLUDEDIRS:%=-I %) $(INCLUDESEXTRA) + +############################################################################## +# Generic ocaml variables +############################################################################## + +# The Caml compilers. +OCAMLCFLAGS ?= -g -dtypes +OCAMLC =ocamlc$(OPTBIN) $(OCAMLCFLAGS) $(INCLUDES) +OCAMLOPT = ocamlopt$(OPTBIN) $(OPTFLAGS) $(INCLUDES) +OCAMLDEP = ocamldep$(OPTBIN) $(INCLUDES) + + +############################################################################## +# Top rules +############################################################################## + +EXEC=$(TARGET).byte +LIB=$(TARGET).cma +OPTLIB=$(LIB:.cma=.cmxa) + +CTLEXEC=$(CTLTARGET) + +OBJS = $(SOURCES:.ml=.cmo) +OPTOBJS = $(OBJS:.cmo=.cmx) + +CTLOBJS = $(CTLSOURCES:.ml=.cmo) +CTLOPTOBJS = $(CTLOBJS:.cmo=.cmx) + + +#all: $(EXEC) $(LIB) +all: $(LIB) + +all.opt: $(OPTLIB) + +ctl: $(CTLEXEC) + + +$(LIB): $(OBJS) + $(OCAMLC) -a -o $(LIB) $(OBJS) + +clean:: + rm -f $(LIB) + + +$(OPTLIB): $(OPTOBJS) + $(OCAMLOPT) -a -o $(OPTLIB) $(OPTOBJS) + + +$(EXEC): $(OBJS) main.cmo $(LIBS) + $(OCAMLC) -o $(EXEC) $(SYSLIBS) $(LIBS) $(OBJS) main.cmo + +$(CTLEXEC): $(CTLOBJS) $(LIBS) + $(OCAMLC) -o $(CTLEXEC) $(SYSLIBS) $(LIBS) $(CTLOBJS) + + +clean:: + rm -f $(OPTLIB) $(LIB:.cma=.a) + rm -f $(TARGET) rm -f $(TARGET).byte + rm -f $(CTLTARGET) + + +#pycocci.ml: ../pycaml/pycaml.ml ../pycaml/pycaml_ml.c +#pycocci_aux.ml: ../pycaml/pycaml.ml ../pycaml/pycaml_ml.c + +rmlinks: + rm -f pycocci.ml pycocci_aux.ml + +############################################################################## +# Generic ocaml rules +############################################################################## + +.SUFFIXES: +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) -c $< + +.mli.cmi: + $(OCAMLC) -c $< + +.ml.cmx: + $(OCAMLOPT) -c $< + + +# clean rule for others files +clean:: + rm -f *.cm[iox] *.o *.annot + rm -f *~ .*~ #*# + +beforedepend: + +depend: beforedepend + $(OCAMLDEP) *.mli *.ml > .depend + +.depend: + $(OCAMLDEP) *.mli *.ml > .depend + +-include .depend diff --git a/python/coccilib/Makefile b/python/coccilib/Makefile new file mode 100644 index 0000000..0170db2 --- /dev/null +++ b/python/coccilib/Makefile @@ -0,0 +1,10 @@ +MAKESUBDIRS=coccigui + +all: +all.opt: + +depend: + +clean: + set -e; for i in $(MAKESUBDIRS); do $(MAKE) -C $$i clean; done + rm -f *.pyc diff --git a/python/coccilib/__init__.py b/python/coccilib/__init__.py new file mode 100644 index 0000000..ea33379 --- /dev/null +++ b/python/coccilib/__init__.py @@ -0,0 +1 @@ +# python infrastructure diff --git a/python/coccilib/coccigui/Makefile b/python/coccilib/coccigui/Makefile new file mode 100644 index 0000000..b4a49cc --- /dev/null +++ b/python/coccilib/coccigui/Makefile @@ -0,0 +1,6 @@ +all: + +depend: + +clean: + rm -f *.pyc diff --git a/python/coccilib/coccigui/__init__.py b/python/coccilib/coccigui/__init__.py new file mode 100644 index 0000000..ea33379 --- /dev/null +++ b/python/coccilib/coccigui/__init__.py @@ -0,0 +1 @@ +# python infrastructure diff --git a/python/coccilib/coccigui/coccigui.py b/python/coccilib/coccigui/coccigui.py new file mode 100644 index 0000000..7911262 --- /dev/null +++ b/python/coccilib/coccigui/coccigui.py @@ -0,0 +1,129 @@ +import pygtk +pygtk.require("2.0") +import sys, gtk, gtk.glade, gobject, os, locale, gettext +from pycoccimodel import * +import vimembed, vimcom + +class VimCallback(object): + def __init__(self, app): + self.app = app + + def vim_new_serverlist(self, serverlist): + self.app.vimcom.stop_fetching_serverlist() + self.app.vimcom.open_file(self.app.vimsock.get_server_name(), '~/.vimrc') + +class pycocci(object): + def __init__(self): + self.local_path = os.path.realpath(os.path.dirname(sys.argv[0])) + self.initialize_translation() + self.gladefile = os.path.join(self.local_path, "coccilib/coccigui/pygui.glade") + self.wTree = gtk.glade.XML(self.gladefile, "mainWindow") + self.setup_tree_columns() + self.wTree.signal_autoconnect(self) + self.initialise_tree() + self.main_window = self.wTree.get_widget("mainWindow") + + self.vimsock = vimembed.VimEmbedWidget('gvim', '~/.vimrc') + self.vimsock.visible = True + self.vbox1 = self.wTree.get_widget("vbox1") + self.vbox1.pack_end(self.vimsock) + self.setup_vim() + + def setup_vim(self): + self.vimcb = VimCallback(self) + self.vimcom = vimcom.VimCom(self.vimcb) + self.vimsock.run() + self.vimsock.connect('destroy', self.on_vimsock_destroy) + + def on_vimsock_destroy(self, widget): + self.setup_vim() + + def initialise_tree(self): + tree_type_list = [] + self.__column_dict = {} + self.bugTreeView = self.wTree.get_widget("bugView") + self.bugTreeView.set_rules_hint(True) + + for c in self.__tree_columns: + self.__column_dict[c.id] = c + tree_type_list.append(c.type) + + if c.visible: + column = gtk.TreeViewColumn(c.name, c.cellrenderer, text=c.pos) + column.set_resizable(True) + column.set_sort_column_id(c.pos) + self.bugTreeView.append_column(column) + + self.bugTree = gtk.TreeStore(*tree_type_list) + self.bugTreeView.set_model(self.bugTree) + self.bugTreeView.connect('row-activated', self.row_activated) + + def row_activated(self, view, path, view_column): + it = view.get_model().get_iter(path) + obj, objtype, bugdesc, file, line, col = view.get_model().get(it, 0, 1, 2, 3, 4, 5) + + if file != '': + server = self.vimsock.get_server_name() + + self.vimcom.open_file(server, file) + if line != '': + self.vimcom.send_ex(server, line) + + if col != '': + self.vimcom.send_keys(server, col + '|') + + def setup_tree_columns(self): + self.__tree_columns = [ + pycoccicolumn(COL_OBJECT, gobject.TYPE_PYOBJECT, "object", 0), + pycoccicolumn(COL_OBJECT, gobject.TYPE_INT, "object_type", 1), + pycoccicolumn(COL_TITLE, gobject.TYPE_STRING, _("Bug type"), 2, True, gtk.CellRendererText()), + pycoccicolumn(COL_FILE, gobject.TYPE_STRING, _("File"), 3, True, gtk.CellRendererText()), + pycoccicolumn(COL_LINE, gobject.TYPE_STRING, _("Line"), 4, True, gtk.CellRendererText()), + pycoccicolumn(COL_COLUMN, gobject.TYPE_STRING, _("Column"), 5, True, gtk.CellRendererText()) + ] + + def initialize_translation(self): + langs = [] + lc, encoding = locale.getdefaultlocale() + if lc: + langs = [lc] + language = os.environ.get('LANGUAGE', None) + if language: + langs += language.split(':') + + gettext.bindtextdomain('pycocci', self.local_path) + gettext.textdomain('pycocci') + self.lang = gettext.translation('pycocci', self.local_path, + languages=langs, fallback = True) + gettext.install('pycocci', self.local_path) + + def on_mainWindow_destroy(self, widget): + gtk.main_quit() + + def add_result(self, cocci_file, l): + root = self.bugTreeView.get_model().get_iter_root() + it = None + + while root != None: + c_cocci_file = self.bugTreeView.get_model().get(root, 2)[0] + if c_cocci_file == cocci_file: + it = root + break + + root = self.bugTreeView.get_model().iter_next(root) + + if it == None: + it = self.bugTree.insert_after(None, None, (None, 0, cocci_file, '', '', '')) + + description, file, line, col = l[0] + mit = self.bugTree.append(it, (None, 1, description, file, line, col)) + + for i in xrange(1, len(l)): + description, file, line, col = l[i] + self.bugTree.append(mit, (None, 2, description, file, line, col)) + +#if __name__ == '__main__': +# app = pycocci() +# app.add_result('Test.cocci', [('Array identified: z', '/home/hstuart/thesis/py-cocci/tests/scripting/array/script4.c', '6', '7'), ('Array use: z', '/home/hstuart/thesis/py-cocci/tests/scripting/array/script4.c', '8', '3')]) +# app.add_result('Test.cocci', [('Array identified: foo', '/home/hstuart/thesis/py-cocci/tests/scripting/array/script4.c', '12', '17')]) +# gtk.main() diff --git a/python/coccilib/coccigui/pycoccimodel.py b/python/coccilib/coccigui/pycoccimodel.py new file mode 100644 index 0000000..2c798e6 --- /dev/null +++ b/python/coccilib/coccigui/pycoccimodel.py @@ -0,0 +1,22 @@ +import pygtk +import gtk, gtk.glade + +COL_OBJECT = 0 +COL_OBJECT_TYPE = 1 +COL_TITLE = 2 +COL_FILE = 3 +COL_LINE = 4 +COL_COLUMN = 5 + +class pycoccicolumn(object): + def __init__(self, id, type, name, pos, visible=False, cellrenderer=None): + self.id = id + self.type = type + self.name = name + self.pos = pos + self.visible = visible + self.cellrenderer = cellrenderer + self.colour = 0 + + def __str__(self): + return "" % (self.id, self.type, self.name, self.pos, self.visible, self.cellrenderer) diff --git a/python/coccilib/coccigui/pygui.glade b/python/coccilib/coccigui/pygui.glade new file mode 100644 index 0000000..8a5c5e1 --- /dev/null +++ b/python/coccilib/coccigui/pygui.glade @@ -0,0 +1,108 @@ + + + + + + True + pycocci + GTK_WIN_POS_CENTER + 1000 + 800 + + + + True + + + True + + + True + _File + True + + + + + True + gtk-new + True + True + + + + + + True + gtk-open + True + True + + + + + + True + gtk-save + True + True + + + + + + True + gtk-save-as + True + True + + + + + + True + + + + + True + gtk-quit + True + True + + + + + + + + + + False + False + + + + + True + True + GTK_SHADOW_IN + + + True + True + True + + + + + 1 + + + + + + + + + diff --git a/python/coccilib/coccigui/pygui.gladep b/python/coccilib/coccigui/pygui.gladep new file mode 100644 index 0000000..d987c74 --- /dev/null +++ b/python/coccilib/coccigui/pygui.gladep @@ -0,0 +1,8 @@ + + + + + pygui + pygui + FALSE + diff --git a/python/coccilib/coccigui/vim.py b/python/coccilib/coccigui/vim.py new file mode 100644 index 0000000..0fb9ff3 --- /dev/null +++ b/python/coccilib/coccigui/vim.py @@ -0,0 +1,282 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2007 The PIDA Project + +#Permission is hereby granted, free of charge, to any person obtaining a copy +#of this software and associated documentation files (the "Software"), to deal +#in the Software without restriction, including without limitation the rights +#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +#copies of the Software, and to permit persons to whom the Software is +#furnished to do so, subject to the following conditions: + +#The above copyright notice and this permission notice shall be included in +#all copies or substantial portions of the Software. + +#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +#SOFTWARE. + + +import os + +# PIDA Imports +from pida.core.environment import get_data_path + +from pida.ui.views import PidaView + +from pida.utils.vim.vimembed import VimEmbedWidget +from pida.utils.vim.vimcom import VimCom + +from pida.core.editors import EditorService, _ + + +class VimView(PidaView): + + def create_ui(self): + self._vim = VimEmbedWidget('gvim', self.svc.script_path) + self.add_main_widget(self._vim) + + def run(self): + return self._vim.run() + + def get_server_name(self): + return self._vim.get_server_name() + + def grab_input_focus(self): + self._vim.grab_input_focus() + + +class VimCallback(object): + + def __init__(self, svc): + self.svc = svc + + def vim_new_serverlist(self, servers): + if self.svc.server in servers: + self.svc.init_vim_server() + + def vim_bufferchange(self, server, cwd, file_name, bufnum): + if server == self.svc.server: + if file_name: + if os.path.abspath(file_name) != file_name: + file_name = os.path.join(cwd, file_name) + if os.path.isdir(file_name): + self.svc.boss.cmd('filemanager', 'browse', new_path=file_name) + self.svc.boss.cmd('filemanager', 'present_view') + self.svc.open_last() + else: + self.svc.boss.cmd('buffer', 'open_file', file_name=file_name) + + def vim_bufferunload(self, server, file_name): + if server == self.svc.server: + if file_name: + self.svc.remove_file(file_name) + self.svc.boss.get_service('buffer').cmd('close_file', file_name=file_name) + + def vim_filesave(self, server, file_name): + if server == self.svc.server: + self.svc.boss.cmd('buffer', 'current_file_saved') + + def vim_cursor_move(self, server, line_number): + if server == self.svc.server: + self.svc.set_current_line(int(line_number)) + + def vim_shutdown(self, server, args): + if server == self.svc.server: + self.svc.boss.stop(force=True) + + def vim_complete(self, server, temp_buffer_filename, offset): + buffer = open(temp_buffer_filename).read() + offset = int(offset) - 1 + from rope.ide.codeassist import PythonCodeAssist + from rope.base.project import Project + p = Project(self.svc.boss.cmd('buffer', 'get_current').directory) + c = PythonCodeAssist(p) + co = c.assist(buffer, offset).completions + print co + for comp in co: + self.svc._com.add_completion(server, comp.name) + # do this a few times + #self.svc._com.add_completion(server, 'banana') + pass + + +# Service class +class Vim(EditorService): + """Describe your Service Here""" + + ##### Vim Things + + def _create_initscript(self): + self.script_path = get_data_path('pida_vim_init.vim') + + def init_vim_server(self): + if self.started == False: + self._com.stop_fetching_serverlist() + self.started = True + self._emit_editor_started() + + def _emit_editor_started(self): + self.boss.get_service('editor').emit('started') + + def get_server_name(self): + return self._view.get_server_name() + + server = property(get_server_name) + + def pre_start(self): + """Start the editor""" + self.started = False + self._create_initscript() + self._cb = VimCallback(self) + self._com = VimCom(self._cb) + self._view = VimView(self) + self.boss.cmd('window', 'add_view', paned='Editor', view=self._view) + self._documents = {} + self._current = None + self._sign_index = 0 + self._signs = {} + self._current_line = 1 + success = self._view.run() + if not success: + err = _('There was a problem running the "gvim" ' + 'executable. This is usually because it is not ' + 'installed. Please check that you can run "gvim" ' + 'from the command line.') + self.error_dlg(err) + raise RuntimeError(err) + + + def open(self, document): + """Open a document""" + if document is not self._current: + if document.unique_id in self._documents: + fn = document.filename + self._com.change_buffer(self.server, fn) + self._com.foreground(self.server) + else: + self._com.open_file(self.server, document.filename) + self._documents[document.unique_id] = document + self._current = document + + + def open_many(documents): + """Open a few documents""" + + def open_last(self): + self._com.change_buffer(self.server, '#') + + def close(self, document): + if document.unique_id in self._documents: + self._remove_document(document) + self._com.close_buffer(self.server, document.filename) + + def remove_file(self, file_name): + document = self._get_document_for_filename(file_name) + if document is not None: + self._remove_document(document) + + def _remove_document(self, document): + del self._documents[document.unique_id] + + def _get_document_for_filename(self, file_name): + for uid, doc in self._documents.iteritems(): + if doc.filename == file_name: + return doc + + def close_all(): + """Close all the documents""" + + def save(self): + """Save the current document""" + self._com.save(self.server) + + def save_as(filename): + """Save the current document as another filename""" + + def revert(): + """Revert to the loaded version of the file""" + + def goto_line(self, line): + """Goto a line""" + self._com.goto_line(self.server, line) + self.grab_focus() + + def cut(self): + """Cut to the clipboard""" + self._com.cut(self.server) + + def copy(self): + """Copy to the clipboard""" + self._com.copy(self.server) + + def paste(self): + """Paste from the clipboard""" + self._com.paste(self.server) + + def undo(self): + self._com.undo(self.server) + + def redo(self): + self._com.redo(self.server) + + def grab_focus(self): + """Grab the focus""" + self._view.grab_input_focus() + + def define_sign_type(self, name, icon, linehl, text, texthl): + self._com.define_sign(self.server, name, icon, linehl, text, texthl) + + def undefine_sign_type(self, name): + self._com.undefine_sign(self.server, name) + + def _add_sign(self, type, filename, line): + self._sign_index += 1 + self._signs[(filename, line, type)] = self._sign_index + return self._sign_index + + def _del_sign(self, type, filename, line): + return self._signs.pop((filename, line, type)) + + def show_sign(self, type, filename, line): + index = self._add_sign(type, filename, line) + self._com.show_sign(self.server, index, type, filename, line) + + def hide_sign(self, type, filename, line): + try: + index = self._del_sign(type, filename, line) + self._com.hide_sign(self.server, index, filename) + except KeyError: + self.window.error_dlg(_('Tried to remove non-existent sign')) + + def set_current_line(self, line_number): + self._current_line = line_number + + def get_current_line(self): + return self._current_line + + def delete_current_word(self): + self._com.delete_cword(self.server) + + def insert_text(self, text): + self._com.insert_text(self.server, text) + + def call_with_current_word(self, callback): + return self._com.get_cword(self.server, callback) + + def call_with_selection(self, callback): + return self._com.get_selection(self.server, callback) + + def set_path(self, path): + return self._com.set_path(self.server, path) + +# Required Service attribute for service loading +Service = Vim + + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/python/coccilib/coccigui/vimcom.py b/python/coccilib/coccigui/vimcom.py new file mode 100644 index 0000000..a72a464 --- /dev/null +++ b/python/coccilib/coccigui/vimcom.py @@ -0,0 +1,728 @@ +# -*- coding: utf-8 -*- + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: +#Copyright (c) 2005 Ali Afshar aafshar@gmail.com + +#Permission is hereby granted, free of charge, to any person obtaining a copy +#of this software and associated documentation files (the "Software"), to deal +#in the Software without restriction, including without limitation the rights +#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +#copies of the Software, and to permit persons to whom the Software is +#furnished to do so, subject to the following conditions: + +#The above copyright notice and this permission notice shall be included in +#all copies or substantial portions of the Software. + +#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +#SOFTWARE. + + +""" + +A library to control vim -g using its X protocol interface (with gdk). + +============ +How it works +============ + +=== General Communication === + +The Vim client/server protocol communicates by sending messages to and from an +X communication window. The details are explained in the Vim source. +Essentially, Vim understands two sorts of messages over this interface. + +;asynchronous key sends : that are exactly equivalent to to the user of the +remote Vim typing commands. + +;synchronous expression evaluations : these are Vim expressions that are +evaluated by the remote Vim, and an answer is replied with the result over the +same protocol. + +Although the synchronous messages are called synchronous, the reply itself, in +programming terms is entirely asynchronous, in that there is no way of knowing +when a reply will be received, and one cannot block for it. + +Thus, this library allows you to make both of these calls to remote Vims. +Synchronous expressions must provide a call back function that will be called +when the message is replied to. + +=== The Server List === + +(It has been an utter nightmare.) + +The primary problem is that GTK does not actually know accurately whether +a window with a given window ID has been destroyed. This is how Vim does +it (using the X libraries) after checking an attribute for registered Vim +sessions with the X root window. This way each Vim doesn't need to +unregister itself with the X root window on dying, it just assumes that +any other client attempting to connect to it will know that the window +has been destroyed. As mentioned, GTK totally fails to do what the X +library does, and ascertain whether the window is alive. It succeeds +sometimes, but not at others. The result is a GDK window that appears +alive, and ready to communicate with, but which causes an uncatchable and +fatal application error. + +Step in other potential methods of getting an accurate list of servers. +Firstly, and most obviously, one can call the command 'vim --serverlist' +on a simple system pipe and read the list off. This is entirely reliable, +and effective, but the cost of forking a process and starting Vim each +time is not fun, and effectively blocks. + +Another option is to force users to start Vim through Pida and keep an +account of the child processes. This would work very effectively, but it +restricts the user, and the entire system. + +The final, and current solution is to start Vim itself on a +pseudoterminal as a hidden instance, and then communicate with that over +the Vim protocol. The reason this can be reliably done, is that since the +process is a child, it can be polled to check whether it is alive. This +is performed each time the serverlist is requested, and if the hidden +instance has been destroyed (eg by the user) a new one is spawned, thus +preventing an attempt to communicate with an already-destroyed GDK +window. + +The cost of this solution is that we spawn an extra Vim process. I +believe that the added solidity it brings to the entire system is easily +worth it, and it ensures that Pida can communicate with Vim it started +and Vim it didn't start. +""" +# Gtk imports +import gtk +import gtk.gdk as gdk +import gobject +# System imports +import os +import pty +import time +import tempfile + +class poller(object): + """ + DEPRECATED: WE DO NOT USE THIS ANYMORE + + An instance of Vim on a pseudoterminal which can be reliably polled. + + This class is used to provide an instance of Vim which can be communicated + with using the Vim client/server protocol, in order to retrieve an accurate + and current server list, and also which can be polled accurately as to + whether it is alive before communicating with it. + + This method is much cheaper in resources than running vim --serverlist each + time, and much more accurate than using the root window's VimRegistry + property, and also more accurate than using GDK methods for assessing + whether a window is alive. + """ + + def __init__(self): + """ + Constructor. + + Create a temporary and unique name for use as the servername, and + initialise the instance variables. + + @param cb: An instance of the main application class. + @type cb: pida.main.Application. + """ + # Prefacing with '__' means it will be ignored in the internal server + # list. + self.name = '__%s_PIDA_HIDDEN' % time.time() + # Checked to evaluate False on starting. + self.pid = None + + def start(self): + """ + Start the Vim instance if it is not already running. + + This command forks in a pseudoterminal, and starts Vim, if Vim is not + already running. The pid is stored for later use. + """ + if not self.pid: + # Get the console vim executable path + #command = self.prop_main_registry.commands.vim.value() + command = 'gvim' + # Fork using pty.fork to prevent Vim taking the terminal + sock = gtk.Socket() + w = gtk.Window() + w.realize() + w.add(sock) + xid = sock.get_id() + pid, fd = pty.fork() + if pid == 0: + # Child, execute Vim with the correct servername argument + os.execvp(command, ['gvim', '-f', '--servername', self.name, + '--socketid', '%s' % xid]) + #'-v']) + # os.system('%s -v --servername %s' % (command, self.name)) + else: + # Parent, store the pid, and file descriptor for later. + self.pid = pid + self.childfd = fd + #self.do_action('accountfork', self.pid) + + def is_alive(self): + """ + Check if the Vim instance is alive. + + This method uses os.waitpid, with no blocking to determine whether the + process is still alive. If it is not, it sets the internal pid + attribute to None, so that it may be restarted. + + @returns: alive + @rtype alive: boolean + """ + if self.pid: + try: + # call os.waitpid, returns 0 if the pid is alive + pid, sts = os.waitpid(self.pid, os.WNOHANG) + except OSError: + # might still be starting up + return False + if pid == self.pid: + # has shut down + self.pid = None + return False + else: + # is still alive + return True + else: + # Not started yet + return False + +class communication_window(gtk.Window): + """ + A GTK window that can communicate with any number Vim instances. + + This is an actual GTK window (which it must be to accurately detect + property events inside the GTK main loop) but has its GDK window correctly + set to receive such events. This is notably the "Vim" property which must + be present and set to a version string, in this case "6.0" is used. + """ + def __init__(self, cb): + """ + Constructor. + + The Window is instantiated, the properties are correctly set, the event + mask is modified, and the instance variables are initialized. + + @param cb: An instance of the main Application class. + @type cb: pida.main.Application. + """ + gtk.Window.__init__(self) + self.cb = cb + # Window needs to be realized to do anything useful with it. Realizing + # does not show the window to the user, so we can use it, but not have + # an ugly blank frame while it loads. + self.realize() + # The "Vim" property + self.window.property_change("Vim", gdk.SELECTION_TYPE_STRING, 8, + gdk.PROP_MODE_REPLACE, "6.0") + # Set the correct event mask and connect the notify event + self.add_events(gtk.gdk.PROPERTY_CHANGE_MASK) + self.connect('property-notify-event', self.cb_notify) + # The serial number used for sending synchronous messages + self.serial = 1 + # A dictionary of callbacks for synchronous messages. The key is the + # serial number, and the value is a callable that will be called with + # the result of the synchronous evaluation. + self.callbacks = {} + # A dictionary to store the working directories for each Vim so they + # only have to be fetched once. + self.server_cwds = {} + # An instance of the root window, so it only has to be fetched once. + dpy = gdk.display_get_default() + if not dpy: + raise Exception('Unable to get default display') + screen = dpy.get_screen(0) + self.root_window = screen.get_root_window() + # fetch the serverlist to begin with to know when we are started + self.oldservers = None + self.keep_fetching_serverlist = True + gobject.timeout_add(250, self.fetch_serverlist) + + def fetch_serverlist(self): + """ + Fetch the serverlist, and if it has changed, feed it to the client. + + The serverlist is requested asynchrnously, and passed the gotservers + function as a callback. The gotservers function is then called with the + server list, gets the appropriate working directory (if required) and + feeds the new server list to the client if it has changed. + """ + def gotservers(serverlist): + """ + Called back on receiving the serverlist. + + Fetch working directories for new Vim instances, and feed the + server list to the client if it has changed. + """ + for server in serverlist: + # Check if we already have the working directory. + if server not in self.server_cwds: + # We don't, fetch it + self.fetch_cwd(server) + # Check if the server list has changed + if serverlist != self.oldservers: + self.oldservers = serverlist + # A ew serverlist to feed to the client. + self.feed_serverlist(serverlist) + gotservers(self.get_rootwindow_serverlist()) + # decide whether to keep fetching server list + return self.keep_fetching_serverlist + + def stop_fetching_serverlist(self): + self.keep_fetching_serverlist = False + + def get_rootwindow_serverlist(self): + """ + Get the X root window's version of the current Vim serverlist. + + On starting with the client-server feature, GVim or Vim with the + --servername option registers its server name and X window id as part + of the "VimRegistry" parameter on the X root window. + + This method extracts and parses that property, and returns the server + list. + + Note: Vim does not actually unregister itself with the root window on + dying, so the presence of a server in the root window list is no + gurantee that it is alive. + + @return: servers + @rtype servers: dict of ("server", "window id") key, value + """ + servers = {} + # Read the property + vimregistry = self.root_window.property_get("VimRegistry") + # If it exists + if vimregistry: + # Get the list of servers by splitting with '\0' + vimservers = vimregistry[-1].split('\0') + # Parse each individual server and add to the results list + for rawserver in vimservers: + # Sometimes blank servers exist in the list + if rawserver: + # split the raw value for the name and id + name_id = rawserver.split() + # Set the value in the results dict, remembering to convert + # the window id to a long int. + servers[name_id[1]] = long(int(name_id[0], 16)) + # return the list of resuts + return servers + + def get_shell_serverlist(self): + """ + DEPRACATED: WE NEVER NEED A SERVERLIST + (This is here for educative purposes) + + Get the server list by starting console Vim on a Pipe. + + This blocks, so we don't use it. It is one of the alternative methods + of retrieving an accurate serverlist. It is slow, and expensive. + """ + vimcom = 'gvim' + p = os.popen('%s --serverlist' % vimcom) + servers = p.read() + p.close() + return servers.splitlines() + + def get_hidden_serverlist(self, callbackfunc): + """ + DEPRACATED: WE NEVER NEED A SERVERLIST + (This is here for educative purposes) + + Get the serverlist from the hidden Vim instance and call the callback + function with the results. + + This method checks first whther the Vim instance is alive, and then + evaluates the serverlist() function remotely in it, with a local call + back function which parses the result and calls the user-provided + callback function. + + @param callbackfunc: The call back function to be called with the + server list. + @type callbackfunc: callable + """ + def cb(serverstring): + """ + Called back with the raw server list. + + Parse the lines and call the call back function, ignoring any + instances starting with "__" which represent hidden instances. If + the hidden Vim instance is not alive, it is restarted. + """ + servers = serverstring.splitlines() + # Call the callback function + callbackfunc([svr for svr in servers if not svr.startswith('__')]) + # Check if the hidden Vim is alive. + if self.vim_hidden.is_alive(): + # It is alive, get the serverlist. + self.send_expr(self.vim_hidden.name, 'serverlist()', cb) + else: + # It is not alive, restart it. + self.vim_hidden.start() + + def get_server_wid(self, servername): + """ + Get the X Window id for a named Vim server. + + This function returns the id from the root window server list, if it + exists, or None if it does not. + + @param servername: The name of the server + @type servername: str + + @return: wid + @rtype wid: long + """ + try: + # get the window id from the root window + wid = self.get_rootwindow_serverlist()[servername] + except KeyError: + # The server is not registered in the root window so return None + wid = None + # Return wid if it is not none, or None + return wid and long(wid) or None + + def get_server_window(self, wid): + """ + Create and return a GDK window for a given window ID. + + This method simply calls gdk.window_foreign_new, which should return + None if the window has been destroyed, but does not, in some cases. + + @param wid: The window ID. + @type wid: long + """ + return gtk.gdk.window_foreign_new(wid) + + def feed_serverlist(self, serverlist): + """ + Feed the given list of servers to the client. + + This is achieved by calling the clients serverlist event. In Pida, this + event is passed on to all the plugins. + + @param serverlist: The list of servers. + @type serverlist: list + """ + # Call the event. + #self.do_evt('serverlist', serverlist) + self.cb.vim_new_serverlist(serverlist) + + def fetch_cwd(self, servername): + """ + Fetch the working directory for a named server and store the result. + """ + def gotcwd(cwd): + """ + Called back on receiving the working directory, store it for later + use. + """ + self.server_cwds[servername] = cwd + # Evaluate the expression with the gotcwd callback + self.send_expr(servername, "getcwd()", gotcwd) + + def get_cwd(self, server): + if server in self.server_cwds: + return self.server_cwds[server] + + def abspath(self, servername, filename): + """ + Return the absolute path of a buffer name in the context of the named + server. + """ + # Only alter non-absolute paths + if not filename.startswith('/'): + try: + # Try to find the current working directory + cwd = self.server_cwds[servername] + except KeyError: + # The working directory is not set + # Use a sane default, and fetch it + cwd = os.path.expanduser('~') + self.fetch_cwd(servername) + filename = os.path.join(cwd, filename) + return filename + + def generate_message(self, server, cork, message, sourceid): + """ + Generate a message. + """ + # Increment the serial number used for synchronous messages + if cork: + self.serial = self.serial + 1 + # Pick an arbitrary number where we recycle. + if self.serial > 65530: + self.serial = 1 + # return the generated string + return '\0%s\0-n %s\0-s %s\0-r %x %s\0' % (cork, + server, + message, + sourceid, + self.serial) + + def parse_message(self, message): + """ + Parse a received message and return the message atributes as a + dictionary. + """ + messageattrs = {} + for t in [s.split(' ') for s in message.split('\0')]: + if t and len(t[0]): + name = t[0] + value = ' '.join(t[1:]) + if name.startswith('-'): + #attributes start with a '-', strip it and set the value + name = name[1:] + messageattrs[name] = value + else: + # Otherwise set the t attribute + messageattrs['t'] = name + return messageattrs + + def send_message(self, servername, message, asexpr, callback): + wid = self.get_server_wid(servername) + if wid: + cork = (asexpr and 'c') or 'k' + sw = self.get_server_window(wid) + if sw and sw.property_get("Vim"): + mp = self.generate_message(servername, cork, message, + self.window.xid) + sw.property_change("Comm", gdk.TARGET_STRING, 8, + gdk.PROP_MODE_APPEND, mp) + if asexpr and callback: + self.callbacks['%s' % (self.serial)] = callback + + def send_expr(self, server, message, callback): + self.send_message(server, message, True, callback) + + def send_keys(self, server, message): + self.send_message(server, message, False, False) + + def send_esc(self, server): + self.send_keys(server, '') + + def send_ret(self, server): + self.send_keys(server, '') + + def send_ex(self, server, message): + self.send_esc(server) + self.send_keys(server, ':%s' % message) + self.send_ret(server) + + def send_ex_via_tempfile(self, server, message): + """For really long ugly messages""" + tf, tp = tempfile.mkstemp() + os.write(tf, '%s\n' % message) + os.close(tf) + self.load_script(server, tp) + # delay removing the temporary file to make sure it is loaded + gobject.timeout_add(6000, os.unlink, tp) + + + def get_option(self, server, option, callbackfunc): + self.send_expr(server, '&%s' % option, callbackfunc) + + def foreground(self, server): + def cb(*args): + pass + self.send_expr(server, 'foreground()', cb) + + def change_buffer(self, server, filename): + self.send_ex(server, "exe 'b!'.bufnr('%s')" % filename) + + def change_buffer_number(self, server, number): + self.send_ex(server, "b!%s" % number) + + def close_buffer(self, server, buffername): + self.send_ex(server, "exe 'confirm bw'.bufnr('%s')" % buffername) + + def close_current_buffer(self, server): + self.send_ex(server, 'confirm bw') + + def change_cursor(self, server, x, y): + self.send_message(server, 'cursor(%s, %s)' % (y, x), True, False) + self.send_esc(server) + + def save_session(self, server, file_name): + self.send_ex(server, 'mks %s' % file_name) + + def load_session(self, server, file_name): + self.load_script(server, file_name) + + def escape_filename(self, name): + for s in ['\\', '?', '*', ' ', "'", '"', '[', ' ', '$', '{', '}']: + name = name.replace (s, '\\%s' % s) + return name + + def open_file(self, server, name): + self.send_ex(server, 'confirm e %s' % self.escape_filename(name)) + + def new_file(self, server): + f, path = tempfile.mkstemp() + self.open_file(server, path) + return path + + def goto_line(self, server, linenumber): + self.send_ex(server, '%s' % linenumber) + self.send_esc(server) + self.send_keys(server, 'zz') + self.send_keys(server, 'zv') + + def revert(self, server): + self.send_ex(server, 'e') + + def load_script(self, server, scriptpath): + self.send_ex(server, 'so %s' % scriptpath) + + def preview_file(self, server, fn): + self.send_ex(server, 'pc') + self.send_ex(server, 'set nopreviewwindow') + self.send_ex(server, 'pedit %s' % fn) + + def get_bufferlist(self, server): + def cb(bl): + if bl: + l = [i.split(':') for i in bl.strip(';').split(';')] + L = [] + for n in l: + if not n[0].startswith('E'): + L.append([n[0], self.abspath(server, n[1])]) + self.do_evt('bufferlist', L) + #self.get_cwd(server) + self.send_expr(server, 'Bufferlist()', cb) + + def get_current_buffer(self, server): + def cb(bs): + bn = bs.split(chr(5)) + bn[1] = self.abspath(server, bn[1]) + self.do_evt('bufferchange', *bn) + #self.get_cwd(server) + self.send_expr(server, "bufnr('%').'\\5'.bufname('%')", cb) + + def save(self, server): + self.send_ex(server, 'w') + + def save_as(self, server, filename): + print filename + self.send_ex(server, 'saveas %s' % filename) + + def undo(self, server): + self.send_esc(server) + self.send_keys(server, 'u') + + def redo(self, server): + self.send_esc(server) + self.send_keys(server, '') + + def cut(self, server): + self.send_keys(server, '"+x') + + def copy(self, server): + self.send_keys(server, '"+y') + + def paste(self, server): + self.send_esc(server) + self.send_keys(server, 'p') + + def set_colorscheme(self, server, colorscheme): + self.send_ex(server, 'colorscheme %s' % colorscheme) + + def set_menu_visible(self, server, visible): + if visible: + op = '+' + else: + op = '-' + self.send_ex(server, 'set guioptions%s=m' % op) + + def quit(self, server): + self.send_ex(server, 'q!') + + def define_sign(self, server, name, icon, linehl, text, texthl, + direct=False): + cmd = ('sign define %s icon=%s linehl=%s text=%s texthl=%s '% + (name, icon, linehl, text, texthl)) + if direct: + self.send_ex(server, cmd) + else: + self.send_ex_via_tempfile(server, cmd) + + def undefine_sign(self, server, name): + self.send_ex(server, 'sign undefine %s' % name) + + def show_sign(self, server, index, type, filename, line): + self.send_ex(server, 'sign place %s line=%s name=%s file=%s' % + (index + 1, line, type, filename)) + + def hide_sign(self, server, index, filename): + self.send_ex(server, 'sign unplace %s' % (index + 1)) + + def get_cword(self, server, callback): + self.send_esc(server) + self.send_expr(server, 'expand("")', callback) + + def get_selection(self, server, callback): + self.send_expr(server, 'getreg("*")', callback) + + def delete_cword(self, server): + self.send_esc(server) + self.send_keys(server, 'ciw') + + def insert_text(self, server, text): + self.send_esc(server) + self.send_keys(server, 'a') + self.send_keys(server, text) + + def set_path(self, server, path): + self.send_ex(server, 'cd %s' % path) + + def add_completion(self, server, s): + self.send_expr(server, 'complete_add("%s")' % s, lambda *a: None) + + def finish_completion(self, server): + self.send_keys(server, chr(3)) + + def cb_notify(self, *a): + win, ev = a + if hasattr(ev, 'atom'): + if ev.atom == 'Comm': + message = self.window.property_get('Comm', pdelete=True) + if message: + self.cb_reply(message[-1]) + return True + + def cb_reply(self, data): + mdict = self.parse_message(data) + if mdict['t'] == 'r': + if mdict['s'] in self.callbacks: + self.callbacks[mdict['s']](mdict['r']) + else: + s = [t for t in data.split('\0') if t.startswith('-n')].pop()[3:] + self.cb_reply_async(s) + + def cb_reply_async(self, data): + if data.count(':'): + server, data = data.split(':', 1) + else: + server = None + sep = chr(4) + if data.count(sep): + evt, d = data.split(sep, 1) + self.vim_event(server, evt, d) + else: + print 'bad async reply', data + + def vim_event(self, server, evt, d): + funcname = 'vim_%s' % evt + if hasattr(self.cb, funcname): + getattr(self.cb, funcname)(server, *d.split(chr(4))) + else: + print 'unhandled event', evt + +VimCom = communication_window + diff --git a/python/coccilib/coccigui/vimeditor.py b/python/coccilib/coccigui/vimeditor.py new file mode 100644 index 0000000..43a797e --- /dev/null +++ b/python/coccilib/coccigui/vimeditor.py @@ -0,0 +1,269 @@ +# -*- coding: utf-8 -*- + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: +#Copyright (c) 2005-2006 The PIDA Project + +#Permission is hereby granted, free of charge, to any person obtaining a copy +#of this software and associated documentation files (the "Software"), to deal +#in the Software without restriction, including without limitation the rights +#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +#copies of the Software, and to permit persons to whom the Software is +#furnished to do so, subject to the following conditions: + +#The above copyright notice and this permission notice shall be included in +#all copies or substantial portions of the Software. + +#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +#SOFTWARE. + +import os +import gobject + +import pida.core.service as service +from pida.core import errors + +defs = service.definitions +types = service.types + +import vimcom + +class vim_editor(object): + + single_view = None + + class display(defs.optiongroup): + class colour_scheme(defs.option): + """The colour scheme to use in vim (Empty will be ignored).""" + rtype = types.string + default = '' + class hide_vim_menu(defs.option): + """Whether the vim menu will be hidden.""" + rtype = types.boolean + default = False + + def init(self): + self.__servers = {} + self.__documents = {} + self.__old_shortcuts = {'n':{}, 'v':{}} + self.__currentdocument = None + self._create_initscript() + self.__cw = vimcom.communication_window(self) + self.__newdocs = {} + + def _create_initscript(self): + script_path = os.path.join(self.boss.get_pida_home(), 'pida_vim_init.vim') + if not os.path.exists(script_path): + f = open(script_path, 'w') + f.write(vimcom.VIMSCRIPT) + f.close() + + def vim_init_server(self): + self.__cw.load_script(self.server, + os.path.join(self.boss.get_pida_home(), 'pida_vim_init.vim')) + + def stop_fetching_serverlist(self): + self.__cw.keep_fetching_serverlist = False + + def get_server(self): + raise NotImplementedError + + def vim_start(self): + raise NotImplementedError + + def vim_new_serverlist(self, serverlist): + raise NotImplementedError + + def cmd_start(self): + self.vim_start() + + def cmd_revert(self): + self.__cw.revert(self.server) + + def cmd_close(self, document): + if document.unique_id in self.__newdocs: + fn = self.__newdocs[document.unique_id] + else: + fn = document.filename + self.__cw.close_buffer(self.server, fn) + + def cmd_edit(self, document): + """Open and edit.""" + if document is not self.__currentdocument: + if (document.unique_id in + self.__servers.setdefault(self.server, [])): + if document.unique_id in self.__newdocs: + fn = self.__newdocs[document.unique_id] + else: + fn = document.filename + self.__cw.change_buffer(self.server, fn) + self.__cw.foreground(self.server) + else: + found = False + for server in self.__servers: + serverdocs = self.__servers[server] + if document.unique_id in serverdocs: + self.__cw.change_buffer(server, document.filename) + self.__cw.foreground(server) + found = True + break + if not found: + if document.filename is None: + newname = self.__cw.new_file(self.server) + self.__newdocs[document.unique_id] = newname + else: + self.__cw.open_file(self.server, document.filename) + self.__servers[self.server].append(document.unique_id) + self.__documents[document.unique_id] = document + self.__currentdocument = document + if self.single_view is not None: + self.single_view.raise_page() + if document.filename is None: + title = 'New File' + else: + title = document.filename + self.single_view.long_title = title + + def cmd_undo(self): + self.__cw.undo(self.server) + + def cmd_redo(self): + self.__cw.redo(self.server) + + def cmd_cut(self): + self.__cw.cut(self.server) + + def cmd_copy(self): + self.__cw.copy(self.server) + + def cmd_paste(self): + self.__cw.paste(self.server) + + def cmd_save(self): + self.__cw.save(self.server) + + def cmd_save_as(self, filename): + del self.__newdocs[self.__currentdocument.unique_id] + self.__cw.save_as(self.server, filename) + + def cmd_goto_line(self, linenumber): + self.__cw.goto_line(self.server, linenumber + 1) + + def cmd_show_mark(self, index, filename, line): + self.__cw.show_sign(self.server, index, filename, line) + + def cmd_hide_mark(self, index): + pass + + def reset(self): + colorscheme = self.opts.display__colour_scheme + if colorscheme: + self.__cw.set_colorscheme(self.server, colorscheme) + if self.opts.display__hide_vim_menu: + self.__cw.set_menu_visible(self.server, False) + #self.__load_shortcuts() + + def open_file_line(self, filename, linenumber): + if self.__currentfile != filename: + self.open_file(filename) + self.__bufferevents.append([self.goto_line, (linenumber, )]) + else: + self.goto_line(linenumber) + + def goto_line(self, linenumber): + self.__cw.change_cursor(self.server, 1, linenumber) + + def vim_bufferchange(self, server, cwd, filename, bufnr): + self.log.debug('vim buffer change "%s"', filename) + if not filename or filename in '-MiniBufExplorer-': + return + if os.path.abspath(filename) != filename: + filename = os.path.join(cwd, filename) + if os.path.isdir(filename): + if self.opts.behaviour__open_directories_in_pida: + self.boss.call_command('filemanager', 'browse', + directory=filename) + self.__cw.close_buffer(self.server, filename) + return + if self.__currentdocument is None or filename != self.__currentdocument.filename: + for uid, fn in self.__newdocs.iteritems(): + if fn == filename: + doc = self.__documents[uid] + self.__current_doc_set(doc) + return + for doc in self.__documents.values(): + if doc.filename == filename: + self.__current_doc_set(doc) + return + self.boss.call_command('buffermanager', 'open_file', + filename=filename) + + def __current_doc_set(self, doc): + self.__currentdocument = doc + self.boss.call_command('buffermanager', 'open_document', + document=doc) + + def vim_bufferunload(self, server, filename, *args): + self.log.debug('vim unloaded "%s"', filename) + if filename != '': + doc = None + for uid, fn in self.__newdocs.iteritems(): + if fn == filename: + doc = self.__documents[uid] + break + if doc is None: + for uid, document in self.__documents.iteritems(): + if document.filename == filename: + doc = document + break + if doc is not None: + self.__servers[server].remove(doc.unique_id) + del self.__documents[uid] + self.__currentdocument = None + self.boss.call_command('buffermanager', 'document_closed', + document=doc, dorefresh=True) + + def vim_started(self, server): + print 'started' + + def vim_filesave(self, server, *args): + self.boss.call_command('buffermanager', 'reset_current_document') + + def vim_globalkp(self, server, name): + self.boss.command('keyboardshortcuts', 'keypress-by-name', + kpname=name) + + def vim_shutdown(self, server, *args): + #self.clean_after_shutdown(server) + self.after_shutdown(server) + + def vim_set_breakpoint(self, server, line): + self.boss.call_command('pythondebugger', 'set_breakpoint', + filename=self.__currentdocument.filename, line=int(line)) + + def clean_after_shutdown(self, server): + for docid in self.__servers.setdefault(server, []): + doc = self.__documents[docid] + del self.__documents[docid] + self.boss.call_command('buffermanager', 'document_closed', + document=doc) + self.__servers[server] = [] + self.__currentdocument = None + + def after_shutdown(self, server): + pass + + def get_vim_window(self): + return self.__cw + vim_window= property(get_vim_window) + + def get_current_document(self): + return self.__currentdocument + current_document = property(get_current_document) + + def stop(self): + self.__cw.quit(self.server) diff --git a/python/coccilib/coccigui/vimembed.py b/python/coccilib/coccigui/vimembed.py new file mode 100644 index 0000000..483ab1d --- /dev/null +++ b/python/coccilib/coccigui/vimembed.py @@ -0,0 +1,142 @@ +# -*- coding: utf-8 -*- + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: +#Copyright (c) 2005-2006 The PIDA Project + +#Permission is hereby granted, free of charge, to any person obtaining a copy +#of this software and associated documentation files (the "Software"), to deal +#in the Software without restriction, including without limitation the rights +#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +#copies of the Software, and to permit persons to whom the Software is +#furnished to do so, subject to the following conditions: + +#The above copyright notice and this permission notice shall be included in +#all copies or substantial portions of the Software. + +#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +#SOFTWARE. + + +''' A library to embed vim in a gtk socket ''' + + +import gtk +import os +import time + + +import subprocess + +class vim_embed(object): + + HAS_CONTROL_BOX = False + + HAS_TITLE = False + + def init(self, command='gvim', args=[]): + self.__servername = self.__generate_servername() + self.pid = None + self.args = args + self.r_cb_plugged = None + self.r_cb_unplugged = None + self.__eb = None + + def __pack(self): + socket = gtk.Socket() + eb = gtk.EventBox() + self.widget.pack_start(eb) + eb.add_events(gtk.gdk.KEY_PRESS_MASK) + eb.add(socket) + self.show_all() + self.__eb = eb + return socket.get_id() + + def __generate_servername(self): + return 'PIDA_EMBEDDED_%s' % time.time() + + def get_servername(self): + return self.__servername + servername = property(get_servername) + + def should_remove(self): + self.service.remove_attempt() + return False + + def run(self, command): + self.command = command + xid = self.__pack() + args = self.args[:] # a copy + args.extend(['--socketid', '%s' % xid]) + if not xid: + return + if not self.pid: + popen = subprocess.Popen([self.command, '--servername', + self.servername, '--cmd', + 'let PIDA_EMBEDDED=1'] + args, + close_fds=True) + self.pid = popen.pid + self.show_all() + + def grab_input_focus(self): + self.__eb.child_focus(gtk.DIR_TAB_FORWARD) + +class VimEmbedWidget(gtk.EventBox): + + def __init__(self, command, script_path, args=[]): + gtk.EventBox.__init__(self) + self._servername = self._generate_servername() + self._command = command + self._init_script = script_path + self.pid = None + self.args = args + self.r_cb_plugged = None + self.r_cb_unplugged = None + self.__eb = None + + def _create_ui(self): + socket = gtk.Socket() + self.add_events(gtk.gdk.KEY_PRESS_MASK) + self.add(socket) + self.show_all() + return socket.get_id() + + def _generate_servername(self): + return 'PIDA_EMBEDDED_%s' % time.time() + + def get_server_name(self): + return self._servername + + def should_remove(self): + self.service.remove_attempt() + return False + + def run(self): + xid = self._create_ui() + args = self.args[:] # a copy + args.extend(['--socketid', '%s' % xid]) + if not xid: + return + if not self.pid: + try: + popen = subprocess.Popen( + [self._command, + '--servername', self.get_server_name(), + '--cmd', 'let PIDA_EMBEDDED=1', + '-c', 'so %s' % self._init_script + ] + args, + close_fds=True + ) + self.pid = popen.pid + except OSError: + return False + self.show_all() + return True + + def grab_input_focus(self): + self.child_focus(gtk.DIR_TAB_FORWARD) + diff --git a/python/coccilib/elems.py b/python/coccilib/elems.py new file mode 100644 index 0000000..325c8b0 --- /dev/null +++ b/python/coccilib/elems.py @@ -0,0 +1,28 @@ +class Location: + def __init__(self, file, line, column, line_end, column_end): + self.file = file + self.line = line + self.column = column + self.line_end = line_end + self.column_end = column_end + +class ElemBase: + def __init__(self): + pass + + +class Expression(ElemBase): + def __init__(self, expr): + ElemBase.__init__(self) + self.expr = expr + + def __str__(self): + return self.expr + +class Identifier(ElemBase): + def __init__(self, ident): + ElemBase.__init__(self) + self.ident = ident + + def __str__(self): + return self.ident diff --git a/python/coccilib/output.py b/python/coccilib/output.py new file mode 100644 index 0000000..b1efa8a --- /dev/null +++ b/python/coccilib/output.py @@ -0,0 +1,115 @@ +import pygtk +import gtk, gobject +import coccilib.coccigui +import coccilib.coccigui.coccigui +from threading import Thread, Lock +import time +from copy import deepcopy + +class Output: + """In order to implement an output class for use with Coccinelle, + one can inherit from this class and overload register_match with + the same number of arguments. + + include_match will be overwritten by inheriting from your actual + class, and thus if your class is a.b.C then Coccinelle will create + a Python class "class Coccinelle(a.b.C)" that hooks include_match + into the O'Caml internals. + """ + def include_match(self, b): + pass + + def register_match(self, include, messages): + pass + + def combine(self, meta_variable, locations): + nmv = deepcopy(meta_variable) + nloc = [deepcopy(loc) for loc in locations] + nmv.location = nloc[0] + nmv.locations = nloc + + return nmv + + def finalise(self): + pass + +class Console(Output): + def __init__(self): + pass + + def register_match(self, include, messages): + self.include_match(include) + if include: + for variable, message in messages: + print "%s:%s:%s: %s - %s" % (variable.location.file, variable.location.line, variable.location.column, message, variable) + +class GtkRunner(Thread): + def __init__(self): + Thread.__init__(self) + self.lock = Lock() + self.rows = [] + + def add_row(self, cocci, l): + for i in xrange(0, len(l)): + l[i] = (l[i][1], l[i][0].location.file, l[i][0].location.line, l[i][0].location.column) + + self.lock.acquire() + try: + self.rows.append((cocci, l)) + finally: + self.lock.release() + + def has_row(self): + self.lock.acquire() + try: + return len(self.rows) > 0 + finally: + self.lock.release() + + def get_row(self): + self.lock.acquire() + try: + return self.rows.pop(0) + finally: + self.lock.release() + + def update(self): + while self.has_row(): + cocci, l = self.get_row() + self.gui.add_result(cocci, l) + gobject.timeout_add(1000, self.update) + + def run(self): + self.gui = coccilib.coccigui.coccigui.pycocci() + globals()['gtk_sock'] = self.gui + gobject.timeout_add(1000, self.update) + + gtk.gdk.threads_init() + gtk.gdk.threads_enter() + + gtk.main() + + gtk.gdk.threads_leave() + + globals().pop('gtk_thread') + globals().pop('gtk_sock') + +class Gtk(Output): + def check_availability(self): + if not globals().has_key('gtk_sock'): + t = GtkRunner() + globals()['gtk_thread'] = t + globals()['gtk_thread'].start() + time.sleep(2) + + def register_match(self, include, messages): + self.check_availability() + + self.include_match(include) + if include: + globals()['gtk_thread'].add_row(self.cocci_file, messages) + + def finalise(self): + self.check_availability() + + globals()['gtk_thread'].join() diff --git a/python/no_pycocci.ml b/python/no_pycocci.ml new file mode 100644 index 0000000..d138580 --- /dev/null +++ b/python/no_pycocci.ml @@ -0,0 +1,93 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Ast_c +open Common +open Pycocci_aux +module StringMap = Map.Make (String) + +exception Pycocciexception + +let check_return_value v = failwith "no python" +let check_int_return_value v = failwith "no python" + +let initialised = ref false + +let cocci_file_name = ref "" + +(* dealing with python modules loaded *) +let get_module module_name = failwith "no python" + +let is_module_loaded module_name = failwith "no python" + +let load_module module_name = failwith "no python" +(* end python module handling part *) + +(* initialisation routines *) +let pycocci_init () = initialised := true + +(*let _ = pycocci_init ()*) +(* end initialisation routines *) + +(* python interaction *) +let split_fqn fqn = failwith "no python" + +let pycocci_get_class_type fqn = failwith "no python" + +let pycocci_instantiate_class fqn args = failwith "no python" + +(* end python interaction *) + +let inc_match = ref false + +let include_match v = failwith "no python" + +let build_method (mname, camlfunc, args) pymodule classx classdict = + failwith "no python" + +let build_class cname parent methods pymodule = failwith "no python" + +let has_environment_binding env name = failwith "no python" + +let get_cocci_file args = failwith "no python" + +let build_classes env = failwith "no python" + +let build_variable name value = failwith "no python" + +let contains_binding e (_,(r,m)) = failwith "no python" + +let construct_variables mv e = failwith "no python" + +let set_coccifile cocci_file = + cocci_file_name := cocci_file; + () + + +let pyrun_simplestring s = + failwith "no python" + +let py_isinitialized () = + failwith "no python" + +let py_finalize () = + failwith "no python" diff --git a/python/no_pycocci_aux.ml b/python/no_pycocci_aux.ml new file mode 100644 index 0000000..47f9146 --- /dev/null +++ b/python/no_pycocci_aux.ml @@ -0,0 +1,76 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Ast_c +open Common + +let rec exprrep expr = match expr with + Ast_c.Ident s -> s +| Ast_c.Constant c -> constantrep c +| Ast_c.FunCall (e,args) -> "TODO: FunCall" +| Ast_c.CondExpr (e1,e2,e3) -> "TODO: CondExpr" +| Ast_c.Sequence (e1,e2) -> "TODO: Sequence" +| Ast_c.Assignment (e1,op,e2) -> "TODO: Assignment" +| Ast_c.Postfix (e,op) -> "TODO: Postfix" +| Ast_c.Infix (e,op) -> "TODO: Infix" +| Ast_c.Unary (e,op) -> "TODO: Unary" +| Ast_c.Binary (e1,op,e2) -> "TODO: Binary" +| Ast_c.ArrayAccess (e1,e2) -> "TODO: ArrayAccess" +| Ast_c.RecordAccess (e1,s) -> "TODO: RecordAccess" +| Ast_c.RecordPtAccess (e,s) -> "TODO: RecordPtAccess" +| Ast_c.SizeOfExpr e -> "TODO: SizeOfExpr" +| Ast_c.SizeOfType t -> "TODO: SizeOfType" +| Ast_c.Cast (t,e) -> "TODO: Cast" +| Ast_c.StatementExpr c -> "TODO: StatementExpr" +| Ast_c.Constructor (t,i) -> "TODO: Constructor" +| Ast_c.ParenExpr e -> "TODO: ParenExpr" +and constantrep c = match c with + Ast_c.String (s,isWchar) -> s +| Ast_c.MultiString -> "TODO: MultiString" +| Ast_c.Char (s,isWchar) -> s +| Ast_c.Int s -> s +| Ast_c.Float (s,t) -> s + +let call_pretty f a = + let str = ref ([] : string list) in + let pr_elem info = str := (Ast_c.str_of_info info) :: !str in + let pr_sp _ = () in + f pr_elem pr_sp a; + String.concat " " (List.rev !str) + +let stringrep mvb = match mvb with + Ast_c.MetaIdVal s -> s +| Ast_c.MetaFuncVal s -> s +| Ast_c.MetaLocalFuncVal s -> s +| Ast_c.MetaExprVal ((expr,_),[il]) -> (exprrep expr) +| Ast_c.MetaExprVal e -> "TODO: <>" +| Ast_c.MetaExprListVal expr_list -> "TODO: <>" +| Ast_c.MetaTypeVal typ -> call_pretty Pretty_print_c.pp_type_gen typ +| Ast_c.MetaStmtVal statement -> "TODO: stmt" +| Ast_c.MetaParamVal params -> "TODO: <>" +| Ast_c.MetaParamListVal params -> "TODO: <>" +| Ast_c.MetaListlenVal n -> string_of_int n +| Ast_c.MetaPosVal (pos1, pos2) -> + (* Common.sprintf ("pos(%d,%d)") pos1 pos2 *) + "TODO: <>" +| Ast_c.MetaPosValList positions -> "TODO: <>" + diff --git a/python/pycocci.ml b/python/pycocci.ml new file mode 120000 index 0000000..2f2a8da --- /dev/null +++ b/python/pycocci.ml @@ -0,0 +1 @@ +no_pycocci.ml \ No newline at end of file diff --git a/python/pycocci_aux.ml b/python/pycocci_aux.ml new file mode 120000 index 0000000..003ba79 --- /dev/null +++ b/python/pycocci_aux.ml @@ -0,0 +1 @@ +no_pycocci_aux.ml \ No newline at end of file diff --git a/python/yes_pycocci.ml b/python/yes_pycocci.ml new file mode 100644 index 0000000..c252439 --- /dev/null +++ b/python/yes_pycocci.ml @@ -0,0 +1,241 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Ast_c +open Common +open Pycaml +open Pycocci_aux +module StringMap = Map.Make (String) + +exception Pycocciexception + +let check_return_value v = + if v = (pynull ()) then + (pyerr_print (); + raise Pycocciexception) + else () +let check_int_return_value v = + if v = -1 then + (pyerr_print (); + raise Pycocciexception) + else () + +let initialised = ref false + +let coccinelle_module = ref (pynone ()) +let cocci_file_name = ref "" + +(* dealing with python modules loaded *) +let module_map = ref (StringMap.add "__main__" (pynone ()) StringMap.empty) + +let get_module module_name = + StringMap.find module_name (!module_map) + +let is_module_loaded module_name = + try + let _ = get_module module_name in + true + with Not_found -> false + +let load_module module_name = + if not (is_module_loaded module_name) then + let m = pyimport_importmodule module_name in + check_return_value m; + (module_map := (StringMap.add module_name m (!module_map)); + m) + else get_module module_name +(* end python module handling part *) + +(* initialisation routines *) +let pycocci_init () = + (* initialize *) + if not !initialised then ( + initialised := true; + Unix.putenv "PYTHONPATH" + (Printf.sprintf "%s/coccinelle" (Unix.getenv "HOME")); + let _ = if not (py_isinitialized () != 0) then + (if !Flag.show_misc then Common.pr2 "Initializing python\n%!"; + py_initialize()) in + + (* set argv *) + let argv0 = Printf.sprintf "%s%sspatch" (Sys.getcwd ()) (match Sys.os_type with "Win32" -> "\\" | _ -> "/") in + let _ = pycaml_setargs argv0 in + + coccinelle_module := (pymodule_new "coccinelle"); + module_map := StringMap.add "coccinelle" !coccinelle_module !module_map; + let _ = load_module "coccilib.elems" in + let _ = load_module "coccilib.output" in + ()) else + + () + +(*let _ = pycocci_init ()*) +(* end initialisation routines *) + +(* python interaction *) +let split_fqn fqn = + let last_period = String.rindex fqn '.' in + let module_name = String.sub fqn 0 last_period in + let class_name = String.sub fqn (last_period + 1) (String.length fqn - last_period - 1) in + (module_name, class_name) + +let pycocci_get_class_type fqn = + let (module_name, class_name) = split_fqn fqn in + let m = get_module module_name in + let attr = pyobject_getattrstring(m, class_name) in + check_return_value attr; + attr + +let pycocci_instantiate_class fqn args = + let class_type = pycocci_get_class_type fqn in + let obj = pyobject_callobject(class_type, args) in + check_return_value obj; + obj + +(* end python interaction *) + +let inc_match = ref true + +let include_match v = + let truth = pyobject_istrue (pytuple_getitem (v, 1)) in + check_int_return_value truth; + inc_match := truth != 0; + pynone () + +let build_method (mname, camlfunc, args) pymodule classx classdict = + let cmx = pymethod_new(pywrap_closure camlfunc, args, classx) in + let v = pydict_setitemstring(classdict, mname, cmx) in + check_int_return_value v; + () + +let build_class cname parent methods pymodule = + let cd = pydict_new() in + check_return_value cd; + let cx = pyclass_new(pytuple_fromsingle (pycocci_get_class_type parent), cd, pystring_fromstring cname) in + check_return_value cx; + List.iter (function meth -> build_method meth pymodule cx cd) methods; + let v = pydict_setitemstring(pymodule_getdict pymodule, cname, cx) in + check_int_return_value v; + (cd, cx) + +let has_environment_binding env name = + let a = pytuple_toarray name in + let (rule, name) = (Array.get a 1, Array.get a 2) in + let orule = pystring_asstring rule in + let oname = pystring_asstring name in + let e = List.exists (function (x,y) -> orule = x && oname = y) env in + if e then pytrue () else pyfalse () + +let pyoutputinstance = ref (pynone ()) +let pyoutputdict = ref (pynone ()) + +let get_cocci_file args = + pystring_fromstring (!cocci_file_name) + +let build_classes env = + let _ = pycocci_init () in + let module_dictionary = pyimport_getmoduledict() in + coccinelle_module := pymodule_new "coccinelle"; + let mx = !coccinelle_module in + inc_match := true; + let (cd, cx) = build_class "Cocci" (!Flag.pyoutput) + [("include_match", include_match, (pynull())); + ("has_env_binding", has_environment_binding env, (pynull()))] mx in + pyoutputinstance := cx; + pyoutputdict := cd; + let v1 = pydict_setitemstring(module_dictionary, "coccinelle", mx) in + check_int_return_value v1; + let mypystring = pystring_fromstring !cocci_file_name in + let v2 = pydict_setitemstring(cd, "cocci_file", mypystring) in + check_int_return_value v2; + () + +let build_variable name value = + let mx = !coccinelle_module in + check_int_return_value (pydict_setitemstring(pymodule_getdict mx, name, value)) + +let contains_binding e (_,(r,m)) = + try + let _ = List.find (function ((re, rm), _) -> r = re && m = rm) e in true + with Not_found -> false + +let construct_variables mv e = + let find_binding (r,m) = + try + let elem = List.find (function ((re,rm),_) -> r = re && m = rm) e in + Some elem + with Not_found -> None + in + + let instantiate_Expression(x) = + let str = pystring_fromstring (Pycocci_aux.exprrep x) in + pycocci_instantiate_class "coccilib.elems.Expression" (pytuple_fromsingle (str)) + in + + let instantiate_Identifier(x) = + let str = pystring_fromstring x in + pycocci_instantiate_class "coccilib.elems.Identifier" (pytuple_fromsingle (str)) + in + + List.iter (function (py,(r,m)) -> + match find_binding (r,m) with + None -> () + | Some (_, Ast_c.MetaExprVal ((expr, _), info_list)) -> + let expr_repr = instantiate_Expression(expr) in + let _ = build_variable py expr_repr in + () + | Some (_, Ast_c.MetaIdVal id) -> + let id_repr = instantiate_Identifier(id) in + let _ = build_variable py id_repr in + () + | Some (_, Ast_c.MetaPosValList l) -> + let locs = List.map (function (fname,(line,col),(line_end,col_end)) -> + pycocci_instantiate_class "coccilib.elems.Location" (pytuple5 + (pystring_fromstring fname, + pystring_fromstring (Printf.sprintf "%d" line), + pystring_fromstring (Printf.sprintf "%d" col), + pystring_fromstring (Printf.sprintf "%d" line_end), + pystring_fromstring (Printf.sprintf "%d" col_end)))) l in + let pylocs = pytuple_fromarray (Array.of_list locs) in + let _ = build_variable py pylocs in + () + | Some (_,binding) -> + let _ = build_variable py (pystring_fromstring (Pycocci_aux.stringrep binding)) + in () + ) mv; + + () + +let set_coccifile cocci_file = + cocci_file_name := cocci_file; + () + + +let pyrun_simplestring s = + Pycaml.pyrun_simplestring s + +let py_isinitialized () = + Pycaml.py_isinitialized () + + +let py_finalize () = + Pycaml.py_finalize () diff --git a/python/yes_pycocci_aux.ml b/python/yes_pycocci_aux.ml new file mode 100644 index 0000000..efc62f3 --- /dev/null +++ b/python/yes_pycocci_aux.ml @@ -0,0 +1,79 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Ast_c +open Common +open Pycaml + +let rec exprrep expr = match expr with + Ast_c.Ident s -> s +| Ast_c.Constant c -> constantrep c +| Ast_c.FunCall (e,args) -> "TODO: FunCall" +| Ast_c.CondExpr (e1,e2,e3) -> "TODO: CondExpr" +| Ast_c.Sequence (e1,e2) -> "TODO: Sequence" +| Ast_c.Assignment (e1,op,e2) -> "TODO: Assignment" +| Ast_c.Postfix (e,op) -> "TODO: Postfix" +| Ast_c.Infix (e,op) -> "TODO: Infix" +| Ast_c.Unary (e,op) -> "TODO: Unary" +| Ast_c.Binary (e1,op,e2) -> "TODO: Binary" +| Ast_c.ArrayAccess (e1,e2) -> "TODO: ArrayAccess" +| Ast_c.RecordAccess (e1,s) -> "TODO: RecordAccess" +| Ast_c.RecordPtAccess (e,s) -> "TODO: RecordPtAccess" +| Ast_c.SizeOfExpr e -> "TODO: SizeOfExpr" +| Ast_c.SizeOfType t -> "TODO: SizeOfType" +| Ast_c.Cast (t,e) -> "TODO: Cast" +| Ast_c.StatementExpr c -> "TODO: StatementExpr" +| Ast_c.Constructor (t,i) -> "TODO: Constructor" +| Ast_c.ParenExpr e -> "TODO: ParenExpr" +and constantrep c = match c with + Ast_c.String (s,isWchar) -> s +| Ast_c.MultiString -> "TODO: MultiString" +| Ast_c.Char (s,isWchar) -> s +| Ast_c.Int s -> s +| Ast_c.Float (s,t) -> s + +let call_pretty f a = + let str = ref ([] : string list) in + let pr_elem info = str := (Ast_c.str_of_info info) :: !str in + let pr_sp _ = () in + f pr_elem pr_sp a; + String.concat " " (List.rev !str) + +let stringrep mvb = match mvb with + Ast_c.MetaIdVal s -> s +| Ast_c.MetaFuncVal s -> s +| Ast_c.MetaLocalFuncVal s -> s +| Ast_c.MetaExprVal ((expr,_),[il]) -> (exprrep expr) +| Ast_c.MetaExprVal e -> "TODO: <>" +| Ast_c.MetaExprListVal expr_list -> "TODO: <>" +| Ast_c.MetaTypeVal typ -> call_pretty Pretty_print_c.pp_type_gen typ +| Ast_c.MetaStmtVal statement -> "TODO: stmt" +| Ast_c.MetaParamVal params -> "TODO: <>" +| Ast_c.MetaParamListVal params -> "TODO: <>" +| Ast_c.MetaListlenVal n -> string_of_int n +| Ast_c.MetaPosVal (pos1, pos2) -> + let print_pos = function + Ast_cocci.Real x -> string_of_int x + | Ast_cocci.Virt(x,off) -> Printf.sprintf "%d+%d" x off in + Common.sprintf ("pos(%s,%s)") (print_pos pos1) (print_pos pos2) +| Ast_c.MetaPosValList positions -> "TODO: <>" + diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..f299124 --- /dev/null +++ b/readme.txt @@ -0,0 +1,31 @@ +Coccinelle allows programmers to easily write some complex +style-preserving source-to-source transformations on C source code, +like for instance to perform some refactorings. + +To install Coccinelle from its source, see the instructions in install.txt. +For more information on Coccinelle see the files in the docs/ directory. + +Once you have installed Coccinelle (either from the source or from one +of the binary form available on the Coccinelle website), You may have +to setup a few environment variables so that the Coccinelle program +know where to find its configuration files. +For bash do: + + source env.sh + +For tcsh do: + + source env.csh + + + +You can then test coccinelle with: + + spatch -sp_file demos/simple.cocci demos/simple.c + +If you downloaded the bytecode version of spatch you may first +have to install OCaml (which contains the 'ocamlrun' bytecode interpreter, +the equivalent of 'java', the Java virtual machine, but for OCaml) and then do: + + ocamlrun spatch -sp_file demos/simple.cocci demos/simple.c + diff --git a/runspatch.opt b/runspatch.opt new file mode 100755 index 0000000..dbe2b2f --- /dev/null +++ b/runspatch.opt @@ -0,0 +1,18 @@ +#!/bin/bash +DN=`dirname $0` + +if [ -z ${PYTHONPATH} ] +then +export PYTHONPATH=${DN}/python +else +export PYTHONPATH=${PYTHONPATH}:${DN}/python +fi + +if [ -z ${LD_LIBRARY_PATH} ] +then +export LD_LIBRARY_PATH=${DN} +else +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${DN} +fi + +${DN}/spatch.opt $* diff --git a/scripts/extract_c_and_res.pl b/scripts/extract_c_and_res.pl new file mode 100755 index 0000000..4ef3f64 --- /dev/null +++ b/scripts/extract_c_and_res.pl @@ -0,0 +1,231 @@ +#!/usr/bin/perl -w +use strict; + +sub pr2 { print "$_[0]\n"; } +sub mylog { print @_;} + + +# to be launched from the git directory +die "usage: $0 commithashafter [commithashbefore]" + if(@ARGV <= 0 || @ARGV >= 3); + +# update: now I also extract the headers files, the one +# that were modified in the commit and the one that are +# locally used and that may contain useful type information +# for spatch. + +# update: now I also extract some include/linux/header.h files, the +# one having the same name of one of the driver. + +my $target_dir = "/tmp/extract_c_and_res/$ARGV[0]"; +`mkdir -p $target_dir`; +my $old_dir = "/tmp/extract_c_and_res/$ARGV[0]_old"; +`mkdir -p $old_dir`; +my $new_dir = "/tmp/extract_c_and_res/$ARGV[0]_new"; +`mkdir -p $new_dir`; + +my $commit_new = $ARGV[0]; +my $commit_old = $ARGV[1] || "$commit_new^"; # default parent + +my $gitfile = "$target_dir/$commit_new.gitinfo"; +my $makefile = "$target_dir/Makefile"; + +`git show $commit_new > $gitfile `; + + +# processing the patch + +my @files = (); +my $files = {}; +my @driverheaders_in_include = (); + + +open FILE, "$gitfile" or die "$!"; +while() { + + # allow other dir ? # fs|mm there is drivers under arch/ too + if(/^diff --git a\/((drivers|sound)\/.*?\.[ch]) b/){ + mylog " $1\n"; + + push @files, $1; + $files->{$1} = 1; + + } + elsif(/^diff --git a\/(include\/.*?\.h) b/) { + mylog "potential header driver $1\n"; + push @driverheaders_in_include, $1; + } + elsif(/^diff --git a\//) { + mylog " not driver:$_"; + } + elsif(/^diff/) { + die "PB: strange diff line: $_"; + } +} + +# extracting the .c and .h of the patch + +my $counter=0; + +# to be able to later find the corresponding local included header file +my $kerneldir_of_file = {}; + +my @finalcfiles = (); +my $finalcfiles = {}; + +foreach my $f (@files) { + my ($base) = `basename $f`; + chomp $base; + my $res = $base; + if($base =~ /\.c$/) { + $res =~ s/\.c$/.res/; + } + if($base =~ /\.h$/) { + $res =~ s/\.h$/.h.res/; + } + + pr2 "processing: $f $base $res"; + if(-e "$target_dir/$base") { + $counter++; + $base = "${counter}_$base"; + $res = "${counter}_$res"; + pr2 "try transform one file because already exist: $base"; + if($base =~ /\.h$/) { + die "PB: Two header files share the same name: $base."; + } + + } + die "PB: one of the file already exist: $base" if (-e "$target_dir/$base"); + + `git-cat-file blob $commit_old:$f > $target_dir/$base`; + `git-cat-file blob $commit_new:$f > $target_dir/$res`; + + `git-cat-file blob $commit_old:$f > $old_dir/$base`; + `git-cat-file blob $commit_new:$f > $new_dir/$base`; + + $kerneldir_of_file->{$base} = `dirname $f`; + chomp $kerneldir_of_file->{$base}; + + push @finalcfiles, $base; + $finalcfiles->{$base} = 1; + + +} + +# generate Makefile + +open MAKE, ">$makefile" or die "$!"; +print MAKE "CEDESCRIPTION=\"\"\n"; +print MAKE "SP=foo.cocci\n"; +print MAKE "SOURCES = "; +my $last = shift @finalcfiles; +foreach my $f (@finalcfiles) { + print MAKE "$f \\\n\t"; +} +print MAKE "$last\n"; + +print MAKE " + +TOP=../.. +include \$(TOP)/generic_makefile +"; + + + +# process potential driver headers of include/ + +foreach my $f (@driverheaders_in_include) { + my $base = `basename $f`; + chomp $base; + if($base =~ /.h$/) { + $base =~ s/.h$/.c/; + } else { die "PB: internal error"; } + + +# julia want all .h that were in the patch, not just the headers +# of our heuristic. Hence the comment. + +# pr2 "$f $base"; +# if(defined($finalcfiles->{$base})) { + { +# pr2 "found header of driver in include/: $f of $base"; + my $dir = `dirname $f`; + chomp $dir; + `mkdir -p $target_dir/$dir`; + `git-cat-file blob $commit_old:$f > $target_dir/$f`; + `git-cat-file blob $commit_new:$f > $target_dir/$f.res`; + + `mkdir -p $old_dir/$dir`; + `mkdir -p $new_dir/$dir`; + `git-cat-file blob $commit_old:$f > $old_dir/$f`; + `git-cat-file blob $commit_new:$f > $new_dir/$f`; + + } +} + +# compute other linux headers not in the patch + +my @linuxheaders = `cd $target_dir; grep -E \"#include +\<[^>]*\>\" *.c *.h`; +foreach my $line (@linuxheaders) { + chomp $line; + #pr2 ($line); + if($line =~ /^(.*)?:#include *\<([^>]*)\>/) { + my ($_file, $f) = ($1, $2); + + my $base = `basename $f`; + chomp $base; + if($base =~ /.h$/) { + $base =~ s/.h$/.c/; + } else { die "PB: internal error"; } + + if(defined($finalcfiles->{$base}) && ! -e "$target_dir/include/$f") { + pr2 "found header of driver in include/: $f of $base"; + my $dir = `dirname $f`; + chomp $dir; + `mkdir -p $target_dir/include/$dir`; + `git-cat-file blob $commit_old:include/$f > $target_dir/include/$f`; + } + } else { pr2 "pb regexp: $line"; } +} + + +# compute other local headers not in the patch + +my @headers = `cd $target_dir; grep -E \"#include +\\".*\\"\" *.c *.h`; + +my $hfiles = {}; +foreach my $line (@headers) { + chomp $line; + #pr2 ($line); + if($line =~ /^(.*)?:#include *"(.*)"/) { + + my ($file, $header) = ($1, $2); + my $dir = $kerneldir_of_file->{$file}; + + my $fullheader = "$dir/$header"; + #pr2 ($fullheader); + + if($files->{$fullheader}) { + pr2 "INFO: $fullheader was already in commit"; + } else { + $hfiles->{$fullheader} = 1; + } + + } else { pr2 "pb regexp: $line"; } + +} + +foreach my $h (keys %{$hfiles}) { + my ($base) = `basename $h`; + chomp $base; + pr2 "processing additionnal header file: $h $base"; + + if(-e "$target_dir/$base") { + pr2 "-------------------------------------"; + pr2 "PB: local header (not modified in the git) $base already exists"; + pr2 "BUT I CONTINUE, but may have more .failed in the end"; + pr2 "-------------------------------------"; + } else { + `git-cat-file blob $commit_old:$h > $target_dir/$base`; + } +} diff --git a/scripts/extract_examples.pl b/scripts/extract_examples.pl new file mode 100755 index 0000000..f0fed0a --- /dev/null +++ b/scripts/extract_examples.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl +#usage: ./extract_examples.pl ~/week-end/working-documents/examples.tex + +my $ex = 0; +my $are_in = 0; +while(<>) { + + if(/\\section{/) { + $ex++; + open TMP, ">$ex.cocci" or die "$!"; + } + + if(/begin{verbatim}/) { + $are_in = 1; + #old: open TMP, ">$ex.cocci" or die "$!"; + } elsif(/end{verbatim}/) { + $are_in = 0; + #old: $ex++; + } else { + if($are_in) { print TMP "$_"; } + } +} diff --git a/scripts/extractor.awk b/scripts/extractor.awk new file mode 100755 index 0000000..b718a72 --- /dev/null +++ b/scripts/extractor.awk @@ -0,0 +1,94 @@ +#!/usr/bin/awk -f +# +# Extracting time statistics from .failed/.ok files +# + +BEGIN { + no_of_files = 0; + max_running_time = 0.0; + max_running_file = ""; + min_running_time = 100000.0; + min_running_file = ""; + sum_running_time = 0.0; + + min_file_size_lines = 0; + max_file_size_lines = 0; + tot_file_size_lines = 0; + min_file_size_bytes = 0; + max_file_size_bytes = 0; + tot_file_size_bytes = 0; +} +/real[ \t]+[0-9]+m[0-9]+[.][0-9]+/{ + + # The file currently processed + current_file = FILENAME; + + # Count the number of files + no_of_files++; + + # Parse time field + split($2,timearr,/[m.]/); + current_time = timearr[1] * 60.0; # minutes + current_time += timearr[2]; # seconds + current_time += timearr[3] / 1000.0; # 1/1000th sec. + + # Print progress + printf "%6.3fs (%s)\n", current_time, current_file; + + # Update total time + sum_running_time += current_time; + + # Update max and min + if(current_time > max_running_time) + { + max_running_time = current_time; + max_running_file = current_file; + } + if(current_time < min_running_time) + { + min_running_time = current_time; + min_running_file = current_file; + } + + # Find corresponding .c file + gsub(/.(ok|failed|spatch_ok|gave_up)$/,".c",current_file); + + # Update file sizes (in lines) + ("wc -l " current_file) | getline; + current_size_lines = $1; + tot_file_size_lines += current_size_lines; + if(current_size_lines > max_file_size_lines) + { + max_file_size_lines = current_size_lines; + } + if(current_size_lines < min_file_size_lines) + { + min_file_size_lines = current_size_lines; + } + + # Update file sizes (in bytes) + ("du " current_file) | getline; + current_size_bytes = $1; + tot_file_size_bytes += current_size_bytes; + if(current_size_bytes > max_file_size_bytes) + { + max_file_size_lines = current_size_bytes; + } + if(current_size_bytes < min_file_size_bytes) + { + min_file_size_bytes = current_size_bytes; + } +} +END { + printf "!!No. of files : %6d\n", no_of_files; + printf " Total # of lines: %6d\n", tot_file_size_lines; + printf "!!Avg. # of lines : %9.2f\n", (tot_file_size_lines / no_of_files); + printf " Total size (KB) : %6d\n", tot_file_size_bytes; + printf " Avg. size (KB) : %9.2f\n", (tot_file_size_bytes / no_of_files); + printf " Minimum time : %9.2fs (%s)\n", + min_running_time, min_running_file; + printf "!!Maximum time : %9.2fs (%s)\n", + max_running_time, max_running_file; + printf " Total time : %9.2fs\n", sum_running_time; + printf "!!Average time : %9.2fs\n", (sum_running_time / no_of_files); +} diff --git a/scripts/extractor_README.pl b/scripts/extractor_README.pl new file mode 100755 index 0000000..2339422 --- /dev/null +++ b/scripts/extractor_README.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl + +use strict; + +my $ok = 0; #ok+spatch-ok +my $wrong = 0; #Error, file level +my $fail = 0; +my $unknown = 0; +my $nbfiles = 0; + +my $bugfix = 0; # site level ? +my $wrongsites = 0; # Error, site level + +my $SP = ""; + +while(<>) { + + if(/\[status\]/) { $nbfiles++; } + + if(/\[status\]\s*(spatch-ok|ok)\b/) { $ok++; } + if(/\[status\]\s*(wrong)\b/) { $wrong++; } + if(/\[status\]\s*(fail)\b/) { $fail++; } + + if(/\[status\]\s*(UNKNOWN)\b/) { $unknown++; } + + if(/Cocci\s+file\s*:\s*(\w+.cocci)/) { $SP = $1; } + +} + +my $pourcentcorrect = ($ok * 100.0) / $nbfiles; + +print "----------------------------------------\n"; +print "!!Total files = $nbfiles\n"; +print " Correct number = $ok\n"; +printf "!!Correct = %3.1f\%\n", $pourcentcorrect; +print "!!Error = $wrong\n"; +print "!!Bugfix (sites) = $bugfix\n"; + + +my $sizeSP = `cat $SP | perl -p -e "s/\\/\\/.*//g;" | grep -v '^[ \t]*\$' | wc -l`; +chomp $sizeSP; +print "!!Size SP = $sizeSP\n"; + +my $gitinfo = `ls *.gitinfo`; +chomp $gitinfo; +print " gitinfo files = $gitinfo\n"; + +my $sizeP = `cat *.gitinfo | wc -l`; +chomp $sizeP; +print " Size P = $sizeP\n"; + +my $ratioSPvsP = ($sizeSP * 100.0) / $sizeP; +printf "!!Ratio SP vs P = %3.1f\%\n", $ratioSPvsP; + +my $ratioPvsSP = $sizeP / $sizeSP; +printf "!!Ratio SP vs P = %3.1f\n", $ratioPvsSP; + + +my $totalstatus = $ok + $fail + $wrong + $unknown; +print "----------------------------------------------------------------\n"; +print "Sanity checks: nb files = $nbfiles, total status = $totalstatus\n"; +print "NB UNKNOWNS = $unknown\n" if $unknown > 0; diff --git a/scripts/gather_failed.pl b/scripts/gather_failed.pl new file mode 100755 index 0000000..11f32b1 --- /dev/null +++ b/scripts/gather_failed.pl @@ -0,0 +1,12 @@ +#!/usr/bin/perl + +# usage: gather_failed.pl **/*.failed > /tmp/big.failed + +print "-*- mode: outline; -*-\n"; + +map { + print "* FAILED FILE: $_\n"; + print "\n"; + system("cat $_"); + +} @ARGV; diff --git a/scripts/glimpseindex_cocci.sh b/scripts/glimpseindex_cocci.sh new file mode 100755 index 0000000..8b91529 --- /dev/null +++ b/scripts/glimpseindex_cocci.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +find `pwd`/* -name "*.[ch]" | glimpseindex -o -H . -F diff --git a/scripts/readme.pl b/scripts/readme.pl new file mode 100755 index 0000000..84b7091 --- /dev/null +++ b/scripts/readme.pl @@ -0,0 +1,79 @@ +#!/usr/bin/perl +# +# ARGV: 0 = replacement text, 1 = file w. list of files +# + +$debug = 0; +$retain = 1; # 1 = retain old status + +#---------------------------------------------------------------------- +$header = 0; # 0 = not seen header yet; 1 = seen beginning; 2 = seen end + +$currentfile = ""; +$currentstatus = ""; +$oldstatus = ""; +@files = (); + +# Get replacement text +$replace = shift; + +# Get files of interest +open(FILES,shift); +@files = ; +close(FILES); + +# Remove file name suffixes +foreach $_ (@files) { + s/^([^.]+)\..+$/\1/; + chop; + print "--> added [$_]\n" if $debug; +} + +# Process std. input +while(<>) { + + # Find an ignore header + if(/^-+$/) { + $header = $header + 1; + } + + # + if($header > 1) { + + # Filename + if(/^([0-9a-zA-Z_-]+)\.c\s*$/) { + $currentfile = $1; + $currentstatus = ""; + print "--> currentfile: [$currentfile]\n" if $debug; + } + + # Status code + if(/^(\s+\*\s+)\[status\]([ \t\f]*)(\S*)$/) { + $currentstatus = $3; + + print "--> $currentfile [$currentstatus]\n" if $debug; + + if(grep {/^$currentfile$/} @files) { + s/^(\s+\*\s+\[status\])[ \t\f]*(.*)$/\1 $replace/; + print "==>" if $debug; + + if($retain && ($currentstatus ne "")) { + $oldstatus = " * [old-status] $currentstatus\n"; + } + } + + $currentfile =""; + + } + + } + + # + print "$_"; + + if($oldstatus ne "") { + print $oldstatus; + $oldstatus = ""; + } + +} diff --git a/scripts/stat_directories.pl b/scripts/stat_directories.pl new file mode 100755 index 0000000..10821a7 --- /dev/null +++ b/scripts/stat_directories.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl + +#usage: +# cd tests-big; +# ~/coccinelle/scripts/stat_directories.pl bluetooth/* rules/* megas/* + +printf "%-20s %10s %10s %4s\n", "dir/", "failed" , "total", "%ok"; +print "------------------------------------------------------\n"; + +$totalfailed = 0; +$total = 0; + +foreach my $dir (@ARGV) { + + if(-e "$dir/") { + my ($ok) = `find $dir -name "*.c.*ok" | wc -l`; +# my ($ok) = `find $dir -name "*ok" | wc -l`; + chomp $ok; + my ($failed) = `find $dir -name "*.c.failed" | wc -l`; +# my ($failed) = `find $dir -name "*failed" | wc -l`; + chomp $failed; + $totalfailed += $failed; + my $sum = $failed + $ok; + $total += $sum; + if ($sum == 0) { + print "$dir/ have 0 sum\n"; + } else { + my $pourcent = ($ok * 100.0) / ($sum); + printf "%-20s %10d %10d %5.1f%%\n", "$dir/", $failed, $sum, $pourcent; + } + } + + +} + +my $pourcent = (($total - $totalfailed) * 100.0) / ($total); + +print "------------------------------------------------------\n"; +printf "total failed = %10d / %10d % 3.1f%%\n", + $totalfailed, $total, $pourcent; diff --git a/scripts/stat_directories_complete.pl b/scripts/stat_directories_complete.pl new file mode 100755 index 0000000..58578ea --- /dev/null +++ b/scripts/stat_directories_complete.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl + +#usage: + +if(@ARGV < 1) { die "usage: stat_directories_complete.pl [M|C|B]";} +my $kind = "$ARGV[0]"; + + +my $subdirs = `make subdirs`; +#my $subdirs = "rule9"; +#my $subdirs = "rule1"; +chomp $subdirs; +@subdirs = split /\s+/, $subdirs; + + +my $i = 0; +foreach my $dir (@subdirs) { + if(-e "$dir/") { + #print "RULE: $dir\n"; + + my ($s) = + `cd $dir; ~/coccinelle/scripts/stat_directory_complete.pl | grep $kind:`; + chomp $s; + $i++; + #print "M$i.$s\n"; + $s =~ s/$kind:/$kind$i./; + print "$s\n"; + } + +} diff --git a/scripts/stat_directory_complete.pl b/scripts/stat_directory_complete.pl new file mode 100755 index 0000000..a7d35d2 --- /dev/null +++ b/scripts/stat_directory_complete.pl @@ -0,0 +1,367 @@ +#!/usr/bin/perl + +use strict; +use diagnostics; + +#use Data::Dumper; +#use Date::Manip qw(ParseDate UnixDate); #sudo apt-get install libdate-manip-perl +#use Date::Calc qw(Delta_Days); #sudo apt-get install libdate-calc-perl + +#------------------------------------------------------------------------------ +# Helpers +#------------------------------------------------------------------------------ + +my $debug = 0; + +sub pr2 { print STDERR "@_\n"; } +sub pr { print "@_\n"; } +sub mylog { print STDERR "@_\n" if $debug; } + +sub plural { + my ($n) = @_; + $n > 1 ? "s" : ""; +} + +#------------------------------------------------------------------------------ +# Globals +#------------------------------------------------------------------------------ + +my $ok = 0; +my $so = 0; #spatch ok +my $fa = 0; #failed +my $gu = 0; #gave up + +my $nbfiles = 0; + +my $maxtime = 0; +#my $mintime = 0; +my $sumtime = 0; + +my $sumlinefiles = 0; + +my $errors = 0; + +my $sumlineP = 0; #whole git +my $sumlineP2 = 0; +my $sumlinePchange = 0; + +my $spfile = ""; +my $ruleno = "??"; +my $sizeSP = 0; + +my $cedescr = ""; + +my $numauthors = 0; +my $duration = 0; # in days + +my @cfiles = (); + +#------------------------------------------------------------------------------ +# SP +#------------------------------------------------------------------------------ +$spfile = `make sp_file`; +chomp $spfile; + +if($spfile =~ /(rule|mega|bt)(\d+)\.cocci/) { $ruleno = "$2"; } + +#------------------------------------------------------------------------------ +# CE +#------------------------------------------------------------------------------ + +#$cedescr = `make ce_descr`; +#chomp $cedescr; +#print STDERR (Dumper($cedescr)); +open TMP, "Makefile" or die "no Makefile file ?"; +while() { + if(/^(CE)?DESCRIPTION=["'](.*)["']/) { $cedescr = $2; } +} + + + +#$cedescr =~ s/\\/\\\\/g; +#$cedescr =~ s/ /\\f/g; +#$cedescr =~ s/\t/\\t/g; + +#------------------------------------------------------------------------------ +# List c files +#------------------------------------------------------------------------------ +my $files = `make source_files`; +chomp $files; +@cfiles = split /\s+/, $files; + +$nbfiles = scalar(@cfiles); + +#------------------------------------------------------------------------------ +# Size files (lines) +#------------------------------------------------------------------------------ +map { + my ($linefile) = `wc -l $_`; + chomp $linefile; + die "wierd wc output" unless $linefile =~ /^(\d+) /; + $sumlinefiles += $1; + mylog "filesize $_ $1"; +} @cfiles; + + +#------------------------------------------------------------------------------ +# Size SP +#------------------------------------------------------------------------------ +$sizeSP = + `cat $spfile | perl -p -e "s/\\/\\/.*//g;" | grep -v '^[ \t]*\$' | wc -l`; +chomp $sizeSP; + + +#------------------------------------------------------------------------------ +# Bugs +#------------------------------------------------------------------------------ +if(!(-e "README")) { pr2 "no README file ?"; } +else { + open TMP, "README" or die "no README file ?"; + while() { + if (/\[bug\]/ || /status\]\s*bug/ || /status\]\s*BUG/ ) { + + # can also look for [semibug] but it's often related to [corrected_c] kind of pbs + #|| /status\]\s*semi-bug/ + + #pr2 "OLD BUG FORMAT: $_"; + $errors++ + } + } +} + + + +#------------------------------------------------------------------------------ +# Size P (total) +#------------------------------------------------------------------------------ + +if(-e "gitinfo") { + ($sumlineP) = `cat gitinfo |wc -l`; + chomp $sumlineP; +} else { + pr2 "no GIT INFO?"; +} + +#------------------------------------------------------------------------------ +# Number of authors and duration +#------------------------------------------------------------------------------ + + +if(-e "gitinfo") { + + open TMP, "gitinfo" or die "no gitinfo file ?"; + + #for authors + my $h = {}; + + #for duration + my @mindate = (); + my @maxdate = (); + my $nodateyet = 1; + + while() { + #can also do: egrep "^Author" gitinfo | sort | uniq | wc -l + if (/^Author: (.*)/) { + $h->{$1}++; + } + +# if(/^Date: (.*) ([-+]\d+)?/) { +# my $date = ParseDate($1); +# if (!$date) { die "bad date" } +# else { +# my ($year, $month, $day) = UnixDate($date, "%Y", "%m", "%d"); +# my @current = ($year, $month, $day); +# if($nodateyet) { +# @mindate = @current; +# @maxdate = @current; +# $nodateyet = 0; +# } else { +# my $diff1 = Delta_Days(@mindate, @current); +# if($diff1 < 0) { @mindate = @current; } +# my $diff2 = Delta_Days(@current, @maxdate); +# if($diff2 < 0) { @maxdate = @current; } +# +# #pr2 "$diff1, $diff2"; +# } +# } +# } + + + + } + +# my $diff = Delta_Days(@mindate, @maxdate); +# if($diff == 1 || $diff == 0) { +# $duration = "1 day"; +# } +# elsif($diff < 31) { +# $duration = "$diff days"; +# } +# elsif($diff > 365) { +# my $years = int($diff / 365); +# my $s = plural($years); +# $duration = "$years year$s"; +# } +# elsif($diff > 31) { +# my $months = int($diff / 31); +# my $s = plural($months); +# $duration = "$months month$s"; +# } +# else { die "impossible"; } + + $duration = "xxx months"; + + $numauthors = scalar(keys %{$h}); +} else { + pr2 "no GIT INFO?"; +} + + +#------------------------------------------------------------------------------ +# Size P (only change for .c in drivers/ or sounds/ (the test files)) +#------------------------------------------------------------------------------ + + +foreach my $c (@cfiles) { + die "wierd: $c, with $spfile" unless ($c =~ /(.*)\.c$/); + my $base = $1; + my $bef = "$base.c"; + my $aft = "$base.res"; + if(-e "corrected_$base.res") { + $aft = "corrected_$base.res"; + mylog "found corrected"; + } + my $onlychange = 0; + open TMP, "diff -u -b -B $bef $aft |"; + + my $count = 0; + while() { + $count++; + + if (/^\+[^+]/) { $onlychange++; } + if (/^\-[^-]/) { $onlychange++; } + } + $sumlinePchange += $onlychange; + $sumlineP2 += $count; +} + +#------------------------------------------------------------------------------ +# Time +#------------------------------------------------------------------------------ +foreach my $c (@cfiles) { + die "" unless ($c =~ /(.*)\.c$/); + my $base = $1; + + my $diagnosefile = ""; + mylog "$base"; + + if(-e "$base.c.ok") { $ok++; $diagnosefile = "$base.c.ok"; } + if(-e "$base.c.failed") { $fa++; $diagnosefile = "$base.c.failed"; } + if(-e "$base.c.spatch_ok") { $so++; $diagnosefile = "$base.c.spatch_ok"; } + if(-e "$base.c.gave_up") { $gu++; $diagnosefile = "$base.c.gave_up"; } + + open TMP, $diagnosefile or die "no diagnose $base: $diagnosefile"; + my $found = 0; + my $time = 0; + while() { +# before -test_okfailed +# if (/real[ \t]+([0-9])+m([0-9]+)[.]([0-9]+)/) { +# $found++; +# +# $time = $1 * 60.0; # minutes +# $time += $2; # seconds +# $time += $3 / 1000.0; # 1/1000th sec. +# +# pr2 (sprintf "%4.1fs\n", $time); +# printf "I: %15s & %4.1fs\n", $c, $time; +# +# } + if (/time: (.*)/) { + $found++; + + $time = $1; + + mylog (sprintf "%4.1fs\n", $time); + printf "I: %15s & %4.1fs\n", $c, $time; + + } + + + } + die "not found time information in $diagnosefile" unless $found == 1; + + $sumtime += $time; + $maxtime = $time if $time > $maxtime; + +} + +#------------------------------------------------------------------------------ +# Computations +#------------------------------------------------------------------------------ + +my $correct = $ok + $so; + +my $pourcentcorrect = ($correct * 100.0) / $nbfiles; +my $avglines = $sumlinefiles / $nbfiles; +my $avgtime = $sumtime / $nbfiles; + + +my $ratioPvsSP = $sumlineP / $sizeSP; +my $ratioPvsSP2 = $sumlineP2 / $sizeSP; + + +#------------------------------------------------------------------------------ +# Results +#------------------------------------------------------------------------------ + + +pr "SP = $spfile"; +mylog "FILES = \n"; +map { mylog "\t$_"; } @cfiles; +pr "----------------------------------------"; + + +pr "!!Total files = $nbfiles"; +printf "!!AvgLine = %.1fl\n", $avglines; + +#pr " Correct number = $correct"; +printf "!!Correct = %.1f%s\n", $pourcentcorrect, "%"; + +pr "!!Human errors = $errors"; + +pr "!!Size SP = $sizeSP"; +pr "!!Size P = $sumlineP"; +pr "!!Size P (change only) = $sumlinePchange"; + +printf "!!Ratio P/SP = %3.1f\n", $ratioPvsSP; + + +printf "!!RunTime = %.1fs\n", $sumtime; +printf "!!MaxTime = %.1fs\n", $maxtime; +printf "!!AvgTime = %.1fs\n", $avgtime; + +my $totalstatus = $ok + $fa + $so + $gu; +mylog "----------------------------------------------------------------"; +mylog "Sanity checks: nb files vs total status: $nbfiles =? $totalstatus"; + + + +printf "L: %20s (r%3s) & %5.1f%% & %5dfi & %2de & %6.1fx & %6.1fs \n", + $cedescr, $ruleno, $pourcentcorrect, $nbfiles, $errors, $ratioPvsSP, $sumtime; + + +# Mega, Complex, Bluetooth + +printf "M: %60s & %5d & %6d (%d) & %2d & %s & %2d & %3d & %6.0fx & %6.1fs (%.1fs) & %5.0f\\%% \\\\\\hline%% SP: %s \n", + $cedescr, $nbfiles, $sumlineP, $sumlinePchange, $numauthors, $duration, $errors, $sizeSP, $ratioPvsSP, + $avgtime, $maxtime, $pourcentcorrect, $spfile; + +printf "C: %60s & %5d & %6d (%d) & %2d & %3d & %6.0fx & %6.1fs (%.1fs) & %5.0f\\%% \\\\\\hline%% SP: %s \n", + $cedescr, $nbfiles, $sumlineP, $sumlinePchange, $errors, $sizeSP, $ratioPvsSP, + $avgtime, $maxtime, $pourcentcorrect, $spfile; + +printf "B: %60s & %5d & %5d (%d) & %3d & %6.0fx & %6.1fs (%.1fs) & %5.0f\\%% \\\\\\hline%% SP: %s \n", + $cedescr, $nbfiles, $sumlineP, $sumlinePchange, $sizeSP, $ratioPvsSP, + $avgtime, $maxtime, $pourcentcorrect, $spfile; + + diff --git a/standard.h b/standard.h new file mode 100644 index 0000000..854f414 --- /dev/null +++ b/standard.h @@ -0,0 +1,787 @@ +// clone: yacfe(master), coccinelle, acomment, + +// **************************************************************************** +// Prelude, this file is to be used with the -macro_file option of the C parser +// **************************************************************************** + +/* This file contains: + * - macros found in <.h> + * - macros found in .c; macros that cannot be parsed. + * In the future should be autodetected + * (not so easy to do same for macros in .h cos require to access .h file) + * - macros found in ".h" + * but where we cant detect that it will be a "bad macro" + * - macros found in .c; macros correctly parsed + * but where we cant detect that it will be a "bad macro" + * + * Some of those macros could be deleted and the C code rewritten because + * they are "bad" macros. + * + * todo? perhaps better if could enable/disable some of those expansions + * as different software may use conflicting macros. + * + * + * can maybe have a look in sparse/lib.c to see a list of default #define + * handled builtin apparently by gcc. + */ + +// **************************************************************************** +// Test macros +// **************************************************************************** + +// #define FOO(a, OP, b) a OP b +// #define FOO(a,b) fn(a,b) + + +// **************************************************************************** +// Generic macros +// **************************************************************************** + +// **************************************************************************** +// Yacc macros +// **************************************************************************** + +#define YY_PROTO(x) x +#define yyconst const + + +// **************************************************************************** +// GNU Hello macros +// **************************************************************************** + +#define __getopt_argv_const const + + +// **************************************************************************** +// Gcc (as in the source of gcc code) macros +// **************************************************************************** + + +// **************************************************************************** +// Linux macros +// **************************************************************************** + +// ---------------------------------------------------------------------------- +// Attributes. could perhaps generalize via "__.*" +// ---------------------------------------------------------------------------- +#define __init +#define __exit +#define __user +#define __iomem +#define __initdata +#define __exitdata +#define __devinit +#define __devexit +#define __devinitdata +#define __cpuinit +#define __cpuinitdata +#define __init_or_module +#define __initdata_or_module +#define __pminit +#define __pminitdata + +#define __cacheline_aligned +#define ____cacheline_aligned +#define __cacheline_aligned_in_smp +#define ____cacheline_aligned_in_smp +#define ____cacheline_internodealigned_in_smp + +#define __ALIGNED__ +#define __3xp_aligned + +#define __pmac +#define __force +#define __nocast +#define __read_mostly + +#define __must_check +// pb +#define __unused +#define __maybe_unused + + +#define __attribute_used__ +#define __attribute_pure__ +#define __attribute_const__ +// #define _attribute__const __attribute__((const)) + +#define __always_inline + +#define __xipram + +// in the other part of the kernel, in arch/, mm/, etc +#define __sched +#define __initmv +#define __exception +#define __cpuexit +#define __kprobes +#define __meminit +#define __meminitdata +#define __nosavedata +#define __kernel +#define __nomods_init +#define __apicdebuginit +#define __ipc_init +#define __modinit +#define __lockfunc +#define __weak +#define __tlb_handler_align +#define __lock_aligned +#define __force_data +#define __nongprelbss +#define __nongpreldata +#define __noreturn + +#define __section_jiffies +#define __vsyscall_fn +#define __section_vgetcpu_mode +#define __section_vsyscall_gtod_data + +// in header files +#define __bitwise +#define __bitwise__ +#define __deprecated + + +// last found +#define __init_refok + + +// maybe only in old kernel +#define __openfirmware + + +#define __extension__ + +#define __thread +#define __used +#define __pure + +#define __ref +#define __refdata + +#define __uses_jump_to_uncached + +// ---------------------------------------------------------------------------- +// String macros +// ---------------------------------------------------------------------------- + +/* string macro. normally handle quite well by mu lalr(k), but + * sometimes not enough, if have for instance the XX YY case, could + * be considered as a declaration with XX being a typedef, so would + * Have ambiguity. So at least by adding this special case, we can + * catch more correct string-macro, no more a XX YY but now a good + * "XX" YY + * + * cf include/linux/kernel.h + * + * For stringification I need to have at least a witness, a string, + * and sometimes have just printk(KERN_WARNING MYSTR) and it could + * be transformed in a typedef later, so better to at least + * transform in string already the string-macro we know. + * + * Perhaps better to apply also as soon as possible the + * correct macro-annotation tagging (__init & co) to be able to + * filter them as soon as possible so that they will not polluate + * our pattern-matching that come later. + */ + +#define KERN_EMERG "KERN_EMERG" +#define KERN_ALERT "KERN_ALERT" +#define KERN_CRIT "KERN_CRIT" +#define KERN_ERR "KERN_ERR" +#define KERN_WARNING "KERN_WARNING" +#define KERN_NOTICE "KERN_NOTICE" +#define KERN_INFO "KERN_INFO" +#define KERN_DEBUG "KERN_DEBUG" + + +/* EX_TABLE & co. + * + * Replaced by a string. We can't put everything as comment + * because it can be part of an expression where we wait for + * something, where we wait for a string. So at least we + * must keep the EX_TABLE token and transform it as a string. + * + * normally not needed if have good stringification of macro + * but those macros are sometimes used multiple times + * as in EX_TABLE(0b) EX_TABLE(1b) and we don't detect + * it well yet. + */ + +// TODO don't use x :( +#define EX_TABLE(x) "TOTO" +#define ASM_EXCEPTIONTABLE_ENTRY(x) "TOTO" +#define DCACHE_CLEAR(x) "TOTO" +#define PPC405_ERR77(x) "TOTO" + + + + +// ---------------------------------------------------------------------------- +// Alias keywords +// ---------------------------------------------------------------------------- +// pb, false positive, can also be a #define cst and use as 'case CONST:' +//#define CONST const + + +#define STATIC static +#define _static static + +#define noinline + +#define __CS4231_INLINE__ inline +#define CCIO_INLINE inline +#define SBA_INLINE inline + +#define STATIC_INLINE static inline +#define __EXTERN_INLINE extern inline + +#define AGPEXTERN extern + +#define PNMI_STATIC static +#define RLMT_STATIC static +#define SISINITSTATIC static +#define SCTP_STATIC static + +#define BUGLVL if +#define IFDEBUG if + +#define TRACE_EXIT return + + +// ---------------------------------------------------------------------------- +// linkage +// ---------------------------------------------------------------------------- + +#define fastcall +#define asmlinkage + +#define far +#define SK_FAR + +// pb +//#define near + + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +#define INITSECTION + +#define NORET_TYPE + +#define compat_init_data + +#define DIVA_EXIT_FUNCTION +#define DIVA_INIT_FUNCTION +#define ACPI_SYSTEM_XFACE + +#define ASC_INITDATA +#define in2000__INITDATA +#define PACKED + +#define WPMINFO +#define CPMINFO +#define PMINFO + +#define ACPI_INTERNAL_VAR_XFACE + +#define SISIOMEMTYPE + +#define ACPI_STATE_COMMON +#define ACPI_PARSE_COMMON +#define ACPI_COMMON_DEBUG_MEM_HEADER + + +#define nabi_no_regargs + + +#define ATTRIB_NORET +#define ATTRIBUTE_UNUSED +#define BTEXT +#define BTDATA +#define PAGE_ALIGNED + +#define EARLY_INIT_SECTION_ATTR + +// pb +//#define INIT + +#define IDI_CALL_ENTITY_T +#define IDI_CALL_LINK_T + +/* cf gcc-linux.h + * A trick to suppress uninitialized variable warning without generating any + * code + */ +#define uninitialized_var(x) x = x +// as in u16 uninitialized_var(ioboard_type); /* GCC be quiet */ + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +#define __releases(x) +#define __acquires(x) +#define __declspec(x) +#define __page_aligned(x) +#define __vsyscall(x) + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + + +//conflict with a macro of firefox +//#define FASTCALL(x) x +#define PARAMS(x) x + + + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +// include/asm-arm/mach/arch.h +// #define MACHINE_START(x) struct foo { x } +#define MACHINE_START(_type,_name) \ +static const struct machine_desc __mach_desc_##_type \ +/* __used*/ \ + __attribute__((__section__(".arch.info.init"))) = { \ + .nr = MACH_TYPE_##_type, \ + .name = _name, + +#define MACHINE_END \ +}; + +// include/asm-powerpc/machdep.h +#define define_machine(name) \ + extern struct machdep_calls mach_##name; \ + EXPORT_SYMBOL(mach_##name); \ + struct machdep_calls mach_##name /*__machine_desc*/ = + + +// ---------------------------------------------------------------------------- +// Declare like macros (in structure def), or tricky Declare macros +// ---------------------------------------------------------------------------- + +// include/asm-i386/pci.h +// the DECLARE are detected by parsing_hack but not when they are +// inside a struct def. +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) + +// defined in drivers/infiniband/hw/mthca/mthca_doorbell.h +#define MTHCA_DECLARE_DOORBELL_LOCK(doorbell_lock) + +// include/linux/types.h +//#define BITS_TO_LONGS(bits) \ +// (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) +#define DECLARE_BITMAP(name,bits) \ + /*unsigned*/ long name[BITS_TO_LONGS(bits)] + + +// include/asm-i386/percpu.h +// interesting macro where we see the need of __typeof__(type) with +// for example DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); +#define DEFINE_PER_CPU(type, name) \ + __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name +#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name + + + +// include/linux/kobject.h +#define decl_subsys(_name,_type,_uevent_ops) \ +struct subsystem _name##_subsys = { \ + .kset = { \ + .kobj = { .name = __stringify(_name) }, \ + .ktype = _type, \ + .uevent_ops =_uevent_ops, \ + } \ +} + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +// pb: if use this macro then we will not transform the argument of CS_CHECK +// in some rules. +//#define CS_CHECK(fn, ret) \ +// do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) + + +// bt2/hci_bcsp.c +#define BCSP_CRC_INIT(x) x = 0xffff + + +// sound/oss/cs46xx_wrapper-24.h +#define CS_OWNER .owner = +#define CS_THIS_MODULE THIS_MODULE, + + +// sound/sparc/dbri.c +// "bad macro", have a ',' at the end +#define CS4215_SINGLE(xname, entry, shift, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_cs4215_info_single, \ + .get = snd_cs4215_get_single, .put = snd_cs4215_put_single, \ + .private_value = entry | (shift << 8) | (mask << 16) | (invert << 24) }, + +// drivers/media/video/sn9c102/sn9c102_sensor.h +//#define sn9c102_write_const_regs(sn9c102_device, data...) \ +// ({ const static u8 _valreg[][2] = {data}; \ +// sn9c102_write_regs(sn9c102_device, _valreg, ARRAY_SIZE(_valreg)); }) + + + + + +// drivers/s390/cio/qdio.h +#define SYNC_MEMORY if (unlikely(q->siga_sync)) qdio_siga_sync_q(q) +#define SYNC_MEMORY_ALL if (unlikely(q->siga_sync)) \ + qdio_siga_sync(q,~0U,~0U) +#define SYNC_MEMORY_ALL_OUTB if (unlikely(q->siga_sync)) \ + qdio_siga_sync(q,~0U,0) + +// drivers/scsi/g_NCR5380.c +#define ANDP , + + +// drivers/scsi/ncr53c8xx.c +// generate lots of errors because error en cascade car dans l'initialiseur +// il y'a des '}' dans la premiere colonne +#define PREFETCH_FLUSH SCR_CALL, PADDRH (wait_dma), + +// drivers/net/e100.c +// pbs false positive, defined in another manner in some files +//#define X(a,b) a,b + + +// net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c +// also used in other.c that don't do any include :( +// but locally redefined in drivers/net/bnx2.c :( with a +// #define FNAME 0x8 +#define FNAME(name) name, + + +// drivers/net/tulip/de4x5.c +#define DESC_ALIGN + + +// in .h +#define MPI_POINTER * + +// mega4/soc.c mega4/socal.c +// cause false typedef inference if let soc_printk +#define soc_printk printk +#define socal_printk printk + + +// ---------------------------------------------------------------------------- +// Initializer array macros +// ---------------------------------------------------------------------------- + +// drivers/net/wireless/bcm43xx/bcm43xx_wx.c +// defined in similar way multiple times, in the same file and in another one +#define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT] +// #define WX(x) [(x)-SIOCIWFIRST] + +// drivers/net/wireless/ipw2200.c +#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] + +// drivers/net/wireless/zd1211rw/zd_netdev.c +#define PRIV_OFFSET(x) [(x)-SIOCIWFIRSTPRIV] + +// drivers/net/wireless/zd1211rw/zd_rf.h +#define RF_CHANNEL(ch) [(ch)-1] + +// drivers/net/wireless/zd1211rw/zd_rf_uw2453.c +#define RF_CHANPAIR(a,b) [CHAN_TO_PAIRIDX(a)] + +// drivers/net/wireless/arlan-proc.c +// incomplete macro, the real macro is quite complex and use other macros +#define ARLAN_SYSCTL_TABLE_TOTAL(x) + + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +// drivers/net/cxgb3/t3_hw.c +#define VPD_ENTRY(name, len) \ + u8 name##_kword[2]; u8 name##_len; u8 name##_data[len] + + +// #define rtrc(i) {} + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +// drivers/video/nvidia/nv_type.h +// use: SetBitField(h_blank_e, 5: 5, 7:7) +//#define BITMASK(t,b) (((unsigned)(1U << (((t)-(b)+1)))-1) << (b)) +//#define MASKEXPAND(mask) BITMASK(1?mask,0?mask) +//#define SetBF(mask,value) ((value) << (0?mask)) +//#define GetBF(var,mask) (((unsigned)((var) & MASKEXPAND(mask))) >> (0?mask) ) +//#define SetBitField(value,from,to) SetBF(to, GetBF(value,from)) +//#define SetBit(n) (1<<(n)) +//#define Set8Bits(value) ((value)&0xff) + + +// drivers/video/sis/init.c +// use: GETBITSTR((SiS_Pr->CVTotal -2), 10:10, 0:0) +//#define BITMASK(h,l) (((unsigned)(1U << ((h)-(l)+1))-1)<<(l)) +//#define GENMASK(mask) BITMASK(1?mask,0?mask) +//#define GETBITS(var,mask) (((var) & GENMASK(mask)) >> (0?mask)) +//#define GETBITSTR(val,from,to) ((GETBITS(val,from)) << (0?to)) + + +// fs/afs/internal.h +#define ASSERTCMP(X, OP, Y) \ +do { \ + if (unlikely(!((X) OP (Y)))) { \ + printk(KERN_ERR "\n"); \ + printk(KERN_ERR "AFS: Assertion failed\n"); \ + printk(KERN_ERR "%lu " /*#OP*/ " %lu is false\n", \ + (unsigned long)(X), (unsigned long)(Y)); \ + printk(KERN_ERR "0x%lx " /*#OP*/ " 0x%lx is false\n", \ + (unsigned long)(X), (unsigned long)(Y)); \ + BUG(); \ + } \ +} while(0) + +#define ASSERTIFCMP(C, X, OP, Y) \ +do { \ + if (unlikely((C) && !((X) OP (Y)))) { \ + printk(KERN_ERR "\n"); \ + printk(KERN_ERR "AFS: Assertion failed\n"); \ + printk(KERN_ERR "%lu " /*#OP*/ " %lu is false\n", \ + (unsigned long)(X), (unsigned long)(Y)); \ + printk(KERN_ERR "0x%lx " /*#OP*/ " 0x%lx is false\n", \ + (unsigned long)(X), (unsigned long)(Y)); \ + BUG(); \ + } \ +} while(0) + + +#define ASSERTRANGE(L, OP1, N, OP2, H) \ +do { \ + if (unlikely(!((L) OP1 (N)) || !((N) OP2 (H)))) { \ + printk(KERN_ERR "\n"); \ + printk(KERN_ERR "AFS: Assertion failed\n"); \ + printk(KERN_ERR "%lu "/*#OP1*/" %lu "/*#OP2*/" %lu is false\n", \ + (unsigned long)(L), (unsigned long)(N), \ + (unsigned long)(H)); \ + printk(KERN_ERR "0x%lx "/*#OP1*/" 0x%lx "/*#OP2*/" 0x%lx is false\n", \ + (unsigned long)(L), (unsigned long)(N), \ + (unsigned long)(H)); \ + BUG(); \ + } \ +} while(0) + + + + +// loop, macro without ';', single macro. ex: DEBUG() + +// TODO should find the definition because we don't use 'x' and so +// may lose code sites with coccinelle. If expand correctly, will +// still don't transform correctly but at least will detect the place. + + + + +// Cooperation with parsing_hack.ml: MACROSTATEMENT is a magic string. +// I can't just expand those macros into some 'whatever();' because I need +// to generate a TMacroStmt for solving some ambiguities in the grammar +// for the toplevel stuff I think. +#define ASSERT(x) MACROSTATEMENT +#define IRDA_ASSERT(x) MACROSTATEMENT + +#define CHECK_NULL(x) MACROSTATEMENT + +//#define DEBUG(x) MACROSTATEMENT +#define DEBUG0(x) MACROSTATEMENT +#define DEBUG1(x) MACROSTATEMENT +#define DEBUG2(x) MACROSTATEMENT +#define DEBUG3(x) MACROSTATEMENT + + +#define DBG(x) MACROSTATEMENT +#define DEB(x) MACROSTATEMENT +#define PARSEDEBUG(x) MACROSTATEMENT +#define DEBC(x) MACROSTATEMENT +#define DBG_TRC(x) MACROSTATEMENT +#define DBG_ERR(x) MACROSTATEMENT +#define DBG_FTL(x) MACROSTATEMENT + +#define DBGINFO(x) MACROSTATEMENT +#define DFLOW(x) MACROSTATEMENT +#define DFLIP(x) MACROSTATEMENT +#define DLOG_INT_TRIG(x) MACROSTATEMENT + +#define D3(x) MACROSTATEMENT +#define D1(x) MACROSTATEMENT +#define DB(x) MACROSTATEMENT +#define DCBDEBUG(x) MACROSTATEMENT +#define SCSI_LOG_MLQUEUE(x) MACROSTATEMENT + +#define PLND(x) MACROSTATEMENT +#define FCALND(x) MACROSTATEMENT +#define FCALD(x) MACROSTATEMENT + +#define DEBUGRECURSION(x) MACROSTATEMENT + +#define DEBUGPIO(x) MACROSTATEMENT +#define VDEB(x) MACROSTATEMENT + +#define READ_UNLOCK_IRQRESTORE(x) MACROSTATEMENT + +#define TRACE_CATCH(x) MACROSTATEMENT + +#define PDBGG(x) MACROSTATEMENT + +#define IF_ABR(x) MACROSTATEMENT +#define IF_EVENT(x) MACROSTATEMENT +#define IF_ERR(x) MACROSTATEMENT +#define IF_CBR(x) MACROSTATEMENT +#define IF_INIT(x) MACROSTATEMENT +#define IF_RX(x) MACROSTATEMENT + +#define SOD(x) MACROSTATEMENT + +#define KDBG(x) MACROSTATEMENT + +#define IRDA_ASSERT_LABEL(x) MACROSTATEMENT + + + + + +// ---------------------------------------------------------------------------- +// Difficult foreach +// ---------------------------------------------------------------------------- + +// include/linux/sched.h +#define while_each_thread(g, t) \ + while ((t = next_thread(t)) != g) + + + +// net/decnet/dn_fib.c +#define for_fib_info() { struct dn_fib_info *fi;\ + for(fi = dn_fib_info_list; fi; fi = fi->fib_next) +#define endfor_fib_info() } + +#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\ + for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++) + +#define change_nexthops(fi) { int nhsel; struct dn_fib_nh *nh;\ + for(nhsel = 0, nh = (struct dn_fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++) + +#define endfor_nexthops(fi) } + + +// ---------------------------------------------------------------------------- +// Macros around function prototype +// ---------------------------------------------------------------------------- + + +// net/sched/em_meta.c +#define META_COLLECTOR(FUNC) static void meta_##FUNC(struct sk_buff *skb, \ + struct tcf_pkt_info *info, struct meta_value *v, \ + struct meta_obj *dst, int *err) + + +#define GDTH_INITFUNC(x,y) x y +#define ASC_INITFUNC(x,y) x y + + +// ---------------------------------------------------------------------------- +// If-like macros +// ---------------------------------------------------------------------------- + +// include/linux/lockd/debug.h +// include/linux/nfs_fs.h +// include/linux/nfsd/debug.h +// include/linux/sunrpc/debug.h +//#define ifdebug(flag) if (unlikely(nlm_debug & NLMDBG_##flag)) +#define ifdebug(flag) if (0) + + + +// ---------------------------------------------------------------------------- +//#define __PROM_O32 + +// ---------------------------------------------------------------------------- +// for tests-big/ macros, may be obsolete now cos fixed in latest kernel +// ---------------------------------------------------------------------------- + +// rule10 +//#define ACPI_MODULE_NAME(x) + + + + +// **************************************************************************** +// Httpd (apache) macros +// **************************************************************************** + +#define AP_DECLARE(x) x +#define PROXY_DECLARE(x) x +#define CACHE_DECLARE(x) x +#define DBD_DECLARE_NONSTD(x) x +#define DAV_DECLARE(x) x +#define APU_DECLARE(x) x +#define APU_DECLARE_NONSTD(x) x +#define APR_DECLARE(x) x +#define AP_CORE_DECLARE(x) x +#define AP_DECLARE_NONSTD(x) x +#define AP_CORE_DECLARE_NONSTD(x) x +#define APR_OPTIONAL_FN_TYPE(x) x +#define DAV_DECLARE_NONSTD(x) x +#define APR_DECLARE_NONSTD(x) x + +#define APU_DECLARE_DATA +#define APR_THREAD_FUNC +#define AP_DECLARE_DATA +#define PROXY_DECLARE_DATA +#define AP_MODULE_DECLARE_DATA +#define APR_DECLARE_DATA + + + +#define APR_INLINE inline +#define EXPORT static +#define REGISTER register + +#define MODSSL_D2I_SSL_SESSION_CONST const +#define MODSSL_D2I_X509_CONST const +#define MODSSL_D2I_PrivateKey_CONST const +#define MODSSL_D2I_SSL_SESSION_CONST const + +#define STACK_OF(X509_NAME) X509_NAME + +#define MODSSL_PCHAR_CAST (pchar) + +#define WINAPI +//#define CALLBACK +// generate false positive in Linux +#define APIENTRY +#define __declspec(x) +#define __stdcall + + +//#define module struct xxx + +#define APR_POOL_IMPLEMENT_ACCESSOR(shm) + +#define ADD_SUITE(suite) suite; + +// **************************************************************************** +// CISCO vpn client macros +// **************************************************************************** + +// #define NOREGPARM +// #define IN +// #define OUT +// #define OPTIONAL + +#define likely(x) x +#define unlikely(x) x diff --git a/standard.iso b/standard.iso new file mode 100644 index 0000000..a2e4503 --- /dev/null +++ b/standard.iso @@ -0,0 +1,656 @@ +// **************************************************************************** +// Prelude +// **************************************************************************** + +// Note: some isomorphisms are handled in the engine directly because they +// require special support. They can not be easily described with a +// XX <=> YY. But some of them have names, so they can be disabled, as for +// any other isomorphism rule. That also means that those names can not +// be used for regular isomorphism rule. Those reserved rule names are: +// - optional_storage +// - optional_qualifier +// - value_format +// See parse_cocci.ml, pattern.ml, transformation.ml. + + +// Note: the order of the rules has some importance. As we don't do a fixpoint, +// changing the order may impact the result. For instance, if we have +// +// iso1 = x+y <=> y+x +// iso2 = i++ <=> i=i+1; +// +// and if +// in SP we have i++; +// in C we have i=1+i; +// +// Does the SP matches the C ? +// - Yes if iso2 precedes iso1 in this file, +// - No otherwise. + + +// **************************************************************************** +// Standard C isomorphisms +// **************************************************************************** + +// --------------------------------------------------------------------------- +// Spacing (include comments) isomorphisms +// --------------------------------------------------------------------------- +// They are handled at lex time. + +// --------------------------------------------------------------------------- +// Dataflow isomorphisms (copy propagation, assignments) +// --------------------------------------------------------------------------- +// They are handled in engine (TODO). + + +// --------------------------------------------------------------------------- +// Iso-by-absence (optional qualifier, storage, sign, cast) isomorphisms +// --------------------------------------------------------------------------- +// Some of them are handled in cocci_vs_c. Some of them handled here. + + +// We would like that +// chip = (ak4117_t *)snd_magic_kcalloc(ak4117_t, 0, GFP_KERNEL); +// also matches +// X = snd_magic_kcalloc(T, 0, C) +// +// For the moment because the iso is (T) E => E and not <=>, it forces +// us to rewrite the SP as X = (T) snd_magic_kcalloc(T, 0, C) + +Expression +@ drop_cast @ +expression E; +pure type T; +@@ + +// in the following, the space at the beginning of the line is very important! + (T)E => E + +Type +@ add_signed @ +@@ +int => signed int + +Type +@ add_int1 @ +@@ +unsigned => unsigned int + +Type +@ add_int2 @ +@@ +signed => signed int + + +// --------------------------------------------------------------------------- +// Field isomorphisms +// --------------------------------------------------------------------------- +// Dereferences + + +// Those iso were introduced for the 'generic program matching' paper, +// with sgrep. The idea is that when we want to detect bugs, +// we want to detect something like free(X) ... *X +// meaning that you try to access something that have been freed. +// But *X is not the only way to deference X, there is also +// X->fld, hence those iso. + +// The following don't see like a good idea, because eg fld could be +// instantiated in different ways in different places, meaning that the +// two occurrences of "*E" would not refer to the same thing at all. +// This could be addressed by making E pure, but then I think it would +// have no purpose. + +// Expression +// @@ +// expression E; +// identifier fld; +// @@ +// +// *E => E->fld +// +// Expression +// @@ +// expression E; +// identifier fld; +// @@ +// +// *E => (E)->fld +// +// Expression +// @@ +// expression E,E1; +// @@ +// +// *E => E[E1] + +// --------------------------------------------------------------------------- +// Typedef isomorphisms +// --------------------------------------------------------------------------- +// They are handled in engine. + + +// --------------------------------------------------------------------------- +// Boolean isomorphisms +// --------------------------------------------------------------------------- + +// the space at the beginning of the line is very important! +Expression +@ not_int1 @ +int X; +@@ + !X => 0 == X + +// the space at the beginning of the line is very important! +Expression +@ not_int2 @ +int X; +@@ + !X => X == 0 + +Expression +@ is_zero @ +expression X; +@@ +X == 0 <=> 0 == X => !X + +Expression +@ isnt_zero @ +expression X; +@@ +X != 0 <=> 0 != X => X + +Expression +@ bitor_comm @ +expression X,Y; +@@ +X | Y => Y | X + +Expression +@ bitand_comm @ +expression X,Y; +@@ +X & Y => Y & X + +// only if side effect free in theory ... +Expression +@ and_comm @ +expression X,Y; +@@ +X && Y => Y && X + +Expression +@ or_comm @ +expression X,Y; +@@ +X || Y => Y || X + + +// --------------------------------------------------------------------------- +// Arithmetic isomorphisms +// --------------------------------------------------------------------------- +//todo: require check side-effect free expression + +Expression +@ plus_comm @ +expression X, Y; +@@ +X + Y => Y + X + + +// needed in kcalloc CE, where have a -kzalloc(c * sizeof(T), E) +Expression +@ mult_comm @ +expression X, Y; +@@ +X * Y => Y * X + +Expression +@ plus_assoc @ +expression X, Y, Z; +@@ + // note space before ( + (X + Y) + Z <=> X + Y + Z + +Expression +@ minus_assoc @ +expression X, Y, Z; +@@ + + (X - Y) - Z <=> X - Y - Z + +Expression +@ plus_minus_assoc1 @ +expression X, Y, Z; +@@ + + (X + Y) - Z <=> X + Y - Z + +Expression +@ plus_minus_assoc2 @ +expression X, Y, Z; +@@ + + (X - Y) + Z <=> X - Y + Z + +Expression +@ times_assoc @ +expression X, Y, Z; +@@ + + (X * Y) * Z <=> X * Y * Z + +Expression +@ div_assoc @ +expression X, Y, Z; +@@ + + (X / Y) / Z <=> X / Y / Z + +Expression +@ times_div_assoc1 @ +expression X, Y, Z; +@@ + + (X * Y) / Z <=> X * Y / Z + +Expression +@ times_div_assoc2 @ +expression X, Y, Z; +@@ + + (X / Y) * Z <=> X / Y * Z + +// --------------------------------------------------------------------------- +// Relational isomorphisms +// --------------------------------------------------------------------------- + +Expression +@ gtr_lss @ +expression X, Y; +@@ +X < Y <=> Y > X + +// --------------------------------------------------------------------------- +// Increment isomorphisms +// --------------------------------------------------------------------------- + +// equivalences between i++, +=1, etc. +// note: there is an addition in this SP. +Statement +@ inc @ +identifier i; +@@ +i++; <=> ++i; <=> i+=1; <=> i=i+1; + +// I would like to avoid the following rule, but we cant transform a ++i +// in i++ everywhere. We can do it only when the instruction is alone, +// such as when there is not stuff around it (not as in x = i++) That's why in +// the previous iso, we have explicitely force the i++ do be alone with +// the ';'. But unfortunately in the last expression of the for there is +// no ';' so the previous rule cannot be applied, hence this special +// case. + +Statement +@ for_inc @ +expression X, Y; +statement S; +identifier i; +@@ +for(X;Y;i++) S <=> for(X;Y;++i) S + + +// --------------------------------------------------------------------------- +// Pointer isomorphisms +// --------------------------------------------------------------------------- + +// the space at the beginning of the line is very important! +Expression +@ not_ptr1 @ +expression *X; +@@ + !X => NULL == X + +// the space at the beginning of the line is very important! +Expression +@ not_ptr2 @ +expression *X; +@@ + !X => X == NULL + +Expression +@ is_null @ +expression X; +@@ +X == NULL <=> NULL == X => !X + +Expression +@ isnt_null1 @ +expression X; +@@ +X != NULL <=> NULL != X + +TestExpression +@ isnt_null1 @ +expression X; +@@ +NULL != X => X + +// pointer arithmetic equivalences + +// --------------------------------------------------------------------------- +// Statement isomorphisms +// --------------------------------------------------------------------------- + +// ---------------- +// If +// ---------------- + +Statement +@ int_if_test1 @ +int X; +statement S1, S2; +@@ +if (X) S1 else S2 => if (X != 0) S1 else S2 <=> if (0 != X) S1 else S2 + +Statement +@ int_if_test2 @ +int X; +statement S; +@@ +if (X) S => if (X != 0) S <=> if (0 != X) S + +Statement +@ ptr_if_test1 @ +expression *X; +statement S1, S2; +@@ +if (X) S1 else S2 => if (X != NULL) S1 else S2 => if (NULL != X) S1 else S2 + +Statement +@ ptr_if_test2 @ +expression *X; +statement S; +@@ +if (X) S => if (X != NULL) S <=> if (NULL != X) S + +// --------------------------------------------------------------------------- +// Value isomorphisms +// --------------------------------------------------------------------------- + +// There is also equal_c_int in cocci_vs_c to dealing with other +// integer decimal/hexadecimal isomorphisms. +// an argexpression applies only at top level, in the argument of a +// function call, or on the right-hand side of an assignment +ArgExpression +@ zero_multiple_format @ +@@ + 0 => '\0' + +// **************************************************************************** +// gcc specific isomorphisms +// **************************************************************************** + +// likely and unlikely are used to give hints to gcc to improve performance. + +Expression +@ unlikely @ +expression E; +@@ + +unlikely(E) => E + +Expression +@ likely @ +expression E; +@@ + +likely(E) => E + +// **************************************************************************** +// if structure isomorphisms +// **************************************************************************** + +// these after after the above so that the introduced negation will distribute +// properly over the argument to likely/unlikely + +Statement +@ neg_if @ +expression X; +statement S1, S2; +@@ +if (X) S1 else S2 => if (!X) S2 else S1 + +Statement +@ drop_else @ +expression E; +statement S1; +pure statement S2; +@@ + +if (E) S1 else S2 => if (E) S1 + +Expression +@ neg_if_exp @ +expression E1, E2, E3; +@@ + +E1 ? E2 : E3 => !E1 ? E3 : E2 + + +// if (X) Y else Z <=> X ? Y : Z sometimes. + +// ---------------- +// Loops +// ---------------- + +// --------------------------------------------------------------------------- +// Optional initializers +// --------------------------------------------------------------------------- +// this is not safe when the declaration is replaced +// attempt to indicate that by requiring that Z is context +// no optional static/extern for isos +Declaration +@ decl_init @ +type T; +context identifier Z; +@@ +T Z; => T Z = ...; + +Declaration +@ const_decl_init @ +type T; +identifier Z; +constant C; +@@ +T Z; => T Z = C; + +Declaration +@ extern_decl_init @ +type T; +context identifier Z; +@@ +extern T Z; => extern T Z = ...; + +Declaration +@ const_extern_decl_init @ +type T; +identifier Z; +constant C; +@@ +extern T Z; => extern T Z = C; + +Declaration +@ static_decl_init @ +type T; +context identifier Z; +@@ +static T Z; => static T Z = ...; + +Declaration +@ const_static_decl_init @ +type T; +identifier Z; +constant C; +@@ +static T Z; => static T Z = C; + +// --------------------------------------------------------------------------- +// Branch (or compound) isomorphisms +// --------------------------------------------------------------------------- +// maybe a cocci patch should require something that looks like what is on +// the left above to occur in a if or while + +// could worry that this has to be a simple statement, but this should work +// better as it allows + code on S +Statement +@ braces1 @ +statement S; +@@ +{ ... S } => S + +Statement +@ braces2 @ +statement S; +@@ +{ ... S ... } => S + +Statement +@ braces3 @ +statement S; +@@ +{ S ... } => S + +Statement +@ braces4 @ +statement S; +@@ +{ S } => S + +Statement +@ ret @ +@@ +return ...; => return; + + +// --------------------------------------------------------------------------- +// Declaration isomorphisms +// --------------------------------------------------------------------------- +// They are handled in engine (TODO) + +// int i,j,k; <=> int i; int j; int k; + + +// --------------------------------------------------------------------------- +// Affectation/initialisation isomorphism +// --------------------------------------------------------------------------- +// They are handled in engine. +// 'X = Y' should also match 'type X = Y'; + +// --------------------------------------------------------------------------- +// Parenthesis isomorphisms +// --------------------------------------------------------------------------- +//Expression +//@@ expression E; @@ +// E => (E) +//// E => ((E)) + +// todo: isomorphism avec les () around ? cf sizeof 3. +// (E) => E with some conditions. + + +// --------------------------------------------------------------------------- +// Pointer/Array isomorphisms +// --------------------------------------------------------------------------- + +// pointer arithmetic equivalences +// a + x <=> a[x] + +// --------------------------------------------------------------------------- +// Pointer/Field isomorphisms +// --------------------------------------------------------------------------- + +Expression +@ ptr_to_array @ +expression E1, E2; // was pure, not sure why that's needed, not good for rule27 +identifier fld; +@@ + +E1->fld => E1[E2].fld + + + +TopLevel +@ mkinit @ +type T; +pure context T E; +identifier I; +identifier fld; +expression E1; +@@ + +E.fld = E1; => T I = { .fld = E1, }; + +// --------------------------------------------------------------------------- +// more pointer field iso +// --------------------------------------------------------------------------- + +// pure means that either the whole field reference expression is dropped, +// or E is context code and has no attached + code +// not really... pure means matches a unitary unplussed metavariable +// but this rule doesn't work anyway + +Expression +@ fld_to_ptr @ +type T; +pure T E; +pure T *E1; +identifier fld; +@@ + +E.fld => E1->fld + + +// --------------------------------------------------------------------------- +// sizeof isomorphisms +// --------------------------------------------------------------------------- + +Expression +@ sizeof_parens @ +expression E; +@@ + +sizeof(E) => sizeof E + + +Expression +@ sizeof_type_expr @ +pure type T; // pure because we drop a metavar +T E; +@@ + +sizeof(T) => sizeof(E) + + +// **************************************************************************** +// Linux specific isomorphisms +// **************************************************************************** + +// Examples: many functions are equivalent/related, and one SP modifying +// such a function should also modify the equivalent/related one. + + +// --------------------------------------------------------------------------- +// in rule18, needed ? +// --------------------------------------------------------------------------- +// ( +// - test_and_set_bit(ev, &bcs->event); +// | +// - set_bit(ev, &bcs->event); +// | +// - bcs->event |= 1 << ev; // the only case that is used + + +// **************************************************************************** +// Everything that is required to be in last position, for ugly reasons ... +// **************************************************************************** diff --git a/test.ml b/test.ml new file mode 100644 index 0000000..d1176b7 --- /dev/null +++ b/test.ml @@ -0,0 +1 @@ +let foo_ctl () = failwith "there is no foo_ctl formula" diff --git a/testing.ml b/testing.ml new file mode 100644 index 0000000..57518d9 --- /dev/null +++ b/testing.ml @@ -0,0 +1,430 @@ +(* +* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen +* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller +* This file is part of Coccinelle. +* +* Coccinelle is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, according to version 2 of the License. +* +* Coccinelle is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Coccinelle. If not, see . +* +* The authors reserve the right to distribute this or future versions of +* Coccinelle under other licenses. +*) + + +open Common + +(*****************************************************************************) +(* Test framework *) +(*****************************************************************************) + +(* There can be multiple .c for the same cocci file. The convention + * is to have one base.cocci and a base.c and some optional + * base_vernn.[c,res]. + * + * If want to test without iso, use -iso_file empty.iso option. + *) +let testone x compare_with_expected_flag = + let x = if x =~ "\\(.*\\)_ver0$" then matched1 x else x in + let base = if x =~ "\\(.*\\)_ver[0-9]+$" then matched1 x else x in + + let cfile = "tests/" ^ x ^ ".c" in + let cocci_file = "tests/" ^ base ^ ".cocci" in + + let expected_res = "tests/" ^ x ^ ".res" in + begin + let res = Cocci.full_engine (cocci_file, !Config.std_iso) [cfile] in + let generated = + match Common.optionise (fun () -> List.assoc cfile res) with + | Some (Some outfile) -> + if List.length res > 1 + then pr2 ("note that not just " ^ cfile ^ " was involved"); + + let tmpfile = "/tmp/"^Common.basename cfile in + pr2 (sprintf "One file modified. Result is here: %s" tmpfile); + Common.command2 ("mv "^outfile^" "^tmpfile); + tmpfile + | Some None -> + pr2 "no modification on the input file"; + cfile + | None -> raise Impossible + in + if compare_with_expected_flag + then + Compare_c.compare_default generated expected_res + +> Compare_c.compare_result_to_string + +> pr2; + end + + +(* ------------------------------------------------------------------------ *) +let testall () = + + let newscore = empty_score () in + + let expected_result_files = + Common.glob "tests/*.res" + +> List.filter (fun f -> Common.filesize f > 0) + +> List.map Filename.basename + +> List.sort compare + in + + begin + expected_result_files +> List.iter (fun res -> + let x = if res =~ "\\(.*\\).res" then matched1 res else raise Impossible + in + let base = if x =~ "\\(.*\\)_ver[0-9]+" then matched1 x else x in + let cfile = "tests/" ^ x ^ ".c" in + let cocci_file = "tests/" ^ base ^ ".cocci" in + let expected = "tests/" ^ res in + + let timeout_testall = 30 in + + try ( + Common.timeout_function timeout_testall (fun () -> + + let xs = Cocci.full_engine (cocci_file, !Config.std_iso) [cfile] in + let generated = + match List.assoc cfile xs with + | Some generated -> generated + | None -> cfile + in + + let (correct, diffxs) = Compare_c.compare_default generated expected + in + + pr2 res; + (* I don't use Compare_c.compare_result_to_string because + * I want to indent a little more the messages. + *) + (match correct with + | Compare_c.Correct -> Hashtbl.add newscore res Common.Ok; + | Compare_c.Pb s -> + let s = Str.global_replace + (Str.regexp "\"/tmp/cocci-output.*\"") "" s + in + let s = + "INCORRECT:" ^ s ^ "\n" ^ + " diff (result(<) vs expected_result(>)) = \n" ^ + (diffxs +> List.map(fun s -> " "^s^"\n") +> Common.join "") + in + Hashtbl.add newscore res (Common.Pb s) + | Compare_c.PbOnlyInNotParsedCorrectly s -> + let s = + "seems incorrect, but only because of code that " ^ + "was not parsable" ^ s + in + Hashtbl.add newscore res (Common.Pb s) + ) + ) + ) + with exn -> + Common.reset_pr_indent(); + let s = "PROBLEM\n" ^ (" exn = " ^ Printexc.to_string exn ^ "\n") in + Hashtbl.add newscore res (Common.Pb s) + ); + + + pr2 "--------------------------------"; + pr2 "statistics"; + pr2 "--------------------------------"; + + Common.hash_to_list newscore +> List.iter (fun (s, v) -> + pr_no_nl (Printf.sprintf "%-30s: " s); + pr_no_nl ( + match v with + | Common.Ok -> "CORRECT\n" + | Common.Pb s -> s + ) + ); + flush stdout; flush stderr; + + pr2 "--------------------------------"; + pr2 "regression testing information"; + pr2 "--------------------------------"; + Common.regression_testing newscore + (Filename.concat Config.path "tests/score_cocci_best.marshalled"); + + + pr2 "--------------------------------"; + pr2 "total score"; + pr2 "--------------------------------"; + let total = Common.hash_to_list newscore +> List.length in + let good = Common.hash_to_list newscore +> List.filter + (fun (s, v) -> v = Ok) +> List.length + in + + pr2 (sprintf "good = %d/%d" good total); + + end + +(* ------------------------------------------------------------------------ *) + +type okfailed = Ok | SpatchOK | Failed + +(* test_to_string *) +let t_to_s = function + | Ok -> ".ok" + | SpatchOK -> ".spatch_ok" + | Failed -> ".failed" + +let delete_previous_result_files infile = + [Ok;SpatchOK;Failed] +> List.iter (fun kind -> + Common.command2 ("rm -f " ^ infile ^ t_to_s kind) + ) + +(* quite similar to compare_with_expected below *) +let test_okfailed cocci_file cfiles = + cfiles +> List.iter delete_previous_result_files; + + (* final_files contain the name of an output file (a .ok or .failed + * or .spatch_ok), and also some additionnal strings to be printed in + * this output file in addition to the general error message of + * full_engine. *) + let final_files = ref [] in + + + let newout = + Common.new_temp_file "cocci" ".stdout" + in + + let t = Unix.gettimeofday () in + let time_per_file_str () = + let t' = Unix.gettimeofday () in + let tdiff = t' -. t in + let tperfile = tdiff /. (float_of_int (List.length cfiles)) in + spf "time: %f" tperfile + in + + Common.redirect_stdout_stderr newout (fun () -> + try ( + Common.timeout_function_opt !Flag_cocci.timeout (fun () -> + + + let outfiles = Cocci.full_engine (cocci_file, !Config.std_iso) cfiles + in + + let time_str = time_per_file_str () in + + outfiles +> List.iter (fun (infile, outopt) -> + let (dir, base, ext) = Common.dbe_of_filename infile in + let expected_suffix = + match ext with + | "c" -> "res" + | "h" -> "h.res" + | s -> pr2 ("WIERD: not a .c or .h :" ^ base ^ "." ^ s); + "" (* no extension, will compare to same file *) + in + let expected_res = + Common.filename_of_dbe (dir, base, expected_suffix) in + let expected_res2 = + Common.filename_of_dbe (dir,"corrected_"^ base,expected_suffix) + in + + (* can delete more than the first delete_previous_result_files + * because here we can have more files than in cfiles, for instance + * the header files + *) + delete_previous_result_files infile; + + match outopt, Common.lfile_exists expected_res with + | None, false -> + () + | Some outfile, false -> + let s =("PB: input file " ^ infile ^ " modified but no .res") in + push2 (infile^t_to_s Failed, [s;time_str]) final_files + + | x, true -> + let outfile = + match x with + | Some outfile -> outfile + | None -> infile + in + + let diff = Compare_c.compare_default outfile expected_res in + let s1 = (Compare_c.compare_result_to_string diff) in + if fst diff = Compare_c.Correct + then push2 (infile ^ (t_to_s Ok), [s1;time_str]) final_files + else + if Common.lfile_exists expected_res2 + then begin + let diff = Compare_c.compare_default outfile expected_res2 in + let s2 = Compare_c.compare_result_to_string diff in + if fst diff = Compare_c.Correct + then push2 (infile ^ (t_to_s SpatchOK),[s2;s1;time_str]) + final_files + else push2 (infile ^ (t_to_s Failed), [s2;s1;time_str]) + final_files + end + else push2 (infile ^ (t_to_s Failed), [s1;time_str]) final_files + ) + ); + ) + with exn -> + let clean s = + Str.global_replace (Str.regexp "\\\\n") "\n" + (Str.global_replace (Str.regexp ("\\\\\"")) "\"" + (Str.global_replace (Str.regexp "\\\\t") "\t" s)) in + let s = "PROBLEM\n"^(" exn = " ^ clean(Printexc.to_string exn) ^ "\n") + in + let time_str = time_per_file_str () + in + (* we may miss some file because cfiles is shorter than outfiles. + * For instance the detected local headers are not in cfiles, so + * may have less failed. But at least have some failed. + *) + cfiles +> List.iter (fun infile -> + push2 (infile ^ (t_to_s Failed), [s;time_str]) final_files; + ); + ); + !final_files +> List.iter (fun (file, additional_strs) -> + Common.command2 ("cp " ^ newout ^ " " ^ file); + with_open_outfile file (fun (pr, chan) -> + additional_strs +> List.iter (fun s -> pr (s ^ "\n")) + ); + + ) + + +let test_regression_okfailed () = + + (* it's xxx.c.ok *) + let chop_ext f = f +> Filename.chop_extension in + + let newscore = Common.empty_score () in + let oks = + Common.cmd_to_list ("find -name \"*.ok\"") + ++ + Common.cmd_to_list ("find -name \"*.spatch_ok\"") + in + let failed = Common.cmd_to_list ("find -name \"*.failed\"") in + + if null (oks ++ failed) + then failwith "no ok/failed file, you certainly did a make clean" + else begin + oks +> List.iter (fun s -> + Hashtbl.add newscore (chop_ext s) Common.Ok + ); + failed +> List.iter (fun s -> + Hashtbl.add newscore (chop_ext s) (Common.Pb "fail") + ); + pr2 "--------------------------------"; + pr2 "regression testing information"; + pr2 "--------------------------------"; + Common.regression_testing newscore ("score_failed.marshalled") + end + + +(* ------------------------------------------------------------------------ *) +(* quite similar to test_ok_failed. Maybe could factorize code *) +let compare_with_expected outfiles = + pr2 ""; + outfiles +> List.iter (fun (infile, outopt) -> + let (dir, base, ext) = Common.dbe_of_filename infile in + let expected_suffix = + match ext with + | "c" -> "res" + | "h" -> "h.res" + | s -> failwith ("wierd C file, not a .c or .h :" ^ s) + in + let expected_res = + Common.filename_of_dbe (dir, base, expected_suffix) in + let expected_res2 = + Common.filename_of_dbe (dir,"corrected_"^ base,expected_suffix) + in + + match outopt, Common.lfile_exists expected_res with + | None, false -> () + | Some outfile, false -> + let s =("PB: input file " ^ infile ^ " modified but no .res") in + pr2 s + | x, true -> + let outfile = + match x with + | Some outfile -> outfile + | None -> infile + in + let diff = Compare_c.compare_default outfile expected_res in + let s1 = (Compare_c.compare_result_to_string diff) in + if fst diff = Compare_c.Correct + then pr2_no_nl (infile ^ " " ^ s1) + else + if Common.lfile_exists expected_res2 + then begin + let diff = Compare_c.compare_default outfile expected_res2 in + let s2 = Compare_c.compare_result_to_string diff in + if fst diff = Compare_c.Correct + then pr2 (infile ^ " is spatchOK " ^ s2) + else pr2 (infile ^ " is failed " ^ s2) + end + else pr2 (infile ^ " is failed " ^ s1) + ) + +(*****************************************************************************) +(* Subsystem testing *) +(*****************************************************************************) + +let test_parse_cocci file = + if not (file =~ ".*\\.cocci") + then pr2 "warning: seems not a .cocci file"; + + let (xs,_,_,_,_,grep_tokens,query) = + Parse_cocci.process file (Some !Config.std_iso) false in + xs +> List.iter Pretty_print_cocci.unparse; + Printf.printf "grep tokens\n"; + List.iter (function x -> Printf.printf "%s\n" (String.concat " " x)) + grep_tokens; + if !Flag.use_glimpse + then match query with None -> pr "No query" | Some x -> pr x + + + + + + + + +(*****************************************************************************) +(* to be called by ocaml toplevel, to test. *) +(*****************************************************************************) + +(* no point to memoize this one *) +let sp_of_file file iso = Parse_cocci.process file iso false + +(* TODO: Remove +let (rule_elem_of_string: string -> filename option -> Ast_cocci.rule_elem) = + fun s iso -> + begin + Common.write_file ("/tmp/__cocci.cocci") (s); + let (astcocci, _,_,_,_,_) = sp_of_file ("/tmp/__cocci.cocci") iso in + let stmt = + astcocci +> + List.hd +> (function (_,_,x) -> List.hd x) +> (function x -> + match Ast_cocci.unwrap x with + | Ast_cocci.CODE stmt_dots -> Ast_cocci.undots stmt_dots +> List.hd + | _ -> raise Not_found) + in + match Ast_cocci.unwrap stmt with + | Ast_cocci.Atomic(re) -> re + | _ -> failwith "only atomic patterns allowed" + end +*) + +(* +let flows_of_ast astc = + astc +> Common.map_filter (fun e -> ast_to_flow_with_error_messages e) + +let one_flow flows = + List.hd flows + +let one_ctl ctls = List.hd (List.hd ctls) +*) + diff --git a/testing.mli b/testing.mli new file mode 100644 index 0000000..508e721 --- /dev/null +++ b/testing.mli @@ -0,0 +1,65 @@ +open Common + +(*****************************************************************************) +(* work with tests/ *) +(*****************************************************************************) +val testone : string (*test*) -> bool (*compare_expected*) -> unit +val testall : unit -> unit + +(*****************************************************************************) +(* works with tests-big/. The .res, .ok, .spatch_ok, .failed, .var *) +(*****************************************************************************) +val test_okfailed : filename (*cocci*) -> filename (*c*) list -> unit +val test_regression_okfailed : unit -> unit + + + +(*****************************************************************************) +(* the parameter is the result of Cocci.full_engine *) +(*****************************************************************************) +val compare_with_expected : (filename * filename option) list -> unit + + +(*****************************************************************************) +(* to test/debug the coccinelle subsystems *) +(*****************************************************************************) + +(* pad: + * I moved the parsing_c/ subsystem testing in parsing_c/test_parsing_c.ml + * as I need it for other projects too. + *) + +val test_parse_cocci : filename -> unit + +(*****************************************************************************) +(* to be called by ocaml toplevel, to test. *) +(*****************************************************************************) + +val sp_of_file : + filename (* coccifile *) -> filename option (* isofile *) -> + Ast_cocci.rule list * Ast_cocci.meta_name list list list * + Ast_cocci.meta_name list list list * + Ast_cocci.meta_name list list list * Ast_cocci.meta_name list list list * + string list list * + string option + +(* TODO: Remove +val rule_elem_of_string : string -> filename option -> Ast_cocci.rule_elem +*) + +(* +val flows_of_ast : Ast_c.program -> Control_flow_c.cflow list +val print_flow : Control_flow_c.cflow -> unit + +val ctls_of_ast : + Ast_cocci.rule list -> + Ast_cocci.meta_name list list list -> + (Lib_engine.ctlcocci * + ((Lib_engine.predicate * Ast_cocci.meta_name Ast_ctl.modif) + list list)) + list list + + +val one_flow : Control_flow_c.cflow list -> Control_flow_c.cflow +val one_ctl : Lib_engine.ctlcocci list list -> Lib_engine.ctlcocci +*) diff --git a/tests/A_and_E.c b/tests/A_and_E.c new file mode 100644 index 0000000..fc667d2 --- /dev/null +++ b/tests/A_and_E.c @@ -0,0 +1,10 @@ +void main(int i) { + + g(); + if(1) + f(1,2); + else + f(3,4); + + // return 1; +} diff --git a/tests/A_and_E.cocci b/tests/A_and_E.cocci new file mode 100644 index 0000000..b3b1e6f --- /dev/null +++ b/tests/A_and_E.cocci @@ -0,0 +1,8 @@ +@@ +expression X, Y; +@@ + + g(); ++ f(Y,0); + ... + f(X,Y); diff --git a/tests/A_and_E.res b/tests/A_and_E.res new file mode 100644 index 0000000..fc667d2 --- /dev/null +++ b/tests/A_and_E.res @@ -0,0 +1,10 @@ +void main(int i) { + + g(); + if(1) + f(1,2); + else + f(3,4); + + // return 1; +} diff --git a/tests/A_and_E_ver1.c b/tests/A_and_E_ver1.c new file mode 100644 index 0000000..b4e1b48 --- /dev/null +++ b/tests/A_and_E_ver1.c @@ -0,0 +1,10 @@ +void main(int i) { + + g(); + if(1) + f(1,2); + else + f(2,2); + + // return 1; +} diff --git a/tests/A_and_E_ver1.res b/tests/A_and_E_ver1.res new file mode 100644 index 0000000..1523ea3 --- /dev/null +++ b/tests/A_and_E_ver1.res @@ -0,0 +1,11 @@ +void main(int i) { + + g(); + f(2, 0); + if(1) + f(1,2); + else + f(2,2); + + // return 1; +} diff --git a/tests/a3d.c b/tests/a3d.c new file mode 100644 index 0000000..85bb148 --- /dev/null +++ b/tests/a3d.c @@ -0,0 +1,18 @@ +struct a3d { + struct gameport adc; + struct input_dev dev; +}; + +static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct a3d *a3d; + a3d->adc.idbus = BUS_GAMEPORT; + a3d->dev.idbus = BUS_GAMEPORT; +} + +static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct a3d *a3d; + a3d->adc.idbus = BUS_GAMEPORT; +} + diff --git a/tests/a3d.cocci b/tests/a3d.cocci new file mode 100644 index 0000000..6d8c419 --- /dev/null +++ b/tests/a3d.cocci @@ -0,0 +1,14 @@ +@@ +struct input_dev E; +@@ + +- E.idbus ++ E.id.bustype + + +@@ +struct gameport E; +@@ + +- E.idbus ++ E.id.bustype diff --git a/tests/a3d.res b/tests/a3d.res new file mode 100644 index 0000000..43122da --- /dev/null +++ b/tests/a3d.res @@ -0,0 +1,18 @@ +struct a3d { + struct gameport adc; + struct input_dev dev; +}; + +static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct a3d *a3d; + a3d->adc.id.bustype = BUS_GAMEPORT; + a3d->dev.id.bustype = BUS_GAMEPORT; +} + +static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct a3d *a3d; + a3d->adc.id.bustype = BUS_GAMEPORT; +} + diff --git a/tests/addelse.c b/tests/addelse.c new file mode 100644 index 0000000..3e6c138 --- /dev/null +++ b/tests/addelse.c @@ -0,0 +1,3 @@ +int main () { + if (x == 12) return 6; +} diff --git a/tests/addelse.cocci b/tests/addelse.cocci new file mode 100644 index 0000000..c97c920 --- /dev/null +++ b/tests/addelse.cocci @@ -0,0 +1,14 @@ +@@ +expression E; +statement S; +@@ + +if (E) S ++ else return 12; + +@@ +expression E; +statement S1,S2; +@@ + +- if (E) S1 else S2 diff --git a/tests/addelse.res b/tests/addelse.res new file mode 100644 index 0000000..d6a7729 --- /dev/null +++ b/tests/addelse.res @@ -0,0 +1,2 @@ +int main () { +} diff --git a/tests/after_if.c b/tests/after_if.c new file mode 100644 index 0000000..09179aa --- /dev/null +++ b/tests/after_if.c @@ -0,0 +1,4 @@ +#ifdef ELMC_MULTICAST +static void set_multicast_list(struct net_device *dev); +#endif +static struct ethtool_ops netdev_ethtool_ops; diff --git a/tests/after_if.cocci b/tests/after_if.cocci new file mode 100644 index 0000000..6f05066 --- /dev/null +++ b/tests/after_if.cocci @@ -0,0 +1,4 @@ +@@ identifier I; @@ + ++ static const struct ethtool_ops I; +- static struct ethtool_ops I; diff --git a/tests/after_if.res b/tests/after_if.res new file mode 100644 index 0000000..52fc047 --- /dev/null +++ b/tests/after_if.res @@ -0,0 +1,4 @@ +#ifdef ELMC_MULTICAST +static void set_multicast_list(struct net_device *dev); +#endif +static const struct ethtool_ops netdev_ethtool_ops; diff --git a/tests/ali.c b/tests/ali.c new file mode 100644 index 0000000..ec94b62 --- /dev/null +++ b/tests/ali.c @@ -0,0 +1,18 @@ +static int __init agp_i7x05_probe (struct pci_dev *dev, const struct pci_device_id *ent) +{ + u8 cap_ptr = 0; + + cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); + if (cap_ptr == 0) + return -ENODEV; + + if (agp_lookup_host_bridge(dev) != -ENODEV) { + agp_bridge.dev = dev; + agp_bridge.capndx = cap_ptr; + /* Fill in the mode register */ + pci_read_config_dword(agp_bridge.dev, agp_bridge.capndx+PCI_AGP_STATUS, &agp_bridge.mode) + agp_register_driver(dev); + return 0; + } + return -ENODEV; +} diff --git a/tests/ali.cocci b/tests/ali.cocci new file mode 100644 index 0000000..0d178b9 --- /dev/null +++ b/tests/ali.cocci @@ -0,0 +1,32 @@ +@ rule1 @ +fresh identifier agp_driver_struct; +function fn; +identifier ent,dev; +@@ + ++ static struct agp_driver agp_driver_struct = { ++ .owner = THIS_MODULE, ++ }; +fn (struct pci_dev *dev, struct pci_device_id *ent) { + ... +( +- agp_register_driver(dev); ++ agp_driver_struct.dev = dev; ++ agp_register_driver(&agp_driver_struct); +| + if (...) { // a non-error pathm, but looks like an error path + ... +- agp_register_driver(dev); ++ agp_driver_struct.dev = dev; ++ agp_register_driver(&agp_driver_struct); + ... + return 0; + } +) + ... + } + +@ rule2 extends rule1 @ +@@ +- agp_unregister_driver(); ++ agp_unregister_driver(&agp_driver_struct); diff --git a/tests/allbound.c b/tests/allbound.c new file mode 100644 index 0000000..3066e38 --- /dev/null +++ b/tests/allbound.c @@ -0,0 +1,4 @@ +int main () { + foo(27); + xxx(27); +} diff --git a/tests/allbound.cocci b/tests/allbound.cocci new file mode 100644 index 0000000..37f6bb8 --- /dev/null +++ b/tests/allbound.cocci @@ -0,0 +1,15 @@ +@ rule1 @ +expression E, E1; +@@ + +( +foo(E1) +| +bar(E) +) + +@ rule2 extends rule1 @ +@@ + +- xxx(E1) ++ yyy(E) diff --git a/tests/andparen.c b/tests/andparen.c new file mode 100644 index 0000000..3f51068 --- /dev/null +++ b/tests/andparen.c @@ -0,0 +1,3 @@ +int main() { + if (foo() && (x < 12)) return; +} diff --git a/tests/andparen.cocci b/tests/andparen.cocci new file mode 100644 index 0000000..033f147 --- /dev/null +++ b/tests/andparen.cocci @@ -0,0 +1,16 @@ +// gives already tagged token, because E can bind in two different ways +// so both substitutions are returned. +@@ +expression E; +statement S; +@@ + +if ( +( +- foo() && (E) ++ E +| +- foo() && E ++ E +) + ) S diff --git a/tests/anon.c b/tests/anon.c new file mode 100644 index 0000000..395200d --- /dev/null +++ b/tests/anon.c @@ -0,0 +1,16 @@ +typedef struct { + struct work_struct ppa_tq; /* Polling interrupt stuff */ +} ppa_struct; + +static void ppa_interrupt(void *data) +{ + ppa_struct *dev = (ppa_struct *) data; + schedule_delayed_work(&dev->ppa_tq, 1); +} + +static int ppa_queuecommand(struct scsi_cmnd *cmd, + void (*done) (struct scsi_cmnd *)) +{ + ppa_struct *dev = ppa_dev(cmd->device->host); + schedule_work(&dev->ppa_tq); +} diff --git a/tests/anon.cocci b/tests/anon.cocci new file mode 100644 index 0000000..61c6d7e --- /dev/null +++ b/tests/anon.cocci @@ -0,0 +1,18 @@ +// the case where the third argument is something else (with a type) (delayed) +// pointer type +@ is_delayed @ +type local_type; +local_type *device; +expression E; +identifier fld; +@@ + +schedule_delayed_work(&device->fld,E) + +@ rule2 @ +is_delayed.local_type *device; +identifier is_delayed.fld; +@@ + +- schedule_work(&device->fld) ++ schedule_delayed_work(&device->fld,0) diff --git a/tests/anon.res b/tests/anon.res new file mode 100644 index 0000000..0d0efa5 --- /dev/null +++ b/tests/anon.res @@ -0,0 +1,16 @@ +typedef struct { + struct work_struct ppa_tq; /* Polling interrupt stuff */ +} ppa_struct; + +static void ppa_interrupt(void *data) +{ + ppa_struct *dev = (ppa_struct *) data; + schedule_delayed_work(&dev->ppa_tq, 1); +} + +static int ppa_queuecommand(struct scsi_cmnd *cmd, + void (*done) (struct scsi_cmnd *)) +{ + ppa_struct *dev = ppa_dev(cmd->device->host); + schedule_delayed_work(&dev->ppa_tq,0); +} diff --git a/tests/ar.c b/tests/ar.c new file mode 100644 index 0000000..4e5314f --- /dev/null +++ b/tests/ar.c @@ -0,0 +1,12 @@ +struct bar { struct foo *a; struct foo b[27]; }; + +int main() { + struct foo *x; + struct bar *y; + struct foo z[15]; + + x->y = 12; + y->a->y = 12; + y->b[7].y = 12; + z[15].y = 12; +} diff --git a/tests/ar.cocci b/tests/ar.cocci new file mode 100644 index 0000000..065d7b4 --- /dev/null +++ b/tests/ar.cocci @@ -0,0 +1,11 @@ +@@ +struct foo *x; +@@ + +- x->y = 12; + +@@ +struct foo x; +@@ + +- x.y = 12; diff --git a/tests/ar.res b/tests/ar.res new file mode 100644 index 0000000..552e860 --- /dev/null +++ b/tests/ar.res @@ -0,0 +1,7 @@ +struct bar { struct foo *a; struct foo b[27]; }; + +int main() { + struct foo *x; + struct bar *y; + struct foo z[15]; +} diff --git a/tests/arg.c b/tests/arg.c new file mode 100644 index 0000000..d991960 --- /dev/null +++ b/tests/arg.c @@ -0,0 +1,6 @@ +int main () { + foo(bar()); + foo(1,bar()); + foo(bar(),2); + foo(1,bar(),2); +} diff --git a/tests/arg.cocci b/tests/arg.cocci new file mode 100644 index 0000000..a5ce182 --- /dev/null +++ b/tests/arg.cocci @@ -0,0 +1,14 @@ +//@@ +//@@ +// +// foo(... +//- ,bar() +// ) + + +@@ +@@ + + foo(..., +- bar(), + ...) diff --git a/tests/arg.res b/tests/arg.res new file mode 100644 index 0000000..03b7f94 --- /dev/null +++ b/tests/arg.res @@ -0,0 +1,6 @@ +int main () { + foo(); + foo(1); + foo(2); + foo(1,2); +} diff --git a/tests/argument.c b/tests/argument.c new file mode 100644 index 0000000..b94a2c2 --- /dev/null +++ b/tests/argument.c @@ -0,0 +1,8 @@ +void main(int i){ + + f(1,2,3); + + h(1,2); + h(); + +} diff --git a/tests/argument.cocci b/tests/argument.cocci new file mode 100644 index 0000000..f323d1f --- /dev/null +++ b/tests/argument.cocci @@ -0,0 +1,11 @@ +@@ +@@ + +- f(1,2,3); ++ g(3,2,1); + + +@@ +@@ + +- h(...); diff --git a/tests/argument.res b/tests/argument.res new file mode 100644 index 0000000..cc0b0b1 --- /dev/null +++ b/tests/argument.res @@ -0,0 +1,6 @@ +void main(int i){ + + g(3,2,1); + + +} diff --git a/tests/array.c b/tests/array.c new file mode 100644 index 0000000..774fb83 --- /dev/null +++ b/tests/array.c @@ -0,0 +1,11 @@ +#include + +void main(int i) +{ + float x[] = { 0.1, 0.2, 0.3}; + int y; + y = sizeof(x) / sizeof(float); + printf ("size array = %d\n", y); + + +} diff --git a/tests/array.cocci b/tests/array.cocci new file mode 100644 index 0000000..5c1530a --- /dev/null +++ b/tests/array.cocci @@ -0,0 +1,7 @@ +@@ +type T; +T[] id; +@@ + +- sizeof(id) / sizeof(T) ++ ARRAY_SIZE(id) diff --git a/tests/array_init.c b/tests/array_init.c new file mode 100644 index 0000000..9e6afb7 --- /dev/null +++ b/tests/array_init.c @@ -0,0 +1,3 @@ +static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; +MODULE_PARM(term, "1-8i"); + diff --git a/tests/array_init.cocci b/tests/array_init.cocci new file mode 100644 index 0000000..a421069 --- /dev/null +++ b/tests/array_init.cocci @@ -0,0 +1,16 @@ +@ rule3 @ +identifier I; +type T; +expression E; +@@ + +T I[E]; + +@@ +identifier rule3.I; +expression str; +type rule3.T; +@@ + +- MODULE_PARM(I,str); + diff --git a/tests/array_init.res b/tests/array_init.res new file mode 100644 index 0000000..d9c8b52 --- /dev/null +++ b/tests/array_init.res @@ -0,0 +1,2 @@ +static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; + diff --git a/tests/array_size.c b/tests/array_size.c new file mode 100644 index 0000000..c6636a0 --- /dev/null +++ b/tests/array_size.c @@ -0,0 +1,2 @@ +#define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *)) +#define SETUP_BUFFER_SIZE 200 diff --git a/tests/array_size.cocci b/tests/array_size.cocci new file mode 100644 index 0000000..6dccf19 --- /dev/null +++ b/tests/array_size.cocci @@ -0,0 +1,7 @@ +@ rule1 using "empty.iso" @ +expression E; +type T; +@@ + +- (sizeof(E)/sizeof(T)) ++ ARRAY_SIZE(E) diff --git a/tests/array_size.res b/tests/array_size.res new file mode 100644 index 0000000..8528c3c --- /dev/null +++ b/tests/array_size.res @@ -0,0 +1,2 @@ +#define MAX_SETUP_STRINGS ARRAY_SIZE(setup_strings) +#define SETUP_BUFFER_SIZE 200 diff --git a/tests/arraysz.c b/tests/arraysz.c new file mode 100644 index 0000000..e3cebcc --- /dev/null +++ b/tests/arraysz.c @@ -0,0 +1,10 @@ +typedef struct signature { + const char *sig; /* String to look for */ + unsigned long ofs; /* offset from BIOS base address */ + unsigned len; /* length of string */ +} Signature; + +static const Signature signatures[] = { + {"SSTBIOS", 0x0000d, 7} /* "SSTBIOS" @ offset 0x0000d */ +}; +#define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature)) diff --git a/tests/arraysz.cocci b/tests/arraysz.cocci new file mode 100644 index 0000000..783f3f0 --- /dev/null +++ b/tests/arraysz.cocci @@ -0,0 +1,7 @@ +@ disable all @ +type T; +const T[] E; +@@ + +- (sizeof(E)/sizeof(T)) ++ ARRAY_SIZE(E) diff --git a/tests/arraysz.res b/tests/arraysz.res new file mode 100644 index 0000000..e471337 --- /dev/null +++ b/tests/arraysz.res @@ -0,0 +1,10 @@ +typedef struct signature { + const char *sig; /* String to look for */ + unsigned long ofs; /* offset from BIOS base address */ + unsigned len; /* length of string */ +} Signature; + +static const Signature signatures[] = { + {"SSTBIOS", 0x0000d, 7} /* "SSTBIOS" @ offset 0x0000d */ +}; +#define NUM_SIGNATURES ARRAY_SIZE(signatures) diff --git a/tests/assign.c b/tests/assign.c new file mode 100644 index 0000000..6e5947f --- /dev/null +++ b/tests/assign.c @@ -0,0 +1,4 @@ +int main(int x) { + int x = 100; + x = 45; +} diff --git a/tests/assign.cocci b/tests/assign.cocci new file mode 100644 index 0000000..7a9d2bd --- /dev/null +++ b/tests/assign.cocci @@ -0,0 +1,7 @@ +@@ +expression E; +@@ + + x = +- E ++ E + 25 diff --git a/tests/axnet.c b/tests/axnet.c new file mode 100644 index 0000000..9e741a0 --- /dev/null +++ b/tests/axnet.c @@ -0,0 +1,15 @@ +static void axnet_config(struct pcmcia_device *link) +{ + if (last_ret != CS_SUCCESS) { + cs_error(link, RequestIO, last_ret); + goto failed; + } + return; + +cs_failed: + cs_error(link, last_fn, last_ret); +failed: + axnet_release(link); + link->state &= ~DEV_CONFIG_PENDING; + return; +} diff --git a/tests/axnet.cocci b/tests/axnet.cocci new file mode 100644 index 0000000..c4f6388 --- /dev/null +++ b/tests/axnet.cocci @@ -0,0 +1,28 @@ +@@ +expression E; +identifier link; +@@ + +- void ++ int +axnet_config(struct pcmcia_device *link) { + <... +( + if (E) { + ... + axnet_release(...); + ... +- return; ++ return -ENODEV; + } +| + if (E) { + ... + cs_error(...); + ... +- return; ++ return -ENODEV; + } +) + ...> +} diff --git a/tests/b1.c b/tests/b1.c new file mode 100644 index 0000000..fc987b7 --- /dev/null +++ b/tests/b1.c @@ -0,0 +1,7 @@ +int main () { + while (1) { + if (x > 1 ) { foo(); break; } + } + while (1) + if (x > 1 ) { foo(); break; } +} diff --git a/tests/b1.cocci b/tests/b1.cocci new file mode 100644 index 0000000..b27ec87 --- /dev/null +++ b/tests/b1.cocci @@ -0,0 +1,10 @@ +@@ +@@ + +while(...) { + <... + foo(); ++ bar(); + break; + ...> +} diff --git a/tests/b1.res b/tests/b1.res new file mode 100644 index 0000000..e41b313 --- /dev/null +++ b/tests/b1.res @@ -0,0 +1,7 @@ +int main () { + while (1) { + if (x > 1 ) { foo(); bar(); break; } + } + while (1) + if (x > 1 ) { foo(); bar(); break; } +} diff --git a/tests/b2.c b/tests/b2.c new file mode 100644 index 0000000..19ae320 --- /dev/null +++ b/tests/b2.c @@ -0,0 +1,9 @@ +int main () { + if (1) { + if (x > 1 ) { foo(); brk(); } + } else aaa(); + if (1) + while (x > 1 ) { foo(); brk(); } + else aaa(); + foo(); brk(); +} diff --git a/tests/b2.cocci b/tests/b2.cocci new file mode 100644 index 0000000..e4204b7 --- /dev/null +++ b/tests/b2.cocci @@ -0,0 +1,10 @@ +@@ +@@ + +if(...) { + <... + foo(); ++ bar(); + brk(); + ...> +} else aaa(); diff --git a/tests/b2.res b/tests/b2.res new file mode 100644 index 0000000..ee87d5a --- /dev/null +++ b/tests/b2.res @@ -0,0 +1,9 @@ +int main () { + if (1) { + if (x > 1 ) { foo(); bar(); brk(); } + } else aaa(); + if (1) + while (x > 1 ) { foo(); bar(); brk(); } + else aaa(); + foo(); brk(); +} diff --git a/tests/bad_assign.cocci b/tests/bad_assign.cocci new file mode 100644 index 0000000..f42b462 --- /dev/null +++ b/tests/bad_assign.cocci @@ -0,0 +1,148 @@ +@@ +expression x; +expression E; +constant c; +statement S1, S2; +@@ + ++ x = E; ++ NOTHING_XXX; + if ( +- c == (x = E) ++ x == c + ) + S1 else S2 + +@@ +expression x; +expression E; +constant c; +statement S1, S2; +@@ + ++ x = E; ++ NOTHING_XXX; + if ( +- (x = E) == c ++ x == c + ) + S1 else S2 + +@@ +expression x; +expression E; +constant c; +statement S1, S2; +@@ + ++ x = E; ++ NOTHING_XXX; + if ( +- c != (x = E) ++ x != c + ) + S1 else S2 + +@@ +expression x; +expression E; +constant c; +statement S1, S2; +@@ + ++ x = E; ++ NOTHING_XXX; + if ( +- (x = E) != c ++ x != c + ) + S1 else S2 + +@@ +expression x; +expression E, E1; +statement S1, S2; +@@ + ++ x = E; ++ NOTHING_XXX; + if ( +- E1 == (x = E) ++ E1 == x + ) + S1 else S2 + +@@ +expression x; +expression E, E1; +statement S1, S2; +@@ + ++ x = E; ++ NOTHING_XXX; + if ( +- (x = E) == E1 ++ x == E1 + ) + S1 else S2 + +@@ +expression x; +expression E,E1; +statement S1, S2; +@@ + ++ x = E; ++ NOTHING_XXX; + if ( +- E1 != (x = E) ++ E1 != x + ) + S1 else S2 + +@@ +expression x; +expression E,E1; +statement S1, S2; +@@ + ++ x = E; ++ NOTHING_XXX; + if ( +- (x = E) != E1 ++ x != E1 + ) + S1 else S2 + +@@ +expression x; +expression E; +statement S1, S2; +@@ + ++ x = E; ++ NOTHING_XXX; + if ( +- x = E ++ x + ) + S1 else S2 + +@@ +expression x; +expression E; +statement S1, S2; +@@ + ++ x = E; ++ NOTHING_XXX; + if (! +- (x = E) ++ x + ) + S1 else S2 + +@@ +@@ + +- NOTHING_XXX; diff --git a/tests/bad_define.c b/tests/bad_define.c new file mode 100644 index 0000000..fafa109 --- /dev/null +++ b/tests/bad_define.c @@ -0,0 +1 @@ +#define x a + b diff --git a/tests/bad_define.cocci b/tests/bad_define.cocci new file mode 100644 index 0000000..a0f66ab --- /dev/null +++ b/tests/bad_define.cocci @@ -0,0 +1,25 @@ +@@ +expression E; +identifier y; +constant c; +identifier x,fld; +expression f; +@@ + +( +#define x (E) +| +#define x y +| +#define x c +| +#define x f(...) +| +#define x sizeof(...) +| +#define x E.fld +| +#define x E->fld +| +- #define x E +) diff --git a/tests/bad_define.res b/tests/bad_define.res new file mode 100644 index 0000000..e69de29 diff --git a/tests/bad_iso_example.c b/tests/bad_iso_example.c new file mode 100644 index 0000000..c66e5e9 --- /dev/null +++ b/tests/bad_iso_example.c @@ -0,0 +1,4 @@ +int main() { + if ((x = 3)) return; +} + diff --git a/tests/bad_iso_example.cocci b/tests/bad_iso_example.cocci new file mode 100644 index 0000000..bb8f454 --- /dev/null +++ b/tests/bad_iso_example.cocci @@ -0,0 +1,23 @@ +@r@ +expression E,E1; +statement S1,S2; +@@ + ++ E = E1; +if ( +- !(E = E1) ++ E + ) +S1 else S2 + +// @@ +// expression E,E1; +// statement S1,S2; +// @@ + +// + E = E1; +// if ( +// - E = E1 +// + E +// ) +// S1 else S2 diff --git a/tests/bad_iso_example.res b/tests/bad_iso_example.res new file mode 100644 index 0000000..fc203e2 --- /dev/null +++ b/tests/bad_iso_example.res @@ -0,0 +1,4 @@ +int main() { + if (x) return; +} + diff --git a/tests/bad_noputm1 b/tests/bad_noputm1 new file mode 100644 index 0000000..f72fec6 --- /dev/null +++ b/tests/bad_noputm1 @@ -0,0 +1,168 @@ +diff -u -p -b a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c +OK send +--- a/arch/sparc64/kernel/isa.c 2007-08-12 13:27:06.000000000 +0200 ++++ b/arch/sparc64/kernel/isa.c 2007-11-18 18:32:16.000000000 +0100 +@@ -155,6 +155,7 @@ void __init isa_init(void) + isa_br = kzalloc(sizeof(*isa_br), GFP_KERNEL); + if (!isa_br) { + printk(KERN_DEBUG "isa: cannot allocate sparc_isa_bridge"); ++ pci_dev_put(pdev); + return; + } + +@@ -168,6 +169,7 @@ void __init isa_init(void) + printk(KERN_DEBUG "isa: device registration error for %s!\n", + dp->path_component_name); + kfree(isa_br); ++ pci_dev_put(pdev); + return; + } + +diff -u -p -b a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c +--- a/drivers/char/agp/amd64-agp.c 2007-11-01 10:30:39.000000000 +0100 ++++ b/drivers/char/agp/amd64-agp.c 2007-11-18 18:32:36.000000000 +0100 +NOT SURE +@@ -771,6 +771,7 @@ int __init agp_amd64_init(void) + /* Only one bridge supported right now */ + if (agp_amd64_probe(dev, NULL) == 0) { + err = 0; ++ pci_dev_put(dev); + break; + } + } +diff -u -p -b a/drivers/char/applicom.c b/drivers/char/applicom.c +--- a/drivers/char/applicom.c 2006-11-30 19:04:20.000000000 +0100 ++++ b/drivers/char/applicom.c 2007-11-18 18:32:39.000000000 +0100 +@@ -204,7 +204,9 @@ static int __init applicom_init(void) + continue; + + if (pci_enable_device(dev)) +- return -EIO; ++ { ++ pci_dev_put(dev); ++ return -EIO;} + + RamIO = ioremap(dev->resource[0].start, LEN_RAM_IO); + +@@ -213,6 +215,7 @@ static int __init applicom_init(void) + "space at 0x%llx\n", + (unsigned long long)dev->resource[0].start); + pci_disable_device(dev); ++ pci_dev_put(dev); + return -EIO; + } + +diff -u -p -b a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c +--- a/drivers/macintosh/via-pmu.c 2007-10-22 11:25:10.000000000 +0200 ++++ b/drivers/macintosh/via-pmu.c 2007-11-18 18:33:24.000000000 +0100 +OK sent +@@ -1897,7 +1897,9 @@ pbook_pci_restore(void) + pci_write_config_dword(pd, 4, ps->config[1]); + #else + if (npci-- == 0) +- return; ++ { ++ pci_dev_put(pd); ++ return;} + ps++; + if (ps->command == 0) + continue; +diff -u -p -b a/drivers/mmc/host/ricoh_mmc.c b/drivers/mmc/host/ricoh_mmc.c +--- a/drivers/mmc/host/ricoh_mmc.c 2007-11-18 16:56:19.000000000 +0100 ++++ b/drivers/mmc/host/ricoh_mmc.c 2007-11-18 18:33:44.000000000 +0100 +@@ -68,6 +68,7 @@ static int __devinit ricoh_mmc_probe(str + if (disable & 0x02) { + printk(KERN_INFO DRIVER_NAME + ": Controller already disabled. Nothing to do.\n"); ++ pci_dev_put(fw_dev); + return -ENODEV; + } + +@@ -81,6 +82,7 @@ static int __devinit ricoh_mmc_probe(str + printk(KERN_INFO DRIVER_NAME + ": Controller is now disabled.\n"); + ++ pci_dev_put(fw_dev); + break; + } + } +diff -u -p -b a/drivers/net/s2io.c b/drivers/net/s2io.c +--- a/drivers/net/s2io.c 2007-11-15 15:09:36.000000000 +0100 ++++ b/drivers/net/s2io.c 2007-11-18 18:34:15.000000000 +0100 +BIZARRE submitted +@@ -983,6 +983,7 @@ static int s2io_on_nec_bridge(struct pci + if (tdev->vendor == NEC_VENID && tdev->device == NEC_DEVID) { + if (tdev->bus == s2io_pdev->bus->parent) + pci_dev_put(tdev); ++ pci_dev_put(tdev); + return 1; + } + } +diff -u -p -b a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c +OK sent +--- a/drivers/pci/pci-sysfs.c 2007-07-20 17:45:56.000000000 +0200 ++++ b/drivers/pci/pci-sysfs.c 2007-11-18 18:34:41.000000000 +0100 +@@ -703,7 +703,9 @@ static int __init pci_sysfs_init(void) + for_each_pci_dev(pdev) { + retval = pci_create_sysfs_dev_files(pdev); + if (retval) +- return retval; ++ { ++ pci_dev_put(pdev); ++ return retval;} + } + + return 0; +diff -u -p -b a/drivers/pnp/resource.c b/drivers/pnp/resource.c +OK sent +--- a/drivers/pnp/resource.c 2007-10-22 11:25:20.000000000 +0200 ++++ b/drivers/pnp/resource.c 2007-11-18 18:34:46.000000000 +0100 +@@ -368,7 +368,9 @@ int pnp_check_irq(struct pnp_dev *dev, i + struct pci_dev *pci = NULL; + for_each_pci_dev(pci) { + if (pci->irq == *irq) +- return 0; ++ { ++ pci_dev_put(pci); ++ return 0;} + } + } + #endif +diff -u -p -b a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c +--- a/drivers/scsi/dpt_i2o.c 2007-10-22 11:25:23.000000000 +0200 ++++ b/drivers/scsi/dpt_i2o.c 2007-11-18 18:36:30.000000000 +0100 +NOT SURE +code is written in an inconsistent manner, such that adpt_install_hba +might do a put on pDev, or might not +@@ -189,6 +189,7 @@ static int adpt_detect(void) + if(adpt_install_hba(pDev) ){ + PERROR("Could not Init an I2O RAID device\n"); + PERROR("Will not try to detect others.\n"); ++ pci_dev_put(pDev); + return hba_count-1; + } + pci_dev_get(pDev); +diff -u -p -b a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c +NO. iTCO_wdt_init does put. +--- a/drivers/watchdog/iTCO_wdt.c 2007-11-08 08:00:52.000000000 +0100 ++++ b/drivers/watchdog/iTCO_wdt.c 2007-11-18 18:37:09.000000000 +0100 +@@ -740,6 +740,7 @@ static int __devinit iTCO_wdt_probe(stru + if (ent) { + if (!(iTCO_wdt_init(pdev, ent, dev))) { + found++; ++ pci_dev_put(pdev); + break; + } + } +diff -u -p -b a/sound/core/memalloc.c b/sound/core/memalloc.c +OK sent +--- a/sound/core/memalloc.c 2007-10-22 11:25:51.000000000 +0200 ++++ b/sound/core/memalloc.c 2007-11-18 18:38:21.000000000 +0100 +@@ -568,6 +568,7 @@ static ssize_t snd_mem_proc_write(struct + if (pci_set_dma_mask(pci, mask) < 0 || + pci_set_consistent_dma_mask(pci, mask) < 0) { + printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device); ++ pci_dev_put(pci); + return count; + } + } diff --git a/tests/bad_subsumption.c b/tests/bad_subsumption.c new file mode 100644 index 0000000..e3be852 --- /dev/null +++ b/tests/bad_subsumption.c @@ -0,0 +1,40 @@ +static int __devinit snd_vx222_create(struct snd_card *card, struct pci_dev *pci, + struct snd_vx_hardware *hw, + struct snd_vx222 **rchip) +{ + struct vx_core *chip; + struct snd_vx222 *vx; + static struct snd_device_ops ops = { + .dev_free = snd_vx222_dev_free, + }; + chip = snd_vx_create(card, hw, vx_ops, + sizeof(struct snd_vx222) - sizeof(struct vx_core)); + if (! chip) { + pci_disable_device(pci); + return -ENOMEM; + } + vx = (struct snd_vx222 *)chip; + vx->pci = pci; + + if ((err = pci_request_regions(pci, CARD_NAME)) < 0) { + snd_vx222_free(chip); + return 0; + } + for (i = 0; i < 2; i++) + vx->port[i] = pci_resource_start(pci, i + 1); + + if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED, + CARD_NAME, chip)) { + snd_vx222_free(chip); + return -EBUSY; + } + chip->irq = pci->irq; + + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + snd_vx222_free(chip); + return 0; + } + + + return 0; +} diff --git a/tests/bad_subsumption.cocci b/tests/bad_subsumption.cocci new file mode 100644 index 0000000..b69a87d --- /dev/null +++ b/tests/bad_subsumption.cocci @@ -0,0 +1,73 @@ +@loc exists@ +type T; +identifier E; +identifier f != {kmalloc,kcalloc,kzalloc}; +position pl; +@@ + + T *E; + ... when any + E = f@pl(...) + +@probe forall@ +identifier E; +expression E1,E2; +identifier loc.f,g; +int ret; +statement S; +position loc.pl; +@@ + +( + E = f@pl(...); + ... when != E + if (<+... E == NULL ...+>) S +| + if (<+...(E = f@pl(...)) == NULL...+>) S +) + ... when strict + when any + when != E2 = E + when != E = E2 +( + E1 = E; +| + E = E1;// this could seem bad: the value is being overwritten before being + // saved, but in bd_claim_by_kobject in fs/block_dev, the value is + // first passed to a function that saves it. anyway, we will see if + // this leads to false positives. +| + g(...,E,...); +| + return; +| + return ret; +) + +// might be a different function than the one matched above +@exists@ +identifier E; +identifier loc.f, probe.g,x; +expression E1; +position loc.pl; +int ret; +@@ + + E = f@pl(...) + ... when strict + when any + when != E1 = E + if (...) { + ... when any + when != E1 = E + when != g(...,E,...) + g(E ++ ,"detected allocator",f,g + ); + ... when != E +( + return; +| + return ret; +) + } diff --git a/tests/bad_typedef.c b/tests/bad_typedef.c new file mode 100644 index 0000000..496bebb --- /dev/null +++ b/tests/bad_typedef.c @@ -0,0 +1,17 @@ +typedef struct { + struct semaphore lock; +} scsi_changer; + + +int main1 (scsi_changer *x) { + foo(x->lock); +} + +struct scsi_changer_two { + struct semaphore lock; +}; + + +int main2 (struct scsi_changer_two *x) { + foo(x->lock); +} diff --git a/tests/bad_typedef.cocci b/tests/bad_typedef.cocci new file mode 100644 index 0000000..7c81d75 --- /dev/null +++ b/tests/bad_typedef.cocci @@ -0,0 +1,17 @@ +@ rule1 @ +type T; +identifier lock; +@@ + +T { ... + struct semaphore lock; + ... + }; + +@@ +type rule1.T; +T *x; +@@ + +- x->lock ++ x->new_lock diff --git a/tests/bad_typedef.res b/tests/bad_typedef.res new file mode 100644 index 0000000..8840f5f --- /dev/null +++ b/tests/bad_typedef.res @@ -0,0 +1,17 @@ +typedef struct { + struct semaphore lock; +} scsi_changer; + + +int main1 (scsi_changer *x) { + foo(x->new_lock); +} + +struct scsi_changer_two { + struct semaphore lock; +}; + + +int main2 (struct scsi_changer_two *x) { + foo(x->new_lock); +} diff --git a/tests/bad_zero.cocci b/tests/bad_zero.cocci new file mode 100644 index 0000000..33b14ff --- /dev/null +++ b/tests/bad_zero.cocci @@ -0,0 +1,71 @@ +// to be used without isomorphisms + +@@ +expression *E; +@@ + + E == +- 0 ++ NULL + +@@ +expression *E; +@@ + +- 0 ++ NULL + == E + +@@ +expression *E; +@@ + + E != +- 0 ++ NULL + +@@ +expression *E; +@@ + +- 0 ++ NULL + != E + +// assignments + +@@ +expression *E; +expression E1; +@@ + + (E = E1) == +- 0 ++ NULL + +@@ +expression *E; +expression E1; +@@ + +- 0 ++ NULL + == (E = E1) + +@@ +expression *E; +expression E1; +@@ + + (E = E1) != +- 0 ++ NULL + +@@ +expression *E; +expression E1; +@@ + +- 0 ++ NULL + != (E = E1) diff --git a/tests/badaw.c b/tests/badaw.c new file mode 100644 index 0000000..9e23092 --- /dev/null +++ b/tests/badaw.c @@ -0,0 +1,36 @@ +static int __cpuinit cpuup_prepare(long cpu) +{ + struct kmem_list3 *l3 = NULL; + + list_for_each_entry(cachep, &cache_chain, next) { + if (!cachep->nodelists[node]) { + l3 = kmalloc_node(memsize, GFP_KERNEL, node); + if (!l3) return 0; + kmem_list3_init(l3); + l3->next_reap = jiffies + REAPTIMEOUT_LIST3 + + ((unsigned long)cachep) % REAPTIMEOUT_LIST3; + cachep->nodelists[node] = l3; + } + } + list_for_each_entry(cachep, &cache_chain, next) { + struct array_cache *shared = NULL; + + if (cachep->shared) { + shared = alloc_arraycache(node, + cachep->shared * cachep->batchcount, + 0xbaadf00d); + if (!shared) return 0; + } + if (use_alien_caches) { + if (!alien) { + kfree(shared); + goto bad; + } + } + + kfree(shared); + } + +bad: + return -ENOMEM; +} diff --git a/tests/badaw.cocci b/tests/badaw.cocci new file mode 100644 index 0000000..a4b09f6 --- /dev/null +++ b/tests/badaw.cocci @@ -0,0 +1,30 @@ +@loc@ +identifier f; +position pl; +@@ + + f@pl(...) + +@probe forall@ +identifier E; +identifier f,g; +int ret; +statement S; +position loc.pl; +@@ + + E = f@pl(...); + ... when any +( + g(...,E,...); +| + return ret; +) + +@exists@ +identifier probe.f, probe.g; +@@ + + f(...) + ... + g(...) \ No newline at end of file diff --git a/tests/badcomma.c b/tests/badcomma.c new file mode 100644 index 0000000..3cccd95 --- /dev/null +++ b/tests/badcomma.c @@ -0,0 +1,4 @@ +static struct usb_serial_device_type cp2101_device = { + .owner = THIS_MODULE, + .name = "CP2101", +}; diff --git a/tests/badcomma.cocci b/tests/badcomma.cocci new file mode 100644 index 0000000..259dd6e --- /dev/null +++ b/tests/badcomma.cocci @@ -0,0 +1,3 @@ +@@ @@ +- struct usb_serial_device_type ++ struct usb_serial_driver diff --git a/tests/badexp.c b/tests/badexp.c new file mode 100644 index 0000000..4f1a4c4 --- /dev/null +++ b/tests/badexp.c @@ -0,0 +1,4 @@ +int main() { + foo(a); + b = a; +} diff --git a/tests/badexp.cocci b/tests/badexp.cocci new file mode 100644 index 0000000..1f9c23f --- /dev/null +++ b/tests/badexp.cocci @@ -0,0 +1,9 @@ +@@ +expression x; +@@ + + foo(x); + ... ++ 3 + + x ++ * 27 diff --git a/tests/badexp.res b/tests/badexp.res new file mode 100644 index 0000000..a066d8b --- /dev/null +++ b/tests/badexp.res @@ -0,0 +1,4 @@ +int main() { + foo(a); + b = 3+a*27; +} diff --git a/tests/badexp1.c b/tests/badexp1.c new file mode 100644 index 0000000..e7c4985 --- /dev/null +++ b/tests/badexp1.c @@ -0,0 +1,4 @@ +int main() { + foo(a); + a(y); +} diff --git a/tests/badexp1.cocci b/tests/badexp1.cocci new file mode 100644 index 0000000..a36967f --- /dev/null +++ b/tests/badexp1.cocci @@ -0,0 +1,9 @@ +@@ +expression x; +@@ + + foo(x); + ... ++ 3 + + x(...,y,...) ++ * 27 diff --git a/tests/badfree.c b/tests/badfree.c new file mode 100644 index 0000000..a67bc07 --- /dev/null +++ b/tests/badfree.c @@ -0,0 +1,6 @@ +int main() { + free(x); + if (a) { + foo(a,x,b); + } +} diff --git a/tests/badfree.cocci b/tests/badfree.cocci new file mode 100644 index 0000000..8eda517 --- /dev/null +++ b/tests/badfree.cocci @@ -0,0 +1,10 @@ +@@ +expression x; +expression E; +expression f; +@@ + + free(x); + ... WHEN != x = E ++ printf("possible use after free!!\n"); + f(...,x,...); diff --git a/tests/badpos.c b/tests/badpos.c new file mode 100644 index 0000000..9f288e0 --- /dev/null +++ b/tests/badpos.c @@ -0,0 +1,6 @@ +static irqreturn_t +elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr) +{ + printk(KERN_ERR "foo", + (int) -(((struct pt_regs *) reg_ptr)->orig_eax + 2)); +} diff --git a/tests/badpos.cocci b/tests/badpos.cocci new file mode 100644 index 0000000..ed9546a --- /dev/null +++ b/tests/badpos.cocci @@ -0,0 +1,8 @@ +@@ +struct pt_regs *regs; +expression E; +expression f; +@@ + +- regs ++ xxx diff --git a/tests/badpos.res b/tests/badpos.res new file mode 100644 index 0000000..be99a97 --- /dev/null +++ b/tests/badpos.res @@ -0,0 +1,6 @@ +static irqreturn_t +elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr) +{ + printk(KERN_ERR "foo", + (int) -(xxx->orig_eax + 2)); +} diff --git a/tests/badpost.cocci b/tests/badpost.cocci new file mode 100644 index 0000000..065b1b6 --- /dev/null +++ b/tests/badpost.cocci @@ -0,0 +1,17 @@ +@x@ +position p; +identifier f; +expression E; +@@ + +- f(3, ++ f(3, + E@p,...) + +@@ +position x.p; +identifier g; +expression E; +@@ + +- g(3,E@p,...); \ No newline at end of file diff --git a/tests/badprint.c b/tests/badprint.c new file mode 100644 index 0000000..472dd4c --- /dev/null +++ b/tests/badprint.c @@ -0,0 +1,7 @@ +#define PRINTK(x) printk x + +#include "foo.h" + +int main () { + printk("some stuff\n"); +} diff --git a/tests/badtypedef.c b/tests/badtypedef.c new file mode 100644 index 0000000..067dfd9 --- /dev/null +++ b/tests/badtypedef.c @@ -0,0 +1,11 @@ +typedef struct foo { int a; } foo_t; + +int main() { + struct foo *a; + foo_t *b; + foo_t *c; + + xxx(a); + yyy(b); +} + diff --git a/tests/badtypedef.cocci b/tests/badtypedef.cocci new file mode 100644 index 0000000..e74f64e --- /dev/null +++ b/tests/badtypedef.cocci @@ -0,0 +1,12 @@ +// need the merge_val facility for typedef and struct equivalence + +@@ +type T; +T E, E1; +@@ + +- xxx(E); ++ aaa(E); + ... +- yyy(E1); ++ bbb(E1); diff --git a/tests/badtypedef.res b/tests/badtypedef.res new file mode 100644 index 0000000..952b794 --- /dev/null +++ b/tests/badtypedef.res @@ -0,0 +1,11 @@ +typedef struct foo { int a; } foo_t; + +int main() { + struct foo *a; + foo_t *b; + foo_t *c; + + aaa(a); + bbb(b); +} + diff --git a/tests/bitfield.c b/tests/bitfield.c new file mode 100644 index 0000000..1fec088 --- /dev/null +++ b/tests/bitfield.c @@ -0,0 +1,15 @@ +struct dvb_frontend { + struct dvb_frontend_ops* ops; +}; + +typedef struct { + u8 RESET :1; + u8 IDLE :1; + u8 STOP :1; + u8 HIRQ0 :1; + u8 HIRQ1 :1; + u8 na0 :1; + u8 HABAV :1; + u8 na1 :1; + +} bcm3510_register_value; diff --git a/tests/bitfield.cocci b/tests/bitfield.cocci new file mode 100644 index 0000000..129c409 --- /dev/null +++ b/tests/bitfield.cocci @@ -0,0 +1,9 @@ +@@ +@@ + +struct dvb_frontend { + ... +- struct dvb_frontend_ops* ops; ++ struct dvb_frontend_ops ops; + ... +}; diff --git a/tests/bitfield.res b/tests/bitfield.res new file mode 100644 index 0000000..934cffb --- /dev/null +++ b/tests/bitfield.res @@ -0,0 +1,15 @@ +struct dvb_frontend { + struct dvb_frontend_ops ops; +}; + +typedef struct { + u8 RESET :1; + u8 IDLE :1; + u8 STOP :1; + u8 HIRQ0 :1; + u8 HIRQ1 :1; + u8 na0 :1; + u8 HABAV :1; + u8 na1 :1; + +} bcm3510_register_value; diff --git a/tests/braces.c b/tests/braces.c new file mode 100644 index 0000000..753c650 --- /dev/null +++ b/tests/braces.c @@ -0,0 +1,9 @@ +#define main { foo(); } + +int main() { foo(); } + +int main() { if (x) { foo(); } } + +int main() { while (x) { foo(); } } + +int main() { if (x) { foo(); } else { foo(); } } diff --git a/tests/braces.cocci b/tests/braces.cocci new file mode 100644 index 0000000..be6af83 --- /dev/null +++ b/tests/braces.cocci @@ -0,0 +1,6 @@ +@@ +@@ + +- { + foo(); +- } diff --git a/tests/braces.res b/tests/braces.res new file mode 100644 index 0000000..ac8747c --- /dev/null +++ b/tests/braces.res @@ -0,0 +1,9 @@ +#define main foo(); + +int main() { foo(); } + +int main() { if (x) foo(); } + +int main() { while (x) foo(); } + +int main() { if (x) foo(); else foo(); } diff --git a/tests/break.c b/tests/break.c new file mode 100644 index 0000000..1bc4370 --- /dev/null +++ b/tests/break.c @@ -0,0 +1,23 @@ +int main () { + while (1) { + x = 12; + do { + x = 15; + if (x > 1 ) { foo(); break; } + } while (a == 3); + if (x > 1 ) { foo(); break; } + if (x > 1 ) { foo(); break; } + } +} + +int mainx () { + while (1) { + x = 12; + do { + x = 15; + if (x > 1 ) { xxx(); continue; } + } while (a == 3); + if (x > 1 ) { xxx(); break; } + if (x > 1 ) { xxx(); continue; } + } +} diff --git a/tests/break.cocci b/tests/break.cocci new file mode 100644 index 0000000..03022dc --- /dev/null +++ b/tests/break.cocci @@ -0,0 +1,21 @@ +@@ +@@ + +while(...) { + <... + foo(); ++ bar(); + break; + ...> +} + +@@ +@@ + +while(...) { + <... + xxx(); ++ bar(); + continue; + ...> +} \ No newline at end of file diff --git a/tests/break.res b/tests/break.res new file mode 100644 index 0000000..03dda13 --- /dev/null +++ b/tests/break.res @@ -0,0 +1,23 @@ +int main () { + while (1) { + x = 12; + do { + x = 15; + if (x > 1 ) { foo(); break; } + } while (a == 3); + if (x > 1 ) { foo(); bar(); break; } + if (x > 1 ) { foo(); bar(); break; } + } +} + +int mainx () { + while (1) { + x = 12; + do { + x = 15; + if (x > 1 ) { xxx(); continue; } + } while (a == 3); + if (x > 1 ) { xxx(); break; } + if (x > 1 ) { xxx(); bar(); continue; } + } +} diff --git a/tests/bug1.c b/tests/bug1.c new file mode 100644 index 0000000..2cd6672 --- /dev/null +++ b/tests/bug1.c @@ -0,0 +1,5 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd,void *arg) +{ + struct typhoon_device *typhoon = dev->priv; + return 0; +} diff --git a/tests/bug1.cocci b/tests/bug1.cocci new file mode 100644 index 0000000..869611e --- /dev/null +++ b/tests/bug1.cocci @@ -0,0 +1,11 @@ +@r@ +identifier ioctlfn; +identifier dev, cmd, arg; +@@ + + ioctlfn( +- struct video_device *dev, ++ struct inode *i, struct file *f, + unsigned int cmd, void *arg) { + ... + } diff --git a/tests/bug1.res b/tests/bug1.res new file mode 100644 index 0000000..3fcff70 --- /dev/null +++ b/tests/bug1.res @@ -0,0 +1,6 @@ +static int typhoon_ioctl(struct inode *i, struct file *f, unsigned int cmd, +void *arg) +{ + struct typhoon_device *typhoon = dev->priv; + return 0; +} diff --git a/tests/bug_expopt.c b/tests/bug_expopt.c new file mode 100644 index 0000000..50d1dec --- /dev/null +++ b/tests/bug_expopt.c @@ -0,0 +1,63 @@ +static int __init xpram_setup_blkdev(void) +{ + unsigned long offset; + int i, rc = -ENOMEM; + + for (i = 0; i < xpram_devs; i++) { + struct gendisk *disk = alloc_disk(1); + if (!disk) + goto out; + xpram_disks[i] = disk; + } + + /* + * Register xpram major. + */ + rc = register_blkdev(XPRAM_MAJOR, XPRAM_NAME); + if (rc < 0) + goto out; + + devfs_mk_dir("slram"); + + /* + * Assign the other needed values: make request function, sizes and + * hardsect size. All the minor devices feature the same value. + */ + xpram_queue = blk_alloc_queue(GFP_KERNEL); + if (!xpram_queue) { + rc = -ENOMEM; + goto out_unreg; + } + blk_queue_make_request(xpram_queue, xpram_make_request); + blk_queue_hardsect_size(xpram_queue, 4096); + + /* + * Setup device structures. + */ + offset = 0; + for (i = 0; i < xpram_devs; i++) { + struct gendisk *disk = xpram_disks[i]; + + xpram_devices[i].size = xpram_sizes[i] / 4; + xpram_devices[i].offset = offset; + offset += xpram_devices[i].size; + disk->major = XPRAM_MAJOR; + disk->first_minor = i; + disk->fops = &xpram_devops; + disk->private_data = &xpram_devices[i]; + disk->queue = xpram_queue; + sprintf(disk->disk_name, "slram%d", i); + sprintf(disk->devfs_name, "slram/%d", i); + set_capacity(disk, xpram_sizes[i] << 1); + add_disk(disk); + } + + return 0; +out_unreg: + devfs_remove("slram"); + unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); +out: + while (i--) + put_disk(xpram_disks[i]); + return rc; +} diff --git a/tests/bug_expopt.cocci b/tests/bug_expopt.cocci new file mode 100644 index 0000000..795f4f2 --- /dev/null +++ b/tests/bug_expopt.cocci @@ -0,0 +1,16 @@ +@@ +identifier x; +// struct xx struc; +@@ +( +- sprintf +| +- strlcpy +| +- strcpy +| +- strcat +| +- snprintf +) +- (x->devfs_name, ...); diff --git a/tests/bugloop.c b/tests/bugloop.c new file mode 100644 index 0000000..efb639c --- /dev/null +++ b/tests/bugloop.c @@ -0,0 +1,17 @@ +/* this doesn't work, because on the paths where we don't find refrigerator, +we expect to reach Exit without first going through current->flags & PF_FREEZE, +but of course any path that goes around the loop does precisely that */ + +static int stir_transmit_thread(void *arg) +{ + + while (x) + { + /* if suspending, then power off and wait */ + if (unlikely(current->flags & PF_FREEZE)) { + refrigerator(PF_FREEZE); + + } + } +} + diff --git a/tests/bugloop.cocci b/tests/bugloop.cocci new file mode 100644 index 0000000..e659a6e --- /dev/null +++ b/tests/bugloop.cocci @@ -0,0 +1,9 @@ +@@ expression current; @@ + +- current->flags & PF_FREEZE ++ freezing(current) + ... +?- refrigerator(PF_FREEZE) ++ refrigerator() + ... +? current->flags & PF_FREEZE diff --git a/tests/bugloop.res b/tests/bugloop.res new file mode 100644 index 0000000..3c195dc --- /dev/null +++ b/tests/bugloop.res @@ -0,0 +1,13 @@ +static int stir_transmit_thread(void *arg) +{ + + while (x) + { + /* if suspending, then power off and wait */ + if (unlikely(freezing(current))) { + refrigerator(); + + } + } +} + diff --git a/tests/bugon.c b/tests/bugon.c new file mode 100644 index 0000000..7e449c1 --- /dev/null +++ b/tests/bugon.c @@ -0,0 +1,5 @@ +static void b44_tx(struct b44 *bp) +{ + if (unlikely(skb == NULL)) + BUG(); +} diff --git a/tests/bugon.cocci b/tests/bugon.cocci new file mode 100644 index 0000000..bc478a4 --- /dev/null +++ b/tests/bugon.cocci @@ -0,0 +1,4 @@ +@@ expression E; @@ + +- if (unlikely(E)) { BUG(); } ++ BUG_ON(E); diff --git a/tests/bugon.res b/tests/bugon.res new file mode 100644 index 0000000..047bb23 --- /dev/null +++ b/tests/bugon.res @@ -0,0 +1,4 @@ +static void b44_tx(struct b44 *bp) +{ + BUG(skb == NULL); +} diff --git a/tests/cards.c b/tests/cards.c new file mode 100644 index 0000000..8f77635 --- /dev/null +++ b/tests/cards.c @@ -0,0 +1,3 @@ +MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i"); + +int x; diff --git a/tests/cards.cocci b/tests/cards.cocci new file mode 100644 index 0000000..33a6511 --- /dev/null +++ b/tests/cards.cocci @@ -0,0 +1,6 @@ +@@ +identifier I; +expression str; +@@ + +- MODULE_PARM(I,str); diff --git a/tests/cards.res b/tests/cards.res new file mode 100644 index 0000000..6d1a0d4 --- /dev/null +++ b/tests/cards.res @@ -0,0 +1 @@ +int x; diff --git a/tests/cast.c b/tests/cast.c new file mode 100644 index 0000000..b41c448 --- /dev/null +++ b/tests/cast.c @@ -0,0 +1,3 @@ +int main () { + ((struct xxx *)E)->foo = 12; +} diff --git a/tests/cast.cocci b/tests/cast.cocci new file mode 100644 index 0000000..5069931 --- /dev/null +++ b/tests/cast.cocci @@ -0,0 +1,6 @@ +@@ +struct xxx *E; +@@ + +- E->foo = 12; + diff --git a/tests/cast.res b/tests/cast.res new file mode 100644 index 0000000..d6a7729 --- /dev/null +++ b/tests/cast.res @@ -0,0 +1,2 @@ +int main () { +} diff --git a/tests/cast_iso.c b/tests/cast_iso.c new file mode 100644 index 0000000..8f3f485 --- /dev/null +++ b/tests/cast_iso.c @@ -0,0 +1,6 @@ +static int vx_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) +{ + vx_core_t *vx = snd_magic_cast(vx_core_t, hw->private_data, return -ENXIO); + ak4117_t *chip = snd_magic_cast(ak4117_t, (void *)data, return); + +} diff --git a/tests/cast_iso.cocci b/tests/cast_iso.cocci new file mode 100644 index 0000000..f111ec4 --- /dev/null +++ b/tests/cast_iso.cocci @@ -0,0 +1,15 @@ +@@ +expression B; +type T; +@@ + +- snd_magic_cast(T, (void*) B ,...) ++ (T *) B + +@@ +expression B; +type T; +@@ + +- snd_magic_cast(T,B,...) ++ B diff --git a/tests/cast_iso.res b/tests/cast_iso.res new file mode 100644 index 0000000..7f4b4ad --- /dev/null +++ b/tests/cast_iso.res @@ -0,0 +1,5 @@ +static int vx_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) +{ + vx_core_t *vx = hw->private_data; + ak4117_t *chip = (ak4117_t *)data; +} diff --git a/tests/comment.c b/tests/comment.c new file mode 100644 index 0000000..f32baac --- /dev/null +++ b/tests/comment.c @@ -0,0 +1,6 @@ +void f(int i) { + + + x = 1/* comment*/ ; + x = /* comment*/1 ; +} diff --git a/tests/comment.cocci b/tests/comment.cocci new file mode 100644 index 0000000..a690a37 --- /dev/null +++ b/tests/comment.cocci @@ -0,0 +1,5 @@ +@@ +@@ + +- 1 ++ 2 \ No newline at end of file diff --git a/tests/compare.c b/tests/compare.c new file mode 100644 index 0000000..2f6f09d --- /dev/null +++ b/tests/compare.c @@ -0,0 +1,14 @@ +struct aic7xxx_host { + struct aic7xxx_cmd_queue { + Scsi_Cmnd *head; + Scsi_Cmnd *tail; + } completeq; + unsigned char msg_buf[13]; /* The message for the target */ + unsigned char msg_type; +#define MSG_TYPE_NONE 0x00 +#define MSG_TYPE_INITIATOR_MSGOUT 0x01 +#define MSG_TYPE_INITIATOR_MSGIN 0x02 + unsigned char msg_len; /* Length of message */ + unsigned char msg_index; /* Index into msg_buf array */ +}; + diff --git a/tests/compare.cocci b/tests/compare.cocci new file mode 100644 index 0000000..7a75dc3 --- /dev/null +++ b/tests/compare.cocci @@ -0,0 +1,4 @@ +@@ typedef Scsi_Cmnd; @@ + +- Scsi_Cmnd ++ struct scsi_cmnd diff --git a/tests/compare.res b/tests/compare.res new file mode 100644 index 0000000..8a2f4f7 --- /dev/null +++ b/tests/compare.res @@ -0,0 +1,14 @@ +struct aic7xxx_host { + struct aic7xxx_cmd_queue { + struct scsi_cmnd *head; + struct scsi_cmnd *tail; + } completeq; + unsigned char msg_buf[13]; /* The message for the target */ + unsigned char msg_type; +#define MSG_TYPE_NONE 0x00 +#define MSG_TYPE_INITIATOR_MSGOUT 0x01 +#define MSG_TYPE_INITIATOR_MSGIN 0x02 + unsigned char msg_len; /* Length of message */ + unsigned char xmsg_index; /* Index into msg_buf array */ +}; + diff --git a/tests/const.c b/tests/const.c new file mode 100644 index 0000000..960ecc9 --- /dev/null +++ b/tests/const.c @@ -0,0 +1,3 @@ +void foo(const char *text) { + strcat(buf->data, text); +} diff --git a/tests/const.cocci b/tests/const.cocci new file mode 100644 index 0000000..d14a4d8 --- /dev/null +++ b/tests/const.cocci @@ -0,0 +1,5 @@ +@@ @@ +void foo(char *text) { +- strcat(buf->data, text); ++ strcat_safe(buf->data, buf->len, text); +} diff --git a/tests/const.res b/tests/const.res new file mode 100644 index 0000000..42bf8fd --- /dev/null +++ b/tests/const.res @@ -0,0 +1,3 @@ +void foo(const char *text) { + strcat_safe(buf->data, buf->len, text); +} diff --git a/tests/const1.c b/tests/const1.c new file mode 100644 index 0000000..9dda9b8 --- /dev/null +++ b/tests/const1.c @@ -0,0 +1,5 @@ +void foo(int j) { + const char *i; + int i; + i++; +} diff --git a/tests/const1.cocci b/tests/const1.cocci new file mode 100644 index 0000000..87a79a5 --- /dev/null +++ b/tests/const1.cocci @@ -0,0 +1,6 @@ +@@ identifier func;@@ +func (...) { +- const char *i; ++ float i; + ... +} diff --git a/tests/const1bis.c b/tests/const1bis.c new file mode 100644 index 0000000..93f0ff1 --- /dev/null +++ b/tests/const1bis.c @@ -0,0 +1,5 @@ +void foo(int j) { + const int i; + int i; + i++; +} diff --git a/tests/const1bis.cocci b/tests/const1bis.cocci new file mode 100644 index 0000000..cecb19b --- /dev/null +++ b/tests/const1bis.cocci @@ -0,0 +1,6 @@ +@@ identifier func;@@ +func (...) { +- const int i; ++ float i; + ... +} diff --git a/tests/const1bis.res b/tests/const1bis.res new file mode 100644 index 0000000..20d157a --- /dev/null +++ b/tests/const1bis.res @@ -0,0 +1,5 @@ +void foo(int j) { + float i; + int i; + i++; +} diff --git a/tests/const_adding.c b/tests/const_adding.c new file mode 100644 index 0000000..8cb503a --- /dev/null +++ b/tests/const_adding.c @@ -0,0 +1,7 @@ +void main(int i) +{ + + const struct file_operations a; + struct file_operations b; + +} diff --git a/tests/const_adding.cocci b/tests/const_adding.cocci new file mode 100644 index 0000000..74f6681 --- /dev/null +++ b/tests/const_adding.cocci @@ -0,0 +1,13 @@ +@@ +identifier I; +@@ + +( + const struct file_operations I; +| ++ const + struct file_operations I; +) + +//- const struct file_operations I; + diff --git a/tests/const_adding.res b/tests/const_adding.res new file mode 100644 index 0000000..8107eff --- /dev/null +++ b/tests/const_adding.res @@ -0,0 +1,7 @@ +void main(int i) +{ + + const struct file_operations a; + const struct file_operations b; + +} diff --git a/tests/const_array.c b/tests/const_array.c new file mode 100644 index 0000000..3931b8f --- /dev/null +++ b/tests/const_array.c @@ -0,0 +1,32 @@ +static const char *r128_family[] __devinitdata = { + "AGP", + "PCI", +}; + +static const char *r128_family1[] = { + "AGP", + "PCI", +}; + +static char *r128_family2[] = { + "AGP", + "PCI", +}; + +static struct foo *r128_family3[] = { + "AGP", + "PCI", +}; + +static const struct foo *r128_family4[] = { + "AGP", + "PCI", +}; + +int main () { + ent->driver_data = sizeof(r128_family)/sizeof(char *); + ent->driver_data = sizeof(r128_family1)/sizeof(char *); + ent->driver_data = sizeof(r128_family2)/sizeof(char *); + ent->driver_data = sizeof(r128_family3)/sizeof(struct foo *); + ent->driver_data = sizeof(r128_family4)/sizeof(struct foo *); +} diff --git a/tests/const_array.cocci b/tests/const_array.cocci new file mode 100644 index 0000000..c240055 --- /dev/null +++ b/tests/const_array.cocci @@ -0,0 +1,15 @@ +@@ +type T; +T[] E; +@@ + +- sizeof(E)/sizeof(T) ++ ARRAY_SIZE(E) + +@@ +type T; +const T*[] E; +@@ + +- sizeof(E)/sizeof(T*) ++ ARRAY_SIZE(E) diff --git a/tests/const_array.res b/tests/const_array.res new file mode 100644 index 0000000..7544988 --- /dev/null +++ b/tests/const_array.res @@ -0,0 +1,21 @@ +static const char *r128_family[] __devinitdata = { + "AGP", + "PCI", +}; + +static const char *r128_family1[] = { + "AGP", + "PCI", +}; + +static char *r128_family2[] = { + "AGP", + "PCI", +}; + +int main () { + ent->driver_data = ARRAY_SIZE(r128_family); + ent->driver_data = ARRAY_SIZE(r128_family1); + ent->driver_data = ARRAY_SIZE(r128_family2); + ent->driver_data = ARRAY_SIZE(r128_family3); +} diff --git a/tests/const_implicit_iso.c b/tests/const_implicit_iso.c new file mode 100644 index 0000000..188b709 --- /dev/null +++ b/tests/const_implicit_iso.c @@ -0,0 +1,4 @@ +void main(double y) { + const int x; + +} diff --git a/tests/const_implicit_iso.cocci b/tests/const_implicit_iso.cocci new file mode 100644 index 0000000..bfdc21b --- /dev/null +++ b/tests/const_implicit_iso.cocci @@ -0,0 +1,6 @@ +@@ +identifier x; +@@ + +- int x; ++ float x; diff --git a/tests/const_implicit_iso.res b/tests/const_implicit_iso.res new file mode 100644 index 0000000..19b6d3b --- /dev/null +++ b/tests/const_implicit_iso.res @@ -0,0 +1,4 @@ +void main(double y) { + const float x; + +} diff --git a/tests/constty.c b/tests/constty.c new file mode 100644 index 0000000..fd2d007 --- /dev/null +++ b/tests/constty.c @@ -0,0 +1,7 @@ +int main () { + const int x; + int y; + f(x,int); + f(y,int); + f(x,const int); +} diff --git a/tests/constty.cocci b/tests/constty.cocci new file mode 100644 index 0000000..821a0a6 --- /dev/null +++ b/tests/constty.cocci @@ -0,0 +1,6 @@ +@@ +type T; +const T x; +@@ + +- f(x,T); diff --git a/tests/constty.res b/tests/constty.res new file mode 100644 index 0000000..059626f --- /dev/null +++ b/tests/constty.res @@ -0,0 +1,6 @@ +int main () { + const int x; + int y; + f(y,int); + f(x,const int); +} diff --git a/tests/constx.c b/tests/constx.c new file mode 100644 index 0000000..8e42cde --- /dev/null +++ b/tests/constx.c @@ -0,0 +1,8 @@ +int main() { + foo(12); + foo(x); + foo(CONSTANT); + foo('a'); + foo("string"); + foo(1.0001); +} diff --git a/tests/constx.cocci b/tests/constx.cocci new file mode 100644 index 0000000..2a4db6b --- /dev/null +++ b/tests/constx.cocci @@ -0,0 +1,7 @@ +@@ +constant X; +@@ + +- foo(X); ++ foobar(X,X); + diff --git a/tests/constx.res b/tests/constx.res new file mode 100644 index 0000000..364d4d7 --- /dev/null +++ b/tests/constx.res @@ -0,0 +1,8 @@ +int main() { + foobar(12, 12); + foo(x); + foobar(CONSTANT, CONSTANT); + foobar('a', 'a'); + foobar("string", "string"); + foobar(1.0001, 1.0001); +} diff --git a/tests/cr.c b/tests/cr.c new file mode 100644 index 0000000..6b5ff8f --- /dev/null +++ b/tests/cr.c @@ -0,0 +1,12 @@ +int main() { + int x; + x = request_region(a,b,c); + if (!x) { foo(); } + if (x) { foo(); return 1; } + if (x) { foo(); release_region(a,b); return 2; } + if (x) { foo(); release_region(a,b); return 3; } + release_region(a,b); + if (!y) { foo(); } + if (y) { foo(); return 1; } + if (y) { foo(); release_region(a,b); return 1; } +} diff --git a/tests/cr.cocci b/tests/cr.cocci new file mode 100644 index 0000000..ed11429 --- /dev/null +++ b/tests/cr.cocci @@ -0,0 +1,13 @@ +@@ +identifier x; +expression E1, E2, E3; +@@ + +- x = request_region(E1,E2,E3); + <... +- if (...) { +- ... when != release_region(E1,E2); +- return ...; +- } + ...> +?- release_region(E1,E2); diff --git a/tests/cr1.c b/tests/cr1.c new file mode 100644 index 0000000..b63f149 --- /dev/null +++ b/tests/cr1.c @@ -0,0 +1,20 @@ +int __init probe_base_port(int base) +{ + int b = 0x300, e = 0x370; /* this is the range of start addresses */ + volatile int fool, i; + + if (base) + b = e = base; + for (base = b; base <= e; base += 0x10) { + if (check_region(base, 0x10)) + continue; + for (i = 0; i < 3; i++) + fool = inw(base + 2); /* empty possibly uart_receive_buffer */ + if ((inw(base + 6) & 0xffef) != 0x0001 || /* line_status */ + (inw(base) & 0xad00) != 0) /* data status */ + continue; + return (base); + } + return 0; +} + diff --git a/tests/cr1.cocci b/tests/cr1.cocci new file mode 100644 index 0000000..5ba0da5 --- /dev/null +++ b/tests/cr1.cocci @@ -0,0 +1,20 @@ +@@ +expression E, req_reg_arg2; +identifier probe; +@@ + +probe(...) { + ... + for(...; ...; ...) { + ... ++ if (!request_region(E, req_reg_arg2, req_reg_arg3)) +- if (check_region(E, req_reg_arg2)) + { continue; } + <... ++ release_region(E, req_reg_arg2); + continue; + ...> ++ release_region(E, req_reg_arg2); + } + ... +} diff --git a/tests/cs_check.c b/tests/cs_check.c new file mode 100644 index 0000000..cf4bb5f --- /dev/null +++ b/tests/cs_check.c @@ -0,0 +1,10 @@ +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) + +static void nsp_cs_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); +cs_failed: + return; +} diff --git a/tests/cs_check.cocci b/tests/cs_check.cocci new file mode 100644 index 0000000..5393099 --- /dev/null +++ b/tests/cs_check.cocci @@ -0,0 +1,6 @@ +@@ +expression E1; +@@ + +- pcmcia_get_first_tuple(handle,E1) ++ pcmcia_get_first_tuple(link,E1) diff --git a/tests/cs_check.res b/tests/cs_check.res new file mode 100644 index 0000000..10b2c8e --- /dev/null +++ b/tests/cs_check.res @@ -0,0 +1,10 @@ +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) + +static void nsp_cs_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); +cs_failed: + return; +} diff --git a/tests/cst.c b/tests/cst.c new file mode 100644 index 0000000..496ca86 --- /dev/null +++ b/tests/cst.c @@ -0,0 +1,5 @@ +int main(int x) { + emu10k1_t *emu = snd_magic_cast(1, 2, return -ENXIO); + int z = 12; + return y; +} diff --git a/tests/cst.cocci b/tests/cst.cocci new file mode 100644 index 0000000..8b1be43 --- /dev/null +++ b/tests/cst.cocci @@ -0,0 +1,8 @@ +// we cant say snd_magic_cast(E1, E2, E3) because E3 +// is not an expression. it is an action, which is not even exactly +// a statement. +@@ +expression E1, E2; +@@ +- snd_magic_cast(E1, E2, ...) ++ 4 diff --git a/tests/cst.res b/tests/cst.res new file mode 100644 index 0000000..fea67e3 --- /dev/null +++ b/tests/cst.res @@ -0,0 +1,5 @@ +int main(int x) { + emu10k1_t *emu = 4; + int z = 12; + return y; +} diff --git a/tests/csw.c b/tests/csw.c new file mode 100644 index 0000000..a0156a0 --- /dev/null +++ b/tests/csw.c @@ -0,0 +1,14 @@ +int main() { + switch (x) { + case XYZ: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + bluecard_close(info); + bluecard_release(link); + } + break; + case MID: mid(); break; + case FOO: bar(); break; + } +} + diff --git a/tests/csw.cocci b/tests/csw.cocci new file mode 100644 index 0000000..4bdeb67 --- /dev/null +++ b/tests/csw.cocci @@ -0,0 +1,7 @@ +@@ +@@ + +switch (x) { +- case FOO: ... break; +- case XYZ: ... break; +} diff --git a/tests/csw.res b/tests/csw.res new file mode 100644 index 0000000..59b1904 --- /dev/null +++ b/tests/csw.res @@ -0,0 +1,6 @@ +int main() { + switch (x) { + case MID: mid(); break; + } +} + diff --git a/tests/ctr_unit_test.c b/tests/ctr_unit_test.c new file mode 100644 index 0000000..b55d0a2 --- /dev/null +++ b/tests/ctr_unit_test.c @@ -0,0 +1,28 @@ + +int classA(int i) { + if(classA()) { x=0; } + + UnitTestEntry("A1"); + if(MethodA1()) { } + if(MethodA2()) { } + UnitTestEntry("A3"); + if(MethodA3()) { } + if(MethodA4()) { } + +} + +int classB(int i) { + if(classB()) { x=0; } + + if(MethodB1()) { } + UnitTestEntry("B2"); + if(MethodB2()) { } + if(MethodB3()) { } + UnitTestEntry("B4"); + if(MethodB4()) { } + + +} + +int lastfunction(int i) { +} diff --git a/tests/ctr_unit_test.cocci b/tests/ctr_unit_test.cocci new file mode 100644 index 0000000..197aaf1 --- /dev/null +++ b/tests/ctr_unit_test.cocci @@ -0,0 +1,79 @@ +@ rule1 @ +identifier C, i; +@@ + int C(int i) { + ... + if(C()) { ... } + ... ++ if(UnitTest()) { ++ int c; ++ C(); ++ } + } + + +@@ +identifier TestMethod, i; +expression name; +statement S1,S2; +identifier rule1.C; +// if put identifier name; then cocci does not help +// to say that there is a partial match :( +@@ + +// int C(int i) { +// ... +// UnitTestEntry(name); +// if(TestMethod()) { ... } +// ... +// if(UnitTest()) { +// int c; +// ... +//+ c = C(); +//+ Console.WriteLine("invoking test", name); +//+ c.TestMethod(); +// } +// } + + +// int C(int i) { +// <... UnitTestEntry(...); ...> +// UnitTestEntry(name); +// if(TestMethod()) { ... } +// <... UnitTestEntry(...); ...> +// } + +// or simply (does not work ) + +// int C(int i) { +// <... +// UnitTestEntry(name); +// if(TestMethod()) { ... } +// ...> +// } + +// or + + int C(int i) { +// <... UnitTestEntry(name); if(TestMethod()) { ... } ...> +// <... UnitTestEntry(...); if(...) { ... } ...> + <... S1 ...> + UnitTestEntry(name); if(TestMethod()) { ... } + <... S2 ...> +// <... UnitTestEntry(...); if(...) { ... } ...> +// <... UnitTestEntry(name); if(TestMethod()) { ... } ...> + } + +@@ +identifier rule1.C, i, c; +@@ + int C(int i) { + ... + if(UnitTest()) { + struct foo c; + ... ++ c = C(); ++ Console.WriteLine("invoking test", name); ++ c.TestMethod(); + } + } diff --git a/tests/dbg.c b/tests/dbg.c new file mode 100644 index 0000000..756d18e --- /dev/null +++ b/tests/dbg.c @@ -0,0 +1,8 @@ + +static inline void alloc_resource(struct pci_dev *dev, int idx) +{ + struct resource *pr, *r = &dev->resource[idx]; + + if (pr) + DBG("PCI"); +} diff --git a/tests/dbg.cocci b/tests/dbg.cocci new file mode 100644 index 0000000..c353d54 --- /dev/null +++ b/tests/dbg.cocci @@ -0,0 +1,7 @@ +@@ +idexpression *E; +statement S1; +@@ + +if (E != NULL) S1 ++ else E = NULL; diff --git a/tests/dbg.res b/tests/dbg.res new file mode 100644 index 0000000..cfccf6c --- /dev/null +++ b/tests/dbg.res @@ -0,0 +1,9 @@ + +static inline void alloc_resource(struct pci_dev *dev, int idx) +{ + struct resource *pr, *r = &dev->resource[idx]; + + if (pr) + DBG("PCI"); + else pr = NULL; +} diff --git a/tests/dc_close.c b/tests/dc_close.c new file mode 100644 index 0000000..ac1fba9 --- /dev/null +++ b/tests/dc_close.c @@ -0,0 +1,11 @@ +void __init +initicc(struct IsdnCardState *cs) +{ + int val, eval; + + INIT_WORK(&cs->work, icc_bh, cs); + cs->setstack_d = setstack_icc; + cs->DC_Close = DC_Close_icc; + cs->dc.icc.mon_rx = NULL; + +} diff --git a/tests/dc_close.cocci b/tests/dc_close.cocci new file mode 100644 index 0000000..a01843f --- /dev/null +++ b/tests/dc_close.cocci @@ -0,0 +1,15 @@ +@@ +//identifier rule3.d_fill_fifo; +struct IsdnCardState *cs; +identifier E; +@@ + + ... when != cs->DC_Send_Data +( ++ cs->DC_Send_Data = d_fill_fifo; + cs->DC_Close = E; +| ++ cs->DC_Send_Data = &d_fill_fifo; + cs->DC_Close = &E; +) + ... when != cs->DC_Send_Data diff --git a/tests/dc_close.res b/tests/dc_close.res new file mode 100644 index 0000000..92a124f --- /dev/null +++ b/tests/dc_close.res @@ -0,0 +1,12 @@ +void __init +initicc(struct IsdnCardState *cs) +{ + int val, eval; + + INIT_WORK(&cs->work, icc_bh, cs); + cs->setstack_d = setstack_icc; + cs->DC_Send_Data = d_fill_fifo; + cs->DC_Close = DC_Close_icc; + cs->dc.icc.mon_rx = NULL; + +} diff --git a/tests/debug.c b/tests/debug.c new file mode 100644 index 0000000..476a392 --- /dev/null +++ b/tests/debug.c @@ -0,0 +1,5 @@ +static int __init init_3c574_cs(void) +{ + DEBUG(0, "%s\n", version); + return 0; +} diff --git a/tests/debug.cocci b/tests/debug.cocci new file mode 100644 index 0000000..78de24c --- /dev/null +++ b/tests/debug.cocci @@ -0,0 +1,7 @@ +@@ +identifier init; +@@ + init(...) { +- DEBUG(...); + ... + } diff --git a/tests/debug.res b/tests/debug.res new file mode 100644 index 0000000..348cb5a --- /dev/null +++ b/tests/debug.res @@ -0,0 +1,4 @@ +static int __init init_3c574_cs(void) +{ + return 0; +} diff --git a/tests/dec.c b/tests/dec.c new file mode 100644 index 0000000..b6c96d5 --- /dev/null +++ b/tests/dec.c @@ -0,0 +1,4 @@ +int f(int x) { + static int y; + return x; +} diff --git a/tests/dec.cocci b/tests/dec.cocci new file mode 100644 index 0000000..026ac81 --- /dev/null +++ b/tests/dec.cocci @@ -0,0 +1,8 @@ +@@ +@@ + +f(int x) { ++ int z; + int y; + return x; +} diff --git a/tests/dec.res b/tests/dec.res new file mode 100644 index 0000000..1b5955d --- /dev/null +++ b/tests/dec.res @@ -0,0 +1,5 @@ +int f(int x) { + int z; + static int y; + return x; +} diff --git a/tests/decl.c b/tests/decl.c new file mode 100644 index 0000000..6b81bc9 --- /dev/null +++ b/tests/decl.c @@ -0,0 +1,5 @@ +static int az_ioctl(int cmd, void *arg) +{ + return 0; +} + diff --git a/tests/decl.cocci b/tests/decl.cocci new file mode 100644 index 0000000..5675cd3 --- /dev/null +++ b/tests/decl.cocci @@ -0,0 +1,10 @@ +// pb: foo doesn't get added +@@ +statement S; +identifier ioctl; +@@ + + ioctl(int cmd, void *arg) { ++ foo(); + ... + } diff --git a/tests/decl.res b/tests/decl.res new file mode 100644 index 0000000..aca201a --- /dev/null +++ b/tests/decl.res @@ -0,0 +1,6 @@ +static int az_ioctl(int cmd, void *arg) +{ + foo(); + return 0; +} + diff --git a/tests/decl1.c b/tests/decl1.c new file mode 100644 index 0000000..27fdea8 --- /dev/null +++ b/tests/decl1.c @@ -0,0 +1,7 @@ +static int az_ioctl(int cmd, void *arg) +{ + int x; + int y; + return 0; +} + diff --git a/tests/decl1.cocci b/tests/decl1.cocci new file mode 100644 index 0000000..1bef0f9 --- /dev/null +++ b/tests/decl1.cocci @@ -0,0 +1,12 @@ +@@ +statement S; +identifier ioctl; +@@ + + ioctl(int cmd, void *arg) { + ... + int x; ++ foo(); + S + ... + } diff --git a/tests/decl2.c b/tests/decl2.c new file mode 100644 index 0000000..e3ff1cd --- /dev/null +++ b/tests/decl2.c @@ -0,0 +1,10 @@ +static int az_ioctl(int cmd, void *arg) +{ + if (x) { + return 0; + } + else { + return 0; + } +} + diff --git a/tests/decl2.cocci b/tests/decl2.cocci new file mode 100644 index 0000000..a0c3a3f --- /dev/null +++ b/tests/decl2.cocci @@ -0,0 +1,11 @@ +// pb: foo doesn't get added +@@ +identifier ioctl, cmd, arg; +@@ + + ioctl(int cmd, void *arg) { + ... +- x ++ y + ... + } diff --git a/tests/decl2.res b/tests/decl2.res new file mode 100644 index 0000000..b8cdd83 --- /dev/null +++ b/tests/decl2.res @@ -0,0 +1,10 @@ +static int az_ioctl(int cmd, void *arg) +{ + if (y) { + return 0; + } + else { + return 0; + } +} + diff --git a/tests/decl_space.c b/tests/decl_space.c new file mode 100644 index 0000000..4738b46 --- /dev/null +++ b/tests/decl_space.c @@ -0,0 +1,4 @@ +int main () { + int *x = y; + int x = y; +} diff --git a/tests/decl_space.cocci b/tests/decl_space.cocci new file mode 100644 index 0000000..5599e61 --- /dev/null +++ b/tests/decl_space.cocci @@ -0,0 +1,13 @@ +@@ +type T; +@@ + +- T *x = y; ++ T *x = g; + +@@ +type T; +@@ + +- T x = y; ++ T x = g; diff --git a/tests/decl_space.res b/tests/decl_space.res new file mode 100644 index 0000000..f803661 --- /dev/null +++ b/tests/decl_space.res @@ -0,0 +1,4 @@ +int main () { + int *x = g; + int x = g; +} diff --git a/tests/decl_split.c b/tests/decl_split.c new file mode 100644 index 0000000..8b0cc64 --- /dev/null +++ b/tests/decl_split.c @@ -0,0 +1,3 @@ +int func(int i) { + int x, y; +} diff --git a/tests/decl_split.cocci b/tests/decl_split.cocci new file mode 100644 index 0000000..75cafa6 --- /dev/null +++ b/tests/decl_split.cocci @@ -0,0 +1,7 @@ +@@ +@@ + +int func(int i) { +- int x, y; +//- int x; +} \ No newline at end of file diff --git a/tests/decl_split.res b/tests/decl_split.res new file mode 100644 index 0000000..153339d --- /dev/null +++ b/tests/decl_split.res @@ -0,0 +1,2 @@ +int func(int i) { +} diff --git a/tests/decl_ver1.c b/tests/decl_ver1.c new file mode 100644 index 0000000..a3ab95b --- /dev/null +++ b/tests/decl_ver1.c @@ -0,0 +1,20 @@ +static int volconvert(int level) +{ + level>>=14; /* Map 16bits down to 2 bit */ + level&=3; + + /* convert to card-friendly values */ + switch (level) + { + case 0: + return 0; + case 1: + return 1; + case 2: + return 4; + case 3: + return 5; + } + return 0; /* Quieten gcc */ +} + diff --git a/tests/define_chip_t.c b/tests/define_chip_t.c new file mode 100644 index 0000000..dc89b1c --- /dev/null +++ b/tests/define_chip_t.c @@ -0,0 +1,22 @@ +#define chip_t vortex_t + +//#define chip_t float + +static int +snd_vortex_pcm_hw_params(snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + chip_t *chip = snd_pcm_substream_chip(substream); + stream_t *stream = (stream_t *) (substream->runtime->private_data); + snd_pcm_sgbuf_t *sgbuf; + int err; + +} + + + +float main(float x) +{ + + float y; +} diff --git a/tests/define_chip_t.cocci b/tests/define_chip_t.cocci new file mode 100644 index 0000000..b6c88cf --- /dev/null +++ b/tests/define_chip_t.cocci @@ -0,0 +1,14 @@ +@ rule1 @ +type T; +@@ + +- #define chip_t T + + +@@ +typedef chip_t; +type rule1.T; +@@ + +- chip_t ++ T diff --git a/tests/define_exp.c b/tests/define_exp.c new file mode 100644 index 0000000..cd1031f --- /dev/null +++ b/tests/define_exp.c @@ -0,0 +1,7 @@ +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? \ + SA_SHIRQ : SA_INTERRUPT) + + +void main(int i) +{ +} diff --git a/tests/define_exp.cocci b/tests/define_exp.cocci new file mode 100644 index 0000000..2300c0a --- /dev/null +++ b/tests/define_exp.cocci @@ -0,0 +1,9 @@ +@@ +@@ +( +- SA_INTERRUPT ++ IRQF_DISABLED +| +- SA_SHIRQ ++ IRQF_SHARED +) diff --git a/tests/define_exp.res b/tests/define_exp.res new file mode 100644 index 0000000..4f1536d --- /dev/null +++ b/tests/define_exp.res @@ -0,0 +1,6 @@ +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED) + + +void main(int i) +{ +} diff --git a/tests/define_param.c b/tests/define_param.c new file mode 100644 index 0000000..1da194a --- /dev/null +++ b/tests/define_param.c @@ -0,0 +1,14 @@ +#define fieldsize(a) (sizeof(a)/sizeof(*a)) + +static int +atari_proc_infos(unsigned char *nvram, char *buffer, int *len, + off_t *begin, off_t offset, int size) +{ + for (i = fieldsize(boot_prefs) - 1; i >= 0; --i) { + if (nvram[1] == boot_prefs[i].val) { + PRINT_PROC("%s\n", boot_prefs[i].name); + break; + } + } +} + diff --git a/tests/define_param.cocci b/tests/define_param.cocci new file mode 100644 index 0000000..35a7e30 --- /dev/null +++ b/tests/define_param.cocci @@ -0,0 +1,21 @@ + +@ rule2 disable all @ +expression E; +@@ + +- (sizeof(E)/sizeof(*E)) ++ ARRAY_SIZE(E) + +@ rule53 @ +identifier NUM, x; +@@ + +- #define NUM(x) ARRAY_SIZE(x) + +@@ +expression E; +identifier rule53.NUM; +@@ + +- NUM(E) ++ ARRAY_SIZE(E) diff --git a/tests/define_param.res b/tests/define_param.res new file mode 100644 index 0000000..c951d9b --- /dev/null +++ b/tests/define_param.res @@ -0,0 +1,12 @@ +static int +atari_proc_infos(unsigned char *nvram, char *buffer, int *len, + off_t *begin, off_t offset, int size) +{ + for (i = ARRAY_SIZE(boot_prefs) - 1; i >= 0; --i) { + if (nvram[1] == boot_prefs[i].val) { + PRINT_PROC("%s\n", boot_prefs[i].name); + break; + } + } +} + diff --git a/tests/dep.c b/tests/dep.c new file mode 100644 index 0000000..81259f5 --- /dev/null +++ b/tests/dep.c @@ -0,0 +1,3 @@ +int main () { + xxx(); +} diff --git a/tests/dep.cocci b/tests/dep.cocci new file mode 100644 index 0000000..8c72976 --- /dev/null +++ b/tests/dep.cocci @@ -0,0 +1,14 @@ +@ rule1 @ +@@ + +- foo(); + +@ rule2 @ +@@ + +- bar(); + +@ rule3 depends on rule1 && rule2 @ +@@ + +- xxx(); diff --git a/tests/deref.c b/tests/deref.c new file mode 100644 index 0000000..61be488 --- /dev/null +++ b/tests/deref.c @@ -0,0 +1,6 @@ +int main () { + int **q; + foo(*q+12); + xxx(q[0]+12); + yyy(q+12); +} diff --git a/tests/deref.cocci b/tests/deref.cocci new file mode 100644 index 0000000..219a28b --- /dev/null +++ b/tests/deref.cocci @@ -0,0 +1,6 @@ +@@ +int * x; +@@ + +- x+12 ++ 12 diff --git a/tests/deref.res b/tests/deref.res new file mode 100644 index 0000000..2c95d9e --- /dev/null +++ b/tests/deref.res @@ -0,0 +1,6 @@ +int main () { + int **q; + foo(12); + xxx(12); + yyy(q+12); +} diff --git a/tests/desc.c b/tests/desc.c new file mode 100644 index 0000000..92b5712 --- /dev/null +++ b/tests/desc.c @@ -0,0 +1,2 @@ +MODULE_PARM_DESC(devices, "number of dsp devices allocated by the driver"); +module_param(devices, int, 0); diff --git a/tests/detect_alloc.cocci b/tests/detect_alloc.cocci new file mode 100644 index 0000000..c8195c9 --- /dev/null +++ b/tests/detect_alloc.cocci @@ -0,0 +1,13 @@ +@@ +type T; +identifier f; +T *x; +@@ + +* T *f(...) +{ + ... + x = kmalloc(...); + ... + return x; +} diff --git a/tests/devlink.c b/tests/devlink.c new file mode 100644 index 0000000..93d3eb3 --- /dev/null +++ b/tests/devlink.c @@ -0,0 +1,12 @@ +static void cm4000_release(dev_link_t *link); + +int main () { + memset(&dev->atr_csum,0, + sizeof(dev_link_t) - sizeof(dev_node)); +} + +int xmain () { + dev_link_t x; + memset(&dev->atr_csum,0, + sizeof(dev_link_t) - sizeof(dev_node)); +} diff --git a/tests/devlink.cocci b/tests/devlink.cocci new file mode 100644 index 0000000..8a6c07a --- /dev/null +++ b/tests/devlink.cocci @@ -0,0 +1,4 @@ +@@ typedef dev_link_t; @@ + +- dev_link_t ++ struct pcmcia_device diff --git a/tests/devlink.res b/tests/devlink.res new file mode 100644 index 0000000..8db7f37 --- /dev/null +++ b/tests/devlink.res @@ -0,0 +1,12 @@ +static void cm4000_release(struct pcmcia_device *link); + +int main () { + memset(&dev->atr_csum,0, + sizeof(struct pcmcia_device) - sizeof(dev_node)); +} + +int xmain () { + struct pcmcia_device x; + memset(&dev->atr_csum,0, + sizeof(struct pcmcia_device) - sizeof(dev_node)); +} diff --git a/tests/disjexpr.c b/tests/disjexpr.c new file mode 100644 index 0000000..49e99c7 --- /dev/null +++ b/tests/disjexpr.c @@ -0,0 +1,3 @@ +int main (int i) { + f(v.fld, v, v.fld2); +} diff --git a/tests/disjexpr.cocci b/tests/disjexpr.cocci new file mode 100644 index 0000000..0b6acd5 --- /dev/null +++ b/tests/disjexpr.cocci @@ -0,0 +1,9 @@ +@@ identifier fld; +@@ +( +- v.fld ++ v->fld +| +- v ++ *v +) diff --git a/tests/disjexpr.res b/tests/disjexpr.res new file mode 100644 index 0000000..12a446e --- /dev/null +++ b/tests/disjexpr.res @@ -0,0 +1,3 @@ +int main (int i) { + f(v->fld, *v, v->fld2); +} diff --git a/tests/disjexpr_ver1.c b/tests/disjexpr_ver1.c new file mode 100644 index 0000000..f3e40e9 --- /dev/null +++ b/tests/disjexpr_ver1.c @@ -0,0 +1,3 @@ +int main (int i) { + f(v.fld); +} diff --git a/tests/disjexpr_ver1.res b/tests/disjexpr_ver1.res new file mode 100644 index 0000000..2e66ee4 --- /dev/null +++ b/tests/disjexpr_ver1.res @@ -0,0 +1,3 @@ +int main (int i) { + f(v->fld); +} diff --git a/tests/disjexpr_ver2.c b/tests/disjexpr_ver2.c new file mode 100644 index 0000000..85888da --- /dev/null +++ b/tests/disjexpr_ver2.c @@ -0,0 +1,3 @@ +int main (int i) { + f(v.fld, v.fld2, v); +} diff --git a/tests/disjexpr_ver2.res b/tests/disjexpr_ver2.res new file mode 100644 index 0000000..bb4f936 --- /dev/null +++ b/tests/disjexpr_ver2.res @@ -0,0 +1,3 @@ +int main (int i) { + f(v->fld, v->fld2, *v); +} diff --git a/tests/distribute.c b/tests/distribute.c new file mode 100644 index 0000000..90b8e00 --- /dev/null +++ b/tests/distribute.c @@ -0,0 +1,4 @@ +int main(int i) { + + f(1+1); +} diff --git a/tests/distribute.cocci b/tests/distribute.cocci new file mode 100644 index 0000000..ff6f321 --- /dev/null +++ b/tests/distribute.cocci @@ -0,0 +1,11 @@ +@@ +expression E; +@@ + + f( ++ g(1) * +- E ++ 0 ++ * g(2) + ) + diff --git a/tests/distribute.res b/tests/distribute.res new file mode 100644 index 0000000..097086f --- /dev/null +++ b/tests/distribute.res @@ -0,0 +1,4 @@ +int main(int i) { + + f(g(1) * 0 * g(2)); +} diff --git a/tests/double.c b/tests/double.c new file mode 100644 index 0000000..63697d7 --- /dev/null +++ b/tests/double.c @@ -0,0 +1,5 @@ +static void BChannel_proc_xmt(struct BCState *bcs) { + if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) { + st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); + } +} diff --git a/tests/double.cocci b/tests/double.cocci new file mode 100644 index 0000000..e5a2809 --- /dev/null +++ b/tests/double.cocci @@ -0,0 +1,9 @@ +@@ expression E; @@ + +( +- (!skb_queue_len(E)) ++ skb_queue_empty(E) +| +- (skb_queue_len(E) == 0) ++ skb_queue_empty(E) +) diff --git a/tests/double.res b/tests/double.res new file mode 100644 index 0000000..15e0d93 --- /dev/null +++ b/tests/double.res @@ -0,0 +1,5 @@ + static void BChannel_proc_xmt(struct BCState *bcs) { + if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && skb_queue_empty(&bcs->squeue)) { + st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); + } + } diff --git a/tests/double_assign.c b/tests/double_assign.c new file mode 100644 index 0000000..15bfde7 --- /dev/null +++ b/tests/double_assign.c @@ -0,0 +1,9 @@ +int main() { + x = 12; + x = x + 1; +} + +int badmain() { + x = 12; + x = 1; +} diff --git a/tests/double_assign.cocci b/tests/double_assign.cocci new file mode 100644 index 0000000..584085d --- /dev/null +++ b/tests/double_assign.cocci @@ -0,0 +1,25 @@ +@s@ +identifier i; +position p0; +@@ + +i =@p0 ...; + +@r exists@ +identifier s.i; +position s.p0,p; +@@ + +i =@p0 ...; +... +i =@p <+... i ...+>; + +@@ +identifier s.i; +position s.p0; +position p != r.p; +@@ + +- i =@p0 ...; +... when strict + i =@p ...; diff --git a/tests/double_assign.res b/tests/double_assign.res new file mode 100644 index 0000000..034ed47 --- /dev/null +++ b/tests/double_assign.res @@ -0,0 +1,8 @@ +int main() { + x = 12; + x = x + 1; +} + +int badmain() { + x = 1; +} diff --git a/tests/doublepos.c b/tests/doublepos.c new file mode 100644 index 0000000..cb50935 --- /dev/null +++ b/tests/doublepos.c @@ -0,0 +1,6 @@ +int main() { + f(1,2); + f(1,5); + f(6,5); +} + diff --git a/tests/doublepos.cocci b/tests/doublepos.cocci new file mode 100644 index 0000000..555d03b --- /dev/null +++ b/tests/doublepos.cocci @@ -0,0 +1,19 @@ +// this shows a constraint on an inherited position variable + +@a@ +position p; +@@ + +f@p(1,...) + +@b@ +position p1; +@@ + +f@p1(...,5) + +@@ +position a.p != b.p1; +@@ + +- f@p(...); diff --git a/tests/doublepos.res b/tests/doublepos.res new file mode 100644 index 0000000..ae4b0e0 --- /dev/null +++ b/tests/doublepos.res @@ -0,0 +1,5 @@ +int main() { + f(1,5); + f(6,5); +} + diff --git a/tests/dowhile.c b/tests/dowhile.c new file mode 100644 index 0000000..94e4cb9 --- /dev/null +++ b/tests/dowhile.c @@ -0,0 +1,7 @@ +int main() { + do { + f(); + } + while (0); + g(); +} diff --git a/tests/dowhile.cocci b/tests/dowhile.cocci new file mode 100644 index 0000000..8756a4a --- /dev/null +++ b/tests/dowhile.cocci @@ -0,0 +1,6 @@ +@@ +@@ + +- f(); + ... +- g(); diff --git a/tests/dowhile.res b/tests/dowhile.res new file mode 100644 index 0000000..e256df5 --- /dev/null +++ b/tests/dowhile.res @@ -0,0 +1,5 @@ +int main() { + do { + } + while (0); +} diff --git a/tests/dropf.c b/tests/dropf.c new file mode 100644 index 0000000..fe2d6e6 --- /dev/null +++ b/tests/dropf.c @@ -0,0 +1,3 @@ +int main() { + x = f(1) + f(3); +} diff --git a/tests/dropf.cocci b/tests/dropf.cocci new file mode 100644 index 0000000..7920922 --- /dev/null +++ b/tests/dropf.cocci @@ -0,0 +1,6 @@ +@@ +expression E; +@@ + +- f(E) ++ f(E+3) \ No newline at end of file diff --git a/tests/dropf.res b/tests/dropf.res new file mode 100644 index 0000000..620395d --- /dev/null +++ b/tests/dropf.res @@ -0,0 +1,3 @@ +int main() { + x = f(1 + 3) + f(3 + 3); +} diff --git a/tests/dropparam.c b/tests/dropparam.c new file mode 100644 index 0000000..c333b8a --- /dev/null +++ b/tests/dropparam.c @@ -0,0 +1,13 @@ +int f(char *x, int y, char* z) { + return; +} + +int g(char *x, int y, char* z) { + return; +} + + +void main(void) +{ + g("toto", 3, "tata"); +} diff --git a/tests/dropparam.cocci b/tests/dropparam.cocci new file mode 100644 index 0000000..a7943d7 --- /dev/null +++ b/tests/dropparam.cocci @@ -0,0 +1,25 @@ +@ rule1 disable add_signed @ +parameter list[n] P; +identifier x; +@@ + +f (P,int x,...) { ... } + +@ rule3 disable add_signed @ +expression list[rule1.n] Es; +expression E; +identifier x; +@@ + +g (Es, +- E, + ...) + +@ rule2 disable add_signed @ +parameter list[rule1.n] P; +identifier x; +@@ + +g (P, +- int x, + ...) { ... } diff --git a/tests/dropparam.res b/tests/dropparam.res new file mode 100644 index 0000000..0432b74 --- /dev/null +++ b/tests/dropparam.res @@ -0,0 +1,12 @@ +int f(char *x, int y, char* z) { + return; +} + +int g(char *x, char* z) { + return; +} + +void main(void) +{ + g("toto", "tata"); +} diff --git a/tests/edots.c b/tests/edots.c new file mode 100644 index 0000000..da63aeb --- /dev/null +++ b/tests/edots.c @@ -0,0 +1,7 @@ +void main(int i) { + foo[45]; + bar[45+v.field]; + + // f(foo[45] + bar[45]); + +} diff --git a/tests/edots.cocci b/tests/edots.cocci new file mode 100644 index 0000000..21a6026 --- /dev/null +++ b/tests/edots.cocci @@ -0,0 +1,6 @@ +@@ +identifier x; +@@ + +- x[...] ++ x \ No newline at end of file diff --git a/tests/edots.res b/tests/edots.res new file mode 100644 index 0000000..832cb1e --- /dev/null +++ b/tests/edots.res @@ -0,0 +1,7 @@ +void main(int i) { + foo; + bar; + + // f(foo[45] + bar[45]); + +} diff --git a/tests/edots_ver1.c b/tests/edots_ver1.c new file mode 100644 index 0000000..50e6b15 --- /dev/null +++ b/tests/edots_ver1.c @@ -0,0 +1,7 @@ +void main(int i) { + foo[45]; + bar[45+v.field]; + + f(foo[45] + bar[45]); + +} diff --git a/tests/edots_ver1.res b/tests/edots_ver1.res new file mode 100644 index 0000000..020496a --- /dev/null +++ b/tests/edots_ver1.res @@ -0,0 +1,7 @@ +void main(int i) { + foo; + bar; + + f(foo + bar); + +} diff --git a/tests/empty.c b/tests/empty.c new file mode 100644 index 0000000..0dd8903 --- /dev/null +++ b/tests/empty.c @@ -0,0 +1,9 @@ +static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + pci_restore_state(pdev, idev->cfg_space); + if (ring_first(idev->tx_ring) == NULL) { + } + else + ; + +} diff --git a/tests/empty.cocci b/tests/empty.cocci new file mode 100644 index 0000000..6581075 --- /dev/null +++ b/tests/empty.cocci @@ -0,0 +1,20 @@ +//---------------------------------------------------------------------- +// Rule 82 +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +@@ +expression E1, E2; +@@ + +- pci_save_state(E1,E2) ++ pci_save_state(E1) + + +//---------------------------------------------------------------------- +@@ +expression E1, E2; +@@ + +- pci_restore_state(E1,E2) ++ pci_restore_state(E1) diff --git a/tests/empty.res b/tests/empty.res new file mode 100644 index 0000000..c506ea8 --- /dev/null +++ b/tests/empty.res @@ -0,0 +1,9 @@ +static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + pci_restore_state(pdev); + if (ring_first(idev->tx_ring) == NULL) { + } + else + ; + +} diff --git a/tests/end_commas.c b/tests/end_commas.c new file mode 100644 index 0000000..858d11d --- /dev/null +++ b/tests/end_commas.c @@ -0,0 +1,4 @@ +static struct i2c_client client_template = { + .name = "adv7175_client", + .driver = &i2c_driver_adv7175 +}; diff --git a/tests/end_commas.cocci b/tests/end_commas.cocci new file mode 100644 index 0000000..7323996 --- /dev/null +++ b/tests/end_commas.cocci @@ -0,0 +1,10 @@ +@@ +identifier I; +expression E; +@@ + +struct i2c_client I = { +- .name = E, +... ++ .dev = { .name = E, }, +}; diff --git a/tests/end_commas.res b/tests/end_commas.res new file mode 100644 index 0000000..d11a7f6 --- /dev/null +++ b/tests/end_commas.res @@ -0,0 +1,4 @@ +static struct i2c_client client_template = { + .driver = &i2c_driver_adv7175, + .dev = { .name = "adv7175_client", }, +}; diff --git a/tests/endif.c b/tests/endif.c new file mode 100644 index 0000000..32de2e3 --- /dev/null +++ b/tests/endif.c @@ -0,0 +1,23 @@ +void f(int i) { + + x = 1; + if(1) x = 3; + + x = 1; + while(1) x = 3; + + x = 1; + do x = 3; while(1); + + x = 1; + for(1;1;1) x = 3; + + x = 1; + for(1;1;1) { x = 3; } + + // switch(1) { + // case 0: x = 3; + // default: x = 3; + // } + +} diff --git a/tests/endif.cocci b/tests/endif.cocci new file mode 100644 index 0000000..63fa8c7 --- /dev/null +++ b/tests/endif.cocci @@ -0,0 +1,7 @@ +@@ +statement S; +@@ + + x = 1; + S ++ foo(); \ No newline at end of file diff --git a/tests/endif.res b/tests/endif.res new file mode 100644 index 0000000..f68323b --- /dev/null +++ b/tests/endif.res @@ -0,0 +1,28 @@ +void f(int i) { + + x = 1; + if(1) x = 3; + foo(); + + x = 1; + while(1) x = 3; + foo(); + + x = 1; + do x = 3; while(1); + foo(); + + x = 1; + for(1;1;1) x = 3; + foo(); + + x = 1; + for(1;1;1) { x = 3; } + foo(); + + // switch(1) { + // case 0: x = 3; + // default: x = 3; + // } + +} diff --git a/tests/exp.c b/tests/exp.c new file mode 100644 index 0000000..f319185 --- /dev/null +++ b/tests/exp.c @@ -0,0 +1,14 @@ +int main(int i) { + + int k = foo(); + + if(1) { + foo(); + } else { + foo(); + } + + foo(); + + +} diff --git a/tests/exp.cocci b/tests/exp.cocci new file mode 100644 index 0000000..4070836 --- /dev/null +++ b/tests/exp.cocci @@ -0,0 +1,5 @@ +@@ +@@ + +- foo() ++ bar() \ No newline at end of file diff --git a/tests/exp.res b/tests/exp.res new file mode 100644 index 0000000..9afbd1a --- /dev/null +++ b/tests/exp.res @@ -0,0 +1,14 @@ +int main(int i) { + + int k = bar(); + + if(1) { + bar(); + } else { + bar(); + } + + bar(); + + +} diff --git a/tests/expnest.c b/tests/expnest.c new file mode 100644 index 0000000..b789f7d --- /dev/null +++ b/tests/expnest.c @@ -0,0 +1,6 @@ +int main() { + x = 3 + 4; + x = f() + 15; + x = 15 + g(); + x = f() + g(); +} diff --git a/tests/expnest.cocci b/tests/expnest.cocci new file mode 100644 index 0000000..7093f8c --- /dev/null +++ b/tests/expnest.cocci @@ -0,0 +1,7 @@ +@expression@ +@@ + + <+... f() ...+> +- + ++ - + <+... g() ...+> diff --git a/tests/expnest.res b/tests/expnest.res new file mode 100644 index 0000000..5e18b7d --- /dev/null +++ b/tests/expnest.res @@ -0,0 +1,6 @@ +int main() { + x = 3 + 4; + x = f() + 15; + x = 15 + g(); + x = f() - g(); +} diff --git a/tests/expopt.c b/tests/expopt.c new file mode 100644 index 0000000..689ec78 --- /dev/null +++ b/tests/expopt.c @@ -0,0 +1,5 @@ +int main() { + int *x; + f(x); + *x = 7; +} diff --git a/tests/expopt.cocci b/tests/expopt.cocci new file mode 100644 index 0000000..8355a35 --- /dev/null +++ b/tests/expopt.cocci @@ -0,0 +1,13 @@ +@@ +expression E; +@@ + + f(E); + ... +( +- *E ++ E +| +- E ++ *E +) diff --git a/tests/expopt.res b/tests/expopt.res new file mode 100644 index 0000000..f6f4c0d --- /dev/null +++ b/tests/expopt.res @@ -0,0 +1,5 @@ +int main() { + int *x; + f(x); + x = 7; +} diff --git a/tests/expopt2.c b/tests/expopt2.c new file mode 100644 index 0000000..6559b2f --- /dev/null +++ b/tests/expopt2.c @@ -0,0 +1,5 @@ +void main(int i) { + + f(v, w.aa); + +} diff --git a/tests/expopt2.cocci b/tests/expopt2.cocci new file mode 100644 index 0000000..4470c83 --- /dev/null +++ b/tests/expopt2.cocci @@ -0,0 +1,13 @@ +@@ +identifier v,w; +identifier fld; +@@ + f(v, +( +- v.fld ++ v->fld +| +- w.aa ++ g(w.aa) +) + ) diff --git a/tests/expopt2.res b/tests/expopt2.res new file mode 100644 index 0000000..b11af48 --- /dev/null +++ b/tests/expopt2.res @@ -0,0 +1,5 @@ +void main(int i) { + + f(v, g(w.aa)); + +} diff --git a/tests/expopt3.c b/tests/expopt3.c new file mode 100644 index 0000000..f2d9a5b --- /dev/null +++ b/tests/expopt3.c @@ -0,0 +1,5 @@ +static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct video_tuner v; + pcm20_getflags(pcm20, &v.flags, &v.xxx, &v.signal); +} diff --git a/tests/expopt3.cocci b/tests/expopt3.cocci new file mode 100644 index 0000000..2cdea3d --- /dev/null +++ b/tests/expopt3.cocci @@ -0,0 +1,15 @@ +@@ +identifier v,fld; +@@ + +- struct video_tuner v; ++ struct video_tuner *v; +<... +( +- v.fld ++ v->fld +| +- v ++ *v +) +...> \ No newline at end of file diff --git a/tests/expopt3.res b/tests/expopt3.res new file mode 100644 index 0000000..6ff8937 --- /dev/null +++ b/tests/expopt3.res @@ -0,0 +1,5 @@ +static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct video_tuner v; + pcm20_getflags(pcm20, &v->flags, &v->xxx, &v->signal); +} diff --git a/tests/expopt3_ver1.c b/tests/expopt3_ver1.c new file mode 100644 index 0000000..2922255 --- /dev/null +++ b/tests/expopt3_ver1.c @@ -0,0 +1,6 @@ +static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct video_tuner v; + //&v.field; + f(&v.field1, &v.field2, &v.field3, &v.field4); +} diff --git a/tests/expopt3_ver1.res b/tests/expopt3_ver1.res new file mode 100644 index 0000000..7c73717 --- /dev/null +++ b/tests/expopt3_ver1.res @@ -0,0 +1,6 @@ +static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct video_tuner v; + //&v.field; + f(&v->field1, &v->field2, &v->field3, &v->field4); +} diff --git a/tests/expopt3_ver2.c b/tests/expopt3_ver2.c new file mode 100644 index 0000000..ad3ccc2 --- /dev/null +++ b/tests/expopt3_ver2.c @@ -0,0 +1,5 @@ +static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct video_tuner v; + f(v.field1, v.field2); +} diff --git a/tests/expopt3_ver2.res b/tests/expopt3_ver2.res new file mode 100644 index 0000000..544d956 --- /dev/null +++ b/tests/expopt3_ver2.res @@ -0,0 +1,5 @@ +static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct video_tuner v; + f(v->field1, v->field2); +} diff --git a/tests/expopt4.c b/tests/expopt4.c new file mode 100644 index 0000000..4cc1f52 --- /dev/null +++ b/tests/expopt4.c @@ -0,0 +1,12 @@ +void xxx(void) +{ + xxx(1); + +} + + +void main(void) +{ + + f((int) 1); +} diff --git a/tests/expopt4.cocci b/tests/expopt4.cocci new file mode 100644 index 0000000..834cc7e --- /dev/null +++ b/tests/expopt4.cocci @@ -0,0 +1,20 @@ +//@ rule1 @ +//expression E; +//@@ +// +// xxx(E); + + +@ r @ +type T; +//expression rule1.E; +expression E; +@@ + +( +- f((T) E) ++ foo() +| +- f(E) ++ bar() +) diff --git a/tests/fields.c b/tests/fields.c new file mode 100644 index 0000000..82cc20f --- /dev/null +++ b/tests/fields.c @@ -0,0 +1,5 @@ +struct foo x = { + .xa = 1, + .xb = 2, + .xc = 3, +}; diff --git a/tests/fields.cocci b/tests/fields.cocci new file mode 100644 index 0000000..a62f086 --- /dev/null +++ b/tests/fields.cocci @@ -0,0 +1,9 @@ +@@ +@@ + +struct foo x = { ++ .a = 1, ++ .b = 2, ++ .c = 3, +}; + diff --git a/tests/fields.res b/tests/fields.res new file mode 100644 index 0000000..99a8178 --- /dev/null +++ b/tests/fields.res @@ -0,0 +1,8 @@ +struct foo x = { + .a = 1, + .b = 2, + .c = 3, + .xa = 1, + .xb = 2, + .xc = 3, +}; diff --git a/tests/fieldsmin.c b/tests/fieldsmin.c new file mode 100644 index 0000000..c1b940f --- /dev/null +++ b/tests/fieldsmin.c @@ -0,0 +1,5 @@ +struct foo x = { + .a = 1, + .b = 2, + .c = 3, +}; diff --git a/tests/fieldsmin.cocci b/tests/fieldsmin.cocci new file mode 100644 index 0000000..0527367 --- /dev/null +++ b/tests/fieldsmin.cocci @@ -0,0 +1,9 @@ +@@ +@@ + +struct foo x = { +- .a = 1, +- .b = 2, + .c = 3, +}; + diff --git a/tests/fieldsmin.res b/tests/fieldsmin.res new file mode 100644 index 0000000..4092b8f --- /dev/null +++ b/tests/fieldsmin.res @@ -0,0 +1,3 @@ +struct foo x = { + .c = 3, +}; diff --git a/tests/fix_flow_need.c b/tests/fix_flow_need.c new file mode 100644 index 0000000..47bd652 --- /dev/null +++ b/tests/fix_flow_need.c @@ -0,0 +1,11 @@ +void main(int i) { + + foobar(); + + if(1) { + foo(); + } + bar(); + + foobar(); +} diff --git a/tests/fix_flow_need.cocci b/tests/fix_flow_need.cocci new file mode 100644 index 0000000..d3184cb --- /dev/null +++ b/tests/fix_flow_need.cocci @@ -0,0 +1,7 @@ +@@ +@@ + + ... + if(1) { foo(); } +- bar(); + ... diff --git a/tests/fix_flow_need.res b/tests/fix_flow_need.res new file mode 100644 index 0000000..a4080d7 --- /dev/null +++ b/tests/fix_flow_need.res @@ -0,0 +1,10 @@ +void main(int i) { + + foobar(); + + if(1) { + foo(); + } + + foobar(); +} diff --git a/tests/fn_todo.c b/tests/fn_todo.c new file mode 100644 index 0000000..28ef758 --- /dev/null +++ b/tests/fn_todo.c @@ -0,0 +1,10 @@ +static void task_kill_later(struct asd_ascb *ascb) +{ + struct asd_ha_struct *asd_ha = ascb->ha; + struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; + struct Scsi_Host *shost = sas_ha->core.shost; + struct sas_task *task = ascb->uldd_task; + + INIT_WORK(&task->abort_work, (void (*)(void *))sas_task_abort, task); + queue_work(shost->work_q, &task->abort_work); +} diff --git a/tests/fn_todo.cocci b/tests/fn_todo.cocci new file mode 100644 index 0000000..005f1d4 --- /dev/null +++ b/tests/fn_todo.cocci @@ -0,0 +1,12 @@ +@ device_arg disable all @ +type T1; +type local_type; +local_type *device; +identifier fld, fn; +@@ + + + INIT_WORK(&device->fld, +- (T1)fn, device ++ fn + ); diff --git a/tests/fn_todo.res b/tests/fn_todo.res new file mode 100644 index 0000000..2fadedd --- /dev/null +++ b/tests/fn_todo.res @@ -0,0 +1,10 @@ +static void task_kill_later(struct asd_ascb *ascb) +{ + struct asd_ha_struct *asd_ha = ascb->ha; + struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; + struct Scsi_Host *shost = sas_ha->core.shost; + struct sas_task *task = ascb->uldd_task; + + INIT_WORK(&task->abort_work, sas_task_abort); + queue_work(shost->work_q, &task->abort_work); +} diff --git a/tests/fnptr.c b/tests/fnptr.c new file mode 100644 index 0000000..34fb564 --- /dev/null +++ b/tests/fnptr.c @@ -0,0 +1,12 @@ +static irqreturn_t sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ +} + +static int sci_request_irq(struct sci_port *port) { + int i; + irqreturn_t (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = { + sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, + sci_br_interrupt, + }; + request_irq(port->irqs[0], sci_mpxed_interrupt, SA_INTERRUPT); +} diff --git a/tests/fnptr.cocci b/tests/fnptr.cocci new file mode 100644 index 0000000..ca61c28 --- /dev/null +++ b/tests/fnptr.cocci @@ -0,0 +1,5 @@ +@@ +@@ + +- SA_INTERRUPT ++ foo() diff --git a/tests/fnptr.res b/tests/fnptr.res new file mode 100644 index 0000000..24fe5c7 --- /dev/null +++ b/tests/fnptr.res @@ -0,0 +1,12 @@ +static irqreturn_t sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ +} + +static int sci_request_irq(struct sci_port *port) { + int i; + irqreturn_t (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = { + sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, + sci_br_interrupt, + }; + request_irq(port->irqs[0], sci_mpxed_interrupt, foo()); +} diff --git a/tests/fnret.c b/tests/fnret.c new file mode 100644 index 0000000..d9029b9 --- /dev/null +++ b/tests/fnret.c @@ -0,0 +1 @@ +static void foo(int x) { return; } diff --git a/tests/fnret.cocci b/tests/fnret.cocci new file mode 100644 index 0000000..c500fe6 --- /dev/null +++ b/tests/fnret.cocci @@ -0,0 +1,6 @@ +@@ +@@ + +// if int x is replaced by ..., there is a todo in transformation.ml + +- foo(int x) { return; } diff --git a/tests/fnret.res b/tests/fnret.res new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/fnret.res @@ -0,0 +1 @@ + diff --git a/tests/fns.c b/tests/fns.c new file mode 100644 index 0000000..223ae6b --- /dev/null +++ b/tests/fns.c @@ -0,0 +1,12 @@ +int __init probe_base_port(int base) { + for (base = b; base <= e; base += 0x10) { + if (check_region(base, 0x10)) + continue; + return (base); + } + return 0; +} + +int __init cm206_init(void) { + request_region(cm206_base, 0x10, "cm206"); +} diff --git a/tests/fns.cocci b/tests/fns.cocci new file mode 100644 index 0000000..be2a8d8 --- /dev/null +++ b/tests/fns.cocci @@ -0,0 +1,42 @@ +// we were using some minirules before where fn1 and fn2 were in same rule + +// pad: il manque un E dans check_region dans rule3 car il a 2 args +// mais je sais pas si faut le propager dans request_region + +@ rule1 @ +expression req8_reg_arg2; +expression E; +identifier fn1; +@@ + +fn1(...) { + ... + for(...; ...; ...) { + ... + if (check_region(E, req8_reg_arg2)) + { ... when = \( printk(...); \| dbg(...); \) + continue; } + ... + } +... +} + +@ rule2 depends on rule1 @ +expression rule1.req8_reg_arg2; +expression req8_reg_arg1; +expression req8_reg_arg3; +identifier fn2; +@@ + +fn2(...) { +- request_region(req8_reg_arg1, req8_reg_arg2, req8_reg_arg3); +} + +@ rule3 depends on rule1 @ +expression rule1.req8_reg_arg2; +expression rule2.req8_reg_arg3; +statement S; +@@ + +- if (check_region(req8_reg_arg2)) S ++ if (!request_region(req8_reg_arg2, req8_reg_arg3)) S diff --git a/tests/four.c b/tests/four.c new file mode 100644 index 0000000..c58694c --- /dev/null +++ b/tests/four.c @@ -0,0 +1,5 @@ +int main () { + f(1); + h(2); + i(2); +} diff --git a/tests/four.cocci b/tests/four.cocci new file mode 100644 index 0000000..bb9b663 --- /dev/null +++ b/tests/four.cocci @@ -0,0 +1,26 @@ +@ rule1 @ +expression E; +@@ + +f(E); + +@ rule2 @ +expression rule1.E; +@@ + +- g(E); + +//---------------------------------------------------------------------------- + +@ rule3 @ +expression E; +@@ + +- h(E); + +@ rule4 @ +expression rule3.E; +@@ + +- i(E); + diff --git a/tests/four.res b/tests/four.res new file mode 100644 index 0000000..ccefd32 --- /dev/null +++ b/tests/four.res @@ -0,0 +1,3 @@ +int main () { + f(1); +} diff --git a/tests/foura.c b/tests/foura.c new file mode 100644 index 0000000..c58694c --- /dev/null +++ b/tests/foura.c @@ -0,0 +1,5 @@ +int main () { + f(1); + h(2); + i(2); +} diff --git a/tests/foura.cocci b/tests/foura.cocci new file mode 100644 index 0000000..fa44701 --- /dev/null +++ b/tests/foura.cocci @@ -0,0 +1,11 @@ +@ rule1 @ +expression E; +@@ + +h(E); + +@ rule2 extends rule1 @ +@@ + +- i(E); + diff --git a/tests/foura.res b/tests/foura.res new file mode 100644 index 0000000..35046bf --- /dev/null +++ b/tests/foura.res @@ -0,0 +1,4 @@ +int main () { + f(1); + h(2); +} diff --git a/tests/fp.c b/tests/fp.c new file mode 100644 index 0000000..f8201af --- /dev/null +++ b/tests/fp.c @@ -0,0 +1,3 @@ +int main(int (*x)(int,int)) { + x(); +} diff --git a/tests/fp.cocci b/tests/fp.cocci new file mode 100644 index 0000000..4a13faa --- /dev/null +++ b/tests/fp.cocci @@ -0,0 +1,9 @@ +@@ +identifier f,g; +@@ + +f(int (*g)(int,int)) { + ... +- g(); + ... +} diff --git a/tests/fp.res b/tests/fp.res new file mode 100644 index 0000000..ab6ea59 --- /dev/null +++ b/tests/fp.res @@ -0,0 +1,2 @@ +int main(int (*x)(int,int)) { +} diff --git a/tests/free.c b/tests/free.c new file mode 100644 index 0000000..4ce2ec8 --- /dev/null +++ b/tests/free.c @@ -0,0 +1,75 @@ +static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl) +{ + struct ip_fw *ftmp,*ltmp; + unsigned short tport1,tport2,tmpnum; + char matches,was_found; + unsigned long flags; + + save_flags(flags); + cli(); + + ftmp=*chainptr; + + if ( ftmp == NULL ) + { +#ifdef DEBUG_IP_FIREWALL + printk("ip_fw_ctl: chain is empty\n"); +#endif + restore_flags(flags); + return( EINVAL ); + } + + ltmp=NULL; + was_found=0; + + while( !was_found && ftmp != NULL ) + { + matches=1; + if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr + || ftmp->fw_dst.s_addr!=frwl->fw_dst.s_addr + || ftmp->fw_smsk.s_addr!=frwl->fw_smsk.s_addr + || ftmp->fw_dmsk.s_addr!=frwl->fw_dmsk.s_addr + || ftmp->fw_via.s_addr!=frwl->fw_via.s_addr + || ftmp->fw_flg!=frwl->fw_flg) + matches=0; + + tport1=ftmp->fw_nsp+ftmp->fw_ndp; + tport2=frwl->fw_nsp+frwl->fw_ndp; + if (tport1!=tport2) + matches=0; + else if (tport1!=0) + { + for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++) + if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum]) + matches=0; + } + if (strncmp(ftmp->fw_vianame, frwl->fw_vianame, IFNAMSIZ)) + matches=0; + if(matches) + { + was_found=1; + if (ltmp) + { + ltmp->fw_next=ftmp->fw_next; + kfree(ftmp); + ftmp=ltmp->fw_next; + } + else + { + *chainptr=ftmp->fw_next; + kfree(ftmp); + ftmp=*chainptr; + } + } + else + { + ltmp = ftmp; + ftmp = ftmp->fw_next; + } + } + restore_flags(flags); + if (was_found) + return 0; + else + return(EINVAL); +} diff --git a/tests/free.cocci b/tests/free.cocci new file mode 100644 index 0000000..ccec1dd --- /dev/null +++ b/tests/free.cocci @@ -0,0 +1,68 @@ +@a@ +identifier x; +expression E; +expression f; +identifier fld; +type T; +@@ + +( + free(x); +| + kfree(x); +| + kfree_skb(x); +| + dev_kfree_skb(x); +| + dev_kfree_skb_anx(x); +) + ... WHEN != x = E + WHEN != \(T x;\| T x = E;\) + f(...,x,...) + +@@ +identifier x; +expression E; +type T; +@@ + +( + free(x); +| + kfree(x); +| + kfree_skb(x); +| + dev_kfree_skb(x); +| + dev_kfree_skb_anx(x); +) + ... WHEN != x = E + WHEN != T x; + WHEN != T x = E; + *x + +@@ +identifier x; +expression E; +identifier fld; +type T; +@@ + +( + free(x); +| + kfree(x); +| + kfree_skb(x); +| + dev_kfree_skb(x); +| + dev_kfree_skb_anx(x); +) + ... WHEN != x = E + WHEN != T x; + WHEN != T x = E; + x->fld + diff --git a/tests/free_ver5.c b/tests/free_ver5.c new file mode 100644 index 0000000..f947568 --- /dev/null +++ b/tests/free_ver5.c @@ -0,0 +1,7 @@ +int main () { +#ifdef FOO + free(foo); +#else + x = foo->x; +#endif +} diff --git a/tests/fun.c b/tests/fun.c new file mode 100644 index 0000000..d3b1838 --- /dev/null +++ b/tests/fun.c @@ -0,0 +1 @@ +int f(int x) { return x; } diff --git a/tests/fun.cocci b/tests/fun.cocci new file mode 100644 index 0000000..ff40f23 --- /dev/null +++ b/tests/fun.cocci @@ -0,0 +1,5 @@ +@@ +@@ + ++struct a {int a;}; +f(int x) { return x; } diff --git a/tests/fun.res b/tests/fun.res new file mode 100644 index 0000000..697b1bd --- /dev/null +++ b/tests/fun.res @@ -0,0 +1,2 @@ +struct a {int a;}; +int f(int x) { return x; } diff --git a/tests/gilles-question.c b/tests/gilles-question.c new file mode 100644 index 0000000..e5a5391 --- /dev/null +++ b/tests/gilles-question.c @@ -0,0 +1,9 @@ +void main(int i) { + + f(0); + if(1) { + g(0); + } + g(0); +} + diff --git a/tests/gilles-question.cocci b/tests/gilles-question.cocci new file mode 100644 index 0000000..8d4ca98 --- /dev/null +++ b/tests/gilles-question.cocci @@ -0,0 +1,6 @@ +@@ +@@ + + f(0); + ... +- g(0); diff --git a/tests/gilles-question.res b/tests/gilles-question.res new file mode 100644 index 0000000..8714f3f --- /dev/null +++ b/tests/gilles-question.res @@ -0,0 +1,9 @@ +void main(int i) { + + f(0); + if(1) { + + } + +} + diff --git a/tests/gotobreak.c b/tests/gotobreak.c new file mode 100644 index 0000000..f336fb3 --- /dev/null +++ b/tests/gotobreak.c @@ -0,0 +1,15 @@ +static void sedlbauer_config(struct pcmcia_device *link) +{ + while (1) { + if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { + goto next_entry; + } + /* If we got this far, we're cool! */ + break; + + next_entry: + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); + } + + return; +} diff --git a/tests/gotobreak.cocci b/tests/gotobreak.cocci new file mode 100644 index 0000000..207e027 --- /dev/null +++ b/tests/gotobreak.cocci @@ -0,0 +1,10 @@ +@@ +identifier config; +@@ + + config(...) { + <... +- return; ++ return 0; + ...> + } diff --git a/tests/gotobreak.res b/tests/gotobreak.res new file mode 100644 index 0000000..bb62300 --- /dev/null +++ b/tests/gotobreak.res @@ -0,0 +1,15 @@ +static void sedlbauer_config(struct pcmcia_device *link) +{ + while (1) { + if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { + goto next_entry; + } + /* If we got this far, we're cool! */ + break; + + next_entry: + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); + } + + return 0; +} diff --git a/tests/hd.c b/tests/hd.c new file mode 100644 index 0000000..cab2e0b --- /dev/null +++ b/tests/hd.c @@ -0,0 +1,3 @@ +#include "hd.h" + +int f(int x, int y) { return x; } diff --git a/tests/hd.cocci b/tests/hd.cocci new file mode 100644 index 0000000..2552846 --- /dev/null +++ b/tests/hd.cocci @@ -0,0 +1,7 @@ +@@ +@@ + +- f(int x, int y) { ++ f(int x) { + ... + } diff --git a/tests/hd.h b/tests/hd.h new file mode 100644 index 0000000..f0a0524 --- /dev/null +++ b/tests/hd.h @@ -0,0 +1 @@ +int f(int x, int y); diff --git a/tests/hd.res b/tests/hd.res new file mode 100644 index 0000000..7e634fe --- /dev/null +++ b/tests/hd.res @@ -0,0 +1,3 @@ +#include "hd.h" + +int f(int x) { return x; } diff --git a/tests/header_modif.c b/tests/header_modif.c new file mode 100644 index 0000000..f26b272 --- /dev/null +++ b/tests/header_modif.c @@ -0,0 +1,6 @@ +#include "header_modif.h" + +int foo(int i) { + +} + diff --git a/tests/header_modif.cocci b/tests/header_modif.cocci new file mode 100644 index 0000000..ce09500 --- /dev/null +++ b/tests/header_modif.cocci @@ -0,0 +1,9 @@ +@@ +identifier x; +@@ + +- int ++ float +foo(int x) { + ... +} \ No newline at end of file diff --git a/tests/header_modif.h b/tests/header_modif.h new file mode 100644 index 0000000..98970d1 --- /dev/null +++ b/tests/header_modif.h @@ -0,0 +1,3 @@ + + +int foo(int); diff --git a/tests/headers.c b/tests/headers.c new file mode 100644 index 0000000..9ea0468 --- /dev/null +++ b/tests/headers.c @@ -0,0 +1,22 @@ +static void empeg_close (struct usb_serial_port *port, struct file *filp); +static void empeg_close (struct usb_serial_port *port, struct file * filp) +{ +} + + +static int empeg_write (struct usb_serial_port *port, const unsigned char *buf, int count) +{ + usb_fill_bulk_urb (empeg_write_bulk_callback); + +} + +static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs) +{ +} + + +static void empeg_read_bulk_callback (struct urb *urb, struct pt_regs *regs) +{ + usb_fill_bulk_urb(empeg_read_bulk_callback); + +} diff --git a/tests/headers.cocci b/tests/headers.cocci new file mode 100644 index 0000000..3145594 --- /dev/null +++ b/tests/headers.cocci @@ -0,0 +1,15 @@ +@ rule1 @ +identifier f; +@@ + +usb_fill_bulk_urb(f) + +@ rule2 extends rule1 @ +identifier p1, p2; +@@ + +- void f (struct urb *p1, struct pt_regs *p2) ++ void f (struct urb *p1) + { + ... when != p2 + } diff --git a/tests/headers.res b/tests/headers.res new file mode 100644 index 0000000..2bf1afd --- /dev/null +++ b/tests/headers.res @@ -0,0 +1,22 @@ +static void empeg_close (struct usb_serial_port *port, struct file *filp); +static void empeg_close (struct usb_serial_port *port, struct file * filp) +{ +} + + +static int empeg_write (struct usb_serial_port *port, const unsigned char *buf, int count) +{ + usb_fill_bulk_urb (empeg_write_bulk_callback); + +} + +static void empeg_write_bulk_callback (struct urb *urb) +{ +} + + +static void empeg_read_bulk_callback (struct urb *urb) +{ + usb_fill_bulk_urb(empeg_read_bulk_callback); + +} diff --git a/tests/hex.c b/tests/hex.c new file mode 100644 index 0000000..c1bcca1 --- /dev/null +++ b/tests/hex.c @@ -0,0 +1,3 @@ +int main() { + f(0x00); +} diff --git a/tests/hex.cocci b/tests/hex.cocci new file mode 100644 index 0000000..a3e3c40 --- /dev/null +++ b/tests/hex.cocci @@ -0,0 +1,3 @@ +@@ +@@ +- f(0); diff --git a/tests/hex.res b/tests/hex.res new file mode 100644 index 0000000..b2f9976 --- /dev/null +++ b/tests/hex.res @@ -0,0 +1,2 @@ +int main() { +} diff --git a/tests/hex2.c b/tests/hex2.c new file mode 100644 index 0000000..3ecc1a3 --- /dev/null +++ b/tests/hex2.c @@ -0,0 +1,3 @@ +int main() { + f(4294967295); +} diff --git a/tests/hex2.cocci b/tests/hex2.cocci new file mode 100644 index 0000000..0e418ea --- /dev/null +++ b/tests/hex2.cocci @@ -0,0 +1,3 @@ +@@ +@@ +- f(0xFFFFFFFF); diff --git a/tests/hex2.res b/tests/hex2.res new file mode 100644 index 0000000..b2f9976 --- /dev/null +++ b/tests/hex2.res @@ -0,0 +1,2 @@ +int main() { +} diff --git a/tests/if2.c b/tests/if2.c new file mode 100644 index 0000000..b7000e7 --- /dev/null +++ b/tests/if2.c @@ -0,0 +1,6 @@ +int main(int x) { + for(x=1;x>1;x++) { + xxx(2); + xxx(1); + } +} diff --git a/tests/if2.cocci b/tests/if2.cocci new file mode 100644 index 0000000..6483055 --- /dev/null +++ b/tests/if2.cocci @@ -0,0 +1,10 @@ +@@ +expression E; +@@ + +- for(...;...;...) { + xxx(2); + <... +- xxx(E); + ...> +- } diff --git a/tests/ifbr.c b/tests/ifbr.c new file mode 100644 index 0000000..93d2b72 --- /dev/null +++ b/tests/ifbr.c @@ -0,0 +1,4 @@ +int main () { + if (x) + return; +} diff --git a/tests/ifbr.cocci b/tests/ifbr.cocci new file mode 100644 index 0000000..0cf15bf --- /dev/null +++ b/tests/ifbr.cocci @@ -0,0 +1,15 @@ +@@ +expression test; +expression E; +@@ + + if (test) { + ... +( ++ pci_dev_put(); + return; +| ++ pci_dev_put(); + return ret; +) + } diff --git a/tests/ifbr.res b/tests/ifbr.res new file mode 100644 index 0000000..93d2b72 --- /dev/null +++ b/tests/ifbr.res @@ -0,0 +1,4 @@ +int main () { + if (x) + return; +} diff --git a/tests/ifdef1.c b/tests/ifdef1.c new file mode 100644 index 0000000..ab8c5ee --- /dev/null +++ b/tests/ifdef1.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + + +void init_IRQ(void) +{ + for (irq = 0; irq < IRQS; irq++) { + *desc = irq_desc; + uselessCall(); + } +} diff --git a/tests/ifdef1.cocci b/tests/ifdef1.cocci new file mode 100644 index 0000000..89bee9e --- /dev/null +++ b/tests/ifdef1.cocci @@ -0,0 +1,7 @@ +@ Exemple1@ @@ + + #include + ++ #ifdef CONFIG_NKERNEL ++ #include ++ #endif diff --git a/tests/ifdef1.res b/tests/ifdef1.res new file mode 100644 index 0000000..13daa55 --- /dev/null +++ b/tests/ifdef1.res @@ -0,0 +1,16 @@ +#include +#include +#ifdef CONFIG_NKERNEL +#include +#endif +#include +#include + + +void init_IRQ(void) +{ + for (irq = 0; irq < IRQS; irq++) { + *desc = irq_desc; + uselessCall(); + } +} diff --git a/tests/ifdef2.c b/tests/ifdef2.c new file mode 100644 index 0000000..ab8c5ee --- /dev/null +++ b/tests/ifdef2.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + + +void init_IRQ(void) +{ + for (irq = 0; irq < IRQS; irq++) { + *desc = irq_desc; + uselessCall(); + } +} diff --git a/tests/ifdef2.cocci b/tests/ifdef2.cocci new file mode 100644 index 0000000..8197a62 --- /dev/null +++ b/tests/ifdef2.cocci @@ -0,0 +1,8 @@ +@ Exemple2 @ @@ + + #include ++ #ifdef CONFIG_NKERNEL ++ #include ++ #include ++ unsigned long maxsize = 0; ++ #endif diff --git a/tests/ifdef2.res b/tests/ifdef2.res new file mode 100644 index 0000000..19a3b14 --- /dev/null +++ b/tests/ifdef2.res @@ -0,0 +1,18 @@ +#include +#include +#include +#ifdef CONFIG_NKERNEL +#include +#include +unsigned long maxsize = 0; +#endif +#include + + +void init_IRQ(void) +{ + for (irq = 0; irq < IRQS; irq++) { + *desc = irq_desc; + uselessCall(); + } +} diff --git a/tests/ifdef3.c b/tests/ifdef3.c new file mode 100644 index 0000000..ab8c5ee --- /dev/null +++ b/tests/ifdef3.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + + +void init_IRQ(void) +{ + for (irq = 0; irq < IRQS; irq++) { + *desc = irq_desc; + uselessCall(); + } +} diff --git a/tests/ifdef3.cocci b/tests/ifdef3.cocci new file mode 100644 index 0000000..1f5da85 --- /dev/null +++ b/tests/ifdef3.cocci @@ -0,0 +1,11 @@ +@ Exemple3 @ @@ + + #include + ++ #ifdef CONFIG_NKERNEL ++ #include ++ #define CONFIG_NKERNEL_NO_SHARED_IRQ // use local (native) mask/unmask ++ #undef CONFIG_NKERNEL_DEBUG_IRQ ++ #endif + ++ static inline void nop(void) { int i; } diff --git a/tests/ifdef3.res b/tests/ifdef3.res new file mode 100644 index 0000000..2e04f08 --- /dev/null +++ b/tests/ifdef3.res @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#ifdef CONFIG_NKERNEL +#include +#define CONFIG_NKERNEL_NO_SHARED_IRQ // use local (native) mask/unmask +#undef CONFIG_NKERNEL_DEBUG_IRQ +#endif + +static inline void nop(void) { int i; } + + +void init_IRQ(void) +{ + for (irq = 0; irq < IRQS; irq++) { + *desc = irq_desc; + uselessCall(); + } +} diff --git a/tests/ifdef4.c b/tests/ifdef4.c new file mode 100644 index 0000000..ab8c5ee --- /dev/null +++ b/tests/ifdef4.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + + +void init_IRQ(void) +{ + for (irq = 0; irq < IRQS; irq++) { + *desc = irq_desc; + uselessCall(); + } +} diff --git a/tests/ifdef4.cocci b/tests/ifdef4.cocci new file mode 100644 index 0000000..b79c9ea --- /dev/null +++ b/tests/ifdef4.cocci @@ -0,0 +1,11 @@ +@ Exemple4 @ @@ + + init_IRQ(...) + { + <... ++ #ifdef CONFIG_NKERNEL ++ if (irq < IRQ_LIMIT) ++ #endif + *desc = irq_desc; + ...> +} diff --git a/tests/ifdef4.res b/tests/ifdef4.res new file mode 100644 index 0000000..3846799 --- /dev/null +++ b/tests/ifdef4.res @@ -0,0 +1,16 @@ +#include +#include +#include +#include + + +void init_IRQ(void) +{ + for (irq = 0; irq < IRQS; irq++) { +#ifdef CONFIG_NKERNEL + if (irq < IRQ_LIMIT) +#endif + *desc = irq_desc; + uselessCall(); + } +} diff --git a/tests/ifdef5.c b/tests/ifdef5.c new file mode 100644 index 0000000..ab8c5ee --- /dev/null +++ b/tests/ifdef5.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + + +void init_IRQ(void) +{ + for (irq = 0; irq < IRQS; irq++) { + *desc = irq_desc; + uselessCall(); + } +} diff --git a/tests/ifdef5.cocci b/tests/ifdef5.cocci new file mode 100644 index 0000000..644afa5 --- /dev/null +++ b/tests/ifdef5.cocci @@ -0,0 +1,13 @@ +@ Exemple5 @ @@ + + init_IRQ(...) {...} + ++ #ifdef CONFIG_NKERNEL ++ #ifndef TIMER_32K_SYNCHRONIZED ++ #define TIMER_32K_SYNCHRONIZED 0xffffffff ++ #endif + ++ unsigned long nk_vtick_read_stamp(void) ++ { ++ return omap_readl(TIMER_32K_SYNCHRONIZED); ++ } diff --git a/tests/ifdef5.res b/tests/ifdef5.res new file mode 100644 index 0000000..78c0a30 --- /dev/null +++ b/tests/ifdef5.res @@ -0,0 +1,23 @@ +#include +#include +#include +#include + + +void init_IRQ(void) +{ + for (irq = 0; irq < IRQS; irq++) { + *desc = irq_desc; + uselessCall(); + } +} + +#ifdef CONFIG_NKERNEL +#ifndef TIMER_32K_SYNCHRONIZED +#define TIMER_32K_SYNCHRONIZED 0xffffffff +#endif + +unsigned long nk_vtick_read_stamp(void) +{ +return omap_readl(TIMER_32K_SYNCHRONIZED); +} diff --git a/tests/ifdef6.c b/tests/ifdef6.c new file mode 100644 index 0000000..ab8c5ee --- /dev/null +++ b/tests/ifdef6.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + + +void init_IRQ(void) +{ + for (irq = 0; irq < IRQS; irq++) { + *desc = irq_desc; + uselessCall(); + } +} diff --git a/tests/ifdef6.cocci b/tests/ifdef6.cocci new file mode 100644 index 0000000..f5eda43 --- /dev/null +++ b/tests/ifdef6.cocci @@ -0,0 +1,7 @@ +@ Exemple6@ @@ + + #include + ++ #ifdef CONFIG_NKERNEL ++ #define foo(x) f(x) ++ #endif diff --git a/tests/ifdef6.res b/tests/ifdef6.res new file mode 100644 index 0000000..36b351e --- /dev/null +++ b/tests/ifdef6.res @@ -0,0 +1,16 @@ +#include +#include +#ifdef CONFIG_NKERNEL +#define foo(x) f(x) +#endif +#include +#include + + +void init_IRQ(void) +{ + for (irq = 0; irq < IRQS; irq++) { + *desc = irq_desc; + uselessCall(); + } +} diff --git a/tests/ifend.c b/tests/ifend.c new file mode 100644 index 0000000..e8c68d6 --- /dev/null +++ b/tests/ifend.c @@ -0,0 +1,7 @@ +#ifdef VORTEX_DEBUG +static int vortex_debug = VORTEX_DEBUG; +#else +static int vortex_debug = 1; +#endif + +#include diff --git a/tests/ifend.cocci b/tests/ifend.cocci new file mode 100644 index 0000000..b2db38d --- /dev/null +++ b/tests/ifend.cocci @@ -0,0 +1,4 @@ +@@ +@@ + +- #include diff --git a/tests/ifend.res b/tests/ifend.res new file mode 100644 index 0000000..72a2e46 --- /dev/null +++ b/tests/ifend.res @@ -0,0 +1,5 @@ +#ifdef VORTEX_DEBUG +static int vortex_debug = VORTEX_DEBUG; +#else +static int vortex_debug = 1; +#endif diff --git a/tests/ifzer.c b/tests/ifzer.c new file mode 100644 index 0000000..b16d2df --- /dev/null +++ b/tests/ifzer.c @@ -0,0 +1,8 @@ +int main() { +#if 0 /* Accessing floppy->pc is not valid here, the previous pc may be gone + and have lived on another thread's stack; that stack may have become + unmapped meanwhile (CONFIG_DEBUG_PAGEALLOC). */ +#endif + foo(); +} + diff --git a/tests/ifzer.cocci b/tests/ifzer.cocci new file mode 100644 index 0000000..880c705 --- /dev/null +++ b/tests/ifzer.cocci @@ -0,0 +1,4 @@ +@@ +@@ + +- foo(); diff --git a/tests/ifzer.res b/tests/ifzer.res new file mode 100644 index 0000000..f904b94 --- /dev/null +++ b/tests/ifzer.res @@ -0,0 +1,7 @@ +int main() { +#if 0 /* Accessing floppy->pc is not valid here, the previous pc may be gone + and have lived on another thread's stack; that stack may have become + unmapped meanwhile (CONFIG_DEBUG_PAGEALLOC). */ +#endif +} + diff --git a/tests/inc.c b/tests/inc.c new file mode 100644 index 0000000..3ac71bc --- /dev/null +++ b/tests/inc.c @@ -0,0 +1,2 @@ +#define foo 3 +#define xxx 4 diff --git a/tests/inc.cocci b/tests/inc.cocci new file mode 100644 index 0000000..c9ea45a --- /dev/null +++ b/tests/inc.cocci @@ -0,0 +1,11 @@ +@@ +expression X; +@@ + +- #define foo X ++ #define foobar X + +@@ +expression T; +@@ +- #define xxx T diff --git a/tests/inc.res b/tests/inc.res new file mode 100644 index 0000000..163c6a3 --- /dev/null +++ b/tests/inc.res @@ -0,0 +1 @@ +#define foobar 3 diff --git a/tests/incdir.c b/tests/incdir.c new file mode 100644 index 0000000..dafeb15 --- /dev/null +++ b/tests/incdir.c @@ -0,0 +1,5 @@ +#include "sub/incdir2.c" + +int main () { + foo(x); +} diff --git a/tests/incdir.cocci b/tests/incdir.cocci new file mode 100644 index 0000000..e519313 --- /dev/null +++ b/tests/incdir.cocci @@ -0,0 +1,6 @@ +@@ +char *x; +@@ + +- x ++ 12 diff --git a/tests/incdir.res b/tests/incdir.res new file mode 100644 index 0000000..239a733 --- /dev/null +++ b/tests/incdir.res @@ -0,0 +1,5 @@ +#include "sub/incdir2.c" + +int main () { + foo(12); +} diff --git a/tests/incdir2.c b/tests/incdir2.c new file mode 100644 index 0000000..b90177e --- /dev/null +++ b/tests/incdir2.c @@ -0,0 +1 @@ +char *x; diff --git a/tests/incl.c b/tests/incl.c new file mode 100644 index 0000000..c56044d --- /dev/null +++ b/tests/incl.c @@ -0,0 +1,6 @@ +#include +#include +#include +#ifdef FOO +#include +#endif FOO diff --git a/tests/incl.cocci b/tests/incl.cocci new file mode 100644 index 0000000..9f8be41 --- /dev/null +++ b/tests/incl.cocci @@ -0,0 +1,11 @@ +@@ +@@ + ++ #include "before.h" + #include + +@@ +@@ + + #include ++ #include "after.h" diff --git a/tests/incl.res b/tests/incl.res new file mode 100644 index 0000000..0eb30e9 --- /dev/null +++ b/tests/incl.res @@ -0,0 +1,8 @@ +#include "before.h" +#include +#include +#include +#include "after.h" +#ifdef FOO +#include +#endif FOO diff --git a/tests/inclifdef.c b/tests/inclifdef.c new file mode 100644 index 0000000..a309e9a --- /dev/null +++ b/tests/inclifdef.c @@ -0,0 +1,4 @@ +#include +#ifdef CONFIG +#include +#endif diff --git a/tests/inclifdef.cocci b/tests/inclifdef.cocci new file mode 100644 index 0000000..d021b6b --- /dev/null +++ b/tests/inclifdef.cocci @@ -0,0 +1,5 @@ +@@ +@@ + + #include ++ #include diff --git a/tests/inclifdef.res b/tests/inclifdef.res new file mode 100644 index 0000000..f088537 --- /dev/null +++ b/tests/inclifdef.res @@ -0,0 +1,5 @@ +#include +#include +#ifdef CONFIG +#include +#endif diff --git a/tests/include.c b/tests/include.c new file mode 100644 index 0000000..9a3644c --- /dev/null +++ b/tests/include.c @@ -0,0 +1,10 @@ + +#include +#include +#include +#include + + +void main(int i) { + i++; +} diff --git a/tests/include.cocci b/tests/include.cocci new file mode 100644 index 0000000..ffedfad --- /dev/null +++ b/tests/include.cocci @@ -0,0 +1,6 @@ +@@ +@@ + +-#include + + diff --git a/tests/include.res b/tests/include.res new file mode 100644 index 0000000..1a367f2 --- /dev/null +++ b/tests/include.res @@ -0,0 +1,8 @@ + +#include +#include + + +void main(int i) { + i++; +} diff --git a/tests/include/linux/serio.h b/tests/include/linux/serio.h new file mode 100644 index 0000000..0041a18 --- /dev/null +++ b/tests/include/linux/serio.h @@ -0,0 +1,4 @@ +struct serio { + struct semaphore drv_sem; /* mutex for mixer */ + +}; diff --git a/tests/include/linux/serio.h.res b/tests/include/linux/serio.h.res new file mode 100644 index 0000000..53e6a1f --- /dev/null +++ b/tests/include/linux/serio.h.res @@ -0,0 +1,4 @@ +struct serio { + struct mutex new_lock; /* mutex for mixer */ + +}; diff --git a/tests/incompatible_value.c b/tests/incompatible_value.c new file mode 100644 index 0000000..2d68c83 --- /dev/null +++ b/tests/incompatible_value.c @@ -0,0 +1,12 @@ +int main() { + f(1); + f(2); +} + +int main() { + g(1); + g(2); +} + + + diff --git a/tests/incompatible_value.cocci b/tests/incompatible_value.cocci new file mode 100644 index 0000000..59168e5 --- /dev/null +++ b/tests/incompatible_value.cocci @@ -0,0 +1,20 @@ +@ r1 @ +expression E; +identifier fn; +@@ +fn(...) { + <... + f(E) + ...> + } + + +@@ +expression r1.E; +@@ + +- g(E) ++ h(E) + + + diff --git a/tests/incompatible_value.res b/tests/incompatible_value.res new file mode 100644 index 0000000..2d68c83 --- /dev/null +++ b/tests/incompatible_value.res @@ -0,0 +1,12 @@ +int main() { + f(1); + f(2); +} + +int main() { + g(1); + g(2); +} + + + diff --git a/tests/inherited.c b/tests/inherited.c new file mode 100644 index 0000000..655c4b0 --- /dev/null +++ b/tests/inherited.c @@ -0,0 +1,10 @@ +void main(int i) { + + g(1); + //f(2); + + h(2); + h2(2); + + foo(1); +} diff --git a/tests/inherited.cocci b/tests/inherited.cocci new file mode 100644 index 0000000..c32686f --- /dev/null +++ b/tests/inherited.cocci @@ -0,0 +1,31 @@ +@ rule1 @ +expression X; +@@ + +( + f(X); +| + g(1); +) + +@@ +expression rule1.X; +@@ + +- h(X); ++ hh(X); + + +@@ +expression rule1.X; +@@ +- h2(X); ++ hh22(X); + +@@ +@@ + +- foo(1); ++ bar(1); + + diff --git a/tests/inherited.res b/tests/inherited.res new file mode 100644 index 0000000..6c998e4 --- /dev/null +++ b/tests/inherited.res @@ -0,0 +1,10 @@ +void main(int i) { + + g(1); + //f(2); + + h(2); + h2(2); + + bar(1); +} diff --git a/tests/inherited_ver1.c b/tests/inherited_ver1.c new file mode 100644 index 0000000..ca7c3f1 --- /dev/null +++ b/tests/inherited_ver1.c @@ -0,0 +1,10 @@ +void main(int i) { + + //g(1); + f(2); + + h(2); + h2(2); + + foo(1); +} diff --git a/tests/inherited_ver1.res b/tests/inherited_ver1.res new file mode 100644 index 0000000..886420c --- /dev/null +++ b/tests/inherited_ver1.res @@ -0,0 +1,10 @@ +void main(int i) { + + //g(1); + f(2); + + hh(2); + hh22(2); + + bar(1); +} diff --git a/tests/inhpos.c b/tests/inhpos.c new file mode 100644 index 0000000..4f7ca1d --- /dev/null +++ b/tests/inhpos.c @@ -0,0 +1,3 @@ +int main () { + g(3); +} diff --git a/tests/inhpos.cocci b/tests/inhpos.cocci new file mode 100644 index 0000000..27ed966 --- /dev/null +++ b/tests/inhpos.cocci @@ -0,0 +1,14 @@ +// the point of this example is that if p doesn't get bound, then p1 can +// be anything + +@a@ +position p; +@@ + +f@p(...) + +@@ +position p1 != a.p; +@@ + +- g@p1(...); diff --git a/tests/inhpos.res b/tests/inhpos.res new file mode 100644 index 0000000..d6a7729 --- /dev/null +++ b/tests/inhpos.res @@ -0,0 +1,2 @@ +int main () { +} diff --git a/tests/initializer.c b/tests/initializer.c new file mode 100644 index 0000000..e912ca1 --- /dev/null +++ b/tests/initializer.c @@ -0,0 +1,5 @@ +struct SHT var = { + .f1 = toto1, + .f2 = toto2, + .f3 = toto3, +}; diff --git a/tests/initializer.cocci b/tests/initializer.cocci new file mode 100644 index 0000000..6b132ad --- /dev/null +++ b/tests/initializer.cocci @@ -0,0 +1,11 @@ +@@ +identifier name1, name2; +@@ + +struct SHT var = { + .f1 = name1, +- .f2 = name2, ++ .foo = 12, ++ .foo2 = 12, +}; + diff --git a/tests/initializer.res b/tests/initializer.res new file mode 100644 index 0000000..e647c50 --- /dev/null +++ b/tests/initializer.res @@ -0,0 +1,6 @@ +struct SHT var = { + .f1 = toto1, + .foo = 12, + .foo2 = 12, + .f3 = toto3, +}; diff --git a/tests/initializer_iso.c b/tests/initializer_iso.c new file mode 100644 index 0000000..ae1759a --- /dev/null +++ b/tests/initializer_iso.c @@ -0,0 +1,26 @@ + +struct SHT template = { + .field1 = 1, + .proc_info = my_proc_info, + .field2 = 2, +}; + + +int my_proc_info(int i) +{ +} + + +int foo(struct SHT * tpnt) +{ + tpnt->proc_info = my_proc_info2; +} + +int my_proc_info2(int i) +{ +} + + +int not_proc_info(int i) +{ +} diff --git a/tests/initializer_iso.cocci b/tests/initializer_iso.cocci new file mode 100644 index 0000000..4d75ac9 --- /dev/null +++ b/tests/initializer_iso.cocci @@ -0,0 +1,28 @@ +@ rule1 @ +typedef SHT_t; +{struct SHT, SHT_t} fops; +//struct SHT fops; // this one works +identifier proc_info_func; +@@ + + fops.proc_info = proc_info_func; + + + +@ rule2 extends rule1 @ +@@ + +- proc_info_func ++ foobar + + +// necessary :( because previous rule is a Exp and funheader +// is not an expression. +@ rule3 extends rule1 @ +@@ +- proc_info_func ++ foobar + (...) +{ + ... +} \ No newline at end of file diff --git a/tests/initializer_many_fields.c b/tests/initializer_many_fields.c new file mode 100644 index 0000000..b95296e --- /dev/null +++ b/tests/initializer_many_fields.c @@ -0,0 +1,2 @@ + +struct foo x = { .a = 12 }; diff --git a/tests/initializer_many_fields.cocci b/tests/initializer_many_fields.cocci new file mode 100644 index 0000000..c560d57 --- /dev/null +++ b/tests/initializer_many_fields.cocci @@ -0,0 +1,5 @@ +@@ +@@ + +struct foo x = { .b = 15, .c = 22, }; + diff --git a/tests/initializer_many_fields.res b/tests/initializer_many_fields.res new file mode 100644 index 0000000..b95296e --- /dev/null +++ b/tests/initializer_many_fields.res @@ -0,0 +1,2 @@ + +struct foo x = { .a = 12 }; diff --git a/tests/inline.c b/tests/inline.c new file mode 100644 index 0000000..25a143b --- /dev/null +++ b/tests/inline.c @@ -0,0 +1 @@ +inline void foo(int x) { return; } diff --git a/tests/inline.cocci b/tests/inline.cocci new file mode 100644 index 0000000..66e51ac --- /dev/null +++ b/tests/inline.cocci @@ -0,0 +1,4 @@ +@@ +@@ + +- foo(int x) { ... } diff --git a/tests/inline.res b/tests/inline.res new file mode 100644 index 0000000..139597f --- /dev/null +++ b/tests/inline.res @@ -0,0 +1,2 @@ + + diff --git a/tests/ioctl.cocci b/tests/ioctl.cocci new file mode 100644 index 0000000..91bbc64 --- /dev/null +++ b/tests/ioctl.cocci @@ -0,0 +1,81 @@ +@fn@ +identifier xyz_ioctl; +identifier xyz_ops; +@@ + +struct file_operations xyz_ops = { + .ioctl = xyz_ioctl, +}; + +@safe@ +identifier fn.xyz_ioctl; +identifier i; +@@ + +static int xyz_ioctl(struct inode *i, ...) +{ + ... when != i +} + +@count disable braces1, braces2, braces3, braces4@ +identifier fn.xyz_ioctl; +statement S; +@@ + +int xyz_ioctl(...) { + <+... +( + { + ... when strict + return ...; } +| + if (...) return ...; else S +) + ...+> +} + +@one depends on safe && !count@ +identifier fn.xyz_ioctl; +identifier i, f, cmd, arg; +identifier ret; +constant cret; +statement S,S1; +@@ + +-xyz_ioctl(struct inode *i, struct file *f, unsigned cmd, unsigned long arg) ++xyz_ioctl(struct file *f, unsigned cmd, unsigned long arg) +{ + ... when != S1 ++ lock_kernel(); + S + ... +( ++ unlock_kernel(); + return ret; +| ++ unlock_kernel(); + return cret; +) +} + +@call depends on one@ +identifier fn.xyz_ioctl; +expression E1, E2, E3, E4; +@@ + +- xyz_ioctl(E1, E2, E3, E4) ++ xyz_ioctl(E2, E3, E4) + + +// be sure the changes can be made before transforming +// prototype has to be more complicated, because unsigned int can be +// just unsigned +@decl depends on one@ +identifier xyz_ioctl; +identifier xyz_ops; +@@ + +struct file_operations xyz_ops = { +- .ioctl = xyz_ioctl, ++ .unlocked_ioctl = xyz_ioctl, +}; diff --git a/tests/isococci.c b/tests/isococci.c new file mode 100644 index 0000000..6b3eaf5 --- /dev/null +++ b/tests/isococci.c @@ -0,0 +1,6 @@ + +void f(int i) { + + if(x > 0) return x; + +} diff --git a/tests/isococci.cocci b/tests/isococci.cocci new file mode 100644 index 0000000..a648b23 --- /dev/null +++ b/tests/isococci.cocci @@ -0,0 +1,5 @@ +@@ +identifier x; +@@ + +- if(x > 0) { return ...; } \ No newline at end of file diff --git a/tests/isococci.res b/tests/isococci.res new file mode 100644 index 0000000..9d99500 --- /dev/null +++ b/tests/isococci.res @@ -0,0 +1,5 @@ + +void f(int i) { + + +} diff --git a/tests/isotest.c b/tests/isotest.c new file mode 100644 index 0000000..42d65fb --- /dev/null +++ b/tests/isotest.c @@ -0,0 +1,8 @@ +void main(int i) { + + char j; + int i; // = 1; + + j++; + +} diff --git a/tests/isotest.cocci b/tests/isotest.cocci new file mode 100644 index 0000000..805e289 --- /dev/null +++ b/tests/isotest.cocci @@ -0,0 +1,5 @@ +@@ +identifier id; +@@ + +- int id; \ No newline at end of file diff --git a/tests/isotest.res b/tests/isotest.res new file mode 100644 index 0000000..1c96dbc --- /dev/null +++ b/tests/isotest.res @@ -0,0 +1,8 @@ +void main(int i) { + + char j; + // = 1; + + j++; + +} diff --git a/tests/isotest2.c b/tests/isotest2.c new file mode 100644 index 0000000..9a91e0f --- /dev/null +++ b/tests/isotest2.c @@ -0,0 +1,8 @@ +void main(int i) { + + char j; + int i = 1; + + j++; + +} diff --git a/tests/isotest2.cocci b/tests/isotest2.cocci new file mode 100644 index 0000000..29df057 --- /dev/null +++ b/tests/isotest2.cocci @@ -0,0 +1,7 @@ +@@ +identifier id; +@@ + + ... +- int id; + ... \ No newline at end of file diff --git a/tests/isotest2.res b/tests/isotest2.res new file mode 100644 index 0000000..b404588 --- /dev/null +++ b/tests/isotest2.res @@ -0,0 +1,7 @@ +void main(int i) { + + char j; + + j++; + +} diff --git a/tests/iterator.c b/tests/iterator.c new file mode 100644 index 0000000..f66b1e6 --- /dev/null +++ b/tests/iterator.c @@ -0,0 +1,10 @@ +void pcibios_report_status(u_int status_mask, int warn) +{ + struct list_head *l; + + list_for_each(l, &pci_root_buses) { + struct pci_bus *bus = pci_bus_b(l); + + pcibios_bus_report_status(bus, status_mask, warn); + } +} diff --git a/tests/iterator.cocci b/tests/iterator.cocci new file mode 100644 index 0000000..eb0688d --- /dev/null +++ b/tests/iterator.cocci @@ -0,0 +1,10 @@ +@@ +iterator list_for_each; +expression E1, E2; +statement S; +@@ + + +- list_for_each(E1, E2) +- S ++ foo(); \ No newline at end of file diff --git a/tests/iterator.res b/tests/iterator.res new file mode 100644 index 0000000..1c41f13 --- /dev/null +++ b/tests/iterator.res @@ -0,0 +1,6 @@ +void pcibios_report_status(u_int status_mask, int warn) +{ + struct list_head *l; + + foo(); +} diff --git a/tests/jloop1.c b/tests/jloop1.c new file mode 100644 index 0000000..058b76f --- /dev/null +++ b/tests/jloop1.c @@ -0,0 +1,18 @@ +void cpu_idle(void) +{ + local_fiq_enable(); + + /* endless idle loop with no priority at all */ + while (1) { + int idle = pm_idle; + if (!idle) + idle = default_idle; + preempt_disable(); + leds_event(led_idle_start); + while (!need_resched()) + idle(); + leds_event(led_idle_end); + preempt_enable(); + schedule(); + } +} diff --git a/tests/jloop1.cocci b/tests/jloop1.cocci new file mode 100644 index 0000000..95f17aa --- /dev/null +++ b/tests/jloop1.cocci @@ -0,0 +1,11 @@ +@@ @@ + // TODO: Marche pas + void cpu_idle(...) { + <... +- int idle = pm_idle; + <... +- idle(); ++ nkidle(); + ...> + ...> + } diff --git a/tests/jloop1.res b/tests/jloop1.res new file mode 100644 index 0000000..f588a57 --- /dev/null +++ b/tests/jloop1.res @@ -0,0 +1,17 @@ +void cpu_idle(void) +{ + local_fiq_enable(); + + /* endless idle loop with no priority at all */ + while (1) { + if (!idle) + idle = default_idle; + preempt_disable(); + leds_event(led_idle_start); + while (!need_resched()) + nkidle(); + leds_event(led_idle_end); + preempt_enable(); + schedule(); + } +} diff --git a/tests/join.c b/tests/join.c new file mode 100644 index 0000000..7ab32bd --- /dev/null +++ b/tests/join.c @@ -0,0 +1,11 @@ +int main(int i) { + + f(0); + if(1) { + g(2); + } else { + g(3); + } + h(4); + +} diff --git a/tests/join.cocci b/tests/join.cocci new file mode 100644 index 0000000..b66ae6b --- /dev/null +++ b/tests/join.cocci @@ -0,0 +1,12 @@ +@@ +expression X, Y, Z; +@@ + +f(X); +... +g(Y); +... +- h(Z); ++ h(1); + +// si c'est '+ h(X,Y,Z)' alors la il y'a probleme par contre diff --git a/tests/julia10.c b/tests/julia10.c new file mode 100644 index 0000000..ff388f8 --- /dev/null +++ b/tests/julia10.c @@ -0,0 +1,7 @@ +int main(int x) { + f(); + h(); + g(); + h(); +} + diff --git a/tests/julia10.cocci b/tests/julia10.cocci new file mode 100644 index 0000000..3afdf1b --- /dev/null +++ b/tests/julia10.cocci @@ -0,0 +1,8 @@ +@@ +statement S; +@@ + + f(); +- S + g(); +- S diff --git a/tests/julia10.res b/tests/julia10.res new file mode 100644 index 0000000..6ccf09d --- /dev/null +++ b/tests/julia10.res @@ -0,0 +1,5 @@ +int main(int x) { + f(); + g(); +} + diff --git a/tests/julia7.c b/tests/julia7.c new file mode 100644 index 0000000..ca33a3d --- /dev/null +++ b/tests/julia7.c @@ -0,0 +1,7 @@ +int main(int x) { + foo(); + if (x) {bar(); after(); return 0;} + bar(); + after(); +} + diff --git a/tests/julia7.cocci b/tests/julia7.cocci new file mode 100644 index 0000000..1cf97c4 --- /dev/null +++ b/tests/julia7.cocci @@ -0,0 +1,10 @@ +// foobar(x) comes out to the right of foo(x) +// if bar is alone in a branch, as in julia7.c, the if ends up with no branch + +@@ +@@ + + foo(); + ... +?- bar(); + after(); diff --git a/tests/julia7.res b/tests/julia7.res new file mode 100644 index 0000000..be47e54 --- /dev/null +++ b/tests/julia7.res @@ -0,0 +1,6 @@ +int main(int x) { + foo(); + if (x) { after(); return 0;} + after(); +} + diff --git a/tests/keep_comma.c b/tests/keep_comma.c new file mode 100644 index 0000000..879b5c2 --- /dev/null +++ b/tests/keep_comma.c @@ -0,0 +1,4 @@ +int main () { + foo(); + snd_assert(!atomic_read(&substream->runtime->mmap_count), ); +} diff --git a/tests/keep_comma.cocci b/tests/keep_comma.cocci new file mode 100644 index 0000000..64af1d7 --- /dev/null +++ b/tests/keep_comma.cocci @@ -0,0 +1,5 @@ +@@ +@@ + +- foo(); ++ xxx(); diff --git a/tests/keep_comma.res b/tests/keep_comma.res new file mode 100644 index 0000000..15cf59a --- /dev/null +++ b/tests/keep_comma.res @@ -0,0 +1,4 @@ +int main () { + xxx(); + snd_assert(!atomic_read(&substream->runtime->mmap_count), ); +} diff --git a/tests/km.c b/tests/km.c new file mode 100644 index 0000000..10faa83 --- /dev/null +++ b/tests/km.c @@ -0,0 +1,5 @@ +int main() { + int *data = kmalloc(element->string.length + 1, GFP_KERNEL); + foo(); + memset(*data, 0, element->string.length + 1); +} diff --git a/tests/km.cocci b/tests/km.cocci new file mode 100644 index 0000000..6153aa7 --- /dev/null +++ b/tests/km.cocci @@ -0,0 +1,14 @@ +@@ +type T, T2; +expression x; +expression E1,E2; +@@ + +- x = (T)kmalloc(E1,E2) ++ x = kzalloc(E1,E2) + ... +( +- memset((T2)x,0,E1); +| +- memset((T2)x,0,sizeof(*x)); +) diff --git a/tests/km.res b/tests/km.res new file mode 100644 index 0000000..88ea86f --- /dev/null +++ b/tests/km.res @@ -0,0 +1,5 @@ +int main() { + int *data = kzalloc(element->string.length + 1, GFP_KERNEL); + foo(); + memset(*data, 0, element->string.length + 1); +} diff --git a/tests/kmalloc.c b/tests/kmalloc.c new file mode 100644 index 0000000..b6c9f23 --- /dev/null +++ b/tests/kmalloc.c @@ -0,0 +1,9 @@ +int main() { + struct bar *y; + struct foo *x = kmalloc(sizeof(struct foo),GPF_KERNEL); + if (!x) return -ENOMEM; + y = kmalloc(sizeof(struct bar),GPF_KERNEL); + if (!y) return -ENOMEM; + memset(x,0,sizeof(struct foo)); + memset(y,0,sizeof(struct bar)); +} diff --git a/tests/kmalloc.cocci b/tests/kmalloc.cocci new file mode 100644 index 0000000..a2504ef --- /dev/null +++ b/tests/kmalloc.cocci @@ -0,0 +1,11 @@ +@@ +expression x; +expression E1,E2; +type T; +@@ + + x = +- (T)kmalloc(E1,E2) ++ kzalloc(E1,E2) + ... +- memset(x,0,E1); \ No newline at end of file diff --git a/tests/kmalloc.res b/tests/kmalloc.res new file mode 100644 index 0000000..dcfaf3e --- /dev/null +++ b/tests/kmalloc.res @@ -0,0 +1,7 @@ +int main() { + struct bar *y; + struct foo *x = kzalloc(sizeof(struct foo),GPF_KERNEL); + if (!x) return -ENOMEM; + y = kzalloc(sizeof(struct bar),GPF_KERNEL); + if (!y) return -ENOMEM; +} diff --git a/tests/kmc.c b/tests/kmc.c new file mode 100644 index 0000000..603e88d --- /dev/null +++ b/tests/kmc.c @@ -0,0 +1,14 @@ +int +dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, + unsigned long large_buffer_size) +{ + if (large_buffer_size) { + if (ret) + goto err_destroy; + } + return 0; + + err_destroy: + kfreea(device_info); + return 1; +} diff --git a/tests/kmc.cocci b/tests/kmc.cocci new file mode 100644 index 0000000..dead98f --- /dev/null +++ b/tests/kmc.cocci @@ -0,0 +1,11 @@ +@r@ +identifier E; +statement S; +expression x1; +int ret; +@@ + + if (...) { + ... when != kfree(E) +- return ret; + } diff --git a/tests/kmc.res b/tests/kmc.res new file mode 100644 index 0000000..ad4ffa5 --- /dev/null +++ b/tests/kmc.res @@ -0,0 +1,13 @@ +int +dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, + unsigned long large_buffer_size) +{ + if (large_buffer_size) { + if (ret) + goto err_destroy; + } + return 0; + + err_destroy: + kfreea(device_info); +} diff --git a/tests/ktype.c b/tests/ktype.c new file mode 100644 index 0000000..651e442 --- /dev/null +++ b/tests/ktype.c @@ -0,0 +1,10 @@ +typedef struct r1_private_data_s conf_t; + +static int run(mddev_t *mddev) +{ + conf_t *conf; + conf = kmalloc(sizeof(conf_t), GFP_KERNEL); + if (!conf) return; + + memset(conf, 0, sizeof(*conf)); +} diff --git a/tests/ktype.cocci b/tests/ktype.cocci new file mode 100644 index 0000000..b08e687 --- /dev/null +++ b/tests/ktype.cocci @@ -0,0 +1,12 @@ +@@ +type T, T2; +type T1; +T1 *x; +T1 *y; +expression E2; +@@ + +- x = kmalloc(sizeof(T1),E2) ++ x = kzalloc(sizeof(T1),E2) + ... +- memset(x,0,sizeof(*y)); diff --git a/tests/ktype.res b/tests/ktype.res new file mode 100644 index 0000000..ae5142c --- /dev/null +++ b/tests/ktype.res @@ -0,0 +1,8 @@ +typedef struct r1_private_data_s conf_t; + +static int run(mddev_t *mddev) +{ + conf_t *conf; + conf = kzalloc(sizeof(conf_t), GFP_KERNEL); + if (!conf) return; +} diff --git a/tests/labels_metastatement.c b/tests/labels_metastatement.c new file mode 100644 index 0000000..3697ffc --- /dev/null +++ b/tests/labels_metastatement.c @@ -0,0 +1,9 @@ +int foo(int i) { + + if(1) { + x = 3; + z = 4; + } // we dont want that it add both foo on the } and on the endif + // (note: but need correct endif accrochage) + +} diff --git a/tests/labels_metastatement.cocci b/tests/labels_metastatement.cocci new file mode 100644 index 0000000..eebc52d --- /dev/null +++ b/tests/labels_metastatement.cocci @@ -0,0 +1,6 @@ +@@ +statement S; +@@ + + S ++ foo(); diff --git a/tests/labels_metastatement.res b/tests/labels_metastatement.res new file mode 100644 index 0000000..3e22b44 --- /dev/null +++ b/tests/labels_metastatement.res @@ -0,0 +1,10 @@ +int foo(int i) { + + if(1) { + x = 3; foo(); + z = 4; foo(); + } // we dont want that it add both foo on the } and on the endif + // (note: but need correct endif accrochage) + foo(); + +} diff --git a/tests/labels_metastatement2.cocci b/tests/labels_metastatement2.cocci new file mode 100644 index 0000000..7d1d197 --- /dev/null +++ b/tests/labels_metastatement2.cocci @@ -0,0 +1,5 @@ +@@ +statement S; +@@ + if (x) S // if S1 else S2 ++ else foo(); \ No newline at end of file diff --git a/tests/labels_metastatement3.cocci b/tests/labels_metastatement3.cocci new file mode 100644 index 0000000..64adfd3 --- /dev/null +++ b/tests/labels_metastatement3.cocci @@ -0,0 +1,6 @@ +@@ +statement S; +@@ + ++ foo(); + S \ No newline at end of file diff --git a/tests/labels_metastatement_ver1.c b/tests/labels_metastatement_ver1.c new file mode 100644 index 0000000..302cd34 --- /dev/null +++ b/tests/labels_metastatement_ver1.c @@ -0,0 +1,5 @@ +int foo(int i) { + + if(1) x = 3; + +} diff --git a/tests/labels_metastatement_ver1.res b/tests/labels_metastatement_ver1.res new file mode 100644 index 0000000..584a92d --- /dev/null +++ b/tests/labels_metastatement_ver1.res @@ -0,0 +1,9 @@ +int foo(int i) { + + if(1) { + x = 3; + foo(); + } + foo(); + +} diff --git a/tests/local.c b/tests/local.c new file mode 100644 index 0000000..f00df22 --- /dev/null +++ b/tests/local.c @@ -0,0 +1 @@ +int f(int xx, int yy) { return 0; } diff --git a/tests/local.cocci b/tests/local.cocci new file mode 100644 index 0000000..ac4f3fb --- /dev/null +++ b/tests/local.cocci @@ -0,0 +1,10 @@ +@@ +local function f; +identifier x, y; +@@ + + f( ++ int a, int b, +- int x, + int y + ) { ... } diff --git a/tests/local.res b/tests/local.res new file mode 100644 index 0000000..967d26b --- /dev/null +++ b/tests/local.res @@ -0,0 +1 @@ +int f(int a, int b, int yy) { return 0; } diff --git a/tests/localid.c b/tests/localid.c new file mode 100644 index 0000000..4028824 --- /dev/null +++ b/tests/localid.c @@ -0,0 +1,9 @@ +int c; + +int main () { + int a; + f(a); + f(a+1); + f(b); + f(c); +} diff --git a/tests/localid.cocci b/tests/localid.cocci new file mode 100644 index 0000000..fdfe6de --- /dev/null +++ b/tests/localid.cocci @@ -0,0 +1,19 @@ +@@ +local idexpression int x; +@@ + +- f(x); + +@@ +idexpression int x; +@@ + +- f(x); ++ g(x); + +@@ +idexpression x; +@@ + +- f(x); ++ h(x); diff --git a/tests/localid.res b/tests/localid.res new file mode 100644 index 0000000..20b57e0 --- /dev/null +++ b/tests/localid.res @@ -0,0 +1,8 @@ +int c; + +int main () { + int a; + f(a+1); + h(b); + g(c); +} diff --git a/tests/longint.c b/tests/longint.c new file mode 100644 index 0000000..33638e8 --- /dev/null +++ b/tests/longint.c @@ -0,0 +1,9 @@ + +MODULE_PARM(cm206_base, "i"); /* base */ + + +static void do_cm206_request(request_queue_t * q) +{ + long int i; + +} diff --git a/tests/longint.cocci b/tests/longint.cocci new file mode 100644 index 0000000..9a310e4 --- /dev/null +++ b/tests/longint.cocci @@ -0,0 +1,12 @@ +@ rule2 @ +identifier I; +expression E; +@@ + +MODULE_PARM(I, E); + +@@ +identifier rule2.I; +@@ + +int I; diff --git a/tests/loop.c b/tests/loop.c new file mode 100644 index 0000000..d1c77de --- /dev/null +++ b/tests/loop.c @@ -0,0 +1,5 @@ +int main() { + f(); + while (1) { x : 15; } + g(); +} diff --git a/tests/loop.cocci b/tests/loop.cocci new file mode 100644 index 0000000..8756a4a --- /dev/null +++ b/tests/loop.cocci @@ -0,0 +1,6 @@ +@@ +@@ + +- f(); + ... +- g(); diff --git a/tests/loop.res b/tests/loop.res new file mode 100644 index 0000000..0548e76 --- /dev/null +++ b/tests/loop.res @@ -0,0 +1,3 @@ +int main() { + while (1) { x : 15; } +} diff --git a/tests/lvalue.c b/tests/lvalue.c new file mode 100644 index 0000000..57a0ca8 --- /dev/null +++ b/tests/lvalue.c @@ -0,0 +1,4 @@ +int main() { + x = x + 1; + *x = 12; +} diff --git a/tests/lvalue.cocci b/tests/lvalue.cocci new file mode 100644 index 0000000..1c2b844 --- /dev/null +++ b/tests/lvalue.cocci @@ -0,0 +1,5 @@ +@@ +@@ + +- x ++ f(x) diff --git a/tests/lvalue.res b/tests/lvalue.res new file mode 100644 index 0000000..a94d8a5 --- /dev/null +++ b/tests/lvalue.res @@ -0,0 +1,4 @@ +int main() { + x = f(x) + 1; + *f(x) = 12; // or maybe f(x) has to be in parens? +} diff --git a/tests/macro.c b/tests/macro.c new file mode 100644 index 0000000..4d5b8de --- /dev/null +++ b/tests/macro.c @@ -0,0 +1,5 @@ +#define SC_FCMND(fcmnd) ((Scsi_Cmnd *)((long)fcmnd - (long)&(((Scsi_Cmnd *)0)->SCp))) + +int main() { + return ((Scsi_Cmnd *)((long)fcmnd - (long)&(((Scsi_Cmnd *)0)->SCp))); +} diff --git a/tests/macro.cocci b/tests/macro.cocci new file mode 100644 index 0000000..7eab111 --- /dev/null +++ b/tests/macro.cocci @@ -0,0 +1,6 @@ +@@ +typedef Scsi_Cmnd; +@@ + +- Scsi_Cmnd ++ struct scsi_cmnd diff --git a/tests/macro.res b/tests/macro.res new file mode 100644 index 0000000..732c458 --- /dev/null +++ b/tests/macro.res @@ -0,0 +1 @@ +#define SC_FCMND(fcmnd) ((struct scsi_cmnd *)((long)fcmnd - (long)&(((struct scsi_cmnd *)0)->SCp))) diff --git a/tests/match_const.c b/tests/match_const.c new file mode 100644 index 0000000..5756386 --- /dev/null +++ b/tests/match_const.c @@ -0,0 +1 @@ +const int x; diff --git a/tests/match_const.cocci b/tests/match_const.cocci new file mode 100644 index 0000000..72d812c --- /dev/null +++ b/tests/match_const.cocci @@ -0,0 +1,6 @@ +@r@ +type T; +identifier I; +@@ + +- const T I; diff --git a/tests/match_const.res b/tests/match_const.res new file mode 100644 index 0000000..e69de29 diff --git a/tests/match_no_meta.c b/tests/match_no_meta.c new file mode 100644 index 0000000..8693f2b --- /dev/null +++ b/tests/match_no_meta.c @@ -0,0 +1,7 @@ +void main(int i) +{ + foo(1); + bar(2); + + bar(3); +} diff --git a/tests/match_no_meta.cocci b/tests/match_no_meta.cocci new file mode 100644 index 0000000..a2e096c --- /dev/null +++ b/tests/match_no_meta.cocci @@ -0,0 +1,11 @@ +@ rule1 @ +@@ + + foo(1); + bar(2); + + +@ rule2 depends on rule1 @ +@@ + +- bar(3); \ No newline at end of file diff --git a/tests/match_no_meta.res b/tests/match_no_meta.res new file mode 100644 index 0000000..d529227 --- /dev/null +++ b/tests/match_no_meta.res @@ -0,0 +1,7 @@ +void main(int i) +{ + foo(1); + bar(2); + + +} diff --git a/tests/max.c b/tests/max.c new file mode 100644 index 0000000..8df2933 --- /dev/null +++ b/tests/max.c @@ -0,0 +1,3 @@ +int main () { + if (x < 25) return i; +} diff --git a/tests/max.cocci b/tests/max.cocci new file mode 100644 index 0000000..f2eca10 --- /dev/null +++ b/tests/max.cocci @@ -0,0 +1,15 @@ +@x@ +position pc,pm,pi; +expression E; +@@ + +if@pc (E@pm) return i@pi; + +@@ +position x.pc,x.pm,x.pi; +expression E; +@@ + +if@pc (E@pm) +- return i@pi; ++ return 3; diff --git a/tests/max.res b/tests/max.res new file mode 100644 index 0000000..8869b8c --- /dev/null +++ b/tests/max.res @@ -0,0 +1,3 @@ +int main () { + if (x < 25) return 3; +} diff --git a/tests/mem.cocci b/tests/mem.cocci new file mode 100644 index 0000000..e7a3e40 --- /dev/null +++ b/tests/mem.cocci @@ -0,0 +1,19 @@ +@rule1@ +identifier f; +@@ + +f(...) { +<+... + dev_kfree_skb_irq(...) +...+> +} + +@@ +identifier rule1.f, fld; +identifier I; +type T; +@@ + +T I = { +* .fld = f, +}; diff --git a/tests/memset.cocci b/tests/memset.cocci new file mode 100644 index 0000000..73759de --- /dev/null +++ b/tests/memset.cocci @@ -0,0 +1,69 @@ +// have to duplicate a lot of rules because T E only matches if E has a known +// type, even if T is not used elsewhere. + +@@ +type T, T2; +expression x; +expression E1,E2,E; +@@ + +- x = (T)kmalloc(E1,E2) + ... when != x = E +- memset((T2)x,0,E1); + +@@ +type T, T2; +type T1; +T1 *x; +expression E2,E; +@@ + +- x = (T)kmalloc(sizeof(T1),E2) + ... when != x = E +- memset((T2)x,0,sizeof(*x)); + +@@ +type T, T2; +type T1; +T1 *x; +expression E2,E; +@@ + +- x = (T)kmalloc(sizeof(*x),E2) + ... when != x = E +- memset((T2)x,0,sizeof(T1)); + +// --------------------------------------------------------------------- + + +@@ +type T, T1, T2; +identifier x; +expression E1,E2,E; +@@ + +- T1 x = (T)kmalloc(E1,E2); + ... when != x = E +- memset((T2)x,0,E1); + +@@ +type T, T2; +type T1; +identifier x; +expression E2,E; +@@ + +- T1 x = (T)kmalloc(sizeof(T1),E2); + ... when != x = E +- memset((T2)x,0,sizeof(*x)); + +@@ +type T, T2; +type T1; +identifier x; +expression E2,E; +@@ + +- T1 x = (T)kmalloc(sizeof(*x),E2); + ... when != x = E +- memset((T2)x,0,sizeof(T1)); diff --git a/tests/metahex.c b/tests/metahex.c new file mode 100644 index 0000000..8663523 --- /dev/null +++ b/tests/metahex.c @@ -0,0 +1,4 @@ +int main() { + f(3); + g(0x03); +} diff --git a/tests/metahex.cocci b/tests/metahex.cocci new file mode 100644 index 0000000..584bc12 --- /dev/null +++ b/tests/metahex.cocci @@ -0,0 +1,6 @@ +@@ +expression E; +@@ + +- f(E); +- g(E); \ No newline at end of file diff --git a/tests/metahex.res b/tests/metahex.res new file mode 100644 index 0000000..b2f9976 --- /dev/null +++ b/tests/metahex.res @@ -0,0 +1,2 @@ +int main() { +} diff --git a/tests/metaruleelem.c b/tests/metaruleelem.c new file mode 100644 index 0000000..0ba52f1 --- /dev/null +++ b/tests/metaruleelem.c @@ -0,0 +1,7 @@ +int main(int x) { + f(); + if(1) { + replace(); + } + g(); +} diff --git a/tests/metaruleelem.cocci b/tests/metaruleelem.cocci new file mode 100644 index 0000000..bbe7da8 --- /dev/null +++ b/tests/metaruleelem.cocci @@ -0,0 +1,7 @@ +@@ +statement S; +@@ + + f(); +- S ++ foo(); S diff --git a/tests/metaruleelem.res b/tests/metaruleelem.res new file mode 100644 index 0000000..996e932 --- /dev/null +++ b/tests/metaruleelem.res @@ -0,0 +1,8 @@ +int main(int x) { + f(); + foo(); + if(1) { + replace(); + } + g(); +} diff --git a/tests/metastatement.c b/tests/metastatement.c new file mode 100644 index 0000000..a00bfd4 --- /dev/null +++ b/tests/metastatement.c @@ -0,0 +1,5 @@ +void main(int i) { + g(1); + g(2); + f(1); +} diff --git a/tests/metastatement.cocci b/tests/metastatement.cocci new file mode 100644 index 0000000..8fed69d --- /dev/null +++ b/tests/metastatement.cocci @@ -0,0 +1,9 @@ +// dumb example. does not work well because S is also match +// on the compounds, so it try to erase multiple times the same node. + +@@ +statement S; +@@ + +- S ++ S f(1); diff --git a/tests/metastatement2.c b/tests/metastatement2.c new file mode 100644 index 0000000..bd687c3 --- /dev/null +++ b/tests/metastatement2.c @@ -0,0 +1,6 @@ +void main(int i) { + + f(); + { replace(); replace(); } + g(); +} diff --git a/tests/metastatement2.cocci b/tests/metastatement2.cocci new file mode 100644 index 0000000..d218386 --- /dev/null +++ b/tests/metastatement2.cocci @@ -0,0 +1,6 @@ +@@ +statement S; +@@ + + f(); +- S diff --git a/tests/metastatement2.res b/tests/metastatement2.res new file mode 100644 index 0000000..28168cd --- /dev/null +++ b/tests/metastatement2.res @@ -0,0 +1,5 @@ +void main(int i) { + + f(); + g(); +} diff --git a/tests/metastatement_for.c b/tests/metastatement_for.c new file mode 100644 index 0000000..c8d40d4 --- /dev/null +++ b/tests/metastatement_for.c @@ -0,0 +1,12 @@ +void main(void) +{ + int i; + for (i = 0; i < 10; i++) { + printf("%d", i); + } + + if (i == 0) { + printf("%d", i); + } + +} diff --git a/tests/metastatement_for.cocci b/tests/metastatement_for.cocci new file mode 100644 index 0000000..956ba9f --- /dev/null +++ b/tests/metastatement_for.cocci @@ -0,0 +1,8 @@ + +@@ +expression E1,E2,E3; +statement S; +@@ + +- for(E1; E2; E3) +- S \ No newline at end of file diff --git a/tests/metastatement_for.res b/tests/metastatement_for.res new file mode 100644 index 0000000..d1f7006 --- /dev/null +++ b/tests/metastatement_for.res @@ -0,0 +1,9 @@ +void main(void) +{ + int i; + + if (i == 0) { + printf("%d", i); + } + +} diff --git a/tests/metastatement_if.c b/tests/metastatement_if.c new file mode 100644 index 0000000..c8d40d4 --- /dev/null +++ b/tests/metastatement_if.c @@ -0,0 +1,12 @@ +void main(void) +{ + int i; + for (i = 0; i < 10; i++) { + printf("%d", i); + } + + if (i == 0) { + printf("%d", i); + } + +} diff --git a/tests/metastatement_if.cocci b/tests/metastatement_if.cocci new file mode 100644 index 0000000..928cf1c --- /dev/null +++ b/tests/metastatement_if.cocci @@ -0,0 +1,8 @@ + +@@ +expression E1; +statement S; +@@ + +- if(E1) +- S \ No newline at end of file diff --git a/tests/metastatement_if.res b/tests/metastatement_if.res new file mode 100644 index 0000000..021e4ec --- /dev/null +++ b/tests/metastatement_if.res @@ -0,0 +1,9 @@ +void main(void) +{ + int i; + for (i = 0; i < 10; i++) { + printf("%d", i); + } + + +} diff --git a/tests/mf.c b/tests/mf.c new file mode 100644 index 0000000..ab5e1d7 --- /dev/null +++ b/tests/mf.c @@ -0,0 +1,12 @@ +int fn1() { + foo(12); +} + +int fn2() { + fn1(); + bar(10); +} + +int fn1bis() { + foo(7); +} diff --git a/tests/mf.cocci b/tests/mf.cocci new file mode 100644 index 0000000..8afbea7 --- /dev/null +++ b/tests/mf.cocci @@ -0,0 +1,21 @@ +@ rule1 @ +identifier fn1, fn2; +expression A, B; +@@ + +fn1(...) { + foo(A); +} + +fn2(...) { + fn1(); +- bar(B); ++ xxx(A); +} + +@ rule2 extends rule1 @ +@@ + +fn1(...) { +- foo(A); +} diff --git a/tests/minstruct.c b/tests/minstruct.c new file mode 100644 index 0000000..d4febda --- /dev/null +++ b/tests/minstruct.c @@ -0,0 +1,5 @@ +static struct i2c_client client_template = { + .name = "(unset)", + .id = -1, + .driver = &i2c_driver_videotext +}; diff --git a/tests/minstruct.cocci b/tests/minstruct.cocci new file mode 100644 index 0000000..5f6e6e6 --- /dev/null +++ b/tests/minstruct.cocci @@ -0,0 +1,9 @@ +@@ +identifier I; +expression E; +@@ + +struct i2c_client I = { +- .name = E, ++ .dev = { .name = E, }, +}; diff --git a/tests/minstruct.res b/tests/minstruct.res new file mode 100644 index 0000000..cc4bd6b --- /dev/null +++ b/tests/minstruct.res @@ -0,0 +1,5 @@ +static struct i2c_client client_template = { + .dev = {.name = "(unset)"}, + .id = -1, + .driver = &i2c_driver_videotext +}; diff --git a/tests/minusall.c b/tests/minusall.c new file mode 100644 index 0000000..843adb8 --- /dev/null +++ b/tests/minusall.c @@ -0,0 +1 @@ +static int f () { int x = 12; int y; return x + y; } diff --git a/tests/minusall.cocci b/tests/minusall.cocci new file mode 100644 index 0000000..b0509f4 --- /dev/null +++ b/tests/minusall.cocci @@ -0,0 +1,4 @@ +@@ +@@ + +- f(...) { ... } \ No newline at end of file diff --git a/tests/minusall.res b/tests/minusall.res new file mode 100644 index 0000000..e69de29 diff --git a/tests/minusdots.c b/tests/minusdots.c new file mode 100644 index 0000000..c30ed7a --- /dev/null +++ b/tests/minusdots.c @@ -0,0 +1,9 @@ +void main(int i) { + + if (!hostptr) { + if (hostptr) { + return -ESRCH; + } + } + +} diff --git a/tests/minusdots.cocci b/tests/minusdots.cocci new file mode 100644 index 0000000..440c749 --- /dev/null +++ b/tests/minusdots.cocci @@ -0,0 +1,9 @@ +@@ +identifier ptr; +//statement S; +@@ + +- if (!ptr) +- { +- ... +- } // could be S instead of { ... } diff --git a/tests/minusdots.res b/tests/minusdots.res new file mode 100644 index 0000000..0b46850 --- /dev/null +++ b/tests/minusdots.res @@ -0,0 +1,4 @@ +void main(int i) { + + +} diff --git a/tests/minusdots_ver1.c b/tests/minusdots_ver1.c new file mode 100644 index 0000000..a77c104 --- /dev/null +++ b/tests/minusdots_ver1.c @@ -0,0 +1,6 @@ +void main(int i) { + + if (!hostptr) { + i++; + } +} diff --git a/tests/minusdots_ver1.res b/tests/minusdots_ver1.res new file mode 100644 index 0000000..7759fd3 --- /dev/null +++ b/tests/minusdots_ver1.res @@ -0,0 +1,3 @@ +void main(int i) { + +} diff --git a/tests/mult.c b/tests/mult.c new file mode 100644 index 0000000..e37c4ce --- /dev/null +++ b/tests/mult.c @@ -0,0 +1,6 @@ +// doesn't match + +int main() { + xxx(27); + goo(27); +} diff --git a/tests/mult.cocci b/tests/mult.cocci new file mode 100644 index 0000000..6cf2044 --- /dev/null +++ b/tests/mult.cocci @@ -0,0 +1,13 @@ +@ rule1 @ +expression E; +@@ + +- xxx(E); +- yyy(); ++ bar(); + +@ rule2 extends rule1 @ +@@ + +- goo(E); ++ har(); diff --git a/tests/multi_func.c b/tests/multi_func.c new file mode 100644 index 0000000..4385512 --- /dev/null +++ b/tests/multi_func.c @@ -0,0 +1,15 @@ +void fn1(int i) { + foo_lock(); + i++; +} + + +void fn2(int i) { + foo_unlock(); + i++; +} + + +void fn3(int i) { + i++; +} diff --git a/tests/multi_func.cocci b/tests/multi_func.cocci new file mode 100644 index 0000000..ad1c961 --- /dev/null +++ b/tests/multi_func.cocci @@ -0,0 +1,11 @@ +@@ @@ + + fn1(int i) { +- foo_lock(); + ... + } + + fn2(int i) { +- foo_unlock(); + } + diff --git a/tests/multi_func1.c b/tests/multi_func1.c new file mode 100644 index 0000000..d557d35 --- /dev/null +++ b/tests/multi_func1.c @@ -0,0 +1,26 @@ +int f1() { + foo(12); +} + +int f2() { + bar(12); +} + +int f3() { + bar(7); +} + +int f4() { + foo(12); +} + +int f5() { + bar(12); +} + +int main() { + f1(); + f2(); + f3(); +} + diff --git a/tests/multi_func1.cocci b/tests/multi_func1.cocci new file mode 100644 index 0000000..8c55da2 --- /dev/null +++ b/tests/multi_func1.cocci @@ -0,0 +1,81 @@ +@@ +identifier fn1, fn2, fn3; +expression A; +@@ + + fn1(...) { +- foo(A); +//+ bidon(A, fn1); + + } + + fn2(...) { +- bar(A); +//+ bidon(A, fn1, fn2); + } + + fn3(...) { +//+ bidon(A, fn1, fn2); + fn1(...); + fn2(...); + // bug need: ... (partial match didn't help that much) + ... + } + +//@@ +//@@ +//- bidon(...); + +// @@ +// @@ +// ( +// - fn1(A,1) +// | +// - fn2(A,1) +// ) + + + + +// @@ +// identifier fn1; +// expression A; +// @@ +// fn1(...) { +// foo(A); +// } +// +// @@ +// identifier fn2; +// @@ +// +// fn2(...) { +// bar(A); +// } +// +// +// @@ +// identifier fn3; +// //identifier fn1, fn2; +// @@ +// +// fn3(...) { +// fn1(...); +// fn2(...); +// ... +// } +// +// @@ +// //expression A; +// @@ +// fn1(...) { +// - foo(A); +// } +// +// @@ +// @@ +// +// fn2(...) { +// - bar(A); +// } + diff --git a/tests/multi_func1.res b/tests/multi_func1.res new file mode 100644 index 0000000..3f3e9ec --- /dev/null +++ b/tests/multi_func1.res @@ -0,0 +1,24 @@ +int f1() { +} + +int f2() { +} + +int f3() { + bar(7); +} + +int f4() { + foo(12); +} + +int f5() { + bar(12); +} + +int main() { + f1(); + f2(); + f3(); +} + diff --git a/tests/multi_func1_ver2.c b/tests/multi_func1_ver2.c new file mode 100644 index 0000000..b21b6bf --- /dev/null +++ b/tests/multi_func1_ver2.c @@ -0,0 +1,4 @@ +int main() { + foo(); + bar(); +} diff --git a/tests/multi_inc.c b/tests/multi_inc.c new file mode 100644 index 0000000..61ce47d --- /dev/null +++ b/tests/multi_inc.c @@ -0,0 +1,5 @@ +#include "multi_inc1.h" + +int main () { + f(xxx); +} diff --git a/tests/multi_inc.cocci b/tests/multi_inc.cocci new file mode 100644 index 0000000..5ac97b8 --- /dev/null +++ b/tests/multi_inc.cocci @@ -0,0 +1,5 @@ +@@ +int E; +@@ + +- f(E); diff --git a/tests/multi_inc1.h b/tests/multi_inc1.h new file mode 100644 index 0000000..9665205 --- /dev/null +++ b/tests/multi_inc1.h @@ -0,0 +1 @@ +#include "multi_inc2.h" diff --git a/tests/multi_inc2.h b/tests/multi_inc2.h new file mode 100644 index 0000000..7da48cb --- /dev/null +++ b/tests/multi_inc2.h @@ -0,0 +1 @@ +int xxx; diff --git a/tests/multidecl.c b/tests/multidecl.c new file mode 100644 index 0000000..420cefd --- /dev/null +++ b/tests/multidecl.c @@ -0,0 +1,13 @@ +static void elsa_cs_detach(struct pcmcia_device *link) +{ + +} /* elsa_cs_detach */ + +static void elsa_cs_config(struct pcmcia_device *link) +{ + int i, j, last_fn; +} + +static struct pcmcia_driver elsa_cs_driver = { + .detach = elsa_cs_detach +}; diff --git a/tests/multidecl.cocci b/tests/multidecl.cocci new file mode 100644 index 0000000..ce07615 --- /dev/null +++ b/tests/multidecl.cocci @@ -0,0 +1,24 @@ +// test with -cocci_vs_c_3 -use_ref + +@ rule1 @ +identifier driver; +identifier attach, detach; +@@ + +struct pcmcia_driver driver = { + .remove = detach, +}; + +@@ +identifier link; +identifier rule1.detach; +@@ + +detach(struct pcmcia_device *link) +{ + ... + if (link->state & DEV_CONFIG) { + ... + } + ... +} diff --git a/tests/multiplus.c b/tests/multiplus.c new file mode 100644 index 0000000..785b871 --- /dev/null +++ b/tests/multiplus.c @@ -0,0 +1,19 @@ +static void xm_link_timer(void *arg) +{ + struct net_device *dev = arg; + struct skge_port *skge = netdev_priv(arg); + struct skge_hw *hw = skge->hw; + int port = skge->port; + + if (!netif_running(dev)) + return; + + if (netif_carrier_ok(dev)) { + xm_read16(hw, port, XM_ISRC); + if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)) + goto nochange; + } + +nochange: + schedule_delayed_work(&skge->link_thread, LINK_HZ); +} diff --git a/tests/multiplus.cocci b/tests/multiplus.cocci new file mode 100644 index 0000000..4abf49c --- /dev/null +++ b/tests/multiplus.cocci @@ -0,0 +1,17 @@ +// shows that there is a problem with \+ + +@@ +identifier fn1, fld1; +identifier data, device; +type T; +expression delay; +@@ + + fn1 ( +- void *data ++ struct work_struct *work + ) { + <+... + schedule_delayed_work(&device->fld1,delay); + ...+> + } diff --git a/tests/multiplus.res b/tests/multiplus.res new file mode 100644 index 0000000..0b0ffd3 --- /dev/null +++ b/tests/multiplus.res @@ -0,0 +1,19 @@ +static void xm_link_timer(struct work_struct *work) +{ + struct net_device *dev = arg; + struct skge_port *skge = netdev_priv(arg); + struct skge_hw *hw = skge->hw; + int port = skge->port; + + if (!netif_running(dev)) + return; + + if (netif_carrier_ok(dev)) { + xm_read16(hw, port, XM_ISRC); + if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)) + goto nochange; + } + +nochange: + schedule_delayed_work(&skge->link_thread, LINK_HZ); +} diff --git a/tests/multitype.c b/tests/multitype.c new file mode 100644 index 0000000..fda0ad5 --- /dev/null +++ b/tests/multitype.c @@ -0,0 +1,7 @@ +typedef struct foo { int a; } foo_t; + +int main() { + foo_t * x; + f(x->a); + g(x); +} diff --git a/tests/multitype.cocci b/tests/multitype.cocci new file mode 100644 index 0000000..c26462c --- /dev/null +++ b/tests/multitype.cocci @@ -0,0 +1,14 @@ +@ rule1 @ +type T; +T *E; +identifier fld; +@@ + +f(E->fld) + +@@ +rule1.T *E; +@@ + +- g(E) ++ g(E,NULL) diff --git a/tests/multitype.res b/tests/multitype.res new file mode 100644 index 0000000..cdd68c4 --- /dev/null +++ b/tests/multitype.res @@ -0,0 +1,7 @@ +typedef struct foo { int a; } foo_t; + +int main() { + foo_t * x; + f(x->a); + g(x,NULL); +} diff --git a/tests/multitypedef.c b/tests/multitypedef.c new file mode 100644 index 0000000..14f6682 --- /dev/null +++ b/tests/multitypedef.c @@ -0,0 +1,9 @@ +typedef struct HYSDN_CARD { + struct work_struct irq_queue; +} hysdn_card; + +int +ergo_inithardware(hysdn_card * card) +{ + INIT_WORK(&card->irq_queue, ergo_irq_bh, card); +} diff --git a/tests/multitypedef.cocci b/tests/multitypedef.cocci new file mode 100644 index 0000000..ac2a25a --- /dev/null +++ b/tests/multitypedef.cocci @@ -0,0 +1,8 @@ +@ non_delayed_fn @ +type local_type, T; +local_type *device; +identifier fld, fn; +@@ + +- INIT_WORK(&device->fld, fn, device); ++ INIT_WORK(&device->fld, fn); diff --git a/tests/multitypedef.res b/tests/multitypedef.res new file mode 100644 index 0000000..366c6fa --- /dev/null +++ b/tests/multitypedef.res @@ -0,0 +1,9 @@ +typedef struct HYSDN_CARD { + struct work_struct irq_queue; +} hysdn_card; + +int +ergo_inithardware(hysdn_card * card) +{ + INIT_WORK(&card->irq_queue, ergo_irq_bh); +} diff --git a/tests/multivars.c b/tests/multivars.c new file mode 100644 index 0000000..1dce6b0 --- /dev/null +++ b/tests/multivars.c @@ -0,0 +1,5 @@ +void main(int i) { + + f(1+2+v.field1,1+2+v.field1); + +} diff --git a/tests/multivars.cocci b/tests/multivars.cocci new file mode 100644 index 0000000..7754fb7 --- /dev/null +++ b/tests/multivars.cocci @@ -0,0 +1,6 @@ +@@ +expression X; +@@ + +- f(X,X); ++ h(X); diff --git a/tests/multivars.res b/tests/multivars.res new file mode 100644 index 0000000..8f47d87 --- /dev/null +++ b/tests/multivars.res @@ -0,0 +1,5 @@ +void main(int i) { + + h(1+2+v.field1); + +} diff --git a/tests/multr.c b/tests/multr.c new file mode 100644 index 0000000..9abc047 --- /dev/null +++ b/tests/multr.c @@ -0,0 +1,7 @@ +int main() { + foo(12); +} + +int q() { + xxx(); +} diff --git a/tests/multr.cocci b/tests/multr.cocci new file mode 100644 index 0000000..4bacff9 --- /dev/null +++ b/tests/multr.cocci @@ -0,0 +1,12 @@ +@ rule1 @ +expression x; +@@ + +foo(x); + +@@ +expression rule1.x; +@@ + + xxx(); ++ foo(x); diff --git a/tests/nest.c b/tests/nest.c new file mode 100644 index 0000000..7058200 --- /dev/null +++ b/tests/nest.c @@ -0,0 +1,7 @@ +void info_func(int i) { + foo(); + while (x) { + 1+hostno+xxx; + 2+hostno+xxx; + } +} diff --git a/tests/nest.cocci b/tests/nest.cocci new file mode 100644 index 0000000..3047f7a --- /dev/null +++ b/tests/nest.cocci @@ -0,0 +1,21 @@ +@@ +local function proc_info_func; +@@ + proc_info_func(...) { + <... +- hostno ++ hostptr->host_no + ...> + } + + +@@ +local function proc_info_func; +@@ + proc_info_func(...) { + foo(); + <... +- xxx ++ hostptr->host_no + ...> + } diff --git a/tests/nest.res b/tests/nest.res new file mode 100644 index 0000000..40a1ae6 --- /dev/null +++ b/tests/nest.res @@ -0,0 +1,7 @@ +void info_func(int i) { + foo(); + while (x) { + 1+hostptr->host_no+hostptr->host_no; + 2+hostptr->host_no+hostptr->host_no; + } +} diff --git a/tests/nest2.c b/tests/nest2.c new file mode 100644 index 0000000..045847f --- /dev/null +++ b/tests/nest2.c @@ -0,0 +1,5 @@ +int f(int i) { + a(); + a(); + a(); +} diff --git a/tests/nest2.cocci b/tests/nest2.cocci new file mode 100644 index 0000000..10d443f --- /dev/null +++ b/tests/nest2.cocci @@ -0,0 +1,10 @@ +@@ +identifier func; +@@ + + int func(int i) { + <... a(); ...> +- a(); ++ b(); + <... a(); ...> + } \ No newline at end of file diff --git a/tests/nest3.c b/tests/nest3.c new file mode 100644 index 0000000..dc374b4 --- /dev/null +++ b/tests/nest3.c @@ -0,0 +1,9 @@ +void main(int i) { + + int i; + char j;//int j; + + for (i = 1; i < XXX; i++) + f(i); + +} diff --git a/tests/nest3.cocci b/tests/nest3.cocci new file mode 100644 index 0000000..a33086f --- /dev/null +++ b/tests/nest3.cocci @@ -0,0 +1,10 @@ +@@ +identifier i; +identifier func; +@@ + +- int i; + <... when != i +- for (i = ...; i < ...; i++) f(...); ++ f(1); + ...> diff --git a/tests/nestone.c b/tests/nestone.c new file mode 100644 index 0000000..3a10ec3 --- /dev/null +++ b/tests/nestone.c @@ -0,0 +1,4 @@ +int foo() { + if (x) { xxx(); return;} + yyy(); +} diff --git a/tests/nestone.cocci b/tests/nestone.cocci new file mode 100644 index 0000000..0397eaf --- /dev/null +++ b/tests/nestone.cocci @@ -0,0 +1,15 @@ +@one disable all@ +identifier foo; +statement S; +@@ + +foo(...) { + <+... + xxx(); + ...+> +} + +@two depends on one@ +@@ + +- yyy(); diff --git a/tests/nestone.res b/tests/nestone.res new file mode 100644 index 0000000..dc3953c --- /dev/null +++ b/tests/nestone.res @@ -0,0 +1,3 @@ +int foo() { + if (x) { xxx(); return;} +} diff --git a/tests/nestplus.c b/tests/nestplus.c new file mode 100644 index 0000000..6ae57d5 --- /dev/null +++ b/tests/nestplus.c @@ -0,0 +1,5 @@ +int foo() { + if (x) { xxx(); return;} + yyy(); + xxx(); +} diff --git a/tests/nestplus.cocci b/tests/nestplus.cocci new file mode 100644 index 0000000..b9be5e5 --- /dev/null +++ b/tests/nestplus.cocci @@ -0,0 +1,18 @@ +@one disable all@ +identifier foo; +statement S; +@@ + +foo(...) { + <+... + { + ... + return; + } + ...+> +} + +@two depends on one@ +@@ + +- yyy(); diff --git a/tests/nestseq.c b/tests/nestseq.c new file mode 100644 index 0000000..6e45bab --- /dev/null +++ b/tests/nestseq.c @@ -0,0 +1,5 @@ +int main () { + f(); + g(12); + h(); +} diff --git a/tests/nestseq.cocci b/tests/nestseq.cocci new file mode 100644 index 0000000..74ce9e2 --- /dev/null +++ b/tests/nestseq.cocci @@ -0,0 +1,10 @@ +@@ +expression E; +@@ + +f(); +<... + g(E) +...> +h(); ++ xxx(E); diff --git a/tests/nestseq.res b/tests/nestseq.res new file mode 100644 index 0000000..7491dd3 --- /dev/null +++ b/tests/nestseq.res @@ -0,0 +1,6 @@ +int main () { + f(); + g(12); + h(); + xxx(12); +} diff --git a/tests/neststruct.c b/tests/neststruct.c new file mode 100644 index 0000000..a0203a1 --- /dev/null +++ b/tests/neststruct.c @@ -0,0 +1,13 @@ +struct usb_hub { + union { + struct usb_hub_status hub; + struct usb_port_status port; + } *status; /* buffer for status reports */ + +}; + +static int hub_configure(struct usb_hub *hub) +{ + hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL); + +} diff --git a/tests/neststruct.cocci b/tests/neststruct.cocci new file mode 100644 index 0000000..1ad529b --- /dev/null +++ b/tests/neststruct.cocci @@ -0,0 +1,8 @@ +@r@ +type T1; +T1 *x; +expression E,E2; +@@ + +- x = kmalloc(sizeof(E),E2) ++ x = kzalloc(sizeof(E),E2) diff --git a/tests/neststruct.res b/tests/neststruct.res new file mode 100644 index 0000000..7727f04 --- /dev/null +++ b/tests/neststruct.res @@ -0,0 +1,13 @@ +struct usb_hub { + union { + struct usb_hub_status hub; + struct usb_port_status port; + } *status; /* buffer for status reports */ + +}; + +static int hub_configure(struct usb_hub *hub) +{ + hub->status = kzalloc(sizeof(*hub->status), GFP_KERNEL); + +} diff --git a/tests/nl.c b/tests/nl.c new file mode 100644 index 0000000..7d5bae1 --- /dev/null +++ b/tests/nl.c @@ -0,0 +1,4 @@ +int main() { + if (x) return; + x = x + 1; +} diff --git a/tests/nl.cocci b/tests/nl.cocci new file mode 100644 index 0000000..4c4a493 --- /dev/null +++ b/tests/nl.cocci @@ -0,0 +1,5 @@ +@@ +@@ + +- x ++ y diff --git a/tests/nl.res b/tests/nl.res new file mode 100644 index 0000000..e59edd5 --- /dev/null +++ b/tests/nl.res @@ -0,0 +1,4 @@ +int main() { + if (y) return; + y = y + 1; +} diff --git a/tests/nocast.c b/tests/nocast.c new file mode 100644 index 0000000..44a6120 --- /dev/null +++ b/tests/nocast.c @@ -0,0 +1,4 @@ +int main (unsigned int __nocast gfp_mask, int x) { + buf = kmalloc(sizeof *send_buf + buf_size, gfp_mask); +} + diff --git a/tests/nocast.cocci b/tests/nocast.cocci new file mode 100644 index 0000000..a06a792 --- /dev/null +++ b/tests/nocast.cocci @@ -0,0 +1,13 @@ +@@ +identifier f, gfp; +type T; +@@ + +f(..., +- T gfp ++ gfp_t gfp + , ...) { + ... + kmalloc(...,gfp) + ... +} diff --git a/tests/nocast.res b/tests/nocast.res new file mode 100644 index 0000000..0fa7159 --- /dev/null +++ b/tests/nocast.res @@ -0,0 +1,3 @@ +int main (gfp_t gfp_mask, int x) { + buf = kmalloc(sizeof *send_buf + buf_size, gfp_mask); +} diff --git a/tests/not.c b/tests/not.c new file mode 100644 index 0000000..1c1ac88 --- /dev/null +++ b/tests/not.c @@ -0,0 +1,9 @@ +int main() { + int x; + this(12,x); + this(foo,x); + bar(12,x); + foo(12,x); + this(12,x); + this(12,x); +} diff --git a/tests/not.cocci b/tests/not.cocci new file mode 100644 index 0000000..da78432 --- /dev/null +++ b/tests/not.cocci @@ -0,0 +1,8 @@ +@@ +expression x != foo; +identifier y != {foo,bar}; +expression a; +@@ + +- y(x,a); ++ f(20); diff --git a/tests/not.res b/tests/not.res new file mode 100644 index 0000000..e503968 --- /dev/null +++ b/tests/not.res @@ -0,0 +1,9 @@ +int main() { + int x; + f(20); + this(foo,x); + bar(12,x); + foo(12,x); + f(20); + f(20); +} diff --git a/tests/noty.c b/tests/noty.c new file mode 100644 index 0000000..ebb55d6 --- /dev/null +++ b/tests/noty.c @@ -0,0 +1,3 @@ +int main(int *x) { + if (NULL == x) { return; } +} diff --git a/tests/noty.cocci b/tests/noty.cocci new file mode 100644 index 0000000..7fc9c91 --- /dev/null +++ b/tests/noty.cocci @@ -0,0 +1,7 @@ +@@ +statement S; +expression *x; +@@ + + if (NULL == x) S ++ g(); diff --git a/tests/noty.res b/tests/noty.res new file mode 100644 index 0000000..b4ecbd0 --- /dev/null +++ b/tests/noty.res @@ -0,0 +1,4 @@ +int main(int *x) { + if (NULL == x) { return; } + g(); +} diff --git a/tests/nstruct.c b/tests/nstruct.c new file mode 100644 index 0000000..84aaf48 --- /dev/null +++ b/tests/nstruct.c @@ -0,0 +1,4 @@ +struct saa5249_device +{ + struct i2c_client *client; +}; diff --git a/tests/nstruct.cocci b/tests/nstruct.cocci new file mode 100644 index 0000000..5f6e6e6 --- /dev/null +++ b/tests/nstruct.cocci @@ -0,0 +1,9 @@ +@@ +identifier I; +expression E; +@@ + +struct i2c_client I = { +- .name = E, ++ .dev = { .name = E, }, +}; diff --git a/tests/null.c b/tests/null.c new file mode 100644 index 0000000..a2a062c --- /dev/null +++ b/tests/null.c @@ -0,0 +1,9 @@ +int main() { + fsm->jumpmatrix = + kmalloc(sizeof(FSMFNPTR) * fsm->state_count * fsm->event_count, + GFP_KERNEL); + if (fsm->jumpmatrix == NULL) { foo(fsm->jumpmatrix); return; } + memset(fsm->jumpmatrix, 0, + sizeof(FSMFNPTR) * fsm->state_count * fsm->event_count); +} + diff --git a/tests/null.cocci b/tests/null.cocci new file mode 100644 index 0000000..26cd80c --- /dev/null +++ b/tests/null.cocci @@ -0,0 +1,79 @@ +// The first two rules only work when there is only one reference. + +@@ +expression *x; +type T; +expression e; +expression f; +@@ + if(x == NULL) { + ... when != x = e +( + return x; +| + ... +( + *x +| + *((T)x) +| + f(...,x,...) +| + f(...,(T)x,...) +) + ... +) + ... + } + +@@ +expression *x; +type T; +expression e; +expression f; +statement S; +@@ + if(x != NULL) S else { + ... when != x = e +( + return x; +| + ... +( + *x +| + *((T)x) +| + f(...,x,...) +| + f(...,(T)x,...) +) + ... +) + ... + } + +@@ +expression *x; +type T1, T2, T3; +expression e; +expression f; +statement S; +@@ + x = (T1) kmalloc(...); + ... when != \( if(x == NULL) { ... return ...; } \| if(x == NULL) S else { ... return ...; } \| x = e; \) +( + return x; +| + ... +( + *x +| + *((T2)x) +| + f(...,x,...) +| + f(...,(T3)x,...) +) + ... +) diff --git a/tests/null_type.c b/tests/null_type.c new file mode 100644 index 0000000..29634ac --- /dev/null +++ b/tests/null_type.c @@ -0,0 +1,8 @@ +int main(int i) { + + int *x; + + g(x); + g(NULL); + +} diff --git a/tests/null_type.cocci b/tests/null_type.cocci new file mode 100644 index 0000000..268a8c3 --- /dev/null +++ b/tests/null_type.cocci @@ -0,0 +1,6 @@ +@@ +expression *X; +@@ + +- X ++ f(X) \ No newline at end of file diff --git a/tests/null_type.res b/tests/null_type.res new file mode 100644 index 0000000..3f1881e --- /dev/null +++ b/tests/null_type.res @@ -0,0 +1,8 @@ +int main(int i) { + + int *x; + + g(f(x)); + g(f(NULL)); + +} diff --git a/tests/null_ver11.c b/tests/null_ver11.c new file mode 100644 index 0000000..0fa9640 --- /dev/null +++ b/tests/null_ver11.c @@ -0,0 +1,112 @@ + void udf_fill_spartable(struct super_block *sb, struct udf_sparing_data *sdata, int partlen) + { + Uint16 ident; + Uint32 spartable; + int i; + struct buffer_head *bh; + struct SparingTable *st; + + for (i=0; i<4; i++) + { + if (!(spartable = sdata->s_spar_loc[i])) + continue; + + bh = udf_read_tagged(sb, spartable, spartable, &ident); + + if (!bh) + { + sdata->s_spar_loc[i] = 0; + continue; + } + + if (ident == 0) + { + st = (struct SparingTable *)bh->b_data; + if (!strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING))) + { + SparingEntry *se; + Uint16 rtl = le16_to_cpu(st->reallocationTableLen); + int index; + + if (!sdata->s_spar_map) + { + int num = 1, mapsize; + sdata->s_spar_indexsize = 8; + while (rtl*sizeof(Uint32) >= (1 << sdata->s_spar_indexsize)) + { + num ++; + sdata->s_spar_indexsize <<= 1; + } + mapsize = (rtl * sizeof(Uint32)) + + ((partlen/(1 << sdata->s_spar_pshift)) * sizeof(Uint8) * num); + sdata->s_spar_map = kmalloc(mapsize, GFP_KERNEL); + sdata->s_spar_remap.s_spar_remap32 = &sdata->s_spar_map[rtl]; + memset(sdata->s_spar_map, 0xFF, mapsize); + } + + index = sizeof(struct SparingTable); + for (i=0; i sb->s_blocksize) + { + udf_release_data(bh); + bh = udf_tread(sb, ++spartable, sb->s_blocksize); + if (!bh) + { + sdata->s_spar_loc[i] = 0; + continue; + } + index = 0; + } + se = (SparingEntry *)&(bh->b_data[index]); + index += sizeof(SparingEntry); + + if (sdata->s_spar_map[i] == 0xFFFFFFFF) + sdata->s_spar_map[i] = le32_to_cpu(se->mappedLocation); + else if (sdata->s_spar_map[i] != le32_to_cpu(se->mappedLocation)) + { + udf_debug("Found conflicting Sparing Data (%d vs %d for entry %d)\n", + sdata->s_spar_map[i], le32_to_cpu(se->mappedLocation), i); + } + + if (le32_to_cpu(se->origLocation) < 0xFFFFFFF0) + { + int packet = le32_to_cpu(se->origLocation) >> sdata->s_spar_pshift; + if (sdata->s_spar_indexsize == 8) + { + if (sdata->s_spar_remap.s_spar_remap8[packet] == 0xFF) + sdata->s_spar_remap.s_spar_remap8[packet] = i; + else if (sdata->s_spar_remap.s_spar_remap8[packet] != i) + { + udf_debug("Found conflicting Sparing Data (%d vs %d)\n", + sdata->s_spar_remap.s_spar_remap8[packet], i); + } + } + else if (sdata->s_spar_indexsize == 16) + { + if (sdata->s_spar_remap.s_spar_remap16[packet] == 0xFFFF) + sdata->s_spar_remap.s_spar_remap16[packet] = i; + else if (sdata->s_spar_remap.s_spar_remap16[packet] != i) + { + udf_debug("Found conflicting Sparing Data (%d vs %d)\n", + sdata->s_spar_remap.s_spar_remap16[packet], i); + } + } + else if (sdata->s_spar_indexsize == 32) + { + if (sdata->s_spar_remap.s_spar_remap32[packet] == 0xFFFFFFFF) + sdata->s_spar_remap.s_spar_remap32[packet] = i; + else if (sdata->s_spar_remap.s_spar_remap32[packet] != i) + { + udf_debug("Found conflicting Sparing Data (%d vs %d)\n", + sdata->s_spar_remap.s_spar_remap32[packet], i); + } + } + } + } + } + } + udf_release_data(bh); + } + } + diff --git a/tests/of.c b/tests/of.c new file mode 100644 index 0000000..9c2caf6 --- /dev/null +++ b/tests/of.c @@ -0,0 +1,16 @@ +static struct iommu_table *iommu_table_find(struct iommu_table * tbl) +{ + for (node = NULL; (node = of_find_all_nodes(node)); ) { + if (x) + return it; + } +} + +static struct iommu_table *iommu_table_find(struct iommu_table * tbl) +{ + for (node = NULL; (node = something(node)); ) { + if (x) + return it; + } +} + diff --git a/tests/of.cocci b/tests/of.cocci new file mode 100644 index 0000000..d469e98 --- /dev/null +++ b/tests/of.cocci @@ -0,0 +1,21 @@ +@r@ +identifier d; +expression e; +@@ + +for (d = NULL; (d = of_find_all_nodes(d)); ) + {... +? return e; ++ of_node_put(d); +...} + +@r1@ +identifier d; +expression e; +@@ + +for (d = NULL; (d = something(d)); ) + {... ++ of_node_put(d); +? return e; +...} diff --git a/tests/of.res b/tests/of.res new file mode 100644 index 0000000..5b399bc --- /dev/null +++ b/tests/of.res @@ -0,0 +1,20 @@ +static struct iommu_table *iommu_table_find(struct iommu_table * tbl) +{ + for (node = NULL; (node = of_find_all_nodes(node)); ) { + if (x) { + return it; + of_node_put(node); + } + } +} + +static struct iommu_table *iommu_table_find(struct iommu_table * tbl) +{ + for (node = NULL; (node = something(node)); ) { + if (x) { + of_node_put(node); + return it; + } + } +} + diff --git a/tests/oneline.c b/tests/oneline.c new file mode 100644 index 0000000..ac69ad5 --- /dev/null +++ b/tests/oneline.c @@ -0,0 +1,4 @@ +int main () { + f(); + f(); +} diff --git a/tests/oneline.cocci b/tests/oneline.cocci new file mode 100644 index 0000000..6665797 --- /dev/null +++ b/tests/oneline.cocci @@ -0,0 +1,5 @@ +@@ +@@ + +- f(); ++ g(); diff --git a/tests/oneline.res b/tests/oneline.res new file mode 100644 index 0000000..d40ddf9 --- /dev/null +++ b/tests/oneline.res @@ -0,0 +1,4 @@ +int main () { + g(); + g(); +} diff --git a/tests/opt.c b/tests/opt.c new file mode 100644 index 0000000..274998d --- /dev/null +++ b/tests/opt.c @@ -0,0 +1,3 @@ +int main () { + yyy(); +} diff --git a/tests/opt.cocci b/tests/opt.cocci new file mode 100644 index 0000000..e3e4e13 --- /dev/null +++ b/tests/opt.cocci @@ -0,0 +1,14 @@ +@ disable all @ +identifier f; +@@ + +f (...) { + ... +( +- xxx(); +| +?- yyy(); +) + ... +} + diff --git a/tests/opt.res b/tests/opt.res new file mode 100644 index 0000000..62eb285 --- /dev/null +++ b/tests/opt.res @@ -0,0 +1,3 @@ +int main () { + +} diff --git a/tests/optional_qualifier.c b/tests/optional_qualifier.c new file mode 100644 index 0000000..a8be68f --- /dev/null +++ b/tests/optional_qualifier.c @@ -0,0 +1,2 @@ +int a; +const int b; diff --git a/tests/optional_qualifier.cocci b/tests/optional_qualifier.cocci new file mode 100644 index 0000000..61682b9 --- /dev/null +++ b/tests/optional_qualifier.cocci @@ -0,0 +1,9 @@ +@ disable optional_qualifier @ +identifier x; +@@ + +- int ++ const int + x; + + diff --git a/tests/optional_qualifier.res b/tests/optional_qualifier.res new file mode 100644 index 0000000..8b86b4d --- /dev/null +++ b/tests/optional_qualifier.res @@ -0,0 +1,2 @@ +const int a; +const int b; diff --git a/tests/optional_storage.c b/tests/optional_storage.c new file mode 100644 index 0000000..680d3fd --- /dev/null +++ b/tests/optional_storage.c @@ -0,0 +1,12 @@ +int foo1(void) +{ +} + + +static int foo2(void) +{ +} + +float foo2(void) +{ +} diff --git a/tests/optional_storage.cocci b/tests/optional_storage.cocci new file mode 100644 index 0000000..fc820bf --- /dev/null +++ b/tests/optional_storage.cocci @@ -0,0 +1,9 @@ +@ disable optional_storage @ +identifier func; +@@ + +- int ++ static int + func(...) { ... } + + diff --git a/tests/optional_storage.res b/tests/optional_storage.res new file mode 100644 index 0000000..19d40d8 --- /dev/null +++ b/tests/optional_storage.res @@ -0,0 +1,12 @@ +static int foo1(void) +{ +} + + +static int foo2(void) +{ +} + +float foo2(void) +{ +} diff --git a/tests/orexp.c b/tests/orexp.c new file mode 100644 index 0000000..f9efaf3 --- /dev/null +++ b/tests/orexp.c @@ -0,0 +1,3 @@ +int main() { + bar(12+12); +} diff --git a/tests/orexp.cocci b/tests/orexp.cocci new file mode 100644 index 0000000..dea5d0f --- /dev/null +++ b/tests/orexp.cocci @@ -0,0 +1,9 @@ +@@ +expression E, F; +@@ + +( +- foo(E) +| +- bar(F) +) \ No newline at end of file diff --git a/tests/orexp.res b/tests/orexp.res new file mode 100644 index 0000000..cec667a --- /dev/null +++ b/tests/orexp.res @@ -0,0 +1,3 @@ +int main() { + ; +} diff --git a/tests/param.c b/tests/param.c new file mode 100644 index 0000000..5b18eb5 --- /dev/null +++ b/tests/param.c @@ -0,0 +1 @@ +void foo() { return; } diff --git a/tests/param.cocci b/tests/param.cocci new file mode 100644 index 0000000..2bab5f8 --- /dev/null +++ b/tests/param.cocci @@ -0,0 +1,4 @@ +@@ +@@ + +- foo(...) { ... } diff --git a/tests/param.res b/tests/param.res new file mode 100644 index 0000000..139597f --- /dev/null +++ b/tests/param.res @@ -0,0 +1,2 @@ + + diff --git a/tests/param1.c b/tests/param1.c new file mode 100644 index 0000000..62e0eef --- /dev/null +++ b/tests/param1.c @@ -0,0 +1 @@ +void foo(int x) { return; } diff --git a/tests/param1.cocci b/tests/param1.cocci new file mode 100644 index 0000000..eb61ce5 --- /dev/null +++ b/tests/param1.cocci @@ -0,0 +1,4 @@ +@@ +@@ + +- foo(int x, ...) { ... } diff --git a/tests/param1_ver1.c b/tests/param1_ver1.c new file mode 100644 index 0000000..765eba5 --- /dev/null +++ b/tests/param1_ver1.c @@ -0,0 +1 @@ +void foo(int x,int y) { return; } diff --git a/tests/param_end.c b/tests/param_end.c new file mode 100644 index 0000000..98f523b --- /dev/null +++ b/tests/param_end.c @@ -0,0 +1,15 @@ +int one (int x) { return; } + +int two (int a, int x, int b) { return; } + +int three (int x, int a) { return; } + +int four (int a, int x) { return; } + +int yone (int y) { return; } + +int ytwo (int a, int y, int b) { return; } + +int ythree (int y, int a) { return; } + +int yfour (int a, int y) { return; } diff --git a/tests/param_end.cocci b/tests/param_end.cocci new file mode 100644 index 0000000..b641ce7 --- /dev/null +++ b/tests/param_end.cocci @@ -0,0 +1,15 @@ +@@ +identifier one; +@@ + +one (... +- ,int x + ,...) { ... } + +@@ +identifier one; +@@ + +one (..., +- int y, + ...) { ... } diff --git a/tests/param_end.res b/tests/param_end.res new file mode 100644 index 0000000..09619ef --- /dev/null +++ b/tests/param_end.res @@ -0,0 +1,15 @@ +int one () { return; } + +int two (int a, int b) { return; } + +int three (int a) { return; } + +int four (int a) { return; } + +int yone () { return; } + +int ytwo (int a, int b) { return; } + +int ythree (int a) { return; } + +int yfour (int a) { return; } diff --git a/tests/param_ver1.c b/tests/param_ver1.c new file mode 100644 index 0000000..62e0eef --- /dev/null +++ b/tests/param_ver1.c @@ -0,0 +1 @@ +void foo(int x) { return; } diff --git a/tests/param_ver1.res b/tests/param_ver1.res new file mode 100644 index 0000000..139597f --- /dev/null +++ b/tests/param_ver1.res @@ -0,0 +1,2 @@ + + diff --git a/tests/parameters_dots.c b/tests/parameters_dots.c new file mode 100644 index 0000000..8c4ba0d --- /dev/null +++ b/tests/parameters_dots.c @@ -0,0 +1,7 @@ +void main(int i) { + + f(1); + g(3); + f(1,2); + f(); +} diff --git a/tests/parameters_dots.cocci b/tests/parameters_dots.cocci new file mode 100644 index 0000000..2341f1c --- /dev/null +++ b/tests/parameters_dots.cocci @@ -0,0 +1,3 @@ +@@ +@@ +- f(...); diff --git a/tests/parameters_dots.res b/tests/parameters_dots.res new file mode 100644 index 0000000..f0f5d71 --- /dev/null +++ b/tests/parameters_dots.res @@ -0,0 +1,4 @@ +void main(int i) { + + g(3); +} diff --git a/tests/paren1.c b/tests/paren1.c new file mode 100644 index 0000000..72746b3 --- /dev/null +++ b/tests/paren1.c @@ -0,0 +1,3 @@ +int main () { + return (x) && y; +} diff --git a/tests/paren1.cocci b/tests/paren1.cocci new file mode 100644 index 0000000..77185d8 --- /dev/null +++ b/tests/paren1.cocci @@ -0,0 +1,3 @@ +@@ +@@ +- x && y diff --git a/tests/partial.c b/tests/partial.c new file mode 100644 index 0000000..40d32d6 --- /dev/null +++ b/tests/partial.c @@ -0,0 +1,3 @@ +#define CS_THIS_MODULE THIS_MODULE, +#define CS_OWNER owner: +void cs46xx_null(struct pci_dev *pcidev) { return PAGE_SIZE; } diff --git a/tests/partial.cocci b/tests/partial.cocci new file mode 100644 index 0000000..c1de567 --- /dev/null +++ b/tests/partial.cocci @@ -0,0 +1,6 @@ +@@ +statement S; +@@ + +- PAGE_SIZE ++ PAGE_SIZE2 diff --git a/tests/partial.res b/tests/partial.res new file mode 100644 index 0000000..75df503 --- /dev/null +++ b/tests/partial.res @@ -0,0 +1,3 @@ +#define CS_THIS_MODULE THIS_MODULE, +#define CS_OWNER owner: +void cs46xx_null(struct pci_dev *pcidev) { return PAGE_SIZE2; } diff --git a/tests/pb_cfg.c b/tests/pb_cfg.c new file mode 100644 index 0000000..21d65d6 --- /dev/null +++ b/tests/pb_cfg.c @@ -0,0 +1,10 @@ +void main(int i) { + + f(1); + goto return_0; + f(1); +label1: + f(2); + return; + +} diff --git a/tests/pb_cfg.cocci b/tests/pb_cfg.cocci new file mode 100644 index 0000000..375e7f2 --- /dev/null +++ b/tests/pb_cfg.cocci @@ -0,0 +1,4 @@ +@@ +@@ + +-f(...); diff --git a/tests/pb_distribute_type.c b/tests/pb_distribute_type.c new file mode 100644 index 0000000..2216099 --- /dev/null +++ b/tests/pb_distribute_type.c @@ -0,0 +1,15 @@ +int foo() { + int x; + return 0; +} + + +int foo() { + int *x; + return 0; +} + +int foo() { + int x[45]; + return 0; +} diff --git a/tests/pb_distribute_type.cocci b/tests/pb_distribute_type.cocci new file mode 100644 index 0000000..a2b7617 --- /dev/null +++ b/tests/pb_distribute_type.cocci @@ -0,0 +1,10 @@ +@@ +type T; +@@ + + foo(...) { +- T x; ++ T *x; + ... + } + \ No newline at end of file diff --git a/tests/pb_distribute_type.res b/tests/pb_distribute_type.res new file mode 100644 index 0000000..4899ac4 --- /dev/null +++ b/tests/pb_distribute_type.res @@ -0,0 +1,15 @@ +int foo() { + int *x; + return 0; +} + + +int foo() { + int **x; + return 0; +} + +int foo() { + int (*x)[45]; + return 0; +} diff --git a/tests/pb_distribute_type2.c b/tests/pb_distribute_type2.c new file mode 100644 index 0000000..2216099 --- /dev/null +++ b/tests/pb_distribute_type2.c @@ -0,0 +1,15 @@ +int foo() { + int x; + return 0; +} + + +int foo() { + int *x; + return 0; +} + +int foo() { + int x[45]; + return 0; +} diff --git a/tests/pb_distribute_type2.cocci b/tests/pb_distribute_type2.cocci new file mode 100644 index 0000000..efe12e5 --- /dev/null +++ b/tests/pb_distribute_type2.cocci @@ -0,0 +1,11 @@ +@@ +type T; +@@ + + foo(...) { + T ++ * + x; + ... + } + \ No newline at end of file diff --git a/tests/pb_distribute_type2.res b/tests/pb_distribute_type2.res new file mode 100644 index 0000000..4899ac4 --- /dev/null +++ b/tests/pb_distribute_type2.res @@ -0,0 +1,15 @@ +int foo() { + int *x; + return 0; +} + + +int foo() { + int **x; + return 0; +} + +int foo() { + int (*x)[45]; + return 0; +} diff --git a/tests/pb_distribute_type3.c b/tests/pb_distribute_type3.c new file mode 100644 index 0000000..2216099 --- /dev/null +++ b/tests/pb_distribute_type3.c @@ -0,0 +1,15 @@ +int foo() { + int x; + return 0; +} + + +int foo() { + int *x; + return 0; +} + +int foo() { + int x[45]; + return 0; +} diff --git a/tests/pb_distribute_type3.cocci b/tests/pb_distribute_type3.cocci new file mode 100644 index 0000000..2a560c5 --- /dev/null +++ b/tests/pb_distribute_type3.cocci @@ -0,0 +1,12 @@ +@@ +type T; +//fresh identifier y; +@@ + + foo(...) { + T ++ y, + x; + ... + } + \ No newline at end of file diff --git a/tests/pb_distribute_type3.res b/tests/pb_distribute_type3.res new file mode 100644 index 0000000..3db5d9c --- /dev/null +++ b/tests/pb_distribute_type3.res @@ -0,0 +1,15 @@ +int foo() { + int y, x; + return 0; +} + + +int foo() { + int *y, *x; + return 0; +} + +int foo() { + int y[45], x[45]; + return 0; +} diff --git a/tests/pb_distribute_type4.c b/tests/pb_distribute_type4.c new file mode 100644 index 0000000..2216099 --- /dev/null +++ b/tests/pb_distribute_type4.c @@ -0,0 +1,15 @@ +int foo() { + int x; + return 0; +} + + +int foo() { + int *x; + return 0; +} + +int foo() { + int x[45]; + return 0; +} diff --git a/tests/pb_distribute_type4.cocci b/tests/pb_distribute_type4.cocci new file mode 100644 index 0000000..ea6afc5 --- /dev/null +++ b/tests/pb_distribute_type4.cocci @@ -0,0 +1,11 @@ +@@ +type T; +@@ + + foo(...) { +- T ++ float + x; + ... + } + \ No newline at end of file diff --git a/tests/pb_distribute_type4.res b/tests/pb_distribute_type4.res new file mode 100644 index 0000000..f5dd9cb --- /dev/null +++ b/tests/pb_distribute_type4.res @@ -0,0 +1,15 @@ +int foo() { + float x; + return 0; +} + + +int foo() { + float x; + return 0; +} + +int foo() { + float x; + return 0; +} diff --git a/tests/pb_params_iso.c b/tests/pb_params_iso.c new file mode 100644 index 0000000..848ae34 --- /dev/null +++ b/tests/pb_params_iso.c @@ -0,0 +1,18 @@ + +int f(bool a, int i, bool b) { + i++; +} + +int f(int i, bool b) { + i++; +} + +int f(bool a, int i) { + i++; +} + + +int f(int i) { + i++; +} + diff --git a/tests/pb_params_iso.cocci b/tests/pb_params_iso.cocci new file mode 100644 index 0000000..03c5dd8 --- /dev/null +++ b/tests/pb_params_iso.cocci @@ -0,0 +1,31 @@ +// soluce ? +// - add isomorphism: +// func(..., P, ...) => func(P) , => func(P,...), => func(...,P) ? +// but propagate well the modifiers ? +// but then how specify that we really want match function +// that have parameters before ? use a P metavariable. +// - allow func (... int i ...) in parsing_cocci/ + +@@ +identifier func; +@@ + +// pad: this one does not work because the last comma is tagged +// and so I force it to be present. +// func(..., +// - int i, +// + int i, char j, +// ...) { +// ... +// } + + func(..., +- int i ++ int i, char j + ,...) { + ... + } + + + + diff --git a/tests/pb_params_iso.res b/tests/pb_params_iso.res new file mode 100644 index 0000000..2d27b2e --- /dev/null +++ b/tests/pb_params_iso.res @@ -0,0 +1,17 @@ + +int f(bool a, int i, char j, bool b) { + i++; +} + +int f(int i, char j, bool b) { + i++; +} + +int f(bool a, int i, char j) { + i++; +} + +int f(int i, char j) { + i++; +} + diff --git a/tests/pb_tag_symbols.c b/tests/pb_tag_symbols.c new file mode 100644 index 0000000..c980e07 --- /dev/null +++ b/tests/pb_tag_symbols.c @@ -0,0 +1,5 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + if (copy_from_user(v,arg) != 0) + return -EFAULT; else {} +} diff --git a/tests/pb_tag_symbols.cocci b/tests/pb_tag_symbols.cocci new file mode 100644 index 0000000..2b8e00c --- /dev/null +++ b/tests/pb_tag_symbols.cocci @@ -0,0 +1,7 @@ +@@ +identifier arg; +identifier v; +expression E1;//, E2; +@@ + +- if(copy_from_user(v,arg) != 0) return E1; else { } \ No newline at end of file diff --git a/tests/pb_tag_symbols.res b/tests/pb_tag_symbols.res new file mode 100644 index 0000000..aa80e8e --- /dev/null +++ b/tests/pb_tag_symbols.res @@ -0,0 +1,3 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ +} diff --git a/tests/pci_noputm.cocci b/tests/pci_noputm.cocci new file mode 100644 index 0000000..83540b7 --- /dev/null +++ b/tests/pci_noputm.cocci @@ -0,0 +1,111 @@ +@@ +type T; +identifier d; +expression e; +@@ + +T *d; +... +while ((d = \(pci_get_device\|pci_get_device_reverse\|pci_get_subsys\|pci_get_class\)(..., d)) != NULL) + {... when != pci_dev_put(d) + when != e = d +( + return d; +| ++ pci_dev_put(d); +? return ...; +) +...} + +@@ +identifier d; +type T; +expression e, e1; +@@ + +T *d; +... +while ((d = \(pci_get_device\|pci_get_device_reverse\|pci_get_subsys\|pci_get_class\)(..., d)) != NULL) + {... when != pci_dev_put(d) + when != e = d ++ pci_dev_put(d); +? break; + ...} +... when != pci_dev_put(d) + when != e1 = d + when != return d; + +@@ +identifier d; +type T; +expression e; +iterator for_each_pci_dev; +@@ + +T *d; +... +for_each_pci_dev(d) + {... when != pci_dev_put(d) + when != e = d +( + return d; +| ++ pci_dev_put(d); +? return ...; +) +...} + +@@ +identifier d; +type T; +expression e, e1; +@@ + +T *d; +... +for_each_pci_dev(d) + {... when != pci_dev_put(d) + when != e = d ++ pci_dev_put(d); +? break; + ...} +... when != pci_dev_put(d) + when != e1 = d + when != return d; + +@@ +type T; +identifier d; +expression e; +@@ + +T *d; +... +for (d = \(pci_get_device\|pci_get_device_reverse\|pci_get_subsys\|pci_get_class\)(...); d != NULL; d = \(pci_get_device\|pci_get_device_reverse\|pci_get_subsys\|pci_get_class\)(...,d)) + {... when != pci_dev_put(d) + when != e = d +( + return d; +| ++ pci_dev_put(d); +? return ...; +) +...} + +@@ +identifier d; +type T; +expression e, e1; +@@ + +T *d; +... +for (d = \(pci_get_device\|pci_get_device_reverse\|pci_get_subsys\|pci_get_class\)(...); d != NULL; d = \(pci_get_device\|pci_get_device_reverse\|pci_get_subsys\|pci_get_class\)(...,d)) + {... when != pci_dev_put(d) + when != e = d ++ pci_dev_put(d); +? break; + ...} +... when != pci_dev_put(d) + when != e1 = d + when != return d; diff --git a/tests/pmac.c b/tests/pmac.c new file mode 100644 index 0000000..4d888ea --- /dev/null +++ b/tests/pmac.c @@ -0,0 +1,11 @@ +#ifdef CONFIG_PPC_HAS_FEATURE_CALLS +#include +#else +#include +#endif + +#define chip_t pmac_t + + +static int snd_pmac_register_sleep_notifier(pmac_t *chip); +static int snd_pmac_unregister_sleep_notifier(pmac_t *chip); diff --git a/tests/pmac.cocci b/tests/pmac.cocci new file mode 100644 index 0000000..18cfaac --- /dev/null +++ b/tests/pmac.cocci @@ -0,0 +1,4 @@ +@@ +type T; +@@ +- #define chip_t T diff --git a/tests/pmac.res b/tests/pmac.res new file mode 100644 index 0000000..9a742e5 --- /dev/null +++ b/tests/pmac.res @@ -0,0 +1,8 @@ +#ifdef CONFIG_PPC_HAS_FEATURE_CALLS +#include +#else +#include +#endif + +static int snd_pmac_register_sleep_notifier(pmac_t *chip); +static int snd_pmac_unregister_sleep_notifier(pmac_t *chip); diff --git a/tests/posiso.c b/tests/posiso.c new file mode 100644 index 0000000..a64b561 --- /dev/null +++ b/tests/posiso.c @@ -0,0 +1,11 @@ +int main () { + int *x; + if (x == NULL) x = a; else x = b; + if (!x) x = a; else x = b; + if (x == a) x = a; else x = b; + if (x == NULL) x = a; + if (!x) x = a; + if (x == a) x = a; +} + + diff --git a/tests/posiso.cocci b/tests/posiso.cocci new file mode 100644 index 0000000..f92c8ac --- /dev/null +++ b/tests/posiso.cocci @@ -0,0 +1,14 @@ +@x@ +position p1,p2; +expression E; +statement S1, S2; +@@ + +if@p1 (E ==@p2 NULL) S1 else S2 + +@@ +position x.p1; +statement S1, S2; +@@ + +- if@p1 (...) S1 else S2 diff --git a/tests/posiso.res b/tests/posiso.res new file mode 100644 index 0000000..61fc30a --- /dev/null +++ b/tests/posiso.res @@ -0,0 +1,9 @@ +int main () { + int *x; + if (!x) x = a; else x = b; + if (x == a) x = a; else x = b; + if (!x) x = a; + if (x == a) x = a; +} + + diff --git a/tests/positionc.c b/tests/positionc.c new file mode 100644 index 0000000..1575c0d --- /dev/null +++ b/tests/positionc.c @@ -0,0 +1,9 @@ +int main () { + if (foo(6,7)) x = ret; else x = ret; + if (foo(6,7)) x = ret; else x = ret; + if (foo(7,7)) x = ret; else x = ret; + if (bar(6,7)) x = ret; else x = ret; + if (bar(6,7)) x = ret; else x = ret; + if (bar(7,7)) x = ret; else x = ret; +} + diff --git a/tests/positionc.cocci b/tests/positionc.cocci new file mode 100644 index 0000000..e81432c --- /dev/null +++ b/tests/positionc.cocci @@ -0,0 +1,37 @@ +@x disable all@ +position p; +expression E; +expression A; +statement S1, S2; +@@ + +if@p (foo(E,A)) S1 else S2 + +// here the incoming environment is p = 1,2 E = 6 and p = 3 E = 7 +@disable all@ +position p1 != x.p; +expression x.E; +expression B; +statement S1, S2; +@@ + +- if@p1 (foo(E,B)) S1 else S2 + +@y disable all@ +position p; +expression E; +expression A; +statement S1, S2; +@@ + +if@p (bar(E,A)) S1 else S2 + +// here the incoming environment is p = 4,5 E = 6 and p = 6 E = 7 +@disable all@ +position p1 != y.p; +expression y.E; +expression C; +statement S1, S2; +@@ + +- if@p1 (bar(C,E)) S1 else S2 diff --git a/tests/positionc.res b/tests/positionc.res new file mode 100644 index 0000000..19a2538 --- /dev/null +++ b/tests/positionc.res @@ -0,0 +1,7 @@ +int main () { + if (foo(6,7)) x = ret; else x = ret; + if (foo(6,7)) x = ret; else x = ret; + if (foo(7,7)) x = ret; else x = ret; + if (bar(7,7)) x = ret; else x = ret; +} + diff --git a/tests/positions3.c b/tests/positions3.c new file mode 100644 index 0000000..e3176d5 --- /dev/null +++ b/tests/positions3.c @@ -0,0 +1,12 @@ +int main() { + f(togo,xxx,togo); + h(); + g(togo,xxx,togo); + i(); + g(togo,xxx,togo); + j(); + f(togo,xxx,togo); + h(togo,xxx,togo); + j(); + h(togo,xxx,togo); +} diff --git a/tests/positions3.cocci b/tests/positions3.cocci new file mode 100644 index 0000000..4029cb0 --- /dev/null +++ b/tests/positions3.cocci @@ -0,0 +1,26 @@ +@rule1@ +expression E; +position p1,p2,p3,p4; +@@ + +* f(E@p1, xxx, E@p2); + ... +* f(E@p3, xxx, E@p4); + +@@ +expression rule1.E; +position p1,p2; +@@ + +* g(E@p1, xxx, E); + ... +* g(E, xxx, E@p2); + +@@ +expression rule1.E; +position p1,p2; +@@ + +* h(E, xxx, E@p1); + ... +* h(E@p2, xxx, E); diff --git a/tests/posmult.c b/tests/posmult.c new file mode 100644 index 0000000..33eddb8 --- /dev/null +++ b/tests/posmult.c @@ -0,0 +1,8 @@ +int main() { + int *x = NULL; + int *y = NULL; + if (r) x = ALLOC(); + y = ALLOC(); + if (!x) return; + if (!y) return; +} diff --git a/tests/posmult.cocci b/tests/posmult.cocci new file mode 100644 index 0000000..f0eed88 --- /dev/null +++ b/tests/posmult.cocci @@ -0,0 +1,25 @@ +// shows the expressive power added by positions +// normally, we find one root and then explore its children. +// here the root is in some sense the if, and we want to see if it can +// be reached from two contexts + +@n@ +position p; +expression E; +statement S,S1; +@@ + +E = NULL +... when != E = ALLOC(...) +if@p (\(E\|!E\)) S else S1 + +@@ +expression E, E1; +statement S,S1; +position p1 != n.p; +@@ + +* E = ALLOC(...) +... when != E = E1 +* if@p1 (\(E\|!E\)) + S else S1 diff --git a/tests/posnpb.c b/tests/posnpb.c new file mode 100644 index 0000000..261b42a --- /dev/null +++ b/tests/posnpb.c @@ -0,0 +1,7 @@ +int main() { + x = FN(); + if (y) + x->a = 12; + else + x->b = 15; +} diff --git a/tests/posnpb.cocci b/tests/posnpb.cocci new file mode 100644 index 0000000..56f52d7 --- /dev/null +++ b/tests/posnpb.cocci @@ -0,0 +1,41 @@ +// problem with positions. in check_unprotected, we start with a set of +// positions, but the binding that is deduced is only relevant to one of them +// but since it was deduced from both of them, both of them are printed out +// at the end + +@unprotected exists@ +expression x; +identifier fld; +position p,p1; +statement S; +expression E; +@@ + + x@p1 = FN(...); + ... when != x = E +( + if (x == NULL) { ... return ...; } else S +| + x@p->fld +) + +@check_unprotected exists@ // ensure both are present +position unprotected.p, unprotected.p1; +expression x; +identifier fld; +@@ + +x@p1 = FN(...); +... +x@p->fld + +@ script:python depends on check_unprotected @ +p << unprotected.p; // position of ref +p1 << unprotected.p1; // position of call +fld << check_unprotected.fld; // identifier +@@ + +c = cocci.combine(fld,p1) +print " call to FN on line %s column %s" % (c.location.line,c.location.column) +c1 = cocci.combine(fld,p) +print " ref to field %s on line %s column %s" % (fld,c1.location.line,c1.location.column) diff --git a/tests/post.c b/tests/post.c new file mode 100644 index 0000000..04de053 --- /dev/null +++ b/tests/post.c @@ -0,0 +1,8 @@ +int main() { + f(3, foo + bar, 5); + f(4, 3, 5); + f(4, 3, 5); + h(3, some + thing, 5); + h(4, 3, 5); + h(4, 3, 5); +} diff --git a/tests/post.cocci b/tests/post.cocci new file mode 100644 index 0000000..f5ce269 --- /dev/null +++ b/tests/post.cocci @@ -0,0 +1,15 @@ +@x@ +position p; +identifier f; +expression E; +@@ + +f(3,E@p,...) + +@@ +position x.p; +identifier g; +expression E; +@@ + +- g(3,E@p,...); \ No newline at end of file diff --git a/tests/post.res b/tests/post.res new file mode 100644 index 0000000..be19ef2 --- /dev/null +++ b/tests/post.res @@ -0,0 +1,6 @@ +int main() { + f(4, 3, 5); + f(4, 3, 5); + h(4, 3, 5); + h(4, 3, 5); +} diff --git a/tests/ppos.c b/tests/ppos.c new file mode 100644 index 0000000..baec652 --- /dev/null +++ b/tests/ppos.c @@ -0,0 +1,16 @@ +struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu, + unsigned long spu_elf_start) +{ + for (i = 0; i < n_ovlys; i++) { + map = vma_map_add(map, ovly.vma, ovly.size, ovly.offset, + ovly_buf_table_sym + (ovly.buf-1) * 4, i+1); + if (!map) { map = NULL; + goto fail; } + } + goto out; + + fail: + map = NULL; + out: + return map; +} diff --git a/tests/ppos.cocci b/tests/ppos.cocci new file mode 100644 index 0000000..2e5e05d --- /dev/null +++ b/tests/ppos.cocci @@ -0,0 +1,36 @@ +@a@ +position p; +identifier f; +expression E; +@@ + +f(...) { + <... when strict +( +E@p = ERR_PTR(...) +| +E@p = NULL +) +...> +return E; +} + +@b exists@ +identifier f, fld; +expression E,E1,E2; +position p1, p2 != a.p; +@@ + +f(...) { +( + ... when any + E@p2 = E1 + ... when != E->fld + when != E = E2 + return@p1 E; +| + ... when != E->fld + when != E = E2 + return@p1 E; +) +} diff --git a/tests/print_return.c b/tests/print_return.c new file mode 100644 index 0000000..9c36490 --- /dev/null +++ b/tests/print_return.c @@ -0,0 +1,4 @@ +int config(struct pcmcia_device *link) { + bar(); + return 0; +} diff --git a/tests/print_return.cocci b/tests/print_return.cocci new file mode 100644 index 0000000..bd0fbab --- /dev/null +++ b/tests/print_return.cocci @@ -0,0 +1,11 @@ +@@ +expression E; +identifier config; +@@ + +config(struct pcmcia_device *link) { + ... ++ return + bar(); +- return 0; +} diff --git a/tests/print_return.res b/tests/print_return.res new file mode 100644 index 0000000..e845acb --- /dev/null +++ b/tests/print_return.res @@ -0,0 +1,3 @@ +int config(struct pcmcia_device *link) { + return bar(); +} diff --git a/tests/proto.c b/tests/proto.c new file mode 100644 index 0000000..15912ef --- /dev/null +++ b/tests/proto.c @@ -0,0 +1,10 @@ +static void bch_l2l1(struct PStack *st, int pr, void *arg); +static void bch_sched_event(struct BCState *bcs, int event); +static void bch_empty_fifo(struct BCState *bcs, int count); + +static void +bch_sched_event(struct BCState *bcs, int event) +{ + bcs->event |= 1 << event; + schedule_work(&bcs->work); +} diff --git a/tests/proto.cocci b/tests/proto.cocci new file mode 100644 index 0000000..936a24b --- /dev/null +++ b/tests/proto.cocci @@ -0,0 +1,10 @@ +@r@ +identifier fn2; +identifier bcs, ev; +@@ + +- fn2(struct BCState *bcs, int ev) { +- ... +- bcs->event |= 1 << ev; +- schedule_work(&bcs->work); +- } diff --git a/tests/proto.res b/tests/proto.res new file mode 100644 index 0000000..a28e8a9 --- /dev/null +++ b/tests/proto.res @@ -0,0 +1,3 @@ +static void bch_l2l1(struct PStack *st, int pr, void *arg); +static void bch_empty_fifo(struct BCState *bcs, int count); + diff --git a/tests/proto2.c b/tests/proto2.c new file mode 100644 index 0000000..15912ef --- /dev/null +++ b/tests/proto2.c @@ -0,0 +1,10 @@ +static void bch_l2l1(struct PStack *st, int pr, void *arg); +static void bch_sched_event(struct BCState *bcs, int event); +static void bch_empty_fifo(struct BCState *bcs, int count); + +static void +bch_sched_event(struct BCState *bcs, int event) +{ + bcs->event |= 1 << event; + schedule_work(&bcs->work); +} diff --git a/tests/proto2.cocci b/tests/proto2.cocci new file mode 100644 index 0000000..d81678e --- /dev/null +++ b/tests/proto2.cocci @@ -0,0 +1,11 @@ +@@ +identifier fn2; +identifier bcs, ev; +@@ + +- fn2(struct BCState *bcs, int ev) { ++ fn2(int ev) { + ... + bcs->event |= 1 << ev; + schedule_work(&bcs->work); + } diff --git a/tests/proto2.res b/tests/proto2.res new file mode 100644 index 0000000..fe069ca --- /dev/null +++ b/tests/proto2.res @@ -0,0 +1,10 @@ +static void bch_l2l1(struct PStack *st, int pr, void *arg); +static void bch_sched_event(int event); +static void bch_empty_fifo(struct BCState *bcs, int count); + +static void +bch_sched_event(int event) +{ + bcs->event |= 1 << event; + schedule_work(&bcs->work); +} diff --git a/tests/proto_ver1.c b/tests/proto_ver1.c new file mode 100644 index 0000000..c9ca3e0 --- /dev/null +++ b/tests/proto_ver1.c @@ -0,0 +1,10 @@ +void bch_l2l1(struct PStack *st, int pr, void *arg); +void bch_sched_event(struct BCState *bcs, int event); +void bch_empty_fifo(struct BCState *bcs, int count); + +void +bch_sched_event(struct BCState *bcs, int event) +{ + bcs->event |= 1 << event; + schedule_work(&bcs->work); +} diff --git a/tests/proto_ver1.res b/tests/proto_ver1.res new file mode 100644 index 0000000..4d4c1a0 --- /dev/null +++ b/tests/proto_ver1.res @@ -0,0 +1,3 @@ +void bch_l2l1(struct PStack *st, int pr, void *arg); +void bch_empty_fifo(struct BCState *bcs, int count); + diff --git a/tests/proto_ver2.c b/tests/proto_ver2.c new file mode 100644 index 0000000..b999774 --- /dev/null +++ b/tests/proto_ver2.c @@ -0,0 +1,997 @@ +/* + * + * IPACX specific routines + * + * Author Joerg Petersohn + * Derived from hisax_isac.c, isac.c, hscx.c and others + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ +#include +#include +#include +#include +#include "hisax_if.h" +#include "hisax.h" +#include "isdnl1.h" +#include "ipacx.h" + +#define DBUSY_TIMER_VALUE 80 +#define TIMER3_VALUE 7000 +#define MAX_DFRAME_LEN_L1 300 +#define B_FIFO_SIZE 64 +#define D_FIFO_SIZE 32 +static spinlock_t ipacx_lock = SPIN_LOCK_UNLOCKED; + +// ipacx interrupt mask values +#define _MASK_IMASK 0x2E // global mask +#define _MASKB_IMASK 0x0B +#define _MASKD_IMASK 0x03 // all on + +//---------------------------------------------------------- +// local function declarations +//---------------------------------------------------------- +static void ph_command(struct IsdnCardState *cs, unsigned int command); +static inline void cic_int(struct IsdnCardState *cs); +static void dch_l2l1(struct PStack *st, int pr, void *arg); +static void dbusy_timer_handler(struct IsdnCardState *cs); +static void ipacx_new_ph(struct IsdnCardState *cs); +static void dch_bh(void *data); +static void dch_sched_event(struct IsdnCardState *cs, int event); +static void dch_empty_fifo(struct IsdnCardState *cs, int count); +static void dch_fill_fifo(struct IsdnCardState *cs); +static inline void dch_int(struct IsdnCardState *cs); +static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs); +static void __devinit dch_init(struct IsdnCardState *cs); +static void bch_l2l1(struct PStack *st, int pr, void *arg); +static void bch_sched_event(struct BCState *bcs, int event); +static void bch_empty_fifo(struct BCState *bcs, int count); +static void bch_fill_fifo(struct BCState *bcs); +static void bch_int(struct IsdnCardState *cs, u_char hscx); +static void bch_mode(struct BCState *bcs, int mode, int bc); +static void bch_close_state(struct BCState *bcs); +static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs); +static int bch_setstack(struct PStack *st, struct BCState *bcs); +static void __devinit bch_init(struct IsdnCardState *cs, int hscx); +static void __init clear_pending_ints(struct IsdnCardState *cs); + +//---------------------------------------------------------- +// Issue Layer 1 command to chip +//---------------------------------------------------------- +static void +ph_command(struct IsdnCardState *cs, unsigned int command) +{ + if (cs->debug &L1_DEB_ISAC) + debugl1(cs, "ph_command (%#x) in (%#x)", command, + cs->dc.isac.ph_state); + cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E); +} + +//---------------------------------------------------------- +// Transceiver interrupt handler +//---------------------------------------------------------- +static inline void +cic_int(struct IsdnCardState *cs) +{ + u_char event; + + event = cs->readisac(cs, IPACX_CIR0) >> 4; + if (cs->debug &L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event); + cs->dc.isac.ph_state = event; + dch_sched_event(cs, D_L1STATECHANGE); +} + +//========================================================== +// D channel functions +//========================================================== + +//---------------------------------------------------------- +// Command entry point +//---------------------------------------------------------- +static void +dch_l2l1(struct PStack *st, int pr, void *arg) +{ + struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; + struct sk_buff *skb = arg; + u_char cda1_cr, cda2_cr; + + switch (pr) { + case (PH_DATA |REQUEST): + if (cs->debug &DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); + if (cs->debug &DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG + if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG + if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + dch_fill_fifo(cs); + } + break; + + case (PH_PULL |INDICATION): + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + break; + } + if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG + if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + dch_fill_fifo(cs); + break; + + case (PH_PULL | REQUEST): +#ifdef L2FRAME_DEBUG + if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l2.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + + case (HW_RESET | REQUEST): + case (HW_ENABLE | REQUEST): + ph_command(cs, IPACX_CMD_TIM); + break; + + case (HW_INFO3 | REQUEST): + ph_command(cs, IPACX_CMD_AR8); + break; + + case (HW_TESTLOOP | REQUEST): + cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1 + cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1 + cda1_cr = cs->readisac(cs, IPACX_CDA1_CR); + cda2_cr = cs->readisac(cs, IPACX_CDA2_CR); + if ((long)arg &1) { // loop B1 + cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x0a); + } + else { // B1 off + cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x0a); + } + if ((long)arg &2) { // loop B2 + cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x14); + } + else { // B2 off + cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x14); + } + break; + + case (HW_DEACTIVATE | RESPONSE): + skb_queue_purge(&cs->rq); + skb_queue_purge(&cs->sq); + if (cs->tx_skb) { + dev_kfree_skb_any(cs->tx_skb); + cs->tx_skb = NULL; + } + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + break; + + default: + if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr); + break; + } +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static void +dbusy_timer_handler(struct IsdnCardState *cs) +{ + struct PStack *st; + int rbchd, stard; + + if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + rbchd = cs->readisac(cs, IPACX_RBCHD); + stard = cs->readisac(cs, IPACX_STARD); + if (cs->debug) + debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard); + if (!(stard &0x40)) { // D-Channel Busy + set_bit(FLG_L1_DBUSY, &cs->HW_Flags); + for (st = cs->stlist; st; st = st->next) { + st->l2.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on + } + } else { + // seems we lost an interrupt; reset transceiver */ + clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); + if (cs->tx_skb) { + dev_kfree_skb_any(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } else { + printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n"); + debugl1(cs, "D-Channel Busy no skb"); + } + cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR + } + } +} + +//---------------------------------------------------------- +// L1 state machine intermediate layer to isdnl1 module +//---------------------------------------------------------- +static void +ipacx_new_ph(struct IsdnCardState *cs) +{ + switch (cs->dc.isac.ph_state) { + case (IPACX_IND_RES): + ph_command(cs, IPACX_CMD_DI); + l1_msg(cs, HW_RESET | INDICATION, NULL); + break; + + case (IPACX_IND_DC): + l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); + break; + + case (IPACX_IND_DR): + l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); + break; + + case (IPACX_IND_PU): + l1_msg(cs, HW_POWERUP | CONFIRM, NULL); + break; + + case (IPACX_IND_RSY): + l1_msg(cs, HW_RSYNC | INDICATION, NULL); + break; + + case (IPACX_IND_AR): + l1_msg(cs, HW_INFO2 | INDICATION, NULL); + break; + + case (IPACX_IND_AI8): + l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); + break; + + case (IPACX_IND_AI10): + l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL); + break; + + default: + break; + } +} + +//---------------------------------------------------------- +// bottom half handler for D channel +//---------------------------------------------------------- +static void +dch_bh(void *data) +{ + struct IsdnCardState *cs = data; + struct PStack *st; + + if (!cs) return; + + if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { + if (cs->debug) debugl1(cs, "D-Channel Busy cleared"); + for (st = cs->stlist; st; st = st->next) { + st->l2.l1l2(st, PH_PAUSE | CONFIRM, NULL); + } + } + + if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) { + DChannel_proc_rcv(cs); + } + + if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) { + DChannel_proc_xmt(cs); + } + + if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { + ipacx_new_ph(cs); + } +} + +//---------------------------------------------------------- +// proceed with bottom half handler dch_bh() +//---------------------------------------------------------- +static void +dch_sched_event(struct IsdnCardState *cs, int event) +{ + set_bit(event, &cs->event); + schedule_work(&cs->work); +} + +//---------------------------------------------------------- +// Fill buffer from receive FIFO +//---------------------------------------------------------- +static void +dch_empty_fifo(struct IsdnCardState *cs, int count) +{ + unsigned long flags; + u_char *ptr; + + if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO)) + debugl1(cs, "dch_empty_fifo()"); + + // message too large, remove + if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "dch_empty_fifo() incoming message too large"); + cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC + cs->rcvidx = 0; + return; + } + + ptr = cs->rcvbuf + cs->rcvidx; + cs->rcvidx += count; + + spin_lock_irqsave(&ipacx_lock, flags); + cs->readisacfifo(cs, ptr, count); + cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC + spin_unlock_irqrestore(&ipacx_lock, flags); + + if (cs->debug &L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "dch_empty_fifo() cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } +} + +//---------------------------------------------------------- +// Fill transmit FIFO +//---------------------------------------------------------- +static void +dch_fill_fifo(struct IsdnCardState *cs) +{ + unsigned long flags; + int count; + u_char cmd, *ptr; + + if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO)) + debugl1(cs, "dch_fill_fifo()"); + + if (!cs->tx_skb) return; + count = cs->tx_skb->len; + if (count <= 0) return; + + if (count > D_FIFO_SIZE) { + count = D_FIFO_SIZE; + cmd = 0x08; // XTF + } else { + cmd = 0x0A; // XTF | XME + } + + spin_lock_irqsave(&ipacx_lock, flags); + ptr = cs->tx_skb->data; + skb_pull(cs->tx_skb, count); + cs->tx_cnt += count; + cs->writeisacfifo(cs, ptr, count); + cs->writeisac(cs, IPACX_CMDRD, cmd); + + // set timeout for transmission contol + if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + debugl1(cs, "dch_fill_fifo dbusytimer running"); + del_timer(&cs->dbusytimer); + } + init_timer(&cs->dbusytimer); + cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); + add_timer(&cs->dbusytimer); + spin_unlock_irqrestore(&ipacx_lock, flags); + + if (cs->debug &L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "dch_fill_fifo() cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } +} + +//---------------------------------------------------------- +// D channel interrupt handler +//---------------------------------------------------------- +static inline void +dch_int(struct IsdnCardState *cs) +{ + struct sk_buff *skb; + u_char istad, rstad; + unsigned long flags; + int count; + + istad = cs->readisac(cs, IPACX_ISTAD); + + if (istad &0x80) { // RME + rstad = cs->readisac(cs, IPACX_RSTAD); + if ((rstad &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB) + if (!(rstad &0x80)) + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "dch_int(): invalid frame"); + if ((rstad &0x40)) + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "dch_int(): RDO"); + if (!(rstad &0x20)) + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "dch_int(): CRC error"); + cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC + } else { // received frame ok + count = cs->readisac(cs, IPACX_RBCLD); + if (count) count--; // RSTAB is last byte + count &= D_FIFO_SIZE-1; + if (count == 0) count = D_FIFO_SIZE; + dch_empty_fifo(cs, count); + spin_lock_irqsave(&ipacx_lock, flags); + if ((count = cs->rcvidx) > 0) { + cs->rcvidx = 0; + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n"); + else { + memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_queue_tail(&cs->rq, skb); + } + } + spin_unlock_irqrestore(&ipacx_lock, flags); + } + cs->rcvidx = 0; + dch_sched_event(cs, D_RCVBUFREADY); + } + + if (istad &0x40) { // RPF + dch_empty_fifo(cs, D_FIFO_SIZE); + } + + if (istad &0x20) { // RFO + if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): RFO"); + cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES + } + + if (istad &0x10) { // XPR + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + dch_sched_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + dch_fill_fifo(cs); + goto afterXPR; + } + else { + dev_kfree_skb_irq(cs->tx_skb); + cs->tx_skb = NULL; + cs->tx_cnt = 0; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + dch_fill_fifo(cs); + } + else { + dch_sched_event(cs, D_XMTBUFREADY); + } + } + afterXPR: + + if (istad &0x0C) { // XDU or XMR + if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): XDU"); + if (cs->tx_skb) { + skb_push(cs->tx_skb, cs->tx_cnt); // retransmit + cs->tx_cnt = 0; + dch_fill_fifo(cs); + } else { + printk(KERN_WARNING "HiSax: ISAC XDU no skb\n"); + debugl1(cs, "ISAC XDU no skb"); + } + } +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static void __devinit +dch_setstack(struct PStack *st, struct IsdnCardState *cs) +{ + st->l1.l1hw = dch_l2l1; +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static void __devinit +dch_init(struct IsdnCardState *cs) +{ + printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n"); + + INIT_WORK(&cs->work, dch_bh, cs); + cs->setstack_d = dch_setstack; + + cs->dbusytimer.function = (void *) dbusy_timer_handler; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); + + cs->writeisac(cs, IPACX_TR_CONF0, 0x00); // clear LDD + cs->writeisac(cs, IPACX_TR_CONF2, 0x00); // enable transmitter + cs->writeisac(cs, IPACX_MODED, 0xC9); // transparent mode 0, RAC, stop/go + cs->writeisac(cs, IPACX_MON_CR, 0x00); // disable monitor channel +} + + +//========================================================== +// B channel functions +//========================================================== + +//---------------------------------------------------------- +// Entry point for commands +//---------------------------------------------------------- +static void +bch_l2l1(struct PStack *st, int pr, void *arg) +{ + struct sk_buff *skb = arg; + unsigned long flags; + + switch (pr) { + case (PH_DATA | REQUEST): + spin_lock_irqsave(&ipacx_lock, flags); + if (st->l1.bcs->tx_skb) { + skb_queue_tail(&st->l1.bcs->squeue, skb); + spin_unlock_irqrestore(&ipacx_lock, flags); + } else { + st->l1.bcs->tx_skb = skb; + set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + st->l1.bcs->hw.hscx.count = 0; + spin_unlock_irqrestore(&ipacx_lock, flags); + bch_fill_fifo(st->l1.bcs); + } + break; + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { + printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n"); + break; + } + set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + st->l1.bcs->tx_skb = skb; + st->l1.bcs->hw.hscx.count = 0; + bch_fill_fifo(st->l1.bcs); + break; + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { + clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l2.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (PH_ACTIVATE | REQUEST): + set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + bch_mode(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + bch_mode(st->l1.bcs, 0, st->l1.bc); + st->l2.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; + } +} + +//---------------------------------------------------------- +// proceed with bottom half handler BChannel_bh() +//---------------------------------------------------------- +static void +bch_sched_event(struct BCState *bcs, int event) +{ + bcs->event |= 1 << event; + schedule_work(&bcs->work); +} + +//---------------------------------------------------------- +// Read B channel fifo to receive buffer +//---------------------------------------------------------- +static void +bch_empty_fifo(struct BCState *bcs, int count) +{ + u_char *ptr, hscx; + struct IsdnCardState *cs; + unsigned long flags; + int cnt; + + cs = bcs->cs; + hscx = bcs->hw.hscx.hscx; + if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO)) + debugl1(cs, "bch_empty_fifo()"); + + // message too large, remove + if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_empty_fifo() incoming packet too large"); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC + bcs->hw.hscx.rcvidx = 0; + return; + } + + // Read data uninterruptible + spin_lock_irqsave(&ipacx_lock, flags); + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + cnt = count; + while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC + + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + bcs->hw.hscx.rcvidx += count; + spin_unlock_irqrestore(&ipacx_lock, flags); + + if (cs->debug &L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } +} + +//---------------------------------------------------------- +// Fill buffer to transmit FIFO +//---------------------------------------------------------- +static void +bch_fill_fifo(struct BCState *bcs) +{ + struct IsdnCardState *cs; + int more, count, cnt; + u_char *ptr, *p, hscx; + unsigned long flags; + + cs = bcs->cs; + if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO)) + debugl1(cs, "bch_fill_fifo()"); + + if (!bcs->tx_skb) return; + if (bcs->tx_skb->len <= 0) return; + + hscx = bcs->hw.hscx.hscx; + more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; + if (bcs->tx_skb->len > B_FIFO_SIZE) { + more = 1; + count = B_FIFO_SIZE; + } else { + count = bcs->tx_skb->len; + } + cnt = count; + + spin_lock_irqsave(&ipacx_lock, flags); + p = ptr = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); + bcs->tx_cnt -= count; + bcs->hw.hscx.count += count; + while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a)); + spin_unlock_irqrestore(&ipacx_lock, flags); + + if (cs->debug &L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "chb_fill_fifo() B-%d cnt %d", hscx, count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } +} + +//---------------------------------------------------------- +// B channel interrupt handler +//---------------------------------------------------------- +static void +bch_int(struct IsdnCardState *cs, u_char hscx) +{ + u_char istab; + struct BCState *bcs; + struct sk_buff *skb; + int count; + u_char rstab; + + bcs = cs->bcs + hscx; + istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB); + if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return; + + if (istab &0x80) { // RME + rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB); + if ((rstab &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB) + if (!(rstab &0x80)) + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_int() B-%d: invalid frame", hscx); + if ((rstab &0x40) && (bcs->mode != L1_MODE_NULL)) + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode); + if (!(rstab &0x20)) + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_int() B-%d: CRC error", hscx); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC + } + else { // received frame ok + count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) &(B_FIFO_SIZE-1); + if (count == 0) count = B_FIFO_SIZE; + bch_empty_fifo(bcs, count); + if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { + if (cs->debug &L1_DEB_HSCX_FIFO) + debugl1(cs, "bch_int Frame %d", count); + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n"); + else { + memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); + skb_queue_tail(&bcs->rqueue, skb); + } + } + } + bcs->hw.hscx.rcvidx = 0; + bch_sched_event(bcs, B_RCVBUFREADY); + } + + if (istab &0x40) { // RPF + bch_empty_fifo(bcs, B_FIFO_SIZE); + + if (bcs->mode == L1_MODE_TRANS) { // queue every chunk + // receive transparent audio data + if (!(skb = dev_alloc_skb(B_FIFO_SIZE))) + printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n"); + else { + memcpy(skb_put(skb, B_FIFO_SIZE), bcs->hw.hscx.rcvbuf, B_FIFO_SIZE); + skb_queue_tail(&bcs->rqueue, skb); + } + bcs->hw.hscx.rcvidx = 0; + bch_sched_event(bcs, B_RCVBUFREADY); + } + } + + if (istab &0x20) { // RFO + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_int() B-%d: RFO error", hscx); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES + } + + if (istab &0x10) { // XPR + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + bch_fill_fifo(bcs); + goto afterXPR; + } + skb_queue_tail(&bcs->cmpl_queue, bcs->tx_skb); + bch_sched_event(bcs, B_CMPLREADY); + bcs->hw.hscx.count = 0; + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hscx.count = 0; + set_bit(BC_FLG_BUSY, &bcs->Flag); + bch_fill_fifo(bcs); + } else { + clear_bit(BC_FLG_BUSY, &bcs->Flag); + bch_sched_event(bcs, B_XMTBUFREADY); + } + } + afterXPR: + + if (istab &0x04) { // XDU + if (bcs->mode == L1_MODE_TRANS) { + bch_fill_fifo(bcs); + } + else { + if (bcs->tx_skb) { // restart transmitting the whole frame + skb_push(bcs->tx_skb, bcs->hw.hscx.count); + bcs->tx_cnt += bcs->hw.hscx.count; + bcs->hw.hscx.count = 0; + } + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01); // XRES + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_int() B-%d XDU error", hscx); + } + } +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static void +bch_mode(struct BCState *bcs, int mode, int bc) +{ + struct IsdnCardState *cs = bcs->cs; + int hscx = bcs->hw.hscx.hscx; + + bc = bc ? 1 : 0; // in case bc is greater than 1 + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "mode_bch() switch B-% mode %d chan %d", hscx, mode, bc); + bcs->mode = mode; + bcs->channel = bc; + + // map controller to according timeslot + if (!hscx) + { + cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc); + cs->writeisac(cs, IPACX_BCHA_CR, 0x88); + } + else + { + cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc); + cs->writeisac(cs, IPACX_BCHB_CR, 0x88); + } + + switch (mode) { + case (L1_MODE_NULL): + cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0); // rec off + cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x30); // std adj. + cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF); // ints off + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments + break; + case (L1_MODE_TRANS): + cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88); // ext transp mode + cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x00); // xxx00000 + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments + cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK); + break; + case (L1_MODE_HDLC): + cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8); // transp mode 0 + cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x01); // idle=hdlc flags crc enabled + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments + cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK); + break; + } +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static void +bch_close_state(struct BCState *bcs) +{ + bch_mode(bcs, 0, bcs->channel); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + if (bcs->hw.hscx.rcvbuf) { + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + } + if (bcs->blog) { + kfree(bcs->blog); + bcs->blog = NULL; + } + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); + if (bcs->tx_skb) { + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; + clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + } +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static int +bch_open_state(struct IsdnCardState *cs, struct BCState *bcs) +{ + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax open_bchstate(): No memory for hscx.rcvbuf\n"); + clear_bit(BC_FLG_INIT, &bcs->Flag); + return (1); + } + if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax open_bchstate: No memory for bcs->blog\n"); + clear_bit(BC_FLG_INIT, &bcs->Flag); + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + return (2); + } + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } + bcs->tx_skb = NULL; + clear_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->event = 0; + bcs->hw.hscx.rcvidx = 0; + bcs->tx_cnt = 0; + return (0); +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static int +bch_setstack(struct PStack *st, struct BCState *bcs) +{ + bcs->channel = st->l1.bc; + if (bch_open_state(st->l1.hardware, bcs)) return (-1); + st->l1.bcs = bcs; + st->l1.l2l1 = bch_l2l1; + setstack_manager(st); + bcs->st = st; + setstack_l1_B(st); + return (0); +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static void __devinit +bch_init(struct IsdnCardState *cs, int hscx) +{ + cs->bcs[hscx].BC_SetStack = bch_setstack; + cs->bcs[hscx].BC_Close = bch_close_state; + cs->bcs[hscx].hw.hscx.hscx = hscx; + cs->bcs[hscx].cs = cs; + bch_mode(cs->bcs + hscx, 0, hscx); +} + + +//========================================================== +// Shared functions +//========================================================== + +//---------------------------------------------------------- +// Main interrupt handler +//---------------------------------------------------------- +void +interrupt_ipacx(struct IsdnCardState *cs) +{ + u_char ista; + + while ((ista = cs->readisac(cs, IPACX_ISTA))) { + if (ista &0x80) bch_int(cs, 0); // B channel interrupts + if (ista &0x40) bch_int(cs, 1); + if (ista &0x01) dch_int(cs); // D channel + if (ista &0x10) cic_int(cs); // Layer 1 state + } +} + +//---------------------------------------------------------- +// Clears chip interrupt status +//---------------------------------------------------------- +static void __init +clear_pending_ints(struct IsdnCardState *cs) +{ + int ista; + + // all interrupts off + cs->writeisac(cs, IPACX_MASK, 0xff); + cs->writeisac(cs, IPACX_MASKD, 0xff); + cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff); + cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff); + + ista = cs->readisac(cs, IPACX_ISTA); + if (ista &0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB); + if (ista &0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB); + if (ista &0x10) cs->readisac(cs, IPACX_CIR0); + if (ista &0x01) cs->readisac(cs, IPACX_ISTAD); +} + +//---------------------------------------------------------- +// Does chip configuration work +// Work to do depends on bit mask in part +//---------------------------------------------------------- +void __init +init_ipacx(struct IsdnCardState *cs, int part) +{ + if (part &1) { // initialise chip + clear_pending_ints(cs); + bch_init(cs, 0); + bch_init(cs, 1); + dch_init(cs); + } + if (part &2) { // reenable all interrupts and start chip + cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK); + cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK); + cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK); + cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register + + // reset HDLC Transmitters/receivers + cs->writeisac(cs, IPACX_CMDRD, 0x41); + cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41); + cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41); + ph_command(cs, IPACX_CMD_RES); + } +} + +//----------------- end of file ----------------------- + diff --git a/tests/proto_ver2.res b/tests/proto_ver2.res new file mode 100644 index 0000000..c453242 --- /dev/null +++ b/tests/proto_ver2.res @@ -0,0 +1,987 @@ +/* + * + * IPACX specific routines + * + * Author Joerg Petersohn + * Derived from hisax_isac.c, isac.c, hscx.c and others + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ +#include +#include +#include +#include +#include "hisax_if.h" +#include "hisax.h" +#include "isdnl1.h" +#include "ipacx.h" + +#define DBUSY_TIMER_VALUE 80 +#define TIMER3_VALUE 7000 +#define MAX_DFRAME_LEN_L1 300 +#define B_FIFO_SIZE 64 +#define D_FIFO_SIZE 32 +static spinlock_t ipacx_lock = SPIN_LOCK_UNLOCKED; + +// ipacx interrupt mask values +#define _MASK_IMASK 0x2E // global mask +#define _MASKB_IMASK 0x0B +#define _MASKD_IMASK 0x03 // all on + +//---------------------------------------------------------- +// local function declarations +//---------------------------------------------------------- +static void ph_command(struct IsdnCardState *cs, unsigned int command); +static inline void cic_int(struct IsdnCardState *cs); +static void dch_l2l1(struct PStack *st, int pr, void *arg); +static void dbusy_timer_handler(struct IsdnCardState *cs); +static void ipacx_new_ph(struct IsdnCardState *cs); +static void dch_bh(void *data); +static void dch_sched_event(struct IsdnCardState *cs, int event); +static void dch_empty_fifo(struct IsdnCardState *cs, int count); +static void dch_fill_fifo(struct IsdnCardState *cs); +static inline void dch_int(struct IsdnCardState *cs); +static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs); +static void __devinit dch_init(struct IsdnCardState *cs); +static void bch_l2l1(struct PStack *st, int pr, void *arg); +static void bch_empty_fifo(struct BCState *bcs, int count); +static void bch_fill_fifo(struct BCState *bcs); +static void bch_int(struct IsdnCardState *cs, u_char hscx); +static void bch_mode(struct BCState *bcs, int mode, int bc); +static void bch_close_state(struct BCState *bcs); +static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs); +static int bch_setstack(struct PStack *st, struct BCState *bcs); +static void __devinit bch_init(struct IsdnCardState *cs, int hscx); +static void __init clear_pending_ints(struct IsdnCardState *cs); + +//---------------------------------------------------------- +// Issue Layer 1 command to chip +//---------------------------------------------------------- +static void +ph_command(struct IsdnCardState *cs, unsigned int command) +{ + if (cs->debug &L1_DEB_ISAC) + debugl1(cs, "ph_command (%#x) in (%#x)", command, + cs->dc.isac.ph_state); + cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E); +} + +//---------------------------------------------------------- +// Transceiver interrupt handler +//---------------------------------------------------------- +static inline void +cic_int(struct IsdnCardState *cs) +{ + u_char event; + + event = cs->readisac(cs, IPACX_CIR0) >> 4; + if (cs->debug &L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event); + cs->dc.isac.ph_state = event; + dch_sched_event(cs, D_L1STATECHANGE); +} + +//========================================================== +// D channel functions +//========================================================== + +//---------------------------------------------------------- +// Command entry point +//---------------------------------------------------------- +static void +dch_l2l1(struct PStack *st, int pr, void *arg) +{ + struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; + struct sk_buff *skb = arg; + u_char cda1_cr, cda2_cr; + + switch (pr) { + case (PH_DATA |REQUEST): + if (cs->debug &DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); + if (cs->debug &DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG + if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG + if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + dch_fill_fifo(cs); + } + break; + + case (PH_PULL |INDICATION): + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + break; + } + if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG + if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + dch_fill_fifo(cs); + break; + + case (PH_PULL | REQUEST): +#ifdef L2FRAME_DEBUG + if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l2.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + + case (HW_RESET | REQUEST): + case (HW_ENABLE | REQUEST): + ph_command(cs, IPACX_CMD_TIM); + break; + + case (HW_INFO3 | REQUEST): + ph_command(cs, IPACX_CMD_AR8); + break; + + case (HW_TESTLOOP | REQUEST): + cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1 + cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1 + cda1_cr = cs->readisac(cs, IPACX_CDA1_CR); + cda2_cr = cs->readisac(cs, IPACX_CDA2_CR); + if ((long)arg &1) { // loop B1 + cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x0a); + } + else { // B1 off + cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x0a); + } + if ((long)arg &2) { // loop B2 + cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x14); + } + else { // B2 off + cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x14); + } + break; + + case (HW_DEACTIVATE | RESPONSE): + skb_queue_purge(&cs->rq); + skb_queue_purge(&cs->sq); + if (cs->tx_skb) { + dev_kfree_skb_any(cs->tx_skb); + cs->tx_skb = NULL; + } + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + break; + + default: + if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr); + break; + } +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static void +dbusy_timer_handler(struct IsdnCardState *cs) +{ + struct PStack *st; + int rbchd, stard; + + if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + rbchd = cs->readisac(cs, IPACX_RBCHD); + stard = cs->readisac(cs, IPACX_STARD); + if (cs->debug) + debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard); + if (!(stard &0x40)) { // D-Channel Busy + set_bit(FLG_L1_DBUSY, &cs->HW_Flags); + for (st = cs->stlist; st; st = st->next) { + st->l2.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on + } + } else { + // seems we lost an interrupt; reset transceiver */ + clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); + if (cs->tx_skb) { + dev_kfree_skb_any(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } else { + printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n"); + debugl1(cs, "D-Channel Busy no skb"); + } + cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR + } + } +} + +//---------------------------------------------------------- +// L1 state machine intermediate layer to isdnl1 module +//---------------------------------------------------------- +static void +ipacx_new_ph(struct IsdnCardState *cs) +{ + switch (cs->dc.isac.ph_state) { + case (IPACX_IND_RES): + ph_command(cs, IPACX_CMD_DI); + l1_msg(cs, HW_RESET | INDICATION, NULL); + break; + + case (IPACX_IND_DC): + l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); + break; + + case (IPACX_IND_DR): + l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); + break; + + case (IPACX_IND_PU): + l1_msg(cs, HW_POWERUP | CONFIRM, NULL); + break; + + case (IPACX_IND_RSY): + l1_msg(cs, HW_RSYNC | INDICATION, NULL); + break; + + case (IPACX_IND_AR): + l1_msg(cs, HW_INFO2 | INDICATION, NULL); + break; + + case (IPACX_IND_AI8): + l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); + break; + + case (IPACX_IND_AI10): + l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL); + break; + + default: + break; + } +} + +//---------------------------------------------------------- +// bottom half handler for D channel +//---------------------------------------------------------- +static void +dch_bh(void *data) +{ + struct IsdnCardState *cs = data; + struct PStack *st; + + if (!cs) return; + + if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { + if (cs->debug) debugl1(cs, "D-Channel Busy cleared"); + for (st = cs->stlist; st; st = st->next) { + st->l2.l1l2(st, PH_PAUSE | CONFIRM, NULL); + } + } + + if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) { + DChannel_proc_rcv(cs); + } + + if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) { + DChannel_proc_xmt(cs); + } + + if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { + ipacx_new_ph(cs); + } +} + +//---------------------------------------------------------- +// proceed with bottom half handler dch_bh() +//---------------------------------------------------------- +static void +dch_sched_event(struct IsdnCardState *cs, int event) +{ + set_bit(event, &cs->event); + schedule_work(&cs->work); +} + +//---------------------------------------------------------- +// Fill buffer from receive FIFO +//---------------------------------------------------------- +static void +dch_empty_fifo(struct IsdnCardState *cs, int count) +{ + unsigned long flags; + u_char *ptr; + + if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO)) + debugl1(cs, "dch_empty_fifo()"); + + // message too large, remove + if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "dch_empty_fifo() incoming message too large"); + cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC + cs->rcvidx = 0; + return; + } + + ptr = cs->rcvbuf + cs->rcvidx; + cs->rcvidx += count; + + spin_lock_irqsave(&ipacx_lock, flags); + cs->readisacfifo(cs, ptr, count); + cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC + spin_unlock_irqrestore(&ipacx_lock, flags); + + if (cs->debug &L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "dch_empty_fifo() cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } +} + +//---------------------------------------------------------- +// Fill transmit FIFO +//---------------------------------------------------------- +static void +dch_fill_fifo(struct IsdnCardState *cs) +{ + unsigned long flags; + int count; + u_char cmd, *ptr; + + if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO)) + debugl1(cs, "dch_fill_fifo()"); + + if (!cs->tx_skb) return; + count = cs->tx_skb->len; + if (count <= 0) return; + + if (count > D_FIFO_SIZE) { + count = D_FIFO_SIZE; + cmd = 0x08; // XTF + } else { + cmd = 0x0A; // XTF | XME + } + + spin_lock_irqsave(&ipacx_lock, flags); + ptr = cs->tx_skb->data; + skb_pull(cs->tx_skb, count); + cs->tx_cnt += count; + cs->writeisacfifo(cs, ptr, count); + cs->writeisac(cs, IPACX_CMDRD, cmd); + + // set timeout for transmission contol + if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + debugl1(cs, "dch_fill_fifo dbusytimer running"); + del_timer(&cs->dbusytimer); + } + init_timer(&cs->dbusytimer); + cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); + add_timer(&cs->dbusytimer); + spin_unlock_irqrestore(&ipacx_lock, flags); + + if (cs->debug &L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "dch_fill_fifo() cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } +} + +//---------------------------------------------------------- +// D channel interrupt handler +//---------------------------------------------------------- +static inline void +dch_int(struct IsdnCardState *cs) +{ + struct sk_buff *skb; + u_char istad, rstad; + unsigned long flags; + int count; + + istad = cs->readisac(cs, IPACX_ISTAD); + + if (istad &0x80) { // RME + rstad = cs->readisac(cs, IPACX_RSTAD); + if ((rstad &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB) + if (!(rstad &0x80)) + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "dch_int(): invalid frame"); + if ((rstad &0x40)) + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "dch_int(): RDO"); + if (!(rstad &0x20)) + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "dch_int(): CRC error"); + cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC + } else { // received frame ok + count = cs->readisac(cs, IPACX_RBCLD); + if (count) count--; // RSTAB is last byte + count &= D_FIFO_SIZE-1; + if (count == 0) count = D_FIFO_SIZE; + dch_empty_fifo(cs, count); + spin_lock_irqsave(&ipacx_lock, flags); + if ((count = cs->rcvidx) > 0) { + cs->rcvidx = 0; + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n"); + else { + memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_queue_tail(&cs->rq, skb); + } + } + spin_unlock_irqrestore(&ipacx_lock, flags); + } + cs->rcvidx = 0; + dch_sched_event(cs, D_RCVBUFREADY); + } + + if (istad &0x40) { // RPF + dch_empty_fifo(cs, D_FIFO_SIZE); + } + + if (istad &0x20) { // RFO + if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): RFO"); + cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES + } + + if (istad &0x10) { // XPR + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + dch_sched_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + dch_fill_fifo(cs); + goto afterXPR; + } + else { + dev_kfree_skb_irq(cs->tx_skb); + cs->tx_skb = NULL; + cs->tx_cnt = 0; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + dch_fill_fifo(cs); + } + else { + dch_sched_event(cs, D_XMTBUFREADY); + } + } + afterXPR: + + if (istad &0x0C) { // XDU or XMR + if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): XDU"); + if (cs->tx_skb) { + skb_push(cs->tx_skb, cs->tx_cnt); // retransmit + cs->tx_cnt = 0; + dch_fill_fifo(cs); + } else { + printk(KERN_WARNING "HiSax: ISAC XDU no skb\n"); + debugl1(cs, "ISAC XDU no skb"); + } + } +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static void __devinit +dch_setstack(struct PStack *st, struct IsdnCardState *cs) +{ + st->l1.l1hw = dch_l2l1; +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static void __devinit +dch_init(struct IsdnCardState *cs) +{ + printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n"); + + INIT_WORK(&cs->work, dch_bh, cs); + cs->setstack_d = dch_setstack; + + cs->dbusytimer.function = (void *) dbusy_timer_handler; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); + + cs->writeisac(cs, IPACX_TR_CONF0, 0x00); // clear LDD + cs->writeisac(cs, IPACX_TR_CONF2, 0x00); // enable transmitter + cs->writeisac(cs, IPACX_MODED, 0xC9); // transparent mode 0, RAC, stop/go + cs->writeisac(cs, IPACX_MON_CR, 0x00); // disable monitor channel +} + + +//========================================================== +// B channel functions +//========================================================== + +//---------------------------------------------------------- +// Entry point for commands +//---------------------------------------------------------- +static void +bch_l2l1(struct PStack *st, int pr, void *arg) +{ + struct sk_buff *skb = arg; + unsigned long flags; + + switch (pr) { + case (PH_DATA | REQUEST): + spin_lock_irqsave(&ipacx_lock, flags); + if (st->l1.bcs->tx_skb) { + skb_queue_tail(&st->l1.bcs->squeue, skb); + spin_unlock_irqrestore(&ipacx_lock, flags); + } else { + st->l1.bcs->tx_skb = skb; + set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + st->l1.bcs->hw.hscx.count = 0; + spin_unlock_irqrestore(&ipacx_lock, flags); + bch_fill_fifo(st->l1.bcs); + } + break; + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { + printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n"); + break; + } + set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + st->l1.bcs->tx_skb = skb; + st->l1.bcs->hw.hscx.count = 0; + bch_fill_fifo(st->l1.bcs); + break; + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { + clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l2.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (PH_ACTIVATE | REQUEST): + set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + bch_mode(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + bch_mode(st->l1.bcs, 0, st->l1.bc); + st->l2.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; + } +} + + +//---------------------------------------------------------- +// Read B channel fifo to receive buffer +//---------------------------------------------------------- +static void +bch_empty_fifo(struct BCState *bcs, int count) +{ + u_char *ptr, hscx; + struct IsdnCardState *cs; + unsigned long flags; + int cnt; + + cs = bcs->cs; + hscx = bcs->hw.hscx.hscx; + if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO)) + debugl1(cs, "bch_empty_fifo()"); + + // message too large, remove + if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_empty_fifo() incoming packet too large"); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC + bcs->hw.hscx.rcvidx = 0; + return; + } + + // Read data uninterruptible + spin_lock_irqsave(&ipacx_lock, flags); + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + cnt = count; + while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC + + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + bcs->hw.hscx.rcvidx += count; + spin_unlock_irqrestore(&ipacx_lock, flags); + + if (cs->debug &L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } +} + +//---------------------------------------------------------- +// Fill buffer to transmit FIFO +//---------------------------------------------------------- +static void +bch_fill_fifo(struct BCState *bcs) +{ + struct IsdnCardState *cs; + int more, count, cnt; + u_char *ptr, *p, hscx; + unsigned long flags; + + cs = bcs->cs; + if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO)) + debugl1(cs, "bch_fill_fifo()"); + + if (!bcs->tx_skb) return; + if (bcs->tx_skb->len <= 0) return; + + hscx = bcs->hw.hscx.hscx; + more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; + if (bcs->tx_skb->len > B_FIFO_SIZE) { + more = 1; + count = B_FIFO_SIZE; + } else { + count = bcs->tx_skb->len; + } + cnt = count; + + spin_lock_irqsave(&ipacx_lock, flags); + p = ptr = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); + bcs->tx_cnt -= count; + bcs->hw.hscx.count += count; + while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a)); + spin_unlock_irqrestore(&ipacx_lock, flags); + + if (cs->debug &L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "chb_fill_fifo() B-%d cnt %d", hscx, count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } +} + +//---------------------------------------------------------- +// B channel interrupt handler +//---------------------------------------------------------- +static void +bch_int(struct IsdnCardState *cs, u_char hscx) +{ + u_char istab; + struct BCState *bcs; + struct sk_buff *skb; + int count; + u_char rstab; + + bcs = cs->bcs + hscx; + istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB); + if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return; + + if (istab &0x80) { // RME + rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB); + if ((rstab &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB) + if (!(rstab &0x80)) + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_int() B-%d: invalid frame", hscx); + if ((rstab &0x40) && (bcs->mode != L1_MODE_NULL)) + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode); + if (!(rstab &0x20)) + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_int() B-%d: CRC error", hscx); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC + } + else { // received frame ok + count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) &(B_FIFO_SIZE-1); + if (count == 0) count = B_FIFO_SIZE; + bch_empty_fifo(bcs, count); + if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { + if (cs->debug &L1_DEB_HSCX_FIFO) + debugl1(cs, "bch_int Frame %d", count); + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n"); + else { + memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); + skb_queue_tail(&bcs->rqueue, skb); + } + } + } + bcs->hw.hscx.rcvidx = 0; + bch_sched_event(bcs, B_RCVBUFREADY); + } + + if (istab &0x40) { // RPF + bch_empty_fifo(bcs, B_FIFO_SIZE); + + if (bcs->mode == L1_MODE_TRANS) { // queue every chunk + // receive transparent audio data + if (!(skb = dev_alloc_skb(B_FIFO_SIZE))) + printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n"); + else { + memcpy(skb_put(skb, B_FIFO_SIZE), bcs->hw.hscx.rcvbuf, B_FIFO_SIZE); + skb_queue_tail(&bcs->rqueue, skb); + } + bcs->hw.hscx.rcvidx = 0; + bch_sched_event(bcs, B_RCVBUFREADY); + } + } + + if (istab &0x20) { // RFO + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_int() B-%d: RFO error", hscx); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES + } + + if (istab &0x10) { // XPR + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + bch_fill_fifo(bcs); + goto afterXPR; + } + skb_queue_tail(&bcs->cmpl_queue, bcs->tx_skb); + bch_sched_event(bcs, B_CMPLREADY); + bcs->hw.hscx.count = 0; + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hscx.count = 0; + set_bit(BC_FLG_BUSY, &bcs->Flag); + bch_fill_fifo(bcs); + } else { + clear_bit(BC_FLG_BUSY, &bcs->Flag); + bch_sched_event(bcs, B_XMTBUFREADY); + } + } + afterXPR: + + if (istab &0x04) { // XDU + if (bcs->mode == L1_MODE_TRANS) { + bch_fill_fifo(bcs); + } + else { + if (bcs->tx_skb) { // restart transmitting the whole frame + skb_push(bcs->tx_skb, bcs->hw.hscx.count); + bcs->tx_cnt += bcs->hw.hscx.count; + bcs->hw.hscx.count = 0; + } + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01); // XRES + if (cs->debug &L1_DEB_WARN) + debugl1(cs, "bch_int() B-%d XDU error", hscx); + } + } +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static void +bch_mode(struct BCState *bcs, int mode, int bc) +{ + struct IsdnCardState *cs = bcs->cs; + int hscx = bcs->hw.hscx.hscx; + + bc = bc ? 1 : 0; // in case bc is greater than 1 + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "mode_bch() switch B-% mode %d chan %d", hscx, mode, bc); + bcs->mode = mode; + bcs->channel = bc; + + // map controller to according timeslot + if (!hscx) + { + cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc); + cs->writeisac(cs, IPACX_BCHA_CR, 0x88); + } + else + { + cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc); + cs->writeisac(cs, IPACX_BCHB_CR, 0x88); + } + + switch (mode) { + case (L1_MODE_NULL): + cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0); // rec off + cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x30); // std adj. + cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF); // ints off + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments + break; + case (L1_MODE_TRANS): + cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88); // ext transp mode + cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x00); // xxx00000 + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments + cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK); + break; + case (L1_MODE_HDLC): + cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8); // transp mode 0 + cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x01); // idle=hdlc flags crc enabled + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments + cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK); + break; + } +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static void +bch_close_state(struct BCState *bcs) +{ + bch_mode(bcs, 0, bcs->channel); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + if (bcs->hw.hscx.rcvbuf) { + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + } + if (bcs->blog) { + kfree(bcs->blog); + bcs->blog = NULL; + } + skb_queue_purge(&bcs->rqueue); + skb_queue_purge(&bcs->squeue); + if (bcs->tx_skb) { + dev_kfree_skb_any(bcs->tx_skb); + bcs->tx_skb = NULL; + clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + } +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static int +bch_open_state(struct IsdnCardState *cs, struct BCState *bcs) +{ + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax open_bchstate(): No memory for hscx.rcvbuf\n"); + clear_bit(BC_FLG_INIT, &bcs->Flag); + return (1); + } + if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax open_bchstate: No memory for bcs->blog\n"); + clear_bit(BC_FLG_INIT, &bcs->Flag); + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + return (2); + } + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } + bcs->tx_skb = NULL; + clear_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->event = 0; + bcs->hw.hscx.rcvidx = 0; + bcs->tx_cnt = 0; + return (0); +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static int +bch_setstack(struct PStack *st, struct BCState *bcs) +{ + bcs->channel = st->l1.bc; + if (bch_open_state(st->l1.hardware, bcs)) return (-1); + st->l1.bcs = bcs; + st->l1.l2l1 = bch_l2l1; + setstack_manager(st); + bcs->st = st; + setstack_l1_B(st); + return (0); +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +static void __devinit +bch_init(struct IsdnCardState *cs, int hscx) +{ + cs->bcs[hscx].BC_SetStack = bch_setstack; + cs->bcs[hscx].BC_Close = bch_close_state; + cs->bcs[hscx].hw.hscx.hscx = hscx; + cs->bcs[hscx].cs = cs; + bch_mode(cs->bcs + hscx, 0, hscx); +} + + +//========================================================== +// Shared functions +//========================================================== + +//---------------------------------------------------------- +// Main interrupt handler +//---------------------------------------------------------- +void +interrupt_ipacx(struct IsdnCardState *cs) +{ + u_char ista; + + while ((ista = cs->readisac(cs, IPACX_ISTA))) { + if (ista &0x80) bch_int(cs, 0); // B channel interrupts + if (ista &0x40) bch_int(cs, 1); + if (ista &0x01) dch_int(cs); // D channel + if (ista &0x10) cic_int(cs); // Layer 1 state + } +} + +//---------------------------------------------------------- +// Clears chip interrupt status +//---------------------------------------------------------- +static void __init +clear_pending_ints(struct IsdnCardState *cs) +{ + int ista; + + // all interrupts off + cs->writeisac(cs, IPACX_MASK, 0xff); + cs->writeisac(cs, IPACX_MASKD, 0xff); + cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff); + cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff); + + ista = cs->readisac(cs, IPACX_ISTA); + if (ista &0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB); + if (ista &0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB); + if (ista &0x10) cs->readisac(cs, IPACX_CIR0); + if (ista &0x01) cs->readisac(cs, IPACX_ISTAD); +} + +//---------------------------------------------------------- +// Does chip configuration work +// Work to do depends on bit mask in part +//---------------------------------------------------------- +void __init +init_ipacx(struct IsdnCardState *cs, int part) +{ + if (part &1) { // initialise chip + clear_pending_ints(cs); + bch_init(cs, 0); + bch_init(cs, 1); + dch_init(cs); + } + if (part &2) { // reenable all interrupts and start chip + cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK); + cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK); + cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK); + cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register + + // reset HDLC Transmitters/receivers + cs->writeisac(cs, IPACX_CMDRD, 0x41); + cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41); + cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41); + ph_command(cs, IPACX_CMD_RES); + } +} + +//----------------- end of file ----------------------- + diff --git a/tests/protoassert.c b/tests/protoassert.c new file mode 100644 index 0000000..c7a5825 --- /dev/null +++ b/tests/protoassert.c @@ -0,0 +1,6 @@ +static unsigned mii_rd(ioaddr_t ioaddr, u_char phyaddr, u_char phyreg); + +int init(void) +{ + foo(); +} diff --git a/tests/protoassert.cocci b/tests/protoassert.cocci new file mode 100644 index 0000000..9d87696 --- /dev/null +++ b/tests/protoassert.cocci @@ -0,0 +1,10 @@ +@@ +@@ + ++ static struct pcmcia_driver ZZZ_driver = { ++ .owner = THIS_MODULE, ++ }; + + int init (...) { +- foo(); + } diff --git a/tests/protoassert.res b/tests/protoassert.res new file mode 100644 index 0000000..2c69ec9 --- /dev/null +++ b/tests/protoassert.res @@ -0,0 +1,9 @@ +static unsigned mii_rd(ioaddr_t ioaddr, u_char phyaddr, u_char phyreg); + + static struct pcmcia_driver ZZZ_driver = { + .owner = THIS_MODULE, + }; + +int init(void) +{ +} diff --git a/tests/protox.c b/tests/protox.c new file mode 100644 index 0000000..3cba442 --- /dev/null +++ b/tests/protox.c @@ -0,0 +1,3 @@ +int f(int x); + +int f(int x) { return 12; } diff --git a/tests/protox.cocci b/tests/protox.cocci new file mode 100644 index 0000000..7c33c7e --- /dev/null +++ b/tests/protox.cocci @@ -0,0 +1,17 @@ +// before handling "depends on", when julia was generating +// from this rule the rule to modify the corresponding prototype, +// this rule was applied whatever happend an in particular +// this SP will not match the .c because return x <> return 12 +// but its prototype will still be modified :( + +// with "depends on" the prototype is changed only if the +// function is matched and transformed. + + +@@ +@@ + +- f(int x) ++ f(int x, int y) + { return x; } + diff --git a/tests/protox.res b/tests/protox.res new file mode 100644 index 0000000..3cba442 --- /dev/null +++ b/tests/protox.res @@ -0,0 +1,3 @@ +int f(int x); + +int f(int x) { return 12; } diff --git a/tests/pt_regs_summary b/tests/pt_regs_summary new file mode 100644 index 0000000..c978399 --- /dev/null +++ b/tests/pt_regs_summary @@ -0,0 +1,89 @@ +The semantic patch that does transformation first checks that +linux/interrupt.h is included. This header file specifies the type of +request_irq. There are multiple definitions of request_irq and the +ones in the following two files still expect a parameter with a +pt_regs-typed parameter. Nevertheless, these files also include +linux/interrupt.h, and so it seems that the definitions should be changed +accordingly. + +arch/h8300/platform/h8s/ints.c +arch/arm26/kernel/irq.c + +The semantic patch then identifies an interrupt handler function as +one that is passed to request_irq, checks that the definition of this +function is static (so we don't have to worry about calls to it from other +files), updates its parameter list if there are no references to its regs +parameter, updates any calls to it where the last argument is NULL, and +inserts a warning message in any calls that have a non-NULL argument. The +purpose of the warning, rather than just dropping the argument, is that +dropping the argument may cause some variables to no longer be used, and +thus other changes might be useful. However, in the files that trigger the +collateral evolution there is never a direct call to the interrupt handling +function, either with NULL or some other value as the final argument. + + +The sgrep semantic patch detects the negation of the above: cases where +either linux/interrupt.h is not included, or the interrupt handling +function is not static, or the interrupt handling function uses its +pt_regs-typed parameter. + + +Files that are transformed: +--- /home/julia/linux-2.6/arch/cris/arch-v10/drivers/gpio.c +--- /home/julia/linux-2.6/arch/cris/arch-v10/kernel/fasttimer.c +--- /home/julia/linux-2.6/arch/cris/arch-v32/drivers/cryptocop.c +--- /home/julia/linux-2.6/arch/cris/arch-v32/drivers/gpio.c +--- /home/julia/linux-2.6/arch/cris/arch-v32/drivers/sync_serial.c +--- /home/julia/linux-2.6/arch/cris/arch-v32/kernel/fasttimer.c + In all of the above, the transformation applies straightforwardly. The + interrupt handling function is static and it does not use its + pt_regs-typed parameter. + +--- /home/julia/linux-2.6/arch/cris/kernel/irq.c + In this file the change is to remove the pt_regs-typed argument from + __do_IRQ. The enclosing function now has no need for the pt_regs-typed + parameter, but we have not constructed the semantic patch to transform + it and its callers. Indeed, its callers appear never to be called + themselves. + +--- /home/julia/linux-2.6/arch/v850/kernel/gbus_int.c + In this file the interrupt handling function calls handle_irq with its + pt_regs-typed argument. But handle_irq doesn't need this argument, as + noted below. + +--- /home/julia/linux-2.6/arch/v850/kernel/irq.c + This file contains the definition of handle_irq. It passes its + pt_regs-typed argument to the function __do_IRQ. But __do_IRQ no + longer wants a pt_regs-typed argument either. And so we can remove it + from both the call and the parameter list, enabling the transformation + in gbus_int.c and rte_me2_cb.c. + PROBLEM: The .h file should have been updated as well, but this does + not seem to have been done. + +--- /home/julia/linux-2.6/arch/v850/kernel/rte_me2_cb.c + In this file the interrupt handling function calls handle_irq with its + pt_regs-typed argument. But handle_irq doesn't need this argument, as + noted above. + +--- /home/julia/linux-2.6/drivers/spi/au1550_spi.c + This file was added to the Linux kernel source tree quite recently: + commit 63bd23591e6c3891d34e4c6dba7c6aa41b05caad + Author: Jan Nikitenko + Date: Tue May 8 00:32:25 2007 -0700 + + + +Other cases, noted by sgrep: +--- /home/julia/linux-2.6/arch/cris/arch-v32/kernel/arbiter.c + In this case, the transformation should apply, but the pt_regs-typed + parameter is used in what appears to be debugging code, which has to be + changed by hand. + +--- /home/julia/linux-2.6/arch/m68knommu/kernel/comempci.c + In this case, the interrupt handler has the wrong signature, as it + returns void rather than irqreturn_t. Perhaps this file is dead code. + +--- /home/julia/linux-2.6/arch/blackfin/oprofile/timer_int.c + In this case, the file doesn't (directly) include linux/interrupt.h. + It is not clear what definition of request_irq is being used and thus + what type is expected for the interrupt handling function \ No newline at end of file diff --git a/tests/rcu2.cocci b/tests/rcu2.cocci new file mode 100644 index 0000000..c6f23b2 --- /dev/null +++ b/tests/rcu2.cocci @@ -0,0 +1,287 @@ +// prepare for transformation + +@@ +idexpression struct list_head *I; +@@ + +- I ++ _Y(I) + +@@ +identifier I; +expression E; +iterator list_for_each_rcu; +statement S; +@@ + + list_for_each_rcu( +- _Y(I) ++ _X(I) + ,E) + S + +@@ +identifier I; +expression E; +iterator list_for_each; +statement S; +@@ + + list_for_each( +- _Y(I) ++ _X(I) + ,E) + S + +@@ +identifier I; +expression E; +iterator list_for_each_prev; +statement S; +@@ + + list_for_each_prev( +- _Y(I) ++ _X(I) + ,E) + S + +@@ +type T; +identifier I; +expression E; +@@ + + list_entry( +- _Y(I) ++ _X(I) + ,T,E) + +// the case where the list element is just stored in a variable + +@r@ +type T,T1; +identifier I, x; +expression E, E1, E2; +iterator list_for_each_entry_rcu; +@@ + + <... when != _Y(I) +- list_for_each_rcu(_X(I),E1) ++ list_for_each_entry_rcu(x,E1,E2) + { + ... when != \(_Y(I)\|_X(I)\|x=E\) + when != T1 x; +- x = list_entry(_X(I),T,E2); + ... when != \(_Y(I)\|_X(I)\|x=E\) + } + ...> + +@ra@ +type T,T1; +identifier I, x; +expression E, E1, E2; +iterator list_for_each_entry; +@@ + + <... when != _Y(I) +- list_for_each(_X(I),E1) ++ list_for_each_entry(x,E1,E2) + { + ... when != \(_Y(I)\|_X(I)\|x=E\) + when != T1 x; +- x = list_entry(_X(I),T,E2); + ... when != \(_Y(I)\|_X(I)\|x=E\) + } + ...> + +@rb@ +type T,T1; +identifier I, x; +expression E, E1, E2; +iterator list_for_each_entry_reverse; +@@ + + <... when != _Y(I) +- list_for_each_prev(_X(I),E1) ++ list_for_each_entry_reverse(x,E1,E2) + { + ... when != \(_Y(I)\|_X(I)\|x=E\) + when != T1 x; +- x = list_entry(_X(I),T,E2); + ... when != \(_Y(I)\|_X(I)\|x=E\) + } + ...> + +// instances of the above that we can't treat because of the local variable +// problem. seems better to do nothing. + +@r1@ +type T,T1; +identifier I, x; +expression E1, E2; +@@ + + list_for_each_rcu( +- _X(I) ++ _Y(I) + ,E1) + { + ... +( + T1 x; + ... + x = +- list_entry(_X(I),T,E2); ++ _LOCAL_DECL(list_entry(_X(I),T,E2)); +| + T1 x = +- list_entry(_X(I),T,E2); ++ _LOCAL_DECL(list_entry(_X(I),T,E2)); +) + ... + } + +@r1a@ +type T,T1; +identifier I, x; +expression E1, E2; +@@ + + list_for_each( +- _X(I) ++ _Y(I) + ,E1) + { + ... +( + T1 x; + ... + x = +- list_entry(_X(I),T,E2); ++ _LOCAL_DECL(list_entry(_X(I),T,E2)); +| + T1 x = +- list_entry(_X(I),T,E2); ++ _LOCAL_DECL(list_entry(_X(I),T,E2)); +) + ... + } + +@r1b@ +type T,T1; +identifier I, x; +expression E1, E2; +@@ + + list_for_each_prev( +- _X(I) ++ _Y(I) + ,E1) + { + ... +( + T1 x; + ... + x = +- list_entry(_X(I),T,E2); ++ _LOCAL_DECL(list_entry(_X(I),T,E2)); +| + T1 x = +- list_entry(_X(I),T,E2); ++ _LOCAL_DECL(list_entry(_X(I),T,E2)); +) + ... + } + +// the case where the list element is used for something else (often a return) + +@@ +type T; +identifier I; +expression E1, E2; +@@ + +- struct list_head *I; ++ T *I; + <+... when != _Y(I) +- list_for_each_rcu(_X(I),E1) ++ list_for_each_entry_rcu(I,E1,E2) + { + <+... when != _Y(I) +- list_entry(_X(I),T,E2) ++ I + ...+> + } + ...+> + +@@ +type T; +identifier I; +expression E1, E2; +@@ + +- struct list_head *I; ++ T *I; + <+... when != _Y(I) +- list_for_each(_X(I),E1) ++ list_for_each_entry(I,E1,E2) + { + <+... when != _Y(I) +- list_entry(_X(I),T,E2) ++ I + ...+> + } + ...+> + +@@ +type T; +identifier I; +expression E1, E2; +@@ + +- struct list_head *I; ++ T *I; + <+... when != _Y(I) +- list_for_each_prev(_X(I),E1) ++ list_for_each_entry_reverse(I,E1,E2) + { + <+... when != _Y(I) +- list_entry(_X(I),T,E2) ++ I + ...+> + } + ...+> + +// clean up + +@@ +struct list_head *I; +@@ + +( +- _X(I) ++ I +| +- _Y(I) ++ I +) + +@@ +expression I; +@@ + +( +- _X(I) ++ _INCONSISTENT_MODIF(I) +| +- _Y(I) ++ _INCONSISTENT_MODIF(I) +) + +@ depends on r || ra @ +identifier I; +@@ + +- struct list_head *I; + ... when != I diff --git a/tests/rcu3.c b/tests/rcu3.c new file mode 100644 index 0000000..f83233e --- /dev/null +++ b/tests/rcu3.c @@ -0,0 +1,8 @@ +static struct mtd_chip_driver *get_mtd_chip_driver (const char *name) +{ + struct list_head *pos; + struct mtd_chip_driver *this; + + this = list_entry(pos, typeof(*this), list); + this = list_entry(pos, struct foo, list); +} diff --git a/tests/rcu3.cocci b/tests/rcu3.cocci new file mode 100644 index 0000000..069b5aa --- /dev/null +++ b/tests/rcu3.cocci @@ -0,0 +1,8 @@ +@@ +type T; +identifier I; +expression E2; +@@ + +- list_entry(I,T,E2) ++ list_entry(_X(I),T,E2) diff --git a/tests/rcu3.res b/tests/rcu3.res new file mode 100644 index 0000000..1925d0e --- /dev/null +++ b/tests/rcu3.res @@ -0,0 +1,8 @@ +static struct mtd_chip_driver *get_mtd_chip_driver (const char *name) +{ + struct list_head *pos; + struct mtd_chip_driver *this; + + this = list_entry(_X(pos), typeof(*this), list); + this = list_entry(_X(pos), struct foo, list); +} diff --git a/tests/rcu3_ver1.c b/tests/rcu3_ver1.c new file mode 100644 index 0000000..fd4cc65 --- /dev/null +++ b/tests/rcu3_ver1.c @@ -0,0 +1,15 @@ +int cryptocop_free_session(cryptocop_session_id sid) +{ + struct list_head *node, *tmp; + + for (i = 0; i < cryptocop_prio_no_prios; i++){ + if (!list_empty(&(cryptocop_job_queues[i].jobs))){ + list_for_each_safe(f(node), _Y(tmp), &(cryptocop_job_queues[i].jobs)) { + pj = list_entry(_Y(node), struct cryptocop_prio_job, _Y(node)); + if (pj->oper->sid == sid) { + list_move_tail(_Y(node), &remove_list); + } + } + } + } +} diff --git a/tests/remstruct.c b/tests/remstruct.c new file mode 100644 index 0000000..22e00a1 --- /dev/null +++ b/tests/remstruct.c @@ -0,0 +1,16 @@ +static struct irqchip mpuio_irq_chip = { + .ack = mpuio_ack_irq, + .mask = mpuio_mask_irq, + .unmask = mpuio_unmask_irq +}; + +static struct irqchip xxx = { + .a = 12, + .b = 15, +}; + +int hello ( String input ) +{ + String input = input.lowercase(); + printf(input); +} diff --git a/tests/remstruct.cocci b/tests/remstruct.cocci new file mode 100644 index 0000000..e265f98 --- /dev/null +++ b/tests/remstruct.cocci @@ -0,0 +1,11 @@ +@@ @@ +- static struct irqchip mpuio_irq_chip = { +- ... +- }; + + +@@ @@ +- static struct irqchip xxx = { +- .a = 12, +- ... +- }; diff --git a/tests/remstruct.res b/tests/remstruct.res new file mode 100644 index 0000000..9cace31 --- /dev/null +++ b/tests/remstruct.res @@ -0,0 +1,5 @@ +int hello ( String input ) +{ + String input = input.lowercase(); + printf(input); +} diff --git a/tests/replace_typedef.c b/tests/replace_typedef.c new file mode 100644 index 0000000..dc48d8d --- /dev/null +++ b/tests/replace_typedef.c @@ -0,0 +1,10 @@ +typedef struct foo { int x; } foo_t; + +typedef int int_t; + +int main() { + foo_t x; + int_t y; + x.x = 12; + return x.x + y; +} diff --git a/tests/replace_typedef.cocci b/tests/replace_typedef.cocci new file mode 100644 index 0000000..09e7621 --- /dev/null +++ b/tests/replace_typedef.cocci @@ -0,0 +1,25 @@ +@ rule1 @ +type T1, T2; +@@ + +typedef T1 { ... } T2; + +@@ +type rule1.T1, rule1.T2; +@@ + +- T2 ++ T1 + +@ rule2 @ +type T1, T2; +@@ + +typedef T1 T2; + +@@ +type rule2.T1, rule2.T2; +@@ + +- T2 ++ T1 diff --git a/tests/replace_typedef.res b/tests/replace_typedef.res new file mode 100644 index 0000000..0ca8ac5 --- /dev/null +++ b/tests/replace_typedef.res @@ -0,0 +1,10 @@ +typedef struct foo { int x; } foo_t; + +typedef int int_t; + +int main() { + struct foo x; + int y; + x.x = 12; + return x.x + y; +} diff --git a/tests/request_irq.cocci b/tests/request_irq.cocci new file mode 100644 index 0000000..f8f6a3f --- /dev/null +++ b/tests/request_irq.cocci @@ -0,0 +1,77 @@ +@ rule1 @ +@@ + +#include + +// -------------------------------------------------------------- +// do some cleaup first. +// we should specify that these rules only apply to files in the directory +// arch/v850/kernel + +@@ +int E; +struct pt_regs *regs; +@@ + +( +- handle_irq(E,regs) ++ handle_irq(E) +| +- __do_IRQ(E,regs) ++ __do_IRQ(E) +) + +@@ +identifier irq, regs; +@@ + + unsigned int +- handle_irq (int irq, struct pt_regs *regs) ++ handle_irq (int irq) + { + ... when != regs + } + +// -------------------------------------------------------------- +// now the real transformation + +@ rule2 depends on rule1 @ +expression irq; +identifier handler; +expression irqflags; +expression devname; +expression dev_id; +@@ + +request_irq(irq, handler, irqflags, devname, dev_id) + +@@ +typedef irqreturn_t; +identifier rule2.handler, irq, dev, regs; +@@ + + static irqreturn_t +- handler(int irq, void *dev, struct pt_regs *regs) ++ handler(int irq, void *dev) + { + ... when != regs + } + +@@ +identifier rule2.handler; +expression E1, E2; +@@ + +handler(E1,E2 +- ,NULL + ) + +@@ +identifier rule2.handler; +expression E1, E2, E3; +@@ + +handler(E1,E2, +- E3 ++ NEED_TO_CHECK_THIS_USE_OF(E3) + ) diff --git a/tests/request_irq_sgrep.cocci b/tests/request_irq_sgrep.cocci new file mode 100644 index 0000000..139da8f --- /dev/null +++ b/tests/request_irq_sgrep.cocci @@ -0,0 +1,80 @@ +// sgrep + +// Case 1: search for irq functions where interrupt.h is not used +// these might be ok as is, because some definitions of request_irq still +// have the pt_regs parameter in the signature + +@ rule1 @ +@@ + +#include + +@ rule2 depends on !rule1 @ +expression irq; +identifier handler; +expression irqflags; +expression devname; +expression dev_id; +@@ + +request_irq(irq, handler, irqflags, devname, dev_id) + +@@ +identifier rule2.handler, irq, dev, regs; +@@ + +* handler(int irq, void *dev, struct pt_regs *regs) + { ... } + +// ---------------------------------------------------------------------- + +// Case 2: the function is not static. This only works when there is no +// static handler function in the file, but fortunately this is the case +// (we have detected this by actually doing the transformation, which makes +// the second rule no longer match; unfortunately there is no disjunction +// at the function level) + +@ rule3 depends on rule1 @ +expression irq; +identifier handler; +expression irqflags; +expression devname; +expression dev_id; +@@ + +request_irq(irq, handler, irqflags, devname, dev_id) + +@ rule4 @ +typedef irqreturn_t; +identifier rule3.handler, irq, dev, regs; +@@ + + static irqreturn_t handler(int irq, void *dev, struct pt_regs *regs) + { ... } + +@ rule5 depends on !rule4 @ +identifier rule3.handler, irq, dev, regs; +@@ + +* handler(int irq, void *dev, struct pt_regs *regs) + { ... } + +// ---------------------------------------------------------------------- + +// Case 3: the code contains a reference to the regs parameter + +@@ +identifier rule3.handler, irq, dev, regs; +int E; +@@ + + handler(int irq, void *dev, struct pt_regs *regs) + { + <... +( + handle_irq(E,regs) +| +* regs +) + ...> + } diff --git a/tests/reserved.c b/tests/reserved.c new file mode 100644 index 0000000..046f76f --- /dev/null +++ b/tests/reserved.c @@ -0,0 +1,8 @@ +int main() { + f(1,1); + f(2,2,2); + f(3,3,3,3); + f(1,2); + f(2,3,2); + f(3,4,3,3); +} diff --git a/tests/reserved.cocci b/tests/reserved.cocci new file mode 100644 index 0000000..c6996bc --- /dev/null +++ b/tests/reserved.cocci @@ -0,0 +1,9 @@ +@@ +expression type; +expression error; +expression list; +@@ + +- f(type,type); +- f(list,list,list); +- f(error,error,error,error); \ No newline at end of file diff --git a/tests/reserved.res b/tests/reserved.res new file mode 100644 index 0000000..c9dc98b --- /dev/null +++ b/tests/reserved.res @@ -0,0 +1,5 @@ +int main() { + f(1,2); + f(2,3,2); + f(3,4,3,3); +} diff --git a/tests/ret.c b/tests/ret.c new file mode 100644 index 0000000..5adf87f --- /dev/null +++ b/tests/ret.c @@ -0,0 +1,7 @@ +int f(int x) { + int x; + f(); + if (E) { return 0; } + g(); + return 0; +} diff --git a/tests/ret.cocci b/tests/ret.cocci new file mode 100644 index 0000000..accdb86 --- /dev/null +++ b/tests/ret.cocci @@ -0,0 +1,10 @@ +@@ +expression E; +identifier x; +@@ + + f(...) { ++ spin_lock(); + ... ++ spin_unlock(); + } \ No newline at end of file diff --git a/tests/ret2.c b/tests/ret2.c new file mode 100644 index 0000000..1cad4ae --- /dev/null +++ b/tests/ret2.c @@ -0,0 +1,6 @@ +int main() { + if (foo()) xxx(); + xxx(); + if (foo()) return; + return; +} diff --git a/tests/ret2.cocci b/tests/ret2.cocci new file mode 100644 index 0000000..7ef1e08 --- /dev/null +++ b/tests/ret2.cocci @@ -0,0 +1,10 @@ +@@ +@@ + +- return; + +@@ +@@ + ++ bar(); + xxx(); diff --git a/tests/retmacro.c b/tests/retmacro.c new file mode 100644 index 0000000..d5dc235 --- /dev/null +++ b/tests/retmacro.c @@ -0,0 +1,17 @@ +#define REG_PATTERN_TEST(R, M, W) \ +{ \ + for (pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \ + if (value != (test[pat] & W & M)) { \ + return 1; \ + } \ + } \ +} + + +#define REG_PATTERN_TEST2(R, M, W) \ +{ \ + for (pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \ + if (value != (test[pat] & W & M)) { \ + } \ + } \ +} diff --git a/tests/retmacro.cocci b/tests/retmacro.cocci new file mode 100644 index 0000000..106bc42 --- /dev/null +++ b/tests/retmacro.cocci @@ -0,0 +1,6 @@ +@@ +expression E, E1; +@@ + +- sizeof(E)/sizeof(E[E1]) ++ ARRAY_SIZE(E) diff --git a/tests/retmacro.res b/tests/retmacro.res new file mode 100644 index 0000000..7a024d4 --- /dev/null +++ b/tests/retmacro.res @@ -0,0 +1,17 @@ +#define REG_PATTERN_TEST(R, M, W) \ +{ \ + for (pat = 0; pat < ARRAY_SIZE(test); pat++) { \ + if (value != (test[pat] & W & M)) { \ + return 1; \ + } \ + } \ +} + + +#define REG_PATTERN_TEST2(R, M, W) \ +{ \ + for (pat = 0; pat < ARRAY_SIZE(test); pat++) { \ + if (value != (test[pat] & W & M)) { \ + } \ + } \ +} diff --git a/tests/rets.c b/tests/rets.c new file mode 100644 index 0000000..1ba19ef --- /dev/null +++ b/tests/rets.c @@ -0,0 +1,4 @@ +int main () { + foo(); + return 12; +} diff --git a/tests/rets.cocci b/tests/rets.cocci new file mode 100644 index 0000000..c3cccca --- /dev/null +++ b/tests/rets.cocci @@ -0,0 +1,7 @@ +@@ +statement S; +@@ + +foo(); +- S ++ S diff --git a/tests/rets.res b/tests/rets.res new file mode 100644 index 0000000..1ba19ef --- /dev/null +++ b/tests/rets.res @@ -0,0 +1,4 @@ +int main () { + foo(); + return 12; +} diff --git a/tests/return.c b/tests/return.c new file mode 100644 index 0000000..1152b67 --- /dev/null +++ b/tests/return.c @@ -0,0 +1,6 @@ +void foo(int y) { + int x; + if (x) { aaa(); bbb(); return; } + if (x) { aaa(); bbb(); return; } + ccc(); +} diff --git a/tests/return.cocci b/tests/return.cocci new file mode 100644 index 0000000..dbb60da --- /dev/null +++ b/tests/return.cocci @@ -0,0 +1,26 @@ +// not needed with 'return implicit' feature +// @@ +// statement S; +// @@ +// +// foo(...) { +// ... +// ( +// + before_return(); +// return; +// | +// S +// + before_return(); +// ) +// } + + +@@ +statement S; +@@ + +foo(...) { + ... ++ before_return(); + return; +} diff --git a/tests/return.res b/tests/return.res new file mode 100644 index 0000000..3979545 --- /dev/null +++ b/tests/return.res @@ -0,0 +1,7 @@ +void foo(int y) { + int x; + if (x) { aaa(); bbb(); before_return(); return; } + if (x) { aaa(); bbb(); before_return(); return; } + ccc(); + before_return(); +} diff --git a/tests/return_implicit.c b/tests/return_implicit.c new file mode 100644 index 0000000..9a54dd4 --- /dev/null +++ b/tests/return_implicit.c @@ -0,0 +1,4 @@ +void main(void) +{ + foo(); +} diff --git a/tests/return_implicit.cocci b/tests/return_implicit.cocci new file mode 100644 index 0000000..b06add8 --- /dev/null +++ b/tests/return_implicit.cocci @@ -0,0 +1,11 @@ +@@ +identifier fn; +@@ + +fn(...) +{ + foo(...); + ... +- return; ++ return -ENODEV; +} \ No newline at end of file diff --git a/tests/return_implicit.res b/tests/return_implicit.res new file mode 100644 index 0000000..706da44 --- /dev/null +++ b/tests/return_implicit.res @@ -0,0 +1,5 @@ +void main(void) +{ + foo(); + return -ENODEV; +} diff --git a/tests/rule19a.c b/tests/rule19a.c new file mode 100644 index 0000000..221fe90 --- /dev/null +++ b/tests/rule19a.c @@ -0,0 +1,23 @@ +static void +gazel_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista, val; + int count = 0; + + if (!cs) { + printk(KERN_WARNING "Gazel: Spurious interrupt!\n"); + return; + } + do { + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + } + while ((ista & 0x3f) && (count < MAXCOUNT)); + + WriteISAC(cs, IPAC_MASK - 0x80, 0xFF); + WriteISAC(cs, IPAC_MASK - 0x80, 0xC0); +} + diff --git a/tests/rule19a.cocci b/tests/rule19a.cocci new file mode 100644 index 0000000..8d49c19 --- /dev/null +++ b/tests/rule19a.cocci @@ -0,0 +1,15 @@ +@@ +identifier interrupt; +statement S; +@@ + + interrupt(...) { + ... +( ++ spin_unlock(&cs->lock); + return; +| + S ++ spin_unlock(&cs->lock); +) + } diff --git a/tests/rule3.cocci b/tests/rule3.cocci new file mode 100644 index 0000000..dd2d9a7 --- /dev/null +++ b/tests/rule3.cocci @@ -0,0 +1,13 @@ +@@ +// struct us_data *E1; +// struct us_data E1; +expression E1; +expression E2; +@@ + +//- usb_stor_clear_halt(E1->pusb_dev,E2) +//- usb_stor_clear_halt(E1.pusb_dev,E2) +- usb_clear_halt(E1->pusb_dev, E2) ++ usb_stor_clear_halt(E1, E2) + +//error words = [usb_clear_halt] diff --git a/tests/same_expr.c b/tests/same_expr.c new file mode 100644 index 0000000..d79ad74 --- /dev/null +++ b/tests/same_expr.c @@ -0,0 +1,6 @@ +void main(int i) +{ + f(1,1); + f(1,2); + +} diff --git a/tests/same_expr.cocci b/tests/same_expr.cocci new file mode 100644 index 0000000..db4811e --- /dev/null +++ b/tests/same_expr.cocci @@ -0,0 +1,5 @@ +@@ +expression E; +@@ + +- f(E,E); \ No newline at end of file diff --git a/tests/same_expr.res b/tests/same_expr.res new file mode 100644 index 0000000..77cde62 --- /dev/null +++ b/tests/same_expr.res @@ -0,0 +1,5 @@ +void main(int i) +{ + f(1,2); + +} diff --git a/tests/scope_problem.c b/tests/scope_problem.c new file mode 100644 index 0000000..897c6a7 --- /dev/null +++ b/tests/scope_problem.c @@ -0,0 +1,15 @@ +void main(int i) { + + int a; + foo(a); + a = 1; + + if(1) { + int a; + a = 2; + } + + a = 3; + + +} diff --git a/tests/scope_problem.cocci b/tests/scope_problem.cocci new file mode 100644 index 0000000..331adb7 --- /dev/null +++ b/tests/scope_problem.cocci @@ -0,0 +1,11 @@ +@@ +identifier a; +expression E; +@@ + +- int a; + ... +- foo(a); + <... +- a = E; + ...> \ No newline at end of file diff --git a/tests/scope_problem.res b/tests/scope_problem.res new file mode 100644 index 0000000..304a2a5 --- /dev/null +++ b/tests/scope_problem.res @@ -0,0 +1,12 @@ +void main(int i) { + + + + if(1) { + int a; + a = 2; + } + + + +} diff --git a/tests/scripting/array/script4.c b/tests/scripting/array/script4.c new file mode 100644 index 0000000..12009a9 --- /dev/null +++ b/tests/scripting/array/script4.c @@ -0,0 +1,22 @@ +#include + +const int qqq = 20; + +void foo() { + int z[10]; + + z[2] = 34; +} + +int main() { + int buf[qqq], foo[30]; + int i; + + for (i = 0; i <= 20; ++i) { + buf[i] = i; + foo[i] = i; + } + + for (i = 0; i <= 20; ++i) + printf("%d: %d\n", i, buf[i]); +} diff --git a/tests/scripting/array/script4.cocci b/tests/scripting/array/script4.cocci new file mode 100644 index 0000000..f59abbc --- /dev/null +++ b/tests/scripting/array/script4.cocci @@ -0,0 +1,15 @@ +@ rule1 @ +type T; identifier I; expression C; expression E; +position p1, p2, p3, p4; +@@ +T I@p2[C@p3]; +<... +I[E@p4] +...> +@ script:python @ +x_mv << rule1.C; xp << rule1.p3; +y_mv << rule1.E; yp << rule1.p4; +@@ +x = cocci.combine(x_mv, xp) +y = cocci.combine(y_mv, yp) +cocci.register_match(True, [(x, 'Array match'), (y, 'Array use')]) diff --git a/tests/scripting/script1.c b/tests/scripting/script1.c new file mode 100644 index 0000000..a9d4369 --- /dev/null +++ b/tests/scripting/script1.c @@ -0,0 +1,9 @@ +int main() { + int buf[20]; + int i; + + for (i = 0; i <= 20; ++i) + buf[i] = i; + + f(); +} diff --git a/tests/scripting/script1.cocci b/tests/scripting/script1.cocci new file mode 100644 index 0000000..70a7d9f --- /dev/null +++ b/tests/scripting/script1.cocci @@ -0,0 +1,7 @@ +@ rule1 @ type T; identifier I; constant C; expression E; @@ +T I[C]; +<... +-I[E] +...> +@ script:python @ @@ +print "Hello" diff --git a/tests/scripting/script2.c b/tests/scripting/script2.c new file mode 100644 index 0000000..50180cb --- /dev/null +++ b/tests/scripting/script2.c @@ -0,0 +1,12 @@ +int main() { + int buf[20], foo[30]; + int i; + + for (i = 0; i <= 20; ++i) { + buf[i] = i; + foo[i] = i; + } + + for (i = 0; i <= 20; ++i) + printf("%d: %d\n", i, buf[i]); +} diff --git a/tests/scripting/script2.cocci b/tests/scripting/script2.cocci new file mode 100644 index 0000000..993d85f --- /dev/null +++ b/tests/scripting/script2.cocci @@ -0,0 +1,8 @@ +@ rule1 @ type T; identifier I; constant C; expression E; @@ +T I[C]; +<... +-I[E] ++I[E] +...> +@ script:python @ @@ +print "Hello" diff --git a/tests/scripting/script3.c b/tests/scripting/script3.c new file mode 100644 index 0000000..b29438e --- /dev/null +++ b/tests/scripting/script3.c @@ -0,0 +1,18 @@ +void foo() { + int z[10]; + + z[2] = 34; +} + +int main() { + int buf[20], foo[30]; + int i; + + for (i = 0; i <= 20; ++i) { + buf[i] = i; + foo[i] = i; + } + + for (i = 0; i <= 20; ++i) + printf("%d: %d\n", i, buf[i]); +} diff --git a/tests/scripting/script3.cocci b/tests/scripting/script3.cocci new file mode 100644 index 0000000..c354094 --- /dev/null +++ b/tests/scripting/script3.cocci @@ -0,0 +1,10 @@ +@ rule1 @ type T; identifier I; constant C; expression E; @@ +T I[C]; +<... +-I[E] ++I[E] +...> +@ script:python @ @@ +print "Hello" +@ rule2 @ constant rule1.C; @@ +- C diff --git a/tests/scripting/script4.c b/tests/scripting/script4.c new file mode 100644 index 0000000..b29438e --- /dev/null +++ b/tests/scripting/script4.c @@ -0,0 +1,18 @@ +void foo() { + int z[10]; + + z[2] = 34; +} + +int main() { + int buf[20], foo[30]; + int i; + + for (i = 0; i <= 20; ++i) { + buf[i] = i; + foo[i] = i; + } + + for (i = 0; i <= 20; ++i) + printf("%d: %d\n", i, buf[i]); +} diff --git a/tests/scripting/script4.cocci b/tests/scripting/script4.cocci new file mode 100644 index 0000000..6ee0144 --- /dev/null +++ b/tests/scripting/script4.cocci @@ -0,0 +1,14 @@ +@ rule1 @ +type T; identifier I; constant C; expression E; +position p1, p2, p3, p4; +@@ +T I@p2[C@p3]; +<... +I[E@p4] +...> +@ script:python @ +x << rule1.p3; +y << rule1.p4; +@@ +print "%s:%s:%s:%s" % (x.location.file, x.location.line, x.location.column, x) +print "%s[%s]" % (x,y) diff --git a/tests/scripting/script5.c b/tests/scripting/script5.c new file mode 100644 index 0000000..b29438e --- /dev/null +++ b/tests/scripting/script5.c @@ -0,0 +1,18 @@ +void foo() { + int z[10]; + + z[2] = 34; +} + +int main() { + int buf[20], foo[30]; + int i; + + for (i = 0; i <= 20; ++i) { + buf[i] = i; + foo[i] = i; + } + + for (i = 0; i <= 20; ++i) + printf("%d: %d\n", i, buf[i]); +} diff --git a/tests/scripting/script5.cocci b/tests/scripting/script5.cocci new file mode 100644 index 0000000..a2118e5 --- /dev/null +++ b/tests/scripting/script5.cocci @@ -0,0 +1,11 @@ +@ rule1 @ type T; identifier I; constant C; expression E; @@ +T I[C]; +<... +-I[E] ++I[E] +...> +@ script:python @ t << rule1.T; i << rule1.I; x << rule1.C; y << rule1.E; @@ +print t, i, "[", x, "]; ", i, "[", y, "];" +#print "Hello" +@ rule2 @ constant rule1.C; @@ +- C diff --git a/tests/scripting/script6.c b/tests/scripting/script6.c new file mode 100644 index 0000000..b29438e --- /dev/null +++ b/tests/scripting/script6.c @@ -0,0 +1,18 @@ +void foo() { + int z[10]; + + z[2] = 34; +} + +int main() { + int buf[20], foo[30]; + int i; + + for (i = 0; i <= 20; ++i) { + buf[i] = i; + foo[i] = i; + } + + for (i = 0; i <= 20; ++i) + printf("%d: %d\n", i, buf[i]); +} diff --git a/tests/scripting/script6.cocci b/tests/scripting/script6.cocci new file mode 100644 index 0000000..8f993ca --- /dev/null +++ b/tests/scripting/script6.cocci @@ -0,0 +1,7 @@ +@ rule1 @ type T; identifier I; constant C; expression E; @@ +T I[C]; +<... +*I[E] +...> +@ rule2 @ type rule1.T; @@ +* T diff --git a/tests/scripting/script7.c b/tests/scripting/script7.c new file mode 100644 index 0000000..474920d --- /dev/null +++ b/tests/scripting/script7.c @@ -0,0 +1,14 @@ +int main() { + int x; + + f(2); + if (2 == 2) { + x = 7; + } + + g(2); + + q(x); + + h(); +} diff --git a/tests/scripting/script7.cocci b/tests/scripting/script7.cocci new file mode 100644 index 0000000..28f440b --- /dev/null +++ b/tests/scripting/script7.cocci @@ -0,0 +1,9 @@ +@ rule1 @ expression E; @@ +f(E); +... +g(E); +... +-h() ++h(E); +@ script:python @ x << rule1.E; @@ +print x diff --git a/tests/scripting/script8.c b/tests/scripting/script8.c new file mode 100644 index 0000000..b29438e --- /dev/null +++ b/tests/scripting/script8.c @@ -0,0 +1,18 @@ +void foo() { + int z[10]; + + z[2] = 34; +} + +int main() { + int buf[20], foo[30]; + int i; + + for (i = 0; i <= 20; ++i) { + buf[i] = i; + foo[i] = i; + } + + for (i = 0; i <= 20; ++i) + printf("%d: %d\n", i, buf[i]); +} diff --git a/tests/scripting/script8.cocci b/tests/scripting/script8.cocci new file mode 100644 index 0000000..09e5c2b --- /dev/null +++ b/tests/scripting/script8.cocci @@ -0,0 +1,10 @@ +@ rule1 @ +expression C; +position p1; +@@ +*C@p1 +@ script:python @ +x << rule1.C; +xloc << rule1.p1; +@@ +print "%s[%s]" % (x,xloc) diff --git a/tests/send_pci1 b/tests/send_pci1 new file mode 100644 index 0000000..83b6a08 --- /dev/null +++ b/tests/send_pci1 @@ -0,0 +1,49 @@ +Send to: davej@codemonkey.org.uk, linux-kernel@vger.kernel.org, kernel-janitors@vger.kernel.org + +Subject: [PATCH 1/2]: drivers/char: remove unnecessary pci_dev_put + +--------------------------------------- + +From: Julia Lawall + +pci_get_class implicitly does a pci_dev_put on its second argument, so +pci_dev_put is only needed if there is a break out of the loop. + +The semantic match detecting this problem is as follows: + +// +@@ +expression dev; +expression E; +@@ + +* pci_dev_put(dev) + ... when != dev = E +( +* pci_get_device(...,dev) +| +* pci_get_device_reverse(...,dev) +| +* pci_get_subsys(...,dev) +| +* pci_get_class(...,dev) +) +// + +Signed-off-by: Julia Lawall +--- + +diff -up a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c +--- a/drivers/char/agp/amd-k7-agp.c 2007-11-15 07:33:31.000000000 +0100 ++++ b/drivers/char/agp/amd-k7-agp.c 2007-11-15 07:40:48.000000000 +0100 +@@ -436,10 +436,6 @@ static int __devinit agp_amdk7_probe(str + return -ENODEV; + } + cap_ptr = pci_find_capability(gfxcard, PCI_CAP_ID_AGP); +- if (!cap_ptr) { +- pci_dev_put(gfxcard); +- continue; +- } + } + + /* With so many variants of NVidia cards, it's simpler just diff --git a/tests/send_pci2 b/tests/send_pci2 new file mode 100644 index 0000000..44de622 --- /dev/null +++ b/tests/send_pci2 @@ -0,0 +1,49 @@ +Send to: thomas@winischhofer.net, linux-kernel@vger.kernel.org, kernel-janitors@vger.kernel.org + +Subject: [PATCH 2/2]: drivers/video: remove unnecessary pci_dev_put + +--------------------------------------- + +From: Julia Lawall + +pci_get_class implicitly does a pci_dev_put on its second argument, so +pci_dev_put is only needed if there is a break out of the loop. + +The semantic match detecting this problem is as follows: + +// +@@ +expression dev; +expression E; +@@ + +* pci_dev_put(dev) + ... when != dev = E +( +* pci_get_device(...,dev) +| +* pci_get_device_reverse(...,dev) +| +* pci_get_subsys(...,dev) +| +* pci_get_class(...,dev) +) +// + +Signed-off-by: Julia Lawall +--- + +diff -up a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c +--- a/drivers/video/sis/sis_main.c 2007-11-15 07:33:31.000000000 +0100 ++++ b/drivers/video/sis/sis_main.c 2007-11-15 07:38:48.000000000 +0100 +@@ -4620,9 +4620,9 @@ sisfb_find_host_bridge(struct sis_video_ + + while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) { + temp = pdev->vendor; +- pci_dev_put(pdev); + if(temp == pcivendor) { + ret = 1; ++ pci_dev_put(pdev); + break; + } + } diff --git a/tests/serio.c b/tests/serio.c new file mode 100644 index 0000000..9b136c3 --- /dev/null +++ b/tests/serio.c @@ -0,0 +1,8 @@ +#include +#include +#include + +static void serio_init_port(struct serio *serio) +{ + init_MUTEX(&serio->drv_sem); +} diff --git a/tests/serio.cocci b/tests/serio.cocci new file mode 100644 index 0000000..6a46da0 --- /dev/null +++ b/tests/serio.cocci @@ -0,0 +1,33 @@ +@ rule1 @ +type T; +identifier lock; +@@ + +T { ... + struct semaphore lock; + ... + }; + +@ rule1a @ +type rule1.T; +T data; +identifier rule1.lock; +@@ + +- init_MUTEX ++ mutex_init + (&data. +- lock ++ new_lock + ) + +@@ +type rule1.T; +identifier rule1.lock; +@@ + +T { ... +- struct semaphore lock; ++ struct mutex new_lock; + ... + }; diff --git a/tests/serio.res b/tests/serio.res new file mode 100644 index 0000000..3851508 --- /dev/null +++ b/tests/serio.res @@ -0,0 +1,8 @@ +#include +#include +#include + +static void serio_init_port(struct serio *serio) +{ + mutex_init(&serio->new_lock); +} diff --git a/tests/sgrep.c b/tests/sgrep.c new file mode 100644 index 0000000..74e69e2 --- /dev/null +++ b/tests/sgrep.c @@ -0,0 +1,7 @@ +int main() { + f(); + x(); + a(); + g(); + if (q) y(); +} diff --git a/tests/sgrep.cocci b/tests/sgrep.cocci new file mode 100644 index 0000000..94593c6 --- /dev/null +++ b/tests/sgrep.cocci @@ -0,0 +1,13 @@ +@@ +@@ + +- f(); + ... + g(); + +@@ +@@ + + x(); + ... +- y(); diff --git a/tests/shadow.c b/tests/shadow.c new file mode 100644 index 0000000..d0a1b28 --- /dev/null +++ b/tests/shadow.c @@ -0,0 +1,4 @@ +struct foo bar; + +struct foo bar = { .a = 12 }; + diff --git a/tests/shared_brace.c b/tests/shared_brace.c new file mode 100644 index 0000000..649e531 --- /dev/null +++ b/tests/shared_brace.c @@ -0,0 +1,9 @@ + +int __init ixj_init(void) +{ + if (pci_present()) { + if ((probe = ixj_probe_pci(&cnt)) < 0) { + return probe; + } + } +} diff --git a/tests/shared_brace.cocci b/tests/shared_brace.cocci new file mode 100644 index 0000000..9263ec1 --- /dev/null +++ b/tests/shared_brace.cocci @@ -0,0 +1,9 @@ +@@ +type T; +identifier x; +statement S; +@@ + +- if (pci_present()) { + ... +- } diff --git a/tests/shared_brace.res b/tests/shared_brace.res new file mode 100644 index 0000000..03e9fa4 --- /dev/null +++ b/tests/shared_brace.res @@ -0,0 +1,7 @@ + +int __init ixj_init(void) +{ + if ((probe = ixj_probe_pci(&cnt)) < 0) { + return probe; + } +} diff --git a/tests/signed.c b/tests/signed.c new file mode 100644 index 0000000..a6246d8 --- /dev/null +++ b/tests/signed.c @@ -0,0 +1,5 @@ +int main() { + signed x; + unsigned a; + return x; +} diff --git a/tests/signed.cocci b/tests/signed.cocci new file mode 100644 index 0000000..b3a3b82 --- /dev/null +++ b/tests/signed.cocci @@ -0,0 +1,12 @@ +@@ +@@ + +- signed x; ++ signed y; + +@@ +@@ + +- unsigned a; ++ unsigned b; + diff --git a/tests/signed.res b/tests/signed.res new file mode 100644 index 0000000..e878c51 --- /dev/null +++ b/tests/signed.res @@ -0,0 +1,5 @@ +int main() { + signed y; + unsigned b; + return x; +} diff --git a/tests/sis.c b/tests/sis.c new file mode 100644 index 0000000..a657320 --- /dev/null +++ b/tests/sis.c @@ -0,0 +1,6 @@ +DECLARE_MUTEX(disconnect_sem); +/*int foo() { return; }*/ +// if uncomment, and erase newline, then have Line ID EOF and +// some patterns in parsing_hacks don't apply anymore :( + + diff --git a/tests/sis.cocci b/tests/sis.cocci new file mode 100644 index 0000000..49ba588 --- /dev/null +++ b/tests/sis.cocci @@ -0,0 +1,9 @@ +@@ +declarer name DECLARE_MUTEX; +declarer name DEFINE_MUTEX; +identifier I; +//fresh identifier I1; +@@ + +- DECLARE_MUTEX(I); ++ DEFINE_MUTEX(I); diff --git a/tests/sis.res b/tests/sis.res new file mode 100644 index 0000000..f22caa4 --- /dev/null +++ b/tests/sis.res @@ -0,0 +1,3 @@ +DEFINE_MUTEX(disconnect_sem); + +//int foo() { return; } diff --git a/tests/size_t.cocci b/tests/size_t.cocci new file mode 100644 index 0000000..ade663c --- /dev/null +++ b/tests/size_t.cocci @@ -0,0 +1,46 @@ +@ rule1 @ +identifier f, x; +@@ + +f(...,size_t x,...) { ... } + +@@ +expression E; +type T; +size_t E1; +identifier rule1.f; +@@ + +( +f(...,sizeof(E),...) +| +f(...,sizeof(T),...) +| +f(...,E1,...) +| +* f(...) +) + +@ rule2 @ +identifier f, x; +type T; +@@ + +T f(...,size_t x,...); + +@@ +expression E; +type T; +size_t E1; +identifier rule2.f; +@@ + +( +f(...,sizeof(E),...) +| +f(...,sizeof(T),...) +| +f(...,E1,...) +| +* f(...) +) diff --git a/tests/sizeof.c b/tests/sizeof.c new file mode 100644 index 0000000..77ebefe --- /dev/null +++ b/tests/sizeof.c @@ -0,0 +1,7 @@ +int main (int param) { + + int i = sizeof(3); + int j = sizeof 3; + int k = sizeof (int *); + +} diff --git a/tests/sizeof.cocci b/tests/sizeof.cocci new file mode 100644 index 0000000..810b161 --- /dev/null +++ b/tests/sizeof.cocci @@ -0,0 +1,9 @@ +@@ +expression X; +//type X; +@@ + +//- sizeof(...) +- sizeof(X) ++ sizeof(int) + diff --git a/tests/sizeof.res b/tests/sizeof.res new file mode 100644 index 0000000..5ea8377 --- /dev/null +++ b/tests/sizeof.res @@ -0,0 +1,7 @@ +int main (int param) { + + int i = sizeof(int); + int j = sizeof(int); + int k = sizeof (int *); + +} diff --git a/tests/sizeof_julia.c b/tests/sizeof_julia.c new file mode 100644 index 0000000..2bc072e --- /dev/null +++ b/tests/sizeof_julia.c @@ -0,0 +1,5 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, +void *arg) +{ + copy_from_user(&v, arg, sizeof(v)); +} diff --git a/tests/sizeof_julia.cocci b/tests/sizeof_julia.cocci new file mode 100644 index 0000000..15a65e4 --- /dev/null +++ b/tests/sizeof_julia.cocci @@ -0,0 +1,6 @@ +@@ +identifier arg; +identifier v; +@@ +- copy_from_user(&v,arg,sizeof(v)) ++ foo() diff --git a/tests/sizeof_julia.res b/tests/sizeof_julia.res new file mode 100644 index 0000000..66221e9 --- /dev/null +++ b/tests/sizeof_julia.res @@ -0,0 +1,5 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, +void *arg) +{ + foo(); +} diff --git a/tests/skip.c b/tests/skip.c new file mode 100644 index 0000000..07daabc --- /dev/null +++ b/tests/skip.c @@ -0,0 +1,5 @@ +int main () { + f(1); + f(2); + g(); +} diff --git a/tests/skip.cocci b/tests/skip.cocci new file mode 100644 index 0000000..4667a13 --- /dev/null +++ b/tests/skip.cocci @@ -0,0 +1,17 @@ +@ rule1 @ +expression E; +@@ + +f(E) + +@@ +@@ + +- g(); ++ h(); + +@@ +expression rule1.E; +@@ + +- f(E); diff --git a/tests/skip.res b/tests/skip.res new file mode 100644 index 0000000..09c61d2 --- /dev/null +++ b/tests/skip.res @@ -0,0 +1,3 @@ +int main () { + h(); +} diff --git a/tests/soc.c b/tests/soc.c new file mode 100644 index 0000000..bb33ec6 --- /dev/null +++ b/tests/soc.c @@ -0,0 +1,7 @@ +#define soc_printk printk ("soc%d: ", s->soc_no); printk + + +static inline void soc_init(struct sbus_dev *sdev, int no) +{ + soc_printk ("Cannot order irq %d to go\n", irq); +} diff --git a/tests/sp.c b/tests/sp.c new file mode 100644 index 0000000..f7cf6e4 --- /dev/null +++ b/tests/sp.c @@ -0,0 +1,4 @@ +typedef struct { + unsigned long gcr; + struct pci_dev *pci; +} snd_card_als4000_t; diff --git a/tests/sp.cocci b/tests/sp.cocci new file mode 100644 index 0000000..ad38bc2 --- /dev/null +++ b/tests/sp.cocci @@ -0,0 +1,10 @@ +@ rule0 @ +type T; +@@ + +- typedef + struct ++ name + { ... } +- T + ; diff --git a/tests/sp.res b/tests/sp.res new file mode 100644 index 0000000..7cb28f2 --- /dev/null +++ b/tests/sp.res @@ -0,0 +1,4 @@ +struct name { + unsigned long gcr; + struct pci_dev *pci; +}; diff --git a/tests/spaces.c b/tests/spaces.c new file mode 100644 index 0000000..9332953 --- /dev/null +++ b/tests/spaces.c @@ -0,0 +1,3 @@ +int main () { + foo(x + y); +} diff --git a/tests/spaces.cocci b/tests/spaces.cocci new file mode 100644 index 0000000..b825d84 --- /dev/null +++ b/tests/spaces.cocci @@ -0,0 +1,6 @@ +@@ +expression E; +@@ + +- foo(E) ++ foo(E) diff --git a/tests/spaces.res b/tests/spaces.res new file mode 100644 index 0000000..9332953 --- /dev/null +++ b/tests/spaces.res @@ -0,0 +1,3 @@ +int main () { + foo(x + y); +} diff --git a/tests/spl.c b/tests/spl.c new file mode 100644 index 0000000..e387783 --- /dev/null +++ b/tests/spl.c @@ -0,0 +1,12 @@ +int main() { + spin_lock(&isp116x->lock); + /* take idle endpoints out of the schedule */ + if (!list_empty(&ep->hep->urb_list)) { + return; + } + + /* async deschedule */ + if (!list_empty(&ep->schedule)) { + return; + } +} diff --git a/tests/spl.cocci b/tests/spl.cocci new file mode 100644 index 0000000..947307f --- /dev/null +++ b/tests/spl.cocci @@ -0,0 +1,16 @@ +// this illustrates how when strict is not so effective. if the comment is +// removed, only the first return gets its spin_unlock, because the pattern +// is not found under the then of the first if in the C code. it is not +// good enough that there is a matching pattern around the then + +@@ +expression l; +@@ + +spin_lock(l); +... when any +// when strict +if (...) { ++ spin_unlock(l); + return ...; +} diff --git a/tests/spl.res b/tests/spl.res new file mode 100644 index 0000000..19e2faa --- /dev/null +++ b/tests/spl.res @@ -0,0 +1,14 @@ +int main() { + spin_lock(&isp116x->lock); + /* take idle endpoints out of the schedule */ + if (!list_empty(&ep->hep->urb_list)) { + spin_unlock(&isp116x->lock); + return; + } + + /* async deschedule */ + if (!list_empty(&ep->schedule)) { + spin_unlock(&isp116x->lock); + return; + } +} diff --git a/tests/stat.c b/tests/stat.c new file mode 100644 index 0000000..a170d6b --- /dev/null +++ b/tests/stat.c @@ -0,0 +1 @@ +static dev_info_t dev_info = "orinoco_cs"; diff --git a/tests/stat.cocci b/tests/stat.cocci new file mode 100644 index 0000000..d666a6f --- /dev/null +++ b/tests/stat.cocci @@ -0,0 +1,6 @@ +@@ +expression YYY; +identifier dev_info; +@@ + +- static dev_info_t dev_info = YYY; diff --git a/tests/stat.res b/tests/stat.res new file mode 100644 index 0000000..e69de29 diff --git a/tests/static.c b/tests/static.c new file mode 100644 index 0000000..7685807 --- /dev/null +++ b/tests/static.c @@ -0,0 +1,4 @@ +static inline int i8042_read_data(void) +{ + return jazz_kh->data; +} diff --git a/tests/static.cocci b/tests/static.cocci new file mode 100644 index 0000000..a76871f --- /dev/null +++ b/tests/static.cocci @@ -0,0 +1,8 @@ +@@ +statement S; +identifier f; +@@ + +static f(...) { +- S +} diff --git a/tests/static.res b/tests/static.res new file mode 100644 index 0000000..f2d4161 --- /dev/null +++ b/tests/static.res @@ -0,0 +1,4 @@ +static inline int i8042_read_data(void) +{ + +} diff --git a/tests/stm1.c b/tests/stm1.c new file mode 100644 index 0000000..d2f6922 --- /dev/null +++ b/tests/stm1.c @@ -0,0 +1,5 @@ +int main(int x) { + f(); + replace(); + g(); +} diff --git a/tests/stm1.cocci b/tests/stm1.cocci new file mode 100644 index 0000000..307e513 --- /dev/null +++ b/tests/stm1.cocci @@ -0,0 +1,7 @@ +@@ +statement S; +@@ + + f(); + S + g(); diff --git a/tests/stm1.res b/tests/stm1.res new file mode 100644 index 0000000..d2f6922 --- /dev/null +++ b/tests/stm1.res @@ -0,0 +1,5 @@ +int main(int x) { + f(); + replace(); + g(); +} diff --git a/tests/stm10.c b/tests/stm10.c new file mode 100644 index 0000000..7160589 --- /dev/null +++ b/tests/stm10.c @@ -0,0 +1,6 @@ +int main(int x) { + f(); + if (x) replace(); + g(); + if (x) replace(); +} diff --git a/tests/stm10.cocci b/tests/stm10.cocci new file mode 100644 index 0000000..62b5525 --- /dev/null +++ b/tests/stm10.cocci @@ -0,0 +1,7 @@ +@@ +statement S; +@@ + + f(); + S ++ h(); diff --git a/tests/stm10.res b/tests/stm10.res new file mode 100644 index 0000000..4bcf2e7 --- /dev/null +++ b/tests/stm10.res @@ -0,0 +1,7 @@ +int main(int x) { + f(); + if (x) replace(); + h(); + g(); + if (x) replace(); +} diff --git a/tests/stm10_ver1.c b/tests/stm10_ver1.c new file mode 100644 index 0000000..b42cf66 --- /dev/null +++ b/tests/stm10_ver1.c @@ -0,0 +1,5 @@ +int main(int x) { + f(); + { replace(); replace();} + g(); +} diff --git a/tests/stm10_ver1.res b/tests/stm10_ver1.res new file mode 100644 index 0000000..f162197 --- /dev/null +++ b/tests/stm10_ver1.res @@ -0,0 +1,6 @@ +int main(int x) { + f(); + { replace(); replace();} + h(); + g(); +} diff --git a/tests/stm2.c b/tests/stm2.c new file mode 100644 index 0000000..d2f6922 --- /dev/null +++ b/tests/stm2.c @@ -0,0 +1,5 @@ +int main(int x) { + f(); + replace(); + g(); +} diff --git a/tests/stm2.cocci b/tests/stm2.cocci new file mode 100644 index 0000000..97f4b7e --- /dev/null +++ b/tests/stm2.cocci @@ -0,0 +1,7 @@ +@@ +statement S; +@@ + + f(); +- S + g(); diff --git a/tests/stm2.res b/tests/stm2.res new file mode 100644 index 0000000..5cf4a55 --- /dev/null +++ b/tests/stm2.res @@ -0,0 +1,4 @@ +int main(int x) { + f(); + g(); +} diff --git a/tests/stm3.c b/tests/stm3.c new file mode 100644 index 0000000..d2f6922 --- /dev/null +++ b/tests/stm3.c @@ -0,0 +1,5 @@ +int main(int x) { + f(); + replace(); + g(); +} diff --git a/tests/stm3.cocci b/tests/stm3.cocci new file mode 100644 index 0000000..e60e937 --- /dev/null +++ b/tests/stm3.cocci @@ -0,0 +1,7 @@ +@@ +statement S; +@@ + + f(); +- S ++ g(); diff --git a/tests/stm3.res b/tests/stm3.res new file mode 100644 index 0000000..4ebbcdb --- /dev/null +++ b/tests/stm3.res @@ -0,0 +1,5 @@ +int main(int x) { + f(); + g(); + g(); +} diff --git a/tests/stm4.c b/tests/stm4.c new file mode 100644 index 0000000..d2f6922 --- /dev/null +++ b/tests/stm4.c @@ -0,0 +1,5 @@ +int main(int x) { + f(); + replace(); + g(); +} diff --git a/tests/stm4.cocci b/tests/stm4.cocci new file mode 100644 index 0000000..14a8e31 --- /dev/null +++ b/tests/stm4.cocci @@ -0,0 +1,7 @@ +@@ +statement S; +@@ + + f(); + S ++ g(); diff --git a/tests/stm4.res b/tests/stm4.res new file mode 100644 index 0000000..feaf0ee --- /dev/null +++ b/tests/stm4.res @@ -0,0 +1,6 @@ +int main(int x) { + f(); + replace(); + g(); + g(); +} diff --git a/tests/stm5.c b/tests/stm5.c new file mode 100644 index 0000000..d2f6922 --- /dev/null +++ b/tests/stm5.c @@ -0,0 +1,5 @@ +int main(int x) { + f(); + replace(); + g(); +} diff --git a/tests/stm5.cocci b/tests/stm5.cocci new file mode 100644 index 0000000..8a27f4e --- /dev/null +++ b/tests/stm5.cocci @@ -0,0 +1,8 @@ +@@ +statement S; +@@ + + f(); ++ h(); + S ++ g(); diff --git a/tests/stm5.res b/tests/stm5.res new file mode 100644 index 0000000..1adc12f --- /dev/null +++ b/tests/stm5.res @@ -0,0 +1,7 @@ +int main(int x) { + f(); + h(); + replace(); + g(); + g(); +} diff --git a/tests/stm6.c b/tests/stm6.c new file mode 100644 index 0000000..d2f6922 --- /dev/null +++ b/tests/stm6.c @@ -0,0 +1,5 @@ +int main(int x) { + f(); + replace(); + g(); +} diff --git a/tests/stm6.cocci b/tests/stm6.cocci new file mode 100644 index 0000000..b8f993e --- /dev/null +++ b/tests/stm6.cocci @@ -0,0 +1,7 @@ +@@ +statement S; +@@ + ++ h(); + S + g(); diff --git a/tests/stm6.res b/tests/stm6.res new file mode 100644 index 0000000..7b351f8 --- /dev/null +++ b/tests/stm6.res @@ -0,0 +1,6 @@ +int main(int x) { + f(); + h(); + replace(); + g(); +} diff --git a/tests/stm7.c b/tests/stm7.c new file mode 100644 index 0000000..d2f6922 --- /dev/null +++ b/tests/stm7.c @@ -0,0 +1,5 @@ +int main(int x) { + f(); + replace(); + g(); +} diff --git a/tests/stm7.cocci b/tests/stm7.cocci new file mode 100644 index 0000000..20ae6bb --- /dev/null +++ b/tests/stm7.cocci @@ -0,0 +1,8 @@ +// seems to loop! + +@@ +statement S; +@@ + + f(); + S diff --git a/tests/stm7.res b/tests/stm7.res new file mode 100644 index 0000000..d2f6922 --- /dev/null +++ b/tests/stm7.res @@ -0,0 +1,5 @@ +int main(int x) { + f(); + replace(); + g(); +} diff --git a/tests/stm8.c b/tests/stm8.c new file mode 100644 index 0000000..d2f6922 --- /dev/null +++ b/tests/stm8.c @@ -0,0 +1,5 @@ +int main(int x) { + f(); + replace(); + g(); +} diff --git a/tests/stm8.cocci b/tests/stm8.cocci new file mode 100644 index 0000000..6d657c6 --- /dev/null +++ b/tests/stm8.cocci @@ -0,0 +1,7 @@ +@@ +statement S; +@@ + + f(); +- S ++ g(); S diff --git a/tests/stm8.res b/tests/stm8.res new file mode 100644 index 0000000..701b393 --- /dev/null +++ b/tests/stm8.res @@ -0,0 +1,6 @@ +int main(int x) { + f(); + g(); + replace(); + g(); +} diff --git a/tests/stmt.c b/tests/stmt.c new file mode 100644 index 0000000..619c967 --- /dev/null +++ b/tests/stmt.c @@ -0,0 +1,4 @@ +int f() { + int x; + xxx(); +} diff --git a/tests/stmt.cocci b/tests/stmt.cocci new file mode 100644 index 0000000..91e74c8 --- /dev/null +++ b/tests/stmt.cocci @@ -0,0 +1,11 @@ +@@ +statement S, S1; +identifier f; +@@ + +f (...) { + ... when != S1 ++ foo(); + S + ... +} diff --git a/tests/stmt.res b/tests/stmt.res new file mode 100644 index 0000000..37698c3 --- /dev/null +++ b/tests/stmt.res @@ -0,0 +1,5 @@ +int f() { + int x; + foo(); + xxx(); +} diff --git a/tests/strangeorder.c b/tests/strangeorder.c new file mode 100644 index 0000000..03f1d7c --- /dev/null +++ b/tests/strangeorder.c @@ -0,0 +1,15 @@ +struct i2c_client * +i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) +{ + struct i2c_client *client; + + client = kzalloc(sizeof *client, GFP_KERNEL); + if (!client) + return NULL; + + client->adapter = adap; + if (status < 0) { + client = NULL; + } + return client; +} diff --git a/tests/strangeorder.cocci b/tests/strangeorder.cocci new file mode 100644 index 0000000..cd99e91 --- /dev/null +++ b/tests/strangeorder.cocci @@ -0,0 +1,11 @@ +@@ +expression *E; +identifier f; +statement S1; +@@ + +if (E == NULL) ++{ ++ E = NULL; + S1 ++} diff --git a/tests/strangeorder.res b/tests/strangeorder.res new file mode 100644 index 0000000..cfadd57 --- /dev/null +++ b/tests/strangeorder.res @@ -0,0 +1,17 @@ +struct i2c_client * +i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) +{ + struct i2c_client *client; + + client = kzalloc(sizeof *client, GFP_KERNEL); + if (!client) { + client = NULL; + return NULL; + } + + client->adapter = adap; + if (status < 0) { + client = NULL; + } + return client; +} diff --git a/tests/string.c b/tests/string.c new file mode 100644 index 0000000..2c2b138 --- /dev/null +++ b/tests/string.c @@ -0,0 +1 @@ +MODULE_PARM(suppress_pollack, "x"); diff --git a/tests/string.cocci b/tests/string.cocci new file mode 100644 index 0000000..cf65b8e --- /dev/null +++ b/tests/string.cocci @@ -0,0 +1,6 @@ +@@ +identifier I; +@@ + +- MODULE_PARM(I, "i"); ++ module_param(I, int, 0); diff --git a/tests/string.res b/tests/string.res new file mode 100644 index 0000000..2c2b138 --- /dev/null +++ b/tests/string.res @@ -0,0 +1 @@ +MODULE_PARM(suppress_pollack, "x"); diff --git a/tests/struct.c b/tests/struct.c new file mode 100644 index 0000000..b95b139 --- /dev/null +++ b/tests/struct.c @@ -0,0 +1,14 @@ +struct foo { + int x; + struct bar first; + int y; + struct xxx second; + int z; +}; + +int main() { + struct foo *a; + f(a->first); + f(a->second); +} + diff --git a/tests/struct.cocci b/tests/struct.cocci new file mode 100644 index 0000000..4c0679b --- /dev/null +++ b/tests/struct.cocci @@ -0,0 +1,25 @@ +@ r1 @ +identifier X, Y; +@@ + +struct foo { + ... + struct bar X; + ... + struct xxx Y; + ... +}; + +@@ +struct foo *a; +identifier r1.X; +@@ + +- f(a->X); + +@@ +struct foo *a; +identifier r1.Y; +@@ + +- f(a->Y); diff --git a/tests/struct.res b/tests/struct.res new file mode 100644 index 0000000..547214d --- /dev/null +++ b/tests/struct.res @@ -0,0 +1,12 @@ +struct foo { + int x; + struct bar first; + int y; + struct xxx second; + int z; +}; + +int main() { + struct foo *a; +} + diff --git a/tests/struct_metavar.c b/tests/struct_metavar.c new file mode 100644 index 0000000..ea709d7 --- /dev/null +++ b/tests/struct_metavar.c @@ -0,0 +1,18 @@ +struct foo { + int x; + struct bar first; + int y; + struct xxx second; + int z; +}; + +int main() { + struct foo *a; + struct notfoo *b; + f(a->first); + f(a->second); + f(a->second); + f(b->first); + f(b->second); +} + diff --git a/tests/struct_metavar.cocci b/tests/struct_metavar.cocci new file mode 100644 index 0000000..272b9fa --- /dev/null +++ b/tests/struct_metavar.cocci @@ -0,0 +1,26 @@ +@ rule1 @ +type T; +identifier X, Y; +@@ + +T { + ... + struct bar X; + ... + struct xxx Y; + ... +}; + +@@ +rule1.T *a; +identifier rule1.X; +@@ + +- f(a->X); + +@@ +rule1.T *a; +identifier rule1.Y; +@@ + +- f(a->Y); diff --git a/tests/struct_metavar.res b/tests/struct_metavar.res new file mode 100644 index 0000000..031a7b5 --- /dev/null +++ b/tests/struct_metavar.res @@ -0,0 +1,17 @@ +struct foo { + int x; + struct bar first; + int y; + struct xxx second; + int z; +}; + +int main() { + struct foo *a; + struct notfoo *b; + + + f(b->first); + f(b->second); +} + diff --git a/tests/struct_typedef.c b/tests/struct_typedef.c new file mode 100644 index 0000000..23aeaae --- /dev/null +++ b/tests/struct_typedef.c @@ -0,0 +1,15 @@ +typedef struct dvb_frontend { + struct dvb_frontend_ops* ops; +} xx_t; + +typedef struct { + u8 RESET :1; + u8 IDLE :1; + u8 STOP :1; + u8 HIRQ0 :1; + u8 HIRQ1 :1; + u8 na0 :1; + u8 HABAV :1; + u8 na1 :1; + +} bcm3510_register_value; diff --git a/tests/struct_typedef.cocci b/tests/struct_typedef.cocci new file mode 100644 index 0000000..b7dd005 --- /dev/null +++ b/tests/struct_typedef.cocci @@ -0,0 +1,10 @@ +@@ +@@ + +- struct dvb_frontend { ++ struct dvb2_frontend { + ... +- struct dvb_frontend_ops* ops; ++ struct dvb_frontend_ops ops; + ... +}; diff --git a/tests/struct_typedef.res b/tests/struct_typedef.res new file mode 100644 index 0000000..145e97b --- /dev/null +++ b/tests/struct_typedef.res @@ -0,0 +1,15 @@ +typedef struct dvb2_frontend { + struct dvb_frontend_ops ops; +} xx_t; + +typedef struct { + u8 RESET :1; + u8 IDLE :1; + u8 STOP :1; + u8 HIRQ0 :1; + u8 HIRQ1 :1; + u8 na0 :1; + u8 HABAV :1; + u8 na1 :1; + +} bcm3510_register_value; diff --git a/tests/sw.c b/tests/sw.c new file mode 100644 index 0000000..dc55d80 --- /dev/null +++ b/tests/sw.c @@ -0,0 +1 @@ +int f() { switch (x) { case FOO: return; } } diff --git a/tests/sw.cocci b/tests/sw.cocci new file mode 100644 index 0000000..15debdf --- /dev/null +++ b/tests/sw.cocci @@ -0,0 +1,4 @@ +@@ +@@ + +- f(...) { ... } diff --git a/tests/sw.res b/tests/sw.res new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/sw.res @@ -0,0 +1 @@ + diff --git a/tests/switch.c b/tests/switch.c new file mode 100644 index 0000000..8b38b06 --- /dev/null +++ b/tests/switch.c @@ -0,0 +1,8 @@ +int main () { + switch (x) { + default: + break; + case X: + f(); + } +} diff --git a/tests/switch.cocci b/tests/switch.cocci new file mode 100644 index 0000000..50ef4af --- /dev/null +++ b/tests/switch.cocci @@ -0,0 +1,4 @@ +@@ +@@ + +- f(); diff --git a/tests/switch.res b/tests/switch.res new file mode 100644 index 0000000..2f12163 --- /dev/null +++ b/tests/switch.res @@ -0,0 +1,7 @@ +int main () { + switch (x) { + default: + break; + case X: + } +} diff --git a/tests/switch_case.c b/tests/switch_case.c new file mode 100644 index 0000000..8c5552a --- /dev/null +++ b/tests/switch_case.c @@ -0,0 +1,8 @@ +void main(void) +{ + + switch(1) { + case CASE1: case1(); break; + case CASE2: case2(); break; + } +} diff --git a/tests/switch_case.cocci b/tests/switch_case.cocci new file mode 100644 index 0000000..2f3451d --- /dev/null +++ b/tests/switch_case.cocci @@ -0,0 +1,13 @@ +@@ +@@ + +- switch(1) { ++ switch(2) { + case CASE1: + case1(); + case3(); + //case4(); + //break; + case CASE2: case2(); break; + } + \ No newline at end of file diff --git a/tests/switch_label.c b/tests/switch_label.c new file mode 100644 index 0000000..c3c2902 --- /dev/null +++ b/tests/switch_label.c @@ -0,0 +1,9 @@ +int main () { + switch (event) { + case CS_EVENT_CARD_REMOVAL: + one(); + two(); + three(); + break; + } +} diff --git a/tests/tadb.c b/tests/tadb.c new file mode 100644 index 0000000..6d8bfb2 --- /dev/null +++ b/tests/tadb.c @@ -0,0 +1,12 @@ +static int adbhid_kbd_event() +{ +} + + +static void +adbhid_input_register() +{ + + adbhid[id]->input.event = adbhid_kbd_event; + +} diff --git a/tests/td.c b/tests/td.c new file mode 100644 index 0000000..af95354 --- /dev/null +++ b/tests/td.c @@ -0,0 +1,5 @@ +struct foo {int a;}; + +typedef struct blah {int a;} name; + +typedef struct {int a;} xxx; diff --git a/tests/td.cocci b/tests/td.cocci new file mode 100644 index 0000000..91849e1 --- /dev/null +++ b/tests/td.cocci @@ -0,0 +1,8 @@ +@@ +type T; +@@ + +T { +- int a; ++ int b; +}; diff --git a/tests/td.res b/tests/td.res new file mode 100644 index 0000000..7328fad --- /dev/null +++ b/tests/td.res @@ -0,0 +1,5 @@ +struct foo {int b;}; + +typedef struct blah {int b;} name; + +typedef struct {int b;} xxx; diff --git a/tests/test0.c b/tests/test0.c new file mode 100644 index 0000000..3699051 --- /dev/null +++ b/tests/test0.c @@ -0,0 +1,5 @@ +int main(int i) { + f(1); + f(2); + f(1); +} diff --git a/tests/test0.cocci b/tests/test0.cocci new file mode 100644 index 0000000..5265da3 --- /dev/null +++ b/tests/test0.cocci @@ -0,0 +1,4 @@ +@@ +@@ + +- f(1); diff --git a/tests/test0.res b/tests/test0.res new file mode 100644 index 0000000..d47d272 --- /dev/null +++ b/tests/test0.res @@ -0,0 +1,5 @@ +int main(int i) { + + f(2); + +} diff --git a/tests/test1.c b/tests/test1.c new file mode 100644 index 0000000..bb15614 --- /dev/null +++ b/tests/test1.c @@ -0,0 +1,16 @@ +void main(int foo) { + + f(1); + x(); + g(2); + x(); + if(1) { + // h(3); + h(3); + } else { + h(4); + } + + +} + diff --git a/tests/test1.cocci b/tests/test1.cocci new file mode 100644 index 0000000..43f0d29 --- /dev/null +++ b/tests/test1.cocci @@ -0,0 +1,9 @@ +@ rule1 @ +expression X,Y,Z; +@@ + f(X); + ... + g(Z); + ... +- h(Y); ++ h(X,Y,Z); diff --git a/tests/test1.res b/tests/test1.res new file mode 100644 index 0000000..5c0c8c3 --- /dev/null +++ b/tests/test1.res @@ -0,0 +1,15 @@ +void main(int foo) { + + f(1); + x(); + g(2); + x(); + if(1) { + h(1, 3, 2); + } else { + h(1, 4, 2); + } + + +} + diff --git a/tests/test10.c b/tests/test10.c new file mode 100644 index 0000000..f6ad72f --- /dev/null +++ b/tests/test10.c @@ -0,0 +1,9 @@ +void main(int i) { + f(1); + f(1); + g(1); + g(1); // if comment then should work + h(1); + h(1); + +} diff --git a/tests/test10.cocci b/tests/test10.cocci new file mode 100644 index 0000000..3c4352f --- /dev/null +++ b/tests/test10.cocci @@ -0,0 +1,11 @@ +@@ +expression X; +@@ + + f(X) + ... + g(X) + ... +- h(X) ++ h(X,X) + \ No newline at end of file diff --git a/tests/test10.res b/tests/test10.res new file mode 100644 index 0000000..f6ad72f --- /dev/null +++ b/tests/test10.res @@ -0,0 +1,9 @@ +void main(int i) { + f(1); + f(1); + g(1); + g(1); // if comment then should work + h(1); + h(1); + +} diff --git a/tests/test10_ver1.c b/tests/test10_ver1.c new file mode 100644 index 0000000..3724757 --- /dev/null +++ b/tests/test10_ver1.c @@ -0,0 +1,9 @@ +void main(int i) { + f(1); + f(1); + g(1); + //g(1); + h(1); + h(1); + +} diff --git a/tests/test10_ver1.res b/tests/test10_ver1.res new file mode 100644 index 0000000..b4431b7 --- /dev/null +++ b/tests/test10_ver1.res @@ -0,0 +1,9 @@ +void main(int i) { + f(1); + f(1); + g(1); + //g(1); + h(1, 1); + h(1); + +} diff --git a/tests/test11.c b/tests/test11.c new file mode 100644 index 0000000..80a7ff4 --- /dev/null +++ b/tests/test11.c @@ -0,0 +1,7 @@ +void main(int i) { + f(1); + g(1); + g(1); // if comment then simpler + h(1); + +} diff --git a/tests/test11.cocci b/tests/test11.cocci new file mode 100644 index 0000000..3c4352f --- /dev/null +++ b/tests/test11.cocci @@ -0,0 +1,11 @@ +@@ +expression X; +@@ + + f(X) + ... + g(X) + ... +- h(X) ++ h(X,X) + \ No newline at end of file diff --git a/tests/test11.res b/tests/test11.res new file mode 100644 index 0000000..80a7ff4 --- /dev/null +++ b/tests/test11.res @@ -0,0 +1,7 @@ +void main(int i) { + f(1); + g(1); + g(1); // if comment then simpler + h(1); + +} diff --git a/tests/test11_ver1.c b/tests/test11_ver1.c new file mode 100644 index 0000000..a59f179 --- /dev/null +++ b/tests/test11_ver1.c @@ -0,0 +1,7 @@ +void main(int i) { + f(1); + g(1); + //g(1); + h(1); + +} diff --git a/tests/test11_ver1.res b/tests/test11_ver1.res new file mode 100644 index 0000000..80d7d60 --- /dev/null +++ b/tests/test11_ver1.res @@ -0,0 +1,7 @@ +void main(int i) { + f(1); + g(1); + //g(1); + h(1, 1); + +} diff --git a/tests/test12.c b/tests/test12.c new file mode 100644 index 0000000..99c179b --- /dev/null +++ b/tests/test12.c @@ -0,0 +1,8 @@ +void main(int foo) { + + f(1); + foo(); + g(2); + +} + diff --git a/tests/test12.cocci b/tests/test12.cocci new file mode 100644 index 0000000..8ecfec2 --- /dev/null +++ b/tests/test12.cocci @@ -0,0 +1,8 @@ +@@ +expression X, Y; +@@ + +- f(X) ++ f(X,Y) + ... + g(Y) diff --git a/tests/test12.res b/tests/test12.res new file mode 100644 index 0000000..46e8a19 --- /dev/null +++ b/tests/test12.res @@ -0,0 +1,8 @@ +void main(int foo) { + + f(1, 2); + foo(); + g(2); + +} + diff --git a/tests/test1_ver1.c b/tests/test1_ver1.c new file mode 100644 index 0000000..19704d3 --- /dev/null +++ b/tests/test1_ver1.c @@ -0,0 +1,15 @@ +void main(int foo) { + + f(1); + f(1); // if uncoment then problems + g(2); + g(2);// if uncomment then problems + if(1) { + h(3); + } else { + h(4); + } + + +} + diff --git a/tests/test1_ver2.c b/tests/test1_ver2.c new file mode 100644 index 0000000..842bf15 --- /dev/null +++ b/tests/test1_ver2.c @@ -0,0 +1,15 @@ +void main(int foo) { + + f(1); + //f(1); // if uncoment then problems + g(2); + //g(2);// if uncomment then problems + if(1) { + h(3); + } else { + h(4); + } + + +} + diff --git a/tests/test2.c b/tests/test2.c new file mode 100644 index 0000000..0c0db81 --- /dev/null +++ b/tests/test2.c @@ -0,0 +1,8 @@ +void main() +{ + f(1,2,3); + if(1) + g(1); + else + g(1); +} diff --git a/tests/test2.cocci b/tests/test2.cocci new file mode 100644 index 0000000..fa8d02c --- /dev/null +++ b/tests/test2.cocci @@ -0,0 +1,7 @@ +@@ +expression X,Y; +@@ + f(...,X,Y,...); + ... +- g(X); ++ h(X); diff --git a/tests/test2.res b/tests/test2.res new file mode 100644 index 0000000..940a39f --- /dev/null +++ b/tests/test2.res @@ -0,0 +1,8 @@ +void main() +{ + f(1,2,3); + if(1) + h(1); + else + h(1); +} diff --git a/tests/test3.c b/tests/test3.c new file mode 100644 index 0000000..3d96e82 --- /dev/null +++ b/tests/test3.c @@ -0,0 +1,10 @@ +void main() +{ + /* a comment */ + f(3); + + if(1) + g(1); + else + g(2); +} diff --git a/tests/test3.cocci b/tests/test3.cocci new file mode 100644 index 0000000..30008ce --- /dev/null +++ b/tests/test3.cocci @@ -0,0 +1,9 @@ +@@ +expression X,Y; +@@ + f(X); + ... +- g(Y); ++ h(X,Y); + +//error words = [f] \ No newline at end of file diff --git a/tests/test3.res b/tests/test3.res new file mode 100644 index 0000000..c39a08f --- /dev/null +++ b/tests/test3.res @@ -0,0 +1,10 @@ +void main() +{ + /* a comment */ + f(3); + + if(1) + h(3, 1); + else + h(3, 2); +} diff --git a/tests/test4.c b/tests/test4.c new file mode 100644 index 0000000..08a586e --- /dev/null +++ b/tests/test4.c @@ -0,0 +1,9 @@ +void main() +{ + f(1,2,3); + h(1); + if(1) + g(1); + else + g(1); +} diff --git a/tests/test4.cocci b/tests/test4.cocci new file mode 100644 index 0000000..3472a1c --- /dev/null +++ b/tests/test4.cocci @@ -0,0 +1,9 @@ +@@ +expression X,Y; +@@ + f(...,X,Y,...); + ... +- h(X); + ... + g(X); + diff --git a/tests/test4.res b/tests/test4.res new file mode 100644 index 0000000..43da8fd --- /dev/null +++ b/tests/test4.res @@ -0,0 +1,8 @@ +void main() +{ + f(1,2,3); + if(1) + g(1); + else + g(1); +} diff --git a/tests/test5.c b/tests/test5.c new file mode 100644 index 0000000..4493434 --- /dev/null +++ b/tests/test5.c @@ -0,0 +1,22 @@ +/* + * If still have an edge from the startif to endif (AfterNode), + * with a if-then-and-else, then rene will see this edge, + * and that means that the ctl engine will see this direct path from + * startif to endif as a valid execution path. So on this program, + * CTL will reject the formula f(X) ... g(X) because + * when we take the direct path (which should not exist I repeat), + * we can't find a later g(1). + */ +void main() { + + f(1); + + if(1) { + g(1); + } else { + g(1); + } + + // g(1); // if add this then the CTL even with the direct path will this time + // accept, but we cheat. +} diff --git a/tests/test5.cocci b/tests/test5.cocci new file mode 100644 index 0000000..59b5408 --- /dev/null +++ b/tests/test5.cocci @@ -0,0 +1,8 @@ +@@ +expression X; +@@ + + f(X); + ... +- g(X); ++ h(X); diff --git a/tests/test5.res b/tests/test5.res new file mode 100644 index 0000000..99e3958 --- /dev/null +++ b/tests/test5.res @@ -0,0 +1,22 @@ +/* + * If still have an edge from the startif to endif (AfterNode), + * with a if-then-and-else, then rene will see this edge, + * and that means that the ctl engine will see this direct path from + * startif to endif as a valid execution path. So on this program, + * CTL will reject the formula f(X) ... g(X) because + * when we take the direct path (which should not exist I repeat), + * we can't find a later g(1). + */ +void main() { + + f(1); + + if(1) { + h(1); + } else { + h(1); + } + + // g(1); // if add this then the CTL even with the direct path will this time + // accept, but we cheat. +} diff --git a/tests/test5_ver1.c b/tests/test5_ver1.c new file mode 100644 index 0000000..4504438 --- /dev/null +++ b/tests/test5_ver1.c @@ -0,0 +1,22 @@ +/* + * If still have an edge from the startif to endif (AfterNode), + * with a if-then-and-else, then rene will see this edge, + * and that means that the ctl engine will see this direct path from + * startif to endif as a valid execution path. So on this program, + * CTL will reject the formula f(X) ... g(X) because + * when we take the direct path (which should not exist I repeat), + * we can't find a later g(1). + */ +void main() { + + f(1); + + if(1) { + g(1); + } else { + g(1); + } + + g(1); // if add this then the CTL even with the direct path will this time + // accept, but we cheat. +} diff --git a/tests/test5_ver1.res b/tests/test5_ver1.res new file mode 100644 index 0000000..8686131 --- /dev/null +++ b/tests/test5_ver1.res @@ -0,0 +1,23 @@ +/* + * If still have an edge from the startif to endif (AfterNode), + * with a if-then-and-else, then rene will see this edge, + * and that means that the ctl engine will see this direct path from + * startif to endif as a valid execution path. So on this program, + * CTL will reject the formula f(X) ... g(X) because + * when we take the direct path (which should not exist I repeat), + * we can't find a later g(1). + */ +void main() { + + f(1); + + if(1) { + h(1); + } else { + h(1); + } + + + g(1); // if add this then the CTL even with the direct path will this time + // accept, but we cheat. +} diff --git a/tests/test6.c b/tests/test6.c new file mode 100644 index 0000000..f70fa1d --- /dev/null +++ b/tests/test6.c @@ -0,0 +1,26 @@ +int i; + +void main() +{ + /* a comment */ + + f(4) + f(5); + + //f(f(3)); // if uncomment, should have the warning "already minused token" + if(f(1)) + f(1); + else + f(2); + + if(1) + g(1); + else + g(2); +} + + +void mainbis() { + f(10); +} + + diff --git a/tests/test6.cocci b/tests/test6.cocci new file mode 100644 index 0000000..caf6245 --- /dev/null +++ b/tests/test6.cocci @@ -0,0 +1,8 @@ +@@ +expression X; +@@ + +- f(X) ++ f(X,"foo") + +//error words = [f] \ No newline at end of file diff --git a/tests/test6.res b/tests/test6.res new file mode 100644 index 0000000..73ca258 --- /dev/null +++ b/tests/test6.res @@ -0,0 +1,26 @@ +int i; + +void main() +{ + /* a comment */ + + f(4, "foo") + f(5, "foo"); + + //f(f(3)); // if uncomment, should have the warning "already minused token" + if(f(1, "foo")) + f(1, "foo"); + else + f(2, "foo"); + + if(1) + g(1); + else + g(2); +} + + +void mainbis() { + f(10, "foo"); +} + + diff --git a/tests/test6_ver1.c b/tests/test6_ver1.c new file mode 100644 index 0000000..27c6e46 --- /dev/null +++ b/tests/test6_ver1.c @@ -0,0 +1,26 @@ +int i; + +void main() +{ + /* a comment */ + + f(4) + f(5); + + f(f(3)); // if uncomment, should have the warning "already minused token" + if(f(1)) + f(1); + else + f(2); + + if(1) + g(1); + else + g(2); +} + + +void mainbis() { + f(10); +} + + diff --git a/tests/test7.c b/tests/test7.c new file mode 100644 index 0000000..b43a4db --- /dev/null +++ b/tests/test7.c @@ -0,0 +1,11 @@ +void main() +{ + + if(1) { + f(1); + } + + f(3); + + /* nice comment */ +} diff --git a/tests/test7.cocci b/tests/test7.cocci new file mode 100644 index 0000000..e9ebdd3 --- /dev/null +++ b/tests/test7.cocci @@ -0,0 +1,7 @@ +@@ +expression X; +@@ + +- f(X); ++ f(X,"foo"); ++ f(X,"bar"); diff --git a/tests/test7.res b/tests/test7.res new file mode 100644 index 0000000..d208a76 --- /dev/null +++ b/tests/test7.res @@ -0,0 +1,13 @@ +void main() +{ + + if(1) { + f(1, "foo"); + f(1, "bar"); + } + + f(3, "foo"); + f(3, "bar"); + + /* nice comment */ +} diff --git a/tests/test8.c b/tests/test8.c new file mode 100644 index 0000000..aca6c4b --- /dev/null +++ b/tests/test8.c @@ -0,0 +1,12 @@ +void main(int foo) { + + float k; + int i; + float j; + + { + j++; + } + +} + diff --git a/tests/test8.cocci b/tests/test8.cocci new file mode 100644 index 0000000..326a6ba --- /dev/null +++ b/tests/test8.cocci @@ -0,0 +1,13 @@ +@@ +identifier bar; +identifier i; +identifier func; +@@ + + func( ++ char i, + int bar) { + ... +- int i; + ... + } diff --git a/tests/test8.res b/tests/test8.res new file mode 100644 index 0000000..d2f489e --- /dev/null +++ b/tests/test8.res @@ -0,0 +1,11 @@ +void main(char i, int foo) { + + float k; + float j; + + { + j++; + } + +} + diff --git a/tests/test9.c b/tests/test9.c new file mode 100644 index 0000000..5113ef9 --- /dev/null +++ b/tests/test9.c @@ -0,0 +1,18 @@ +void main(int foo) { + + f(1); +// f(1); // if uncoment then problems + g(2); + if(1) { + h(3); + } else { + h(4); + } + +// if uncomment then problems + { + i++; + } + +} + diff --git a/tests/test9.cocci b/tests/test9.cocci new file mode 100644 index 0000000..efdeb3c --- /dev/null +++ b/tests/test9.cocci @@ -0,0 +1,13 @@ +@@ +identifier func; // work with local function ? with function ? +expression X,Y; +@@ + + func(...) { + ... + f(X); + ... +- h(Y); ++ h(X,Y); + ... + } diff --git a/tests/test9.res b/tests/test9.res new file mode 100644 index 0000000..94ad4fa --- /dev/null +++ b/tests/test9.res @@ -0,0 +1,18 @@ +void main(int foo) { + + f(1); +// f(1); // if uncoment then problems + g(2); + if(1) { + h(1, 3); + } else { + h(1, 4); + } + +// if uncomment then problems + { + i++; + } + +} + diff --git a/tests/test9_ver1.c b/tests/test9_ver1.c new file mode 100644 index 0000000..90f0cd5 --- /dev/null +++ b/tests/test9_ver1.c @@ -0,0 +1,18 @@ +void main(int foo) { + + f(1); + f(1); // if uncoment then problems + g(2); + if(1) { + h(3); + } else { + h(4); + } + + // if uncomment then problems + { + i++; + } + +} + diff --git a/tests/three.c b/tests/three.c new file mode 100644 index 0000000..077d200 --- /dev/null +++ b/tests/three.c @@ -0,0 +1,20 @@ +int ide_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + + DEBUG(1, "ide_event(0x%06x)\n", event); +} /* ide_event */ + +/*====================================================================*/ + +static int init_ide_cs(void) +{ + register_pccard_driver(&ide_attach); + return 0; +} + +static void exit_ide_cs(void) +{ + unregister_pccard_driver(&dev_info); +} diff --git a/tests/three.cocci b/tests/three.cocci new file mode 100644 index 0000000..0f047d3 --- /dev/null +++ b/tests/three.cocci @@ -0,0 +1,31 @@ +@ rule1 @ +identifier init; +identifier XXX_attach, XXX_detach; // pad: XXX_detach useful ? +@@ + + int init (...) { + ... + register_pccard_driver(&XXX_attach) + ... + } + +@ rule2 extends rule1 @ +@@ + + init (...) { + ... +- register_pccard_driver(&XXX_attach); +- return 0; ++ return pcmcia_register_driver(&ZZZ_driver); + } + +@ rule3 extends rule1 @ +identifier exit; +@@ + + exit (...) { + ... +- unregister_pccard_driver(&dev_info); ++ pcmcia_unregister_driver(&XXX_attach); + ... + } diff --git a/tests/three_types.c b/tests/three_types.c new file mode 100644 index 0000000..bde8870 --- /dev/null +++ b/tests/three_types.c @@ -0,0 +1,11 @@ +typedef struct _drm_via_blitq { + struct work_struct wq; +} drm_via_blitq_t; + +void +via_init_dmablit(drm_device_t *dev) +{ + drm_via_blitq_t *blitq; + + INIT_WORK(&blitq->wq, via_dmablit_workqueue,blitq); +} diff --git a/tests/three_types.cocci b/tests/three_types.cocci new file mode 100644 index 0000000..1d26fa6 --- /dev/null +++ b/tests/three_types.cocci @@ -0,0 +1,25 @@ +@ non_delayed_fn disable all @ +type local_type; +local_type *device; +identifier fld, fn; +@@ + + INIT_WORK(&device->fld, +- fn, device ++ fn + ); + +@ rule7a disable all @ +identifier dataq, non_delayed_fn.fn, non_delayed_fn.fld; +type non_delayed_fn.local_type; +@@ + + fn ( +- void *dataq ++ struct work_struct *workq + ) { + <... +- dataq ++ container_of(workq,local_type,fld) + ...> + } diff --git a/tests/three_types.res b/tests/three_types.res new file mode 100644 index 0000000..6879124 --- /dev/null +++ b/tests/three_types.res @@ -0,0 +1,11 @@ +typedef struct _drm_via_blitq { + struct work_struct wq; +} drm_via_blitq_t; + +void +via_init_dmablit(drm_device_t *dev) +{ + drm_via_blitq_t *blitq; + + INIT_WORK(&blitq->wq, via_dmablit_workqueue); +} diff --git a/tests/threea.c b/tests/threea.c new file mode 100644 index 0000000..702e799 --- /dev/null +++ b/tests/threea.c @@ -0,0 +1,4 @@ +int main() { + f(12); + q(12); +} diff --git a/tests/threea.cocci b/tests/threea.cocci new file mode 100644 index 0000000..606210e --- /dev/null +++ b/tests/threea.cocci @@ -0,0 +1,15 @@ +@ rule1 @ +expression E; +@@ + +f(E); + +//@ rule2 extends rule1 @ +//@@ +// +//- h(E); + +@ rule3 extends rule1 @ +@@ + +- q(E); diff --git a/tests/threea.res b/tests/threea.res new file mode 100644 index 0000000..8db466c --- /dev/null +++ b/tests/threea.res @@ -0,0 +1,3 @@ +int main() { + f(12); +} diff --git a/tests/top.c b/tests/top.c new file mode 100644 index 0000000..e6eb8d1 --- /dev/null +++ b/tests/top.c @@ -0,0 +1,2 @@ +MODULE_PARM(suppress_pollack, "i"); + diff --git a/tests/top.cocci b/tests/top.cocci new file mode 100644 index 0000000..f10ae48 --- /dev/null +++ b/tests/top.cocci @@ -0,0 +1,5 @@ +@@ +@@ + +- MODULE_PARM(...); ++ module_param(I, int, 0); diff --git a/tests/top.res b/tests/top.res new file mode 100644 index 0000000..c19e5f5 --- /dev/null +++ b/tests/top.res @@ -0,0 +1 @@ +module_param(I, int, 0); diff --git a/tests/topdec.c b/tests/topdec.c new file mode 100644 index 0000000..a61b806 --- /dev/null +++ b/tests/topdec.c @@ -0,0 +1,8 @@ +#ifdef TUN_DEBUG +static int debug; +#endif + +/* Network device part of the driver */ + +static LIST_HEAD(tun_dev_list); +static struct ethtool_ops tun_ethtool_ops; diff --git a/tests/topdec.cocci b/tests/topdec.cocci new file mode 100644 index 0000000..6865743 --- /dev/null +++ b/tests/topdec.cocci @@ -0,0 +1,6 @@ +@@ +identifier I; +@@ + ++ static const struct ethtool_ops I; +- static struct ethtool_ops I; diff --git a/tests/topdec.res b/tests/topdec.res new file mode 100644 index 0000000..4b33ff4 --- /dev/null +++ b/tests/topdec.res @@ -0,0 +1,8 @@ +#ifdef TUN_DEBUG +static int debug; +#endif + +/* Network device part of the driver */ + +static LIST_HEAD(tun_dev_list); +static const struct ethtool_ops tun_ethtool_ops; diff --git a/tests/topdec_ver1.c b/tests/topdec_ver1.c new file mode 100644 index 0000000..febf5f4 --- /dev/null +++ b/tests/topdec_ver1.c @@ -0,0 +1,7 @@ +#ifdef TUN_DEBUG +static int debug; +#endif + +/* Network device part of the driver */ + +static struct ethtool_ops tun_ethtool_ops; diff --git a/tests/topdec_ver1.res b/tests/topdec_ver1.res new file mode 100644 index 0000000..2f018e2 --- /dev/null +++ b/tests/topdec_ver1.res @@ -0,0 +1,7 @@ +#ifdef TUN_DEBUG +static int debug; +#endif + +/* Network device part of the driver */ + +static const struct ethtool_ops tun_ethtool_ops; diff --git a/tests/topdec_ver2.c b/tests/topdec_ver2.c new file mode 100644 index 0000000..6f7b842 --- /dev/null +++ b/tests/topdec_ver2.c @@ -0,0 +1,8 @@ +#ifdef TUN_DEBUG +static int debug; +#endif + +/* Network device part of the driver */ + +int x; +static struct ethtool_ops tun_ethtool_ops; diff --git a/tests/topdec_ver2.res b/tests/topdec_ver2.res new file mode 100644 index 0000000..c54eb04 --- /dev/null +++ b/tests/topdec_ver2.res @@ -0,0 +1,8 @@ +#ifdef TUN_DEBUG +static int debug; +#endif + +/* Network device part of the driver */ + +int x; +static const struct ethtool_ops tun_ethtool_ops; diff --git a/tests/toplevel_macrostmt.c b/tests/toplevel_macrostmt.c new file mode 100644 index 0000000..c114cb5 --- /dev/null +++ b/tests/toplevel_macrostmt.c @@ -0,0 +1,10 @@ +void main(int i) +{ +} + + +MODULE_PARM(x,y); +MODULE_AUTHOR("me"); + + + diff --git a/tests/toplevel_macrostmt.cocci b/tests/toplevel_macrostmt.cocci new file mode 100644 index 0000000..2ca4ce1 --- /dev/null +++ b/tests/toplevel_macrostmt.cocci @@ -0,0 +1,11 @@ +// better perhaps to use a +// declaration MODULE_PARM; +// declaration module_parm; +// ? +@@ +expression x,y; +@@ + +- MODULE_PARM(x,y); ++ module_param(x,int,y); + diff --git a/tests/toplevel_macrostmt.res b/tests/toplevel_macrostmt.res new file mode 100644 index 0000000..c17a6d3 --- /dev/null +++ b/tests/toplevel_macrostmt.res @@ -0,0 +1,9 @@ +void main(int i) +{ +} + +module_param(x, int , y); +MODULE_AUTHOR("me"); + + + diff --git a/tests/toplevel_struct.c b/tests/toplevel_struct.c new file mode 100644 index 0000000..50edb89 --- /dev/null +++ b/tests/toplevel_struct.c @@ -0,0 +1,85 @@ +struct SHT usb_stor_host_template = { + /* basic userland interface stuff */ + .name = "usb-storage", + .proc_name = "usb-storage", + .proc_info2 = usb_storage_proc_info2, + .proc_info = usb_storage_proc_info, + .proc_dir = NULL, + .info = usb_storage_info, + .ioctl = NULL, + + /* old-style detect and release */ + .detect = NULL, + .release = NULL, + + /* command interface -- queued only */ + .command = NULL, + .queuecommand = usb_storage_queuecommand, + + /* error and abort handlers */ + .eh_abort_handler = usb_storage_command_abort, + .eh_device_reset_handler = usb_storage_device_reset, + .eh_bus_reset_handler = usb_storage_bus_reset, + .eh_host_reset_handler = NULL, + .eh_strategy_handler = NULL, + + /* queue commands only, only one command per LUN */ + .can_queue = 1, + .cmd_per_lun = 1, + + /* unknown initiator id */ + .this_id = -1, + + /* no limit on commands */ + .max_sectors = 0, + + /* pre- and post- device scan functions */ + .slave_alloc = NULL, + .slave_configure = NULL, + .slave_destroy = NULL, + + /* lots of sg segments can be handled */ + .sg_tablesize = SG_ALL, + + /* use 32-bit address space for DMA */ + .unchecked_isa_dma = FALSE, + .highmem_io = FALSE, + + /* merge commands... this seems to help performance, but + * periodically someone should test to see which setting is more + * optimal. + */ + .use_clustering = TRUE, + + /* emulated HBA */ + .emulated = TRUE, + + /* sorry, no BIOS to help us */ + .bios_param = NULL, + + /* module management */ + .module = THIS_MODULE +}; + +/* For a device that is "Not Ready" */ +unsigned char usb_stor_sense_notready[18] = { + [0] = 0x70, /* current error */ + [2] = 0x02, /* not ready */ + [7] = 0x0a, /* additional length */ + [12] = 0x04, /* not ready */ + [13] = 0x03 /* manual intervention */ +}; + + +void usb_storage_proc_info(int i) { + f(1); +} + +void usb_storage_proc_info2(int i) { + f(27); +} + + +void not_usb_storage_proc_info(int i) { + f(1); +} diff --git a/tests/toplevel_struct.cocci b/tests/toplevel_struct.cocci new file mode 100644 index 0000000..c4bc01b --- /dev/null +++ b/tests/toplevel_struct.cocci @@ -0,0 +1,44 @@ +@ rule1 @ +identifier proc_info_func, proc_info_func2; +@@ + +struct SHT usb_stor_host_template = { + .proc_info = proc_info_func, + .proc_info2 = proc_info_func2, ++ .foo = 12, +}; + +//@@ +//identifier proc_info_func, proc_info_func2; +//@@ +// +//struct SHT xxx = { +// .proc_info2 = proc_info_func2, +//+ .proc_info = proc_info_func, +//+ .foo = 12 +//}; +//@@ +//identifier proc_info_func, proc_info_func2; +//@@ +// +//struct SHT yyy = { +//+ .proc_info2 = proc_info_func2, +//+ .proc_info = proc_info_func, +//+ .foo = 12 +//}; + +@ rule2 extends rule1 @ +@@ + +proc_info_func(...) { +- f(1); ++ g(1); +} + +@ rule3 extends rule1 @ +@@ + +proc_info_func2(...) { +- f(27); ++ g(27); +} \ No newline at end of file diff --git a/tests/toplevel_struct.res b/tests/toplevel_struct.res new file mode 100644 index 0000000..8662ac0 --- /dev/null +++ b/tests/toplevel_struct.res @@ -0,0 +1,86 @@ +struct SHT usb_stor_host_template = { + /* basic userland interface stuff */ + .name = "usb-storage", + .proc_name = "usb-storage", + .proc_info2 = usb_storage_proc_info2, + .foo = 12, + .proc_info = usb_storage_proc_info, + .proc_dir = NULL, + .info = usb_storage_info, + .ioctl = NULL, + + /* old-style detect and release */ + .detect = NULL, + .release = NULL, + + /* command interface -- queued only */ + .command = NULL, + .queuecommand = usb_storage_queuecommand, + + /* error and abort handlers */ + .eh_abort_handler = usb_storage_command_abort, + .eh_device_reset_handler = usb_storage_device_reset, + .eh_bus_reset_handler = usb_storage_bus_reset, + .eh_host_reset_handler = NULL, + .eh_strategy_handler = NULL, + + /* queue commands only, only one command per LUN */ + .can_queue = 1, + .cmd_per_lun = 1, + + /* unknown initiator id */ + .this_id = -1, + + /* no limit on commands */ + .max_sectors = 0, + + /* pre- and post- device scan functions */ + .slave_alloc = NULL, + .slave_configure = NULL, + .slave_destroy = NULL, + + /* lots of sg segments can be handled */ + .sg_tablesize = SG_ALL, + + /* use 32-bit address space for DMA */ + .unchecked_isa_dma = FALSE, + .highmem_io = FALSE, + + /* merge commands... this seems to help performance, but + * periodically someone should test to see which setting is more + * optimal. + */ + .use_clustering = TRUE, + + /* emulated HBA */ + .emulated = TRUE, + + /* sorry, no BIOS to help us */ + .bios_param = NULL, + + /* module management */ + .module = THIS_MODULE +}; + +/* For a device that is "Not Ready" */ +unsigned char usb_stor_sense_notready[18] = { + [0] = 0x70, /* current error */ + [2] = 0x02, /* not ready */ + [7] = 0x0a, /* additional length */ + [12] = 0x04, /* not ready */ + [13] = 0x03 /* manual intervention */ +}; + + +void usb_storage_proc_info(int i) { + g(1); +} + +void usb_storage_proc_info2(int i) { + g(27); +} + + +void not_usb_storage_proc_info(int i) { + f(1); +} diff --git a/tests/toplevel_struct_modif.c b/tests/toplevel_struct_modif.c new file mode 100644 index 0000000..c8dc362 --- /dev/null +++ b/tests/toplevel_struct_modif.c @@ -0,0 +1,70 @@ +struct SHT usb_stor_host_template = { + /* basic userland interface stuff */ + .name = "usb-storage", + .proc_name = "usb-storage", + .proc_info = usb_storage_proc_info, + .proc_dir = NULL, + .info = usb_storage_info, + .ioctl = NULL, + + /* old-style detect and release */ + .detect = NULL, + .release = NULL, + + /* command interface -- queued only */ + .command = NULL, + .queuecommand = usb_storage_queuecommand, + + /* error and abort handlers */ + .eh_abort_handler = usb_storage_command_abort, + .eh_device_reset_handler = usb_storage_device_reset, + .eh_bus_reset_handler = usb_storage_bus_reset, + .eh_host_reset_handler = NULL, + .eh_strategy_handler = NULL, + + /* queue commands only, only one command per LUN */ + .can_queue = 1, + .cmd_per_lun = 1, + + /* unknown initiator id */ + .this_id = -1, + + /* no limit on commands */ + .max_sectors = 0, + + /* pre- and post- device scan functions */ + .slave_alloc = NULL, + .slave_configure = NULL, + .slave_destroy = NULL, + + /* lots of sg segments can be handled */ + .sg_tablesize = SG_ALL, + + /* use 32-bit address space for DMA */ + .unchecked_isa_dma = FALSE, + .highmem_io = FALSE, + + /* merge commands... this seems to help performance, but + * periodically someone should test to see which setting is more + * optimal. + */ + .use_clustering = TRUE, + + /* emulated HBA */ + .emulated = TRUE, + + /* sorry, no BIOS to help us */ + .bios_param = NULL, + + /* module management */ + .module = THIS_MODULE +}; + +/* For a device that is "Not Ready" */ +unsigned char usb_stor_sense_notready[18] = { + [0] = 0x70, /* current error */ + [2] = 0x02, /* not ready */ + [7] = 0x0a, /* additional length */ + [12] = 0x04, /* not ready */ + [13] = 0x03 /* manual intervention */ +}; diff --git a/tests/toplevel_struct_modif.cocci b/tests/toplevel_struct_modif.cocci new file mode 100644 index 0000000..5c89ef3 --- /dev/null +++ b/tests/toplevel_struct_modif.cocci @@ -0,0 +1,10 @@ +@@ +identifier proc_info_func; +@@ + +struct SHT usb_stor_host_template = { + .name = "usb-storage", + .proc_name = "usb-storage", +- .proc_info = proc_info_func, + .ioctl = NULL +}; diff --git a/tests/tup.c b/tests/tup.c new file mode 100644 index 0000000..9a50a31 --- /dev/null +++ b/tests/tup.c @@ -0,0 +1,10 @@ +static int cm206_block_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) +{ + return cdrom_ioctl(&cm206_info, inode, cmd, arg); +} + +static struct block_device_operations cm206_bdops = +{ + .ioctl = cm206_block_ioctl +}; diff --git a/tests/tup.cocci b/tests/tup.cocci new file mode 100644 index 0000000..e7e9baf --- /dev/null +++ b/tests/tup.cocci @@ -0,0 +1,22 @@ +@ rule1 @ +identifier I; +identifier f; +@@ + +struct block_device_operations I = { + .ioctl = f, +}; + +@@ +identifier rule1.f; +expression A, B, C; +identifier inodename, filename, cmd, arg; +@@ + +f(struct inode *inodename, struct file *filename, unsigned int cmd, + unsigned long arg) { + <... +- cdrom_ioctl(A, inodename, cmd, arg) ++ xxx() + ...> +} diff --git a/tests/tup.res b/tests/tup.res new file mode 100644 index 0000000..f48155a --- /dev/null +++ b/tests/tup.res @@ -0,0 +1,10 @@ +static int cm206_block_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) +{ + return xxx(); +} + +static struct block_device_operations cm206_bdops = +{ + .ioctl = cm206_block_ioctl +}; diff --git a/tests/twoproto.c b/tests/twoproto.c new file mode 100644 index 0000000..ed7df41 --- /dev/null +++ b/tests/twoproto.c @@ -0,0 +1,11 @@ +static void tc574_config(dev_link_t *link); + +static int tc574_attach(struct pcmcia_device *p_dev) +{ + dev_link_t *link = dev_to_instance(p_dev); +} + +static void tc574_detach(struct pcmcia_device *p_dev) +{ + dev_link_t *link = dev_to_instance(p_dev); +} diff --git a/tests/twoproto.cocci b/tests/twoproto.cocci new file mode 100644 index 0000000..4945b8b --- /dev/null +++ b/tests/twoproto.cocci @@ -0,0 +1,12 @@ +@@ +identifier f, p_dev, link; +@@ + +f(struct pcmcia_device * +- p_dev ++ link + ) { + ... +- dev_link_t *link = dev_to_instance(p_dev); + ... +} diff --git a/tests/twoproto.res b/tests/twoproto.res new file mode 100644 index 0000000..ab08968 --- /dev/null +++ b/tests/twoproto.res @@ -0,0 +1,9 @@ +static void tc574_config(dev_link_t *link); + +static int tc574_attach(struct pcmcia_device *link) +{ +} + +static void tc574_detach(struct pcmcia_device *link) +{ +} diff --git a/tests/ty.c b/tests/ty.c new file mode 100644 index 0000000..3ae7e79 --- /dev/null +++ b/tests/ty.c @@ -0,0 +1,4 @@ +int main () { + struct foo x; + return 12; +} diff --git a/tests/ty.cocci b/tests/ty.cocci new file mode 100644 index 0000000..a99e496 --- /dev/null +++ b/tests/ty.cocci @@ -0,0 +1,5 @@ +@@ +@@ + ++ const + struct foo diff --git a/tests/ty.res b/tests/ty.res new file mode 100644 index 0000000..80fa7de --- /dev/null +++ b/tests/ty.res @@ -0,0 +1,6 @@ +int main () { + const struct foo x; + return 12; +} + + diff --git a/tests/ty1.c b/tests/ty1.c new file mode 100644 index 0000000..dc6f32c --- /dev/null +++ b/tests/ty1.c @@ -0,0 +1,4 @@ +int fn(int y) { + char x; + foo(int,char); +} diff --git a/tests/ty1.cocci b/tests/ty1.cocci new file mode 100644 index 0000000..12a62ad --- /dev/null +++ b/tests/ty1.cocci @@ -0,0 +1,9 @@ +@@ +type T; +identifier fn; +@@ + + fn(...) { + T x; +- foo(int,T); + } diff --git a/tests/ty1.res b/tests/ty1.res new file mode 100644 index 0000000..8177e83 --- /dev/null +++ b/tests/ty1.res @@ -0,0 +1,3 @@ +int fn(int y) { + char x; +} diff --git a/tests/ty_tyexp.c b/tests/ty_tyexp.c new file mode 100644 index 0000000..ee307ff --- /dev/null +++ b/tests/ty_tyexp.c @@ -0,0 +1,12 @@ +void main(double z) { + + int x; + int y; +} + +int main(int z) { +} + + +int main2(int z); + diff --git a/tests/ty_tyexp.cocci b/tests/ty_tyexp.cocci new file mode 100644 index 0000000..81e39c4 --- /dev/null +++ b/tests/ty_tyexp.cocci @@ -0,0 +1,5 @@ +@@ +@@ + +- int ++ float diff --git a/tests/ty_tyexp.res b/tests/ty_tyexp.res new file mode 100644 index 0000000..5ab17b4 --- /dev/null +++ b/tests/ty_tyexp.res @@ -0,0 +1,11 @@ +void main(double z) { + + float x; + float y; +} + +float main(float z) { +} + +float main2(float z); + diff --git a/tests/type.c b/tests/type.c new file mode 100644 index 0000000..6250d57 --- /dev/null +++ b/tests/type.c @@ -0,0 +1,5 @@ +int foo() { + int x; + return 0; +} + diff --git a/tests/type.cocci b/tests/type.cocci new file mode 100644 index 0000000..8a317d9 --- /dev/null +++ b/tests/type.cocci @@ -0,0 +1,11 @@ +@@ +type T; +@@ + + foo(...) { + <... +- T x; ++ T *x; + ...> + } + \ No newline at end of file diff --git a/tests/type.res b/tests/type.res new file mode 100644 index 0000000..498f4a7 --- /dev/null +++ b/tests/type.res @@ -0,0 +1,5 @@ +int foo() { + int *x; + return 0; +} + diff --git a/tests/type1.c b/tests/type1.c new file mode 100644 index 0000000..6250d57 --- /dev/null +++ b/tests/type1.c @@ -0,0 +1,5 @@ +int foo() { + int x; + return 0; +} + diff --git a/tests/type1.cocci b/tests/type1.cocci new file mode 100644 index 0000000..8b0d46c --- /dev/null +++ b/tests/type1.cocci @@ -0,0 +1,11 @@ +@@ +identifier q; +@@ + + foo(...) { + int ++ * + q; + ... + } + \ No newline at end of file diff --git a/tests/type1.res b/tests/type1.res new file mode 100644 index 0000000..498f4a7 --- /dev/null +++ b/tests/type1.res @@ -0,0 +1,5 @@ +int foo() { + int *x; + return 0; +} + diff --git a/tests/type_annotated.c b/tests/type_annotated.c new file mode 100644 index 0000000..6fb83fb --- /dev/null +++ b/tests/type_annotated.c @@ -0,0 +1,20 @@ +void f1(int z) { + + struct foo i; + struct foo2 j; + int k; + + j+i.foo+j.foo; + +} + + + +void f2(struct foo i) { + + struct foo2 j; + int k; + + j+i.foo+j.foo; + +} diff --git a/tests/type_annotated.cocci b/tests/type_annotated.cocci new file mode 100644 index 0000000..ab7c388 --- /dev/null +++ b/tests/type_annotated.cocci @@ -0,0 +1,8 @@ +@@ +struct foo x; +//expression x; +@@ + + +- x.foo ++ x.newfoo \ No newline at end of file diff --git a/tests/type_annotated.res b/tests/type_annotated.res new file mode 100644 index 0000000..10fb43a --- /dev/null +++ b/tests/type_annotated.res @@ -0,0 +1,20 @@ +void f1(int z) { + + struct foo i; + struct foo2 j; + int k; + + j+i.newfoo+j.foo; + +} + + + +void f2(struct foo i) { + + struct foo2 j; + int k; + + j+i.newfoo+j.foo; + +} diff --git a/tests/type_annotated_fields.c b/tests/type_annotated_fields.c new file mode 100644 index 0000000..eb79fc9 --- /dev/null +++ b/tests/type_annotated_fields.c @@ -0,0 +1,42 @@ +typedef struct bluecard_info_t { + dev_link_t link; + dev_node_t node; + + struct hci_dev *hdev; + + spinlock_t lock; /* For serializing operations */ + struct timer_list timer; /* For LED control */ + + struct sk_buff_head txq; + unsigned long tx_state; + + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; + + unsigned char ctrl_reg; + unsigned long hw_state; /* Status of the hardware and LED control */ +} bluecard_info_t; + + +static int bluecard_hci_send_frame(struct sk_buff *skb) +{ + bluecard_info_t *info; + struct hci_dev *hdev = (struct hci_dev *)(skb->dev); + skb->pkt_type; + hdev->stat.cmd_tx++; +} + +static void bluecard_receive(bluecard_info_t *info, unsigned int offset) +{ + + unsigned char buf[31]; + int i, len; + bluecard_info_t info2; + + info->rx_skb->pkt_type = buf[i]; + info2.tx_state; + +} + + diff --git a/tests/type_annotated_fields.cocci b/tests/type_annotated_fields.cocci new file mode 100644 index 0000000..ada5132 --- /dev/null +++ b/tests/type_annotated_fields.cocci @@ -0,0 +1,17 @@ +@@ +struct sk_buff *skb; +@@ + +// and not +// @@ +// expression skb; +// @@ + + +( +- &(skb->pkt_type) ++ &bt_cb(skb)->pkt_type +| +- skb->pkt_type ++ bt_cb(skb)->pkt_type +) diff --git a/tests/type_infer.c b/tests/type_infer.c new file mode 100644 index 0000000..44dd37a --- /dev/null +++ b/tests/type_infer.c @@ -0,0 +1,6 @@ +int __init +snd_pmac_awacs_init(struct snd_pmac *chip) +{ + struct awacs_amp *amp = kmalloc(sizeof(*amp)); + memset(sizeof(*amp)); +} diff --git a/tests/type_infer.cocci b/tests/type_infer.cocci new file mode 100644 index 0000000..dd03e06 --- /dev/null +++ b/tests/type_infer.cocci @@ -0,0 +1,16 @@ +@ disable all @ +expression *xx; +@@ + +- foo(xx); + +@ disable all @ +type T1; +identifier x; +expression E1; +@@ + +- T1 x = kmalloc(E1); + ... +- memset(E1); + diff --git a/tests/type_iso.c b/tests/type_iso.c new file mode 100644 index 0000000..49cc163 --- /dev/null +++ b/tests/type_iso.c @@ -0,0 +1,24 @@ + +struct SHT ops1; +struct SHT2 notops1; + + +void main(int i) +{ + ops1.proc_info =1; + notops1.proc_info =1; + +} + + +typedef struct SHT SHT_t; + +SHT_t ops2; +SHT2_t notops2; + +void main(int i) +{ + ops2.proc_info =1; + notops2.proc_info =1; + +} diff --git a/tests/type_iso.cocci b/tests/type_iso.cocci new file mode 100644 index 0000000..a27478d --- /dev/null +++ b/tests/type_iso.cocci @@ -0,0 +1,5 @@ +@@ +struct SHT fops; +@@ + +- fops.proc_info = 1; \ No newline at end of file diff --git a/tests/type_ver1.c b/tests/type_ver1.c new file mode 100644 index 0000000..80dd2d0 --- /dev/null +++ b/tests/type_ver1.c @@ -0,0 +1,5 @@ +int foo() { + struct foo x; + return 0; +} + diff --git a/tests/type_ver1.res b/tests/type_ver1.res new file mode 100644 index 0000000..e36a037 --- /dev/null +++ b/tests/type_ver1.res @@ -0,0 +1,5 @@ +int foo() { + struct foo *x; + return 0; +} + diff --git a/tests/type_ver2.c b/tests/type_ver2.c new file mode 100644 index 0000000..46ba5c3 --- /dev/null +++ b/tests/type_ver2.c @@ -0,0 +1,5 @@ +int foo() { + int x[10]; + return 0; +} + diff --git a/tests/type_ver2.res b/tests/type_ver2.res new file mode 100644 index 0000000..1b1a82b --- /dev/null +++ b/tests/type_ver2.res @@ -0,0 +1,5 @@ +int foo() { + int *x[10]; + return 0; +} + diff --git a/tests/typedef.c b/tests/typedef.c new file mode 100644 index 0000000..1903969 --- /dev/null +++ b/tests/typedef.c @@ -0,0 +1,15 @@ +typedef struct bluecard_info_t { + dev_link_t link; +} foo; + +static void should_work(u_long arg) +{ + foo *info = (struct bluecard_info_t *)arg; + unsigned int iobase = info->link.io.BasePort1; +} + +static void does_work(u_long arg) +{ + struct bluecard_info_t *info = (struct bluecard_info_t *)arg; + unsigned int iobase = info->link.io.BasePort1; +} diff --git a/tests/typedef.cocci b/tests/typedef.cocci new file mode 100644 index 0000000..25c57e3 --- /dev/null +++ b/tests/typedef.cocci @@ -0,0 +1,19 @@ +@ rule1 @ +type T; +identifier link; +@@ + +T { + ... +- dev_link_t link; ++ struct pcmcia_device *p_dev; + ... +}; + +@ rule2 extends rule1 @ +T *s; +identifier fld; +@@ + +- s->link.fld ++ s->p_dev->fld diff --git a/tests/typedef.res b/tests/typedef.res new file mode 100644 index 0000000..ab434b7 --- /dev/null +++ b/tests/typedef.res @@ -0,0 +1,15 @@ +typedef struct bluecard_info_t { + struct pcmcia_device *p_dev; +} foo; + +static void should_work(u_long arg) +{ + foo *info = (struct bluecard_info_t *)arg; + unsigned int iobase = info->p_dev->io.BasePort1; +} + +static void does_work(u_long arg) +{ + struct bluecard_info_t *info = (struct bluecard_info_t *)arg; + unsigned int iobase = info->p_dev->io.BasePort1; +} diff --git a/tests/typedef3.c b/tests/typedef3.c new file mode 100644 index 0000000..64393e0 --- /dev/null +++ b/tests/typedef3.c @@ -0,0 +1,13 @@ +typedef struct bluecard_info_t { + dev_link_t link; +} foo; + +static void should_work(foo *info) +{ + unsigned int iobase = info->link.io.BasePort1; +} + +static void does_work(struct bluecard_info_t *info) +{ + unsigned int iobase = info->link.io.BasePort1; +} diff --git a/tests/typedef3.cocci b/tests/typedef3.cocci new file mode 100644 index 0000000..8c66d9a --- /dev/null +++ b/tests/typedef3.cocci @@ -0,0 +1,25 @@ +@ rule1 @ +type T; +identifier link; +@@ + +T { + ... +- dev_link_t link; ++ struct pcmcia_device *p_dev; + ... +} + +@ rule2 extends rule1 @ +//T *s; +identifier fld; +identifier fn; +identifier s; +@@ + +fn(...,T *s,...) { + <... +- s->link.fld ++ s->p_dev->fld + ...> +} diff --git a/tests/typedef3.res b/tests/typedef3.res new file mode 100644 index 0000000..0932250 --- /dev/null +++ b/tests/typedef3.res @@ -0,0 +1,13 @@ +typedef struct bluecard_info_t { + struct pcmcia_device *p_dev; +} foo; + +static void should_work(foo *info) +{ + unsigned int iobase = info->p_dev->io.BasePort1; +} + +static void does_work(struct bluecard_info_t *info) +{ + unsigned int iobase = info->p_dev->io.BasePort1; +} diff --git a/tests/typedef_double.c b/tests/typedef_double.c new file mode 100644 index 0000000..9bd1835 --- /dev/null +++ b/tests/typedef_double.c @@ -0,0 +1,7 @@ +typedef struct stlpcibrd { + unsigned short vendid; + unsigned short devid; + int brdtype; +} stlpcibrd_t; + +int main () { sema_init(x); } diff --git a/tests/typedef_double.cocci b/tests/typedef_double.cocci new file mode 100644 index 0000000..db4508d --- /dev/null +++ b/tests/typedef_double.cocci @@ -0,0 +1,19 @@ +@ rule1 @ +type T; +identifier lock; +@@ + +T { ... + struct semaphore lock; + ... + }; + +@ rule1a @ +type rule1.T; +T data; +identifier rule1.lock; +@@ + +- sema_init ++ mutex_init + (&data.lock) diff --git a/tests/typedef_double.res b/tests/typedef_double.res new file mode 100644 index 0000000..9bd1835 --- /dev/null +++ b/tests/typedef_double.res @@ -0,0 +1,7 @@ +typedef struct stlpcibrd { + unsigned short vendid; + unsigned short devid; + int brdtype; +} stlpcibrd_t; + +int main () { sema_init(x); } diff --git a/tests/typeof.c b/tests/typeof.c new file mode 100644 index 0000000..acfbf8d --- /dev/null +++ b/tests/typeof.c @@ -0,0 +1,6 @@ +int main() { + int x; + f(x); + f(sizeof(struct foo)); + f(sizeof(int)); +} diff --git a/tests/typeof.cocci b/tests/typeof.cocci new file mode 100644 index 0000000..392ba1b --- /dev/null +++ b/tests/typeof.cocci @@ -0,0 +1,8 @@ +@@ +type T; +T E; +@@ + +- f(E); + ... +- f(sizeof(T)); diff --git a/tests/typeof.res b/tests/typeof.res new file mode 100644 index 0000000..6b95eab --- /dev/null +++ b/tests/typeof.res @@ -0,0 +1,4 @@ +int main() { + int x; + f(sizeof(struct foo)); +} diff --git a/tests/typeur.c b/tests/typeur.c new file mode 100644 index 0000000..a79d57b --- /dev/null +++ b/tests/typeur.c @@ -0,0 +1,6 @@ +#include "typeur.h" + +int main () { + int y; + f(x + y); +} diff --git a/tests/typeur.h b/tests/typeur.h new file mode 100644 index 0000000..9bd7378 --- /dev/null +++ b/tests/typeur.h @@ -0,0 +1,2 @@ +int x; + diff --git a/tests/used_after.c b/tests/used_after.c new file mode 100644 index 0000000..35d4787 --- /dev/null +++ b/tests/used_after.c @@ -0,0 +1,10 @@ +int my_proc_info(int i); + +void f() { + int x; + x.proc_info = &my_proc_info; +} + +int my_proc_info(int i) { + return i++; +} diff --git a/tests/used_after.cocci b/tests/used_after.cocci new file mode 100644 index 0000000..c79895d --- /dev/null +++ b/tests/used_after.cocci @@ -0,0 +1,20 @@ +@ rule1 @ +identifier x; +//local function func; +identifier func; +@@ + + x.proc_info = &func; + + + +@@ +// type T; +identifier rule1.func; +@@ + +- int func(int i) { ++ int func(int i, char j) { + ... + } + diff --git a/tests/used_after_ver1.c b/tests/used_after_ver1.c new file mode 100644 index 0000000..26c7bf9 --- /dev/null +++ b/tests/used_after_ver1.c @@ -0,0 +1,19 @@ +int my_proc_info(int i); + +void f1() { + int x; +} + +void f2() { + int x; + x.proc_info = &my_proc_info; +} + +int my_proc_info(int i) { + return i++; +} + + +int not_a_proc_info_function(int i) { + return i++; +} diff --git a/tests/useless_cast.c b/tests/useless_cast.c new file mode 100644 index 0000000..93f4bb6 --- /dev/null +++ b/tests/useless_cast.c @@ -0,0 +1,21 @@ + +// from: http://kernelnewbies.org/KernelJanitors/Todo +struct device { + struct netdev_private *priv; + struct netdev_private2 *priv2; + +}; + +struct device *dev; + + +struct netdev_private *np = (struct netdev_private *) + dev->priv; + + +struct netdev_private *np2 = (struct netdev_private *) + dev->priv2; + + +struct netdev_private *np3 = (struct netdev_private *) + dev; diff --git a/tests/useless_cast.cocci b/tests/useless_cast.cocci new file mode 100644 index 0000000..1c92812 --- /dev/null +++ b/tests/useless_cast.cocci @@ -0,0 +1,9 @@ +@r@ +type T; +identifier x; +T E; +@@ + +T x = +- (T) + E; diff --git a/tests/useless_cast.res b/tests/useless_cast.res new file mode 100644 index 0000000..9e3a474 --- /dev/null +++ b/tests/useless_cast.res @@ -0,0 +1,20 @@ + +// from: http://kernelnewbies.org/KernelJanitors/Todo +struct device { + struct netdev_private *priv; + struct netdev_private2 *priv2; + +}; + +struct device *dev; + +struct netdev_private *np = + dev->priv; + + +struct netdev_private *np2 = (struct netdev_private *) + dev->priv2; + + +struct netdev_private *np3 = (struct netdev_private *) + dev; diff --git a/tests/varargs.c b/tests/varargs.c new file mode 100644 index 0000000..651303c --- /dev/null +++ b/tests/varargs.c @@ -0,0 +1,4 @@ + +static void +fas216_log_command(FAS216_Info *info, int level, Scsi_Cmnd *SCpnt, char *fmt, ...) +{} diff --git a/tests/varargs.cocci b/tests/varargs.cocci new file mode 100644 index 0000000..7eab111 --- /dev/null +++ b/tests/varargs.cocci @@ -0,0 +1,6 @@ +@@ +typedef Scsi_Cmnd; +@@ + +- Scsi_Cmnd ++ struct scsi_cmnd diff --git a/tests/varargs.res b/tests/varargs.res new file mode 100644 index 0000000..48b3514 --- /dev/null +++ b/tests/varargs.res @@ -0,0 +1,4 @@ + +static void +fas216_log_command(FAS216_Info *info, int level, struct scsi_cmnd *SCpnt, char *fmt, ...) +{} diff --git a/tests/video.c b/tests/video.c new file mode 100644 index 0000000..192d0a4 --- /dev/null +++ b/tests/video.c @@ -0,0 +1,36 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct typhoon_device *typhoon = dev->priv; + + if (cmd == VIDIOCGTUNER) { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v)) != 0) + return -EFAULT; + if (v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow = 875 * 1600; + v.rangehigh = 1080 * 1600; + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = 0xFFFF; /* We can't get the signal strength */ + strcpy(v.name, "FM"); + if (copy_to_user(arg, v, sizeof(v))) + return -EFAULT; + } + else if (cmd == VIDIOCSTUNER) { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.tuner != 0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + } else return -ENOIOCTLCMD; + /* + else if(cmd == VIDIOCSFREQ) { + if (copy_from_user(typhoon->curfreq, arg, sizeof(typhoon->curfreq))) + return -EFAULT; + typhoon_setfreq(typhoon, typhoon->curfreq); + return 0; + }*/ + return 0; +} diff --git a/tests/video.cocci b/tests/video.cocci new file mode 100644 index 0000000..0a2bf25 --- /dev/null +++ b/tests/video.cocci @@ -0,0 +1,27 @@ +@@ +local function ioctlfn; +identifier dev, cmd, arg; +//fresh identifier i, f; +identifier v; +type T; +identifier fld; +expression E, E1, E2; +statement S; +@@ + + ioctlfn( +- struct video_device *dev, ++ struct inode *i, struct file *f, + unsigned int cmd, void *arg) { + <... +- T v; ++ T *v; + ... +- if (copy_from_user(&v,arg,sizeof(v)) != 0) return E1; + <... +- v.fld ++ v->fld + ...> +?- if (copy_to_user(arg,&v,sizeof(v))) return E2; + ...> + } diff --git a/tests/video1.c b/tests/video1.c new file mode 100644 index 0000000..b669876 --- /dev/null +++ b/tests/video1.c @@ -0,0 +1,35 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct typhoon_device *typhoon = dev->priv; + + if (cmd == VIDIOCGTUNER) { + struct video_tuner v; + if (copy_from_user(v, arg, sizeof(v)) != 0) + return -EFAULT; + if (v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow = 875 * 1600; + v.rangehigh = 1080 * 1600; + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = 0xFFFF; /* We can't get the signal strength */ + strcpy(v.name, "FM"); + if (copy_to_user(arg, v, sizeof(v))) + return -EFAULT; + } + else if (cmd == VIDIOCSTUNER) { + struct video_tuner v; + if (copy_from_user(v, arg, sizeof(v))) + return -EFAULT; + if (v.tuner != 0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + } else return -ENOIOCTLCMD; + /*else if(cmd == VIDIOCSFREQ) { + if (copy_from_user(typhoon->curfreq, arg, sizeof(typhoon->curfreq))) + return -EFAULT; + typhoon_setfreq(typhoon, typhoon->curfreq); + return 0; + }*/ + return 0; +} diff --git a/tests/video1.cocci b/tests/video1.cocci new file mode 100644 index 0000000..0232f2c --- /dev/null +++ b/tests/video1.cocci @@ -0,0 +1,30 @@ +@@ +local function ioctlfn; +identifier dev, cmd, arg; +//fresh identifier i, f; +identifier v; +type T; +identifier fld; +expression E, E1, E2; +statement S; +@@ + + ioctlfn( + struct video_device *dev, + unsigned int cmd, void *arg) { + <... +- T v; ++ T *v; + ... +( +- if (copy_from_user(&v,arg,sizeof(v)) != 0) return ...; +| +- if (copy_from_user(&v,arg,sizeof(v))) return ...; +) + <... +- v.fld ++ v->fld + ...> +?- if (copy_to_user(arg,&v,sizeof(v))) return ...; + ...> + } diff --git a/tests/video1_ver1.c b/tests/video1_ver1.c new file mode 100644 index 0000000..f3eb85b --- /dev/null +++ b/tests/video1_ver1.c @@ -0,0 +1,398 @@ +/* Typhoon Radio Card driver for radio support + * (c) 1999 Dr. Henrik Seidel + * + * Card manufacturer: + * http://194.18.155.92/idc/prod2.idc?nr=50753&lang=e + * + * Notes on the hardware + * + * This card has two output sockets, one for speakers and one for line. + * The speaker output has volume control, but only in four discrete + * steps. The line output has neither volume control nor mute. + * + * The card has auto-stereo according to its manual, although it all + * sounds mono to me (even with the Win/DOS drivers). Maybe it's my + * antenna - I really don't know for sure. + * + * Frequency control is done digitally. + * + * Volume control is done digitally, but there are only four different + * possible values. So you should better always turn the volume up and + * use line control. I got the best results by connecting line output + * to the sound card microphone input. For such a configuration the + * volume control has no effect, since volume control only influences + * the speaker output. + * + * There is no explicit mute/unmute. So I set the radio frequency to a + * value where I do expect just noise and turn the speaker volume down. + * The frequency change is necessary since the card never seems to be + * completely silent. + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* radio card status report */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_TYPHOON_* */ + +#define BANNER "Typhoon Radio Card driver v0.1\n" + +#ifndef CONFIG_RADIO_TYPHOON_PORT +#define CONFIG_RADIO_TYPHOON_PORT -1 +#endif + +#ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ +#define CONFIG_RADIO_TYPHOON_MUTEFREQ 0 +#endif + +#ifndef CONFIG_PROC_FS +#undef CONFIG_RADIO_TYPHOON_PROC_FS +#endif + +struct typhoon_device { + int users; + int iobase; + int curvol; + int muted; + unsigned long curfreq; + unsigned long mutefreq; +}; + +static void typhoon_setvol_generic(struct typhoon_device *dev, int vol); +static int typhoon_setfreq_generic(struct typhoon_device *dev, + unsigned long frequency); +static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency); +static void typhoon_mute(struct typhoon_device *dev); +static void typhoon_unmute(struct typhoon_device *dev); +static int typhoon_setvol(struct typhoon_device *dev, int vol); +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg); +static int typhoon_open(struct video_device *dev, int flags); +static void typhoon_close(struct video_device *dev); +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS +static int typhoon_get_info(char *buf, char **start, off_t offset, int len); +#endif + +static void typhoon_setvol_generic(struct typhoon_device *dev, int vol) +{ + vol >>= 14; /* Map 16 bit to 2 bit */ + vol &= 3; + outb_p(vol / 2, dev->iobase); /* Set the volume, high bit. */ + outb_p(vol % 2, dev->iobase + 2); /* Set the volume, low bit. */ +} + +static int typhoon_setfreq_generic(struct typhoon_device *dev, + unsigned long frequency) +{ + unsigned long outval; + unsigned long x; + + /* + * The frequency transfer curve is not linear. The best fit I could + * get is + * + * outval = -155 + exp((f + 15.55) * 0.057)) + * + * where frequency f is in MHz. Since we don't have exp in the kernel, + * I approximate this function by a third order polynomial. + * + */ + + x = frequency / 160; + outval = (x * x + 2500) / 5000; + outval = (outval * x + 5000) / 10000; + outval -= (10 * x * x + 10433) / 20866; + outval += 4 * x - 11505; + + outb_p((outval >> 8) & 0x01, dev->iobase + 4); + outb_p(outval >> 9, dev->iobase + 6); + outb_p(outval & 0xff, dev->iobase + 8); + + return 0; +} + +static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency) +{ + typhoon_setfreq_generic(dev, frequency); + dev->curfreq = frequency; + return 0; +} + +static void typhoon_mute(struct typhoon_device *dev) +{ + if (dev->muted == 1) + return; + typhoon_setvol_generic(dev, 0); + typhoon_setfreq_generic(dev, dev->mutefreq); + dev->muted = 1; +} + +static void typhoon_unmute(struct typhoon_device *dev) +{ + if (dev->muted == 0) + return; + typhoon_setfreq_generic(dev, dev->curfreq); + typhoon_setvol_generic(dev, dev->curvol); + dev->muted = 0; +} + +static int typhoon_setvol(struct typhoon_device *dev, int vol) +{ + if (dev->muted && vol != 0) { /* user is unmuting the card */ + dev->curvol = vol; + typhoon_unmute(dev); + return 0; + } + if (vol == dev->curvol) /* requested volume == current */ + return 0; + + if (vol == 0) { /* volume == 0 means mute the card */ + typhoon_mute(dev); + dev->curvol = vol; + return 0; + } + typhoon_setvol_generic(dev, vol); + dev->curvol = vol; + return 0; +} + + +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct typhoon_device *typhoon = dev->priv; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability v; + v.type = VID_TYPE_TUNER; + v.channels = 1; + v.audios = 1; + /* No we don't do pictures */ + v.maxwidth = 0; + v.maxheight = 0; + v.minwidth = 0; + v.minheight = 0; + strcpy(v.name, "Typhoon Radio"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v)) != 0) + return -EFAULT; + if (v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow = 875 * 1600; + v.rangehigh = 1080 * 1600; + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = 0xFFFF; /* We can't get the signal strength */ + strcpy(v.name, "FM"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.tuner != 0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + if (copy_to_user(arg, &typhoon->curfreq, + sizeof(typhoon->curfreq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if (copy_from_user(&typhoon->curfreq, arg, + sizeof(typhoon->curfreq))) + return -EFAULT; + typhoon_setfreq(typhoon, typhoon->curfreq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v, 0, sizeof(v)); + v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME; + v.mode |= VIDEO_SOUND_MONO; + v.volume = typhoon->curvol; + v.step = 1 << 14; + strcpy(v.name, "Typhoon Radio"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.audio) + return -EINVAL; + + if (v.flags & VIDEO_AUDIO_MUTE) + typhoon_mute(typhoon); + else + typhoon_unmute(typhoon); + + if (v.flags & VIDEO_AUDIO_VOLUME) + typhoon_setvol(typhoon, v.volume); + + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int typhoon_open(struct video_device *dev, int flags) +{ + struct typhoon_device *typhoon = dev->priv; + if (typhoon->users) + return -EBUSY; + typhoon->users++; + return 0; +} + +static void typhoon_close(struct video_device *dev) +{ + struct typhoon_device *typhoon = dev->priv; + typhoon->users--; +} + +static struct typhoon_device typhoon_unit = +{ + iobase: CONFIG_RADIO_TYPHOON_PORT, + curfreq: CONFIG_RADIO_TYPHOON_MUTEFREQ, + mutefreq: CONFIG_RADIO_TYPHOON_MUTEFREQ, +}; + +static struct video_device typhoon_radio = +{ + owner: THIS_MODULE, + name: "Typhoon Radio", + type: VID_TYPE_TUNER, + hardware: VID_HARDWARE_TYPHOON, + open: typhoon_open, + close: typhoon_close, + ioctl: typhoon_ioctl, +}; + +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + +static int typhoon_get_info(char *buf, char **start, off_t offset, int len) +{ + char *out = buf; + + #ifdef MODULE + #define MODULEPROCSTRING "Driver loaded as a module" + #else + #define MODULEPROCSTRING "Driver compiled into kernel" + #endif + + /* output must be kept under PAGE_SIZE */ + out += sprintf(out, BANNER); + out += sprintf(out, "Load type: " MODULEPROCSTRING "\n\n"); + out += sprintf(out, "frequency = %lu kHz\n", + typhoon_unit.curfreq >> 4); + out += sprintf(out, "volume = %d\n", typhoon_unit.curvol); + out += sprintf(out, "mute = %s\n", typhoon_unit.muted ? + "on" : "off"); + out += sprintf(out, "iobase = 0x%x\n", typhoon_unit.iobase); + out += sprintf(out, "mute frequency = %lu kHz\n", + typhoon_unit.mutefreq >> 4); + return out - buf; +} + +#endif /* CONFIG_RADIO_TYPHOON_PROC_FS */ + +MODULE_AUTHOR("Dr. Henrik Seidel"); +MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); +MODULE_LICENSE("GPL"); + +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); +MODULE_PARM(mutefreq, "i"); +MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); +MODULE_PARM(radio_nr, "i"); + +EXPORT_NO_SYMBOLS; + +static int io = -1; +static int radio_nr = -1; + +#ifdef MODULE +static unsigned long mutefreq = 0; +#endif + +static int __init typhoon_init(void) +{ +#ifdef MODULE + if (io == -1) { + printk(KERN_ERR "radio-typhoon: You must set an I/O address with io=0x316 or io=0x336\n"); + return -EINVAL; + } + typhoon_unit.iobase = io; + + if (mutefreq < 87000 || mutefreq > 108500) { + printk(KERN_ERR "radio-typhoon: You must set a frequency (in kHz) used when muting the card,\n"); + printk(KERN_ERR "radio-typhoon: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); + return -EINVAL; + } + typhoon_unit.mutefreq = mutefreq; +#endif /* MODULE */ + + printk(KERN_INFO BANNER); + io = typhoon_unit.iobase; + if (!request_region(io, 8, "typhoon")) { + printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n", + typhoon_unit.iobase); + return -EBUSY; + } + + typhoon_radio.priv = &typhoon_unit; + if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO, radio_nr) == -1) + { + release_region(io, 8); + return -EINVAL; + } + printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase); + printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n", + typhoon_unit.mutefreq); + typhoon_unit.mutefreq <<= 4; + + /* mute card - prevents noisy bootups */ + typhoon_mute(&typhoon_unit); + +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + if (!create_proc_info_entry("driver/radio-typhoon", 0, NULL, + typhoon_get_info)) + printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n"); +#endif + + return 0; +} + +static void __exit typhoon_cleanup_module(void) +{ + +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + remove_proc_entry("driver/radio-typhoon", NULL); +#endif + + video_unregister_device(&typhoon_radio); + release_region(io, 8); +} + +module_init(typhoon_init); +module_exit(typhoon_cleanup_module); + diff --git a/tests/video1bis.c b/tests/video1bis.c new file mode 100644 index 0000000..c2a1260 --- /dev/null +++ b/tests/video1bis.c @@ -0,0 +1,9 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, +void *arg) +{ + if (cmd == VIDIOCGTUNER) { + struct video_tuner v; + if (copy_from_user(v, arg, sizeof(v)) != 0) + ret(-EFAULT); else {} + } +} diff --git a/tests/video1bis.cocci b/tests/video1bis.cocci new file mode 100644 index 0000000..a427258 --- /dev/null +++ b/tests/video1bis.cocci @@ -0,0 +1,10 @@ +@@ +local function ioctlfn; +identifier dev, cmd, arg; +identifier v; +type T; +statement S1, S2; +identifier fld; +@@ + +- if (copy_from_user(v,arg,sizeof(v)) != 0) S1 else {} diff --git a/tests/video1bis.res b/tests/video1bis.res new file mode 100644 index 0000000..6ee1373 --- /dev/null +++ b/tests/video1bis.res @@ -0,0 +1,7 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, +void *arg) +{ + if (cmd == VIDIOCGTUNER) { + struct video_tuner v; + } +} diff --git a/tests/video2.c b/tests/video2.c new file mode 100644 index 0000000..bf32082 --- /dev/null +++ b/tests/video2.c @@ -0,0 +1,29 @@ +int main(int x) { + if (x == 1) { + x(); + if (f()) return 12; + if (g(1)) return 15; + g(1); + g(2); + y(); + if (i()) return 120; + g(2); + } + else if (x == 2) { + x(); + if (f()) return 16; + x(); + y(); + if (i()) return 160; + g(2); + } + else if (x == 3) { + x(); + if (f()) return 20; + x(); + g(1); + y(); + g(2); + } + else return 0; +} diff --git a/tests/video2.cocci b/tests/video2.cocci new file mode 100644 index 0000000..dced34d --- /dev/null +++ b/tests/video2.cocci @@ -0,0 +1,20 @@ +@@ +expression E, E1, E2; +@@ + +main(int x) { + <... + { + ... +- x(); + ... +- if (f()) return E1; + <... +- g(E) ++ h(E) + ...> +?- if (i()) return E2; + ... + } + ...> +} \ No newline at end of file diff --git a/tests/video3.c b/tests/video3.c new file mode 100644 index 0000000..c3d9853 --- /dev/null +++ b/tests/video3.c @@ -0,0 +1,35 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct typhoon_device *typhoon = dev->priv; + + if (cmd == VIDIOCGTUNER) { + struct video_tuner v; + if (copy_from_user(v, arg, sizeof(v)) != 0) + return -EFAULT; + if (v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow = 875 * 1600; + v.rangehigh = 1080 * 1600; + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = 0xFFFF; /* We can't get the signal strength */ + strcpy(v.name, "FM"); + if (copy_to_user(arg, v, sizeof(v))) + return -EFAULT; + } + else if (cmd == VIDIOCSTUNER) { + struct video_tuner v; + if (copy_from_user(v, arg, sizeof(v))) + return -EFAULT; + if (v.tuner != 0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + } else return -ENOIOCTLCMD; /* + else if(cmd == VIDIOCSFREQ) { + if (copy_from_user(typhoon->curfreq, arg, sizeof(typhoon->curfreq))) + return -EFAULT; + typhoon_setfreq(typhoon, typhoon->curfreq); + return 0; + }*/ + return 0; +} diff --git a/tests/video3.cocci b/tests/video3.cocci new file mode 100644 index 0000000..c9d2c3b --- /dev/null +++ b/tests/video3.cocci @@ -0,0 +1,29 @@ +@@ +local function ioctlfn; +identifier dev, cmd, arg; +identifier v; +type T; +identifier fld; +expression E; +statement S; +@@ + + ioctlfn( + struct video_device *dev, + unsigned int cmd, void *arg) { + <... + { + ... +- T v; ++ T *v; + ... +- if (copy_from_user(v,arg,sizeof(v)) != 0) return ...; + <... +- v.fld ++ v->fld + ...> +?- if (copy_to_user(arg,v,sizeof(v))) return ...; + ... + } + ...> + } diff --git a/tests/video4.c b/tests/video4.c new file mode 100644 index 0000000..6c06fb6 --- /dev/null +++ b/tests/video4.c @@ -0,0 +1,15 @@ +int main() { + int v; + m(); + f(1); + x(); + v.x = 12; + v.y = 21; + g(1); + f(2); + x(); + v.xafter = 12; + v.yafter = 21; + g(2); + n(); +} diff --git a/tests/video4.cocci b/tests/video4.cocci new file mode 100644 index 0000000..29c0720 --- /dev/null +++ b/tests/video4.cocci @@ -0,0 +1,16 @@ +@@ +identifier v; +identifier fld; +expression E; +@@ + + struct foo v; + m(); + <... + f(E); + <... +* v.fld + ...> + g(E); + ...> + n(); diff --git a/tests/video_ver1.c b/tests/video_ver1.c new file mode 100644 index 0000000..140648b --- /dev/null +++ b/tests/video_ver1.c @@ -0,0 +1,36 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct typhoon_device *typhoon = dev->priv; + + if (cmd == VIDIOCGTUNER) { + struct video_tuner v; + if (copy_from_user(v, arg, sizeof(v)) != 0) + ret(-EFAULT); else {} + if (v.tuner) /* Only 1 tuner */ + ret(-EINVAL); + v.rangelow = 875 * 1600; + v.rangehigh = 1080 * 1600; + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = 0xFFFF; /* We can't get the signal strength */ + strcpy(v.name, "FM"); + if (copy_to_user(arg, v, sizeof(v))) + ret(-EFAULT); else {} + ret(0); + }/* + else if (cmd == VIDIOCSTUNER) { + struct video_tuner v; + if (copy_from_user(v, arg, sizeof(v))) + ret(-EFAULT); else {} + if (v.tuner != 0) + ret(-EINVAL); + ret(0); + } + else if(cmd == VIDIOCSFREQ) { + if (copy_from_user(typhoon->curfreq, arg, sizeof(typhoon->curfreq))) + ret(-EFAULT); else {} + typhoon_setfreq(typhoon, typhoon->curfreq); + ret(0); + }*/ + return -ENOIOCTLCMD; +} diff --git a/tests/video_ver2.c b/tests/video_ver2.c new file mode 100644 index 0000000..a83bc13 --- /dev/null +++ b/tests/video_ver2.c @@ -0,0 +1,41 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct typhoon_device *typhoon = dev->priv; + + switch (cmd) { + case VIDIOCGTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v)) != 0) + return -EFAULT; + if (v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow = 875 * 1600; + v.rangehigh = 1080 * 1600; + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = 0xFFFF; /* We can't get the signal strength */ + strcpy(v.name, "FM"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.tuner != 0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCSFREQ: + if (copy_from_user(&typhoon->curfreq, arg, + sizeof(typhoon->curfreq))) + return -EFAULT; + typhoon_setfreq(typhoon, typhoon->curfreq); + return 0; + } + return -ENOIOCTLCMD; +} diff --git a/tests/video_ver3.c b/tests/video_ver3.c new file mode 100644 index 0000000..a9763d1 --- /dev/null +++ b/tests/video_ver3.c @@ -0,0 +1,25 @@ +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct typhoon_device *typhoon = dev->priv; + + switch (cmd) { + case VIDIOCGTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v)) != 0) + return -EFAULT; + if (v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow = 875 * 1600; + v.rangehigh = 1080 * 1600; + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = 0xFFFF; /* We can't get the signal strength */ + strcpy(v.name, "FM"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + } + return -ENOIOCTLCMD; +} diff --git a/tests/void.c b/tests/void.c new file mode 100644 index 0000000..0f87f4f --- /dev/null +++ b/tests/void.c @@ -0,0 +1,5 @@ +int xbar(void) { return; } + +// this is some info about bar + +int bar(void) { return; } diff --git a/tests/void.cocci b/tests/void.cocci new file mode 100644 index 0000000..0f15da7 --- /dev/null +++ b/tests/void.cocci @@ -0,0 +1,6 @@ +@@ +@@ + ++ int foo(void) { return; } + int bar(void) { return; } ++ int foo(void) { return; } diff --git a/tests/void.res b/tests/void.res new file mode 100644 index 0000000..8117653 --- /dev/null +++ b/tests/void.res @@ -0,0 +1,9 @@ +int xbar(void) { return; } + +int foo(void) { return; } + +// this is some info about bar + +int bar(void) { return; } + +int foo(void) { return; } diff --git a/tests/voyager.c b/tests/voyager.c new file mode 100644 index 0000000..5e71824 --- /dev/null +++ b/tests/voyager.c @@ -0,0 +1,8 @@ +void +voyager_cat_init(void) +{ + voyager_module_t **modpp; + + *modpp = kmalloc(sizeof(voyager_module_t), GFP_KERNEL); + memset(*modpp, 0, sizeof(voyager_module_t)); +} diff --git a/tests/voyager.cocci b/tests/voyager.cocci new file mode 100644 index 0000000..9f8eaaf --- /dev/null +++ b/tests/voyager.cocci @@ -0,0 +1,22 @@ +// spatch -test voyager -sgrep2 + +@ r4 @ +type T, T2; +expression x; +expression E1,E2,E; +@@ + +- x = (T)kmalloc(E1,E2) + ... when != x = E +- memset((T2)x,0,E1); + +@ r18 @ +type T, T2; +type T1; +T1 *x; +expression E1,E2; +@@ + +- x = (T)kmalloc(E1,E2) + ... +- memset((T2)x,0,sizeof(T1)); diff --git a/tests/vpos.c b/tests/vpos.c new file mode 100644 index 0000000..4b9c1e4 --- /dev/null +++ b/tests/vpos.c @@ -0,0 +1,9 @@ +int main() { + f(2); + if (x) { + g(1,1); + } + else { + g(1,2); + } +} diff --git a/tests/vpos.cocci b/tests/vpos.cocci new file mode 100644 index 0000000..5416629 --- /dev/null +++ b/tests/vpos.cocci @@ -0,0 +1,17 @@ +// shows how a single position variable can get more than one value + +@a@ +position p; +identifier g; +@@ + +f(...) +... +g@p(1,...) + +@@ +position a.p; +identifier a.g; +@@ + +- g@p(...); diff --git a/tests/vpos.res b/tests/vpos.res new file mode 100644 index 0000000..19018c9 --- /dev/null +++ b/tests/vpos.res @@ -0,0 +1,9 @@ +int main() { + f(2); + if (x) { + + } + else { + + } +} diff --git a/tests/whitespace.c b/tests/whitespace.c new file mode 100644 index 0000000..bf655e2 --- /dev/null +++ b/tests/whitespace.c @@ -0,0 +1,3 @@ +int main () { + foo(sizeof (struct xxx)); +} diff --git a/tests/whitespace.cocci b/tests/whitespace.cocci new file mode 100644 index 0000000..6308e60 --- /dev/null +++ b/tests/whitespace.cocci @@ -0,0 +1,6 @@ +@@ +expression E; +@@ + +- foo(E); ++ foo(E,12); diff --git a/tests/whitespace.res b/tests/whitespace.res new file mode 100644 index 0000000..b59f9de --- /dev/null +++ b/tests/whitespace.res @@ -0,0 +1,3 @@ +int main () { + foo(sizeof (struct xxx),12); +} diff --git a/tests/wierd_argument.c b/tests/wierd_argument.c new file mode 100644 index 0000000..99cddaf --- /dev/null +++ b/tests/wierd_argument.c @@ -0,0 +1,7 @@ +static void ewx_i2c_setlines(snd_i2c_bus_t *bus, int clk, int data) +{ + ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return); + ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, ); + unsigned char tmp = 0; + tmp++; +} diff --git a/tests/wierd_argument.cocci b/tests/wierd_argument.cocci new file mode 100644 index 0000000..89a8910 --- /dev/null +++ b/tests/wierd_argument.cocci @@ -0,0 +1,7 @@ +@@ +expression B; +type T; +@@ + +- snd_magic_cast(T,B,...) ++ B diff --git a/tests/wierd_argument.res b/tests/wierd_argument.res new file mode 100644 index 0000000..b93e830 --- /dev/null +++ b/tests/wierd_argument.res @@ -0,0 +1,7 @@ +static void ewx_i2c_setlines(snd_i2c_bus_t *bus, int clk, int data) +{ + ice1712_t *ice = bus->private_data; + ice1712_t *ice = bus->private_data; + unsigned char tmp = 0; + tmp++; +} diff --git a/tests/wierdinit.c b/tests/wierdinit.c new file mode 100644 index 0000000..a0db9e0 --- /dev/null +++ b/tests/wierdinit.c @@ -0,0 +1,9 @@ + +static int cmm_ioctl() +{ + dev_link_t *link; + char *ioctl_names[CM_IOC_MAXNR + 1] = { + [_IOC_NR(CM_IOSDBGLVL)] "CM4000_DBGLVL", + }; + +} diff --git a/tests/wierdinit.cocci b/tests/wierdinit.cocci new file mode 100644 index 0000000..00168c8 --- /dev/null +++ b/tests/wierdinit.cocci @@ -0,0 +1,6 @@ +@@ +typedef dev_link_t; +@@ + +- dev_link_t ++ struct pcmcia_device diff --git a/tests/wierdinit.res b/tests/wierdinit.res new file mode 100644 index 0000000..85cb916 --- /dev/null +++ b/tests/wierdinit.res @@ -0,0 +1,9 @@ + +static int cmm_ioctl() +{ + struct pcmcia_device *link; + char *ioctl_names[CM_IOC_MAXNR + 1] = { + [_IOC_NR(CM_IOSDBGLVL)] "CM4000_DBGLVL", + }; + +} diff --git a/tests/ws2.c b/tests/ws2.c new file mode 100644 index 0000000..3e40c1f --- /dev/null +++ b/tests/ws2.c @@ -0,0 +1,6 @@ +int main() { + if (foo()) + goto err; + err: return; +} + diff --git a/tests/ws2.cocci b/tests/ws2.cocci new file mode 100644 index 0000000..88f0f50 --- /dev/null +++ b/tests/ws2.cocci @@ -0,0 +1,7 @@ +@@ +statement S; +fresh identifier A; +@@ + +- if (foo()) S ++ S diff --git a/tests/ws2.res b/tests/ws2.res new file mode 100644 index 0000000..694e4a5 --- /dev/null +++ b/tests/ws2.res @@ -0,0 +1,5 @@ +int main() { + goto err; + err: return; +} + diff --git a/tests/x.c b/tests/x.c new file mode 100644 index 0000000..cf8d14b --- /dev/null +++ b/tests/x.c @@ -0,0 +1,6 @@ +int main () { + foo(x); + foo(x); + foo(x); +} + diff --git a/tests/x.cocci b/tests/x.cocci new file mode 100644 index 0000000..3f11563 --- /dev/null +++ b/tests/x.cocci @@ -0,0 +1,9 @@ +@@ @@ + ++ 25 + + x ++ + 4 + ... ++ 125 + + x ++ + 48 diff --git a/tests/xloop.c b/tests/xloop.c new file mode 100644 index 0000000..75ddac9 --- /dev/null +++ b/tests/xloop.c @@ -0,0 +1,5 @@ +int main (int x) { + f(); + for (x=0; x!=10; x++) h(); + g(); +} diff --git a/tests/xloop.cocci b/tests/xloop.cocci new file mode 100644 index 0000000..99bfadf --- /dev/null +++ b/tests/xloop.cocci @@ -0,0 +1,5 @@ +@@ @@ + +- f(); + ... +- g(); diff --git a/tests/y.c b/tests/y.c new file mode 100644 index 0000000..9d99948 --- /dev/null +++ b/tests/y.c @@ -0,0 +1,4 @@ +int main() { + foo(12); + bar(80); +} diff --git a/tests/y.cocci b/tests/y.cocci new file mode 100644 index 0000000..f47408b --- /dev/null +++ b/tests/y.cocci @@ -0,0 +1,19 @@ +@ rule1 @ +expression E; +@@ + ++ xxx(E); + foo(E); + +@@ +expression F; +@@ + + xxx(F); + +@@ +expression rule1.E; +@@ + + foo(E); ++ yyy(E); diff --git a/tests/y2.c b/tests/y2.c new file mode 100644 index 0000000..4a21e8b --- /dev/null +++ b/tests/y2.c @@ -0,0 +1,14 @@ +static void +asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + if (!cs) { + printk(KERN_WARNING "ISDNLink: Spurious interrupt!\n"); + return; + } +Start_IPAC: + debugl1(cs, "IPAC ISTA %02X", ista); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPAC; + } +} diff --git a/tests/y2.cocci b/tests/y2.cocci new file mode 100644 index 0000000..425df24 --- /dev/null +++ b/tests/y2.cocci @@ -0,0 +1,10 @@ +@@ +//local function interrupt; +identifier interrupt, cs; +@@ + +interrupt(...) { + ... +- if (!cs) { ... return; } + ... +} diff --git a/tests/y2.res b/tests/y2.res new file mode 100644 index 0000000..5fee0bb --- /dev/null +++ b/tests/y2.res @@ -0,0 +1,11 @@ +static void +asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + +Start_IPAC: + debugl1(cs, "IPAC ISTA %02X", ista); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPAC; + } +} diff --git a/tests/yellow.c b/tests/yellow.c new file mode 100644 index 0000000..8fde33f --- /dev/null +++ b/tests/yellow.c @@ -0,0 +1,89 @@ +// search for "paren missing" + +static void yellowfin_init_ring(struct net_device *dev) +{ + struct yellowfin_private *yp = netdev_priv(dev); + int i; + + yp->tx_full = 0; + yp->cur_rx = yp->cur_tx = 0; + yp->dirty_tx = 0; + + yp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + + for (i = 0; i < RX_RING_SIZE; i++) { + yp->rx_ring[i].dbdma_cmd = + cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz); + yp->rx_ring[i].branch_addr = cpu_to_le32(yp->rx_ring_dma + + ((i+1)%RX_RING_SIZE)*sizeof(struct yellowfin_desc)); + } + + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz); + yp->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* 16 byte align the IP header. */ + yp->rx_ring[i].addr = cpu_to_le32(pci_map_single(yp->pci_dev, + skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + } + yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP); + yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + +#define NO_TXSTATS +#ifdef NO_TXSTATS + /* In this mode the Tx ring needs only a single descriptor. */ + for (i = 0; i < TX_RING_SIZE; i++) { + yp->tx_skbuff[i] = NULL; + yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP); + yp->tx_ring[i].branch_addr = cpu_to_le32(yp->tx_ring_dma + + ((i+1)%TX_RING_SIZE)*sizeof(struct yellowfin_desc)); + } + /* Wrap ring */ + yp->tx_ring[--i].dbdma_cmd = cpu_to_le32(CMD_STOP | BRANCH_ALWAYS); +#else +{ + int j; + + /* Tx ring needs a pair of descriptors, the second for the status. */ + for (i = 0; i < TX_RING_SIZE; i++) { + j = 2*i; + yp->tx_skbuff[i] = 0; + /* Branch on Tx error. */ + yp->tx_ring[j].dbdma_cmd = cpu_to_le32(CMD_STOP); + yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma + + (j+1)*sizeof(struct yellowfin_desc);//paren missing + j++; + if (yp->flags & FullTxStatus) { + yp->tx_ring[j].dbdma_cmd = + cpu_to_le32(CMD_TXSTATUS | sizeof(*yp->tx_status)); + yp->tx_ring[j].request_cnt = sizeof(*yp->tx_status); + yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma + + i*sizeof(struct tx_status_words);//paren missing + } else { + /* Symbios chips write only tx_errs word. */ + yp->tx_ring[j].dbdma_cmd = + cpu_to_le32(CMD_TXSTATUS | INTR_ALWAYS | 2); + yp->tx_ring[j].request_cnt = 2; + /* Om pade ummmmm... */ + yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma + + i*sizeof(struct tx_status_words) + + &(yp->tx_status[0].tx_errs) - + &(yp->tx_status[0])); + } + yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma + + ((j+1)%(2*TX_RING_SIZE))*sizeof(struct yellowfin_desc)); + } + /* Wrap ring */ + yp->tx_ring[++j].dbdma_cmd |= cpu_to_le32(BRANCH_ALWAYS | INTR_ALWAYS); +} +#endif + yp->tx_tail_desc = &yp->tx_status[0]; + return; +} + +int foo () +{ +return; +} diff --git a/tests/yloop.c b/tests/yloop.c new file mode 100644 index 0000000..2344639 --- /dev/null +++ b/tests/yloop.c @@ -0,0 +1,12 @@ +static int +arxescsi_proc_info(char *buffer) +{ + host = scsi_host_hn_get(hostno); + if (!host) + return 0; + + list_for_each_entry(scd, &host->my_devices, siblings) { + } + return pos; +} + diff --git a/tests/yloop.cocci b/tests/yloop.cocci new file mode 100644 index 0000000..aab39dc --- /dev/null +++ b/tests/yloop.cocci @@ -0,0 +1,11 @@ +@@ +identifier buffer; +identifier hostptr; +@@ + arxescsi_proc_info ( ++ struct Scsi_Host *hostptr, + char *buffer) { + ... +- hostptr = scsi_host_hn_get(hostno); + ... + } diff --git a/tests/zero.c b/tests/zero.c new file mode 100644 index 0000000..a394cef --- /dev/null +++ b/tests/zero.c @@ -0,0 +1,6 @@ +int main () { + memset(command, 0, sizeof(struct sbp2_command_info)); + memset(command, 0x00, sizeof(struct sbp2_command_info)); + memset(command, 0x0, sizeof(struct sbp2_command_info)); + memset(command, '\0', sizeof(struct sbp2_command_info)); +} diff --git a/tests/zero.cocci b/tests/zero.cocci new file mode 100644 index 0000000..71d8f5f --- /dev/null +++ b/tests/zero.cocci @@ -0,0 +1,5 @@ +@@ +expression E1, E2; +@@ + +- memset(E1,0,E2); diff --git a/tests/zero.res b/tests/zero.res new file mode 100644 index 0000000..d6a7729 --- /dev/null +++ b/tests/zero.res @@ -0,0 +1,2 @@ +int main () { +} diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..227e415 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,78 @@ +PROGS=gitgrep split_patch extract_c_and_res meta_files generate_dependencies + +all: $(PROGS) + +# for recursive make +all.opt: $(PROGS) + +gitgrep: gitgrep.ml + ocamlopt -o gitgrep str.cmxa gitgrep.ml + +gitsort: gitsort.ml + ocamlopt -o gitsort str.cmxa gitsort.ml + +isoprof: process_isoprofile.ml + ocamlc -g -o isoprof str.cma process_isoprofile.ml + +alloc_free: alloc_free.ml + ocamlopt -o alloc_free str.cmxa alloc_free.ml + +# more flexible version of alloc_free +bridge: bridge.ml + ocamlopt -o bridge str.cmxa bridge.ml + +install_bridge: bridge + cp -f bridge /usr/local/bin + + +SYSLIBS = str.cma unix.cma + +INCLUDE=-I ../commons -I ../extra -I ../parsing_c +LIBS=../commons/commons.cma ../globals/globals.cma \ + ../parsing_c/c_parser.cma ../extra/extra.cma + +OCAMLC=ocamlc$(OPTBIN) -g -dtypes $(INCLUDE) +OCAMLOPT=ocamlopt$(OPTBIN) $(INCLUDE) $(OPTFLAGS) +#OCAMLLEX=ocamllex$(OPTBIN) -ml +OCAMLLEX=ocamllex$(OPTBIN) +OCAMLYACC=ocamlyacc -v +OCAMLDEP=ocamldep$(OPTBIN) $(INCLUDE) +OCAMLMKTOP=ocamlmktop -g -custom $(INCLUDE) + +split_patch: split_patch.cmo + $(OCAMLC) -o $@ $(SYSLIBS) $(INCLUDE) $(LIBS) $+ + +extract_c_and_res: extract_c_and_res.cmo + $(OCAMLC) -o $@ $(SYSLIBS) $(INCLUDE) $(LIBS) $+ + +meta_files: meta_files.cmo + $(OCAMLC) -o $@ $(SYSLIBS) $(INCLUDE) $(LIBS) $+ + +generate_dependencies: generate_dependencies.cmo + $(OCAMLC) -o $@ $(SYSLIBS) $(INCLUDE) $(LIBS) $+ + + +clean:: + rm -f $(PROGS) + + + +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) -c $< +.mli.cmi: + $(OCAMLC) -c $< +.ml.cmx: + $(OCAMLOPT) -c $< + +clean:: + rm -f *.cm[ioxa] *.o *.a *.cmxa *.annot + + +beforedepend:: + +depend:: beforedepend + ocamldep $(INCLUDE) *.mli *.ml > .depend + +-include .depend diff --git a/tools/alloc_free.ml b/tools/alloc_free.ml new file mode 100644 index 0000000..48b0ea7 --- /dev/null +++ b/tools/alloc_free.ml @@ -0,0 +1,176 @@ +(* The following finds out for each file, how it does deallocation for each +allocator *) + +let collect i = + let info = ref [] in + let rec loop _ = + let l = input_line i in + (if String.length l > 2 && String.get l 0 = '+' + then info := (String.sub l 1 (String.length l - 1))::!info); + loop() in + try loop() + with End_of_file -> List.rev !info + +let split l = + let rec loop acc = function + [] -> acc + | x::xs -> + if String.get x 0 = '+' (* the start of a new file *) + then + (match Str.split (Str.regexp " ") x with + _::x::_ -> loop ((x,[])::acc) xs + | _ -> failwith ("no file: "^x)) + else + let acc = + match acc with + (file,instances)::rest -> (file,x::instances)::rest + | _ -> failwith "not possible" in + loop acc xs in + let res = List.rev (loop [] l) in + List.map (function (x,l) -> (x,List.rev l)) res + +let detect_alloc_free str l = + let try_add a f l = + let (same,diff) = List.partition (function (a1,f1) -> a = a1) l in + match same with + [(a1,f1)] -> if List.mem f f1 then l else (a1,f::f1) :: diff + | _ -> (a,[f])::l in + let rec loop acc = function + [] -> acc + | x::xs -> + match Str.split (Str.regexp (str^"\", ")) x with + _::matches -> + let acc = + List.fold_left + (function acc -> + function rest -> + (match Str.split (Str.regexp "[, )]+") rest with + alloc::free::_ -> try_add alloc free acc + | _ -> acc)) + acc matches in + loop acc xs + | _ -> loop acc xs in + List.sort compare + (List.map (function (a,f) -> (a,List.sort compare f)) (loop [] l)) + +let rec iterate str = function + [] -> [] + | (x,l)::xs -> + List.fold_left + (function rest -> + function info -> + let (same,diff) = + List.partition (function (x1,l1) -> l1 = info) rest in + match same with + [(files,info)] -> (x::files,info)::diff + | _ -> ([x],info)::diff) + (iterate str xs) (detect_alloc_free str l) + +(* ------------------------------------------------------------------------ *) +(* The following prints that information *) + +let print_output l = + List.iter + (function (files,(a,fs)) -> + List.iter (function x -> Printf.printf "%s\n" x) files; + Printf.printf " alloc: %s, free: %s\n" a (String.concat ", " fs); + Printf.printf "\n") + l + +(* ------------------------------------------------------------------------ *) +(* The following makes a semantic patch for that information *) + +let sedify o generic_file dir l = + List.iter + (function (files,(a,fs)) -> + match fs with + [f] -> + let _ = + Sys.command + (Printf.sprintf + "sed s/ALLOC/%s/ %s | sed s/FREE/%s/ > %s/%s-%s.cocci\n" + a generic_file f dir a f) in () + | _ -> ()) + l; + List.iter + (function (files,(a,fs)) -> + match fs with + [f] -> Printf.fprintf o "mono_spatch_linux %s-%s.cocci &\n" a f + | _ -> ()) + l + +let collect_allocs l = + let union = + List.fold_left + (function rest -> function x -> + if List.mem x rest then rest else x::rest) in + List.fold_left + (function rest -> + function (files,(a,fs)) -> + let (same,diff) = + List.partition (function (a1,fs1) -> a = a1) rest in + match same with + [(a1,fs1)] -> (a,union fs fs1)::diff + | [] -> (a,fs)::rest + | _ -> failwith "not possible") + [] l + +let sedify_ors o generic_file dir l = + let l = collect_allocs l in + List.iter + (function (a,fs) -> + match fs with + [_] | [] -> () + | (f::_) -> + let sfs = + Printf.sprintf "\"\\\\\\(%s\\\\\\)\"" + (String.concat "\\\\\\|" fs) in + let _ = + Sys.command + (Printf.sprintf + "sed s/ALLOC/%s/ %s | sed s/FREE/%s/ > %s/%s-%s_et_al.cocci\n" + a generic_file sfs dir a f) in ()) + l; + List.iter + (function (a,fs) -> + match fs with + [_] | [] -> () + | (f::_) -> + Printf.fprintf o "mono_spatch_linux %s-%s_et_al.cocci &\n" a f) + l + +(* ------------------------------------------------------------------------ *) + +let sed = ref false +let gen = ref "generic2.cocci" +let dir = ref "p2" +let file = ref "" +let str = ref "detected allocator" + +let options = [ "-sed", Arg.Set sed, "sed output"; + "-sp", Arg.String (function x -> gen := x), + "detection string"; + "-str", Arg.String (function x -> str := x), + "cocci file for use with sed"; + "-dir", Arg.String (function x -> dir := x), + "dir for sed output"; ] +let usage = "" + +let _ = + Arg.parse (Arg.align options) (fun x -> file := x) usage; + let i = open_in !file in + let l = collect i in + close_in i; + let l = split l in + let l = iterate !str l in + (if !sed + then + begin + let o = open_out (Printf.sprintf "%s/files" !dir) in + Printf.fprintf o "#!/bin/bash\n\n"; + sedify o !gen !dir l; + sedify_ors o !gen !dir l; + Printf.fprintf o "\nwait\n/bin/rm tmp*out\n"; + close_out o + end); + if not !sed then print_output l diff --git a/tools/bridge.ml b/tools/bridge.ml new file mode 100644 index 0000000..7df0b06 --- /dev/null +++ b/tools/bridge.ml @@ -0,0 +1,245 @@ +let drop_spaces s = + String.concat "" (Str.split (Str.regexp "[ ]+") s) + +let parse_line fp l n = + if List.mem l fp + then None + else + if Str.string_match (Str.regexp "#") l 0 + then None (* comment line *) + else + let top_split = Str.split (Str.regexp ":") l in + match top_split with + cocci::first::others -> + let rec loop tag = function + [x] -> + let x = + String.concat "\\ " (Str.split (Str.regexp "[ ]+") x) in + [(tag,x)] + | first::rest -> + let splitted = Str.split (Str.regexp "[ ]+") first in + (match List.rev splitted with + new_tag::info -> + let rest = loop new_tag rest in + (tag,String.concat "\\ " info)::rest + | _ -> failwith "bad element") + | _ -> failwith "no data" in + Some (cocci,loop (drop_spaces first) others) + | _ -> failwith (Printf.sprintf "bad line: %s" l) + +let collect_lines fp i = + let lines = ref [] in + let ln = ref 0 in + let rec loop _ = + ln := !ln + 1; + (match parse_line fp (input_line i) !ln with + Some l -> + if List.mem l !lines + then () + else lines := l::!lines + | None -> ()); + loop() in + try loop() with End_of_file -> !lines + +(* --------------------------------------------------------------------- *) + +let process_fp fl = + let i = open_in fl in + let lines = ref ([] : string list) in + let rec loop _ = + let l = input_line i in + (if not(Str.string_match (Str.regexp "#") l 0) + then lines := l :: !lines); + loop() in + (try loop() with End_of_file -> ()); + close_in i; + !lines + +(* --------------------------------------------------------------------- *) + +let discard_ambiguous lines = + let rec loop = function + [] -> [] + | (cocci,tags)::rest -> + let (same,others) = + List.partition + (function (cocci2,tags2) -> tags = tags2 && not(cocci = cocci2)) + rest in + match same with + [] -> (cocci,tags)::loop rest + | _ -> + Printf.printf "ignoring ambiguity:\n"; + List.iter + (function (cocci,tags) -> + Printf.printf "%s: %s\n" cocci + (String.concat ", " + (List.map + (function (tag,tagval) -> + Printf.sprintf "%s: %s" tag tagval) + tags))) + ((cocci,tags)::same); + loop others in + loop lines + +(* --------------------------------------------------------------------- *) +(* only actually collects the rightmost element into ors *) + +let split_or (cocci,line) = + let rev = List.rev line in + (cocci,List.rev(List.tl rev), List.hd rev) + +let collect_ors fp lines = + let rec loop = function + [] -> failwith "no lines" + | [line] -> + let (c,k,v) = split_or line in + ((c,k,[v]),[]) + | line::xs -> + let (c,k,v) = split_or line in + let ((c1,k1,v1),rest) = loop xs in + if c = c1 && k = k1 + then + if List.mem v v1 + then ((c1,k1,v1),rest) + else ((c1,k1,v::v1),rest) + else ((c,k,[v]),((c1,k1,v1)::rest)) in + let ((c,k,v),rest) = loop lines in + let res = (c,k,v)::rest in + List.fold_left + (function prev -> + function (c,k,v) -> + match v with + [] -> failwith "not possible" + | [x] -> (c,k@v) :: prev + | (tag,_)::_ -> + let vs = + Printf.sprintf "%s:(%s)" tag + (String.concat "|" + (List.sort compare + (List.map (function (_,vl) -> vl) v))) in + let attempt = + Printf.sprintf "%s: %s %s" c + (String.concat " " (List.map (function (k,v) -> k^":"^v) k)) + vs in + if List.mem attempt fp + then + let vs = + Printf.sprintf "\\\\\\\\\\(%s\\\\\\\\\\)" + (String.concat "\\\\\\\\\\|" + (List.sort compare + (List.map (function (_,vl) -> vl) v))) in + (c,k@[(tag,vs)]) :: prev + else (List.map (function vi -> (c,k@[vi])) v) @ prev) + [] res + +(* --------------------------------------------------------------------- *) + +let command s = + let _ = Sys.command s in + () + +let created = ref ([] : (string * (int ref * out_channel)) list) + +let mktag n = Printf.sprintf "x%d" n + +let created_files = ref ([] : (string * int ref) list) + +let process_line env (cocci,tags) = + let files = List.filter (function (c,f) -> c = cocci) env in + List.iter + (function (_,cocci_file) -> + let resdir = Filename.chop_extension cocci_file in + (if not(Sys.file_exists cocci_file) + then failwith "no cocci file"); + let (n,o) = + try List.assoc resdir !created + with Not_found -> + begin + command + (Printf.sprintf "/bin/rm -r -f %s; mkdir %s" resdir resdir); + let files = Printf.sprintf "%s/files" resdir in + let o = open_out files in + Printf.fprintf o "all: real_all\n\n"; + let cell = ((ref 0),o) in + created := (resdir,cell) :: !created; + cell + end in + let temp_file = Filename.temp_file cocci ".cocci" in + command (Printf.sprintf "cp %s %s" cocci_file temp_file); + let first_tag_val = + match tags with + [] -> failwith "no tags" + | (_,first_tag_val)::_ -> + let cell = + try List.assoc first_tag_val !created_files + with Not_found -> + let c = ref (-1) in + created_files := (first_tag_val,c)::!created_files; + c in + cell := !cell + 1; + if !cell = 0 + then first_tag_val + else Printf.sprintf "%s%d" first_tag_val !cell in + List.iter + (function (tag,tagval) -> + command + (Printf.sprintf "sed s/%s/%s/ %s > %s_out; cp %s_out %s" + tag tagval temp_file temp_file temp_file temp_file)) + tags; + command + (Printf.sprintf "mv %s %s/%s.cocci" temp_file resdir first_tag_val); + Printf.fprintf o "%s:\n\tmono_spatch_linux %s.cocci ${ARGS}\n\n" + (mktag !n) first_tag_val; + n := !n + 1) + files + +(* --------------------------------------------------------------------- *) + +let rec mkenv = function + [] -> [] + | [_] -> failwith "required arguments: file (category x cocci file)*" + | category::cocci::rest -> + if Filename.check_suffix cocci ".cocci" + then (category,cocci)::mkenv rest + else failwith "required arguments: file (category x cocci file)*" + +let rec upto = function + 0 -> [] + | n -> (mktag (n-1)) :: (upto (n-1)) + +let _ = + let (file,fp,env) = + match List.tl(Array.to_list Sys.argv) with + file::env -> + let rec loop prev = function + [] -> + if prev = "" + then ([],[]) + else ([prev],[]) + | x::xs -> + try + let _ = Str.search_forward (Str.regexp ".cocci") x 0 in + if prev = "" + then ([],x::xs) + else ([],prev::x::xs) + with Not_found -> + let (fp,env) = loop x xs in + if prev = "" + then (fp,env) + else (prev::fp,env) in + let (fp,env) = loop "" env in + (file,fp,mkenv env) + | _ -> failwith "one argument expected" in + let fp = List.fold_left (@) [] (List.map process_fp fp) in + let i = open_in file in + let lines = collect_lines fp i in + let lines = collect_ors fp lines in + close_in i; + let lines = discard_ambiguous lines in + List.iter (process_line env) lines; + List.iter + (function (resdir,(n,o)) -> + Printf.fprintf o "real_all: %s\n" + (String.concat " " (List.rev (upto !n))); + close_out o) + !created diff --git a/tools/dir_stats.ml b/tools/dir_stats.ml new file mode 100644 index 0000000..a4f1417 --- /dev/null +++ b/tools/dir_stats.ml @@ -0,0 +1,163 @@ +(* for each marked thing, how often does it occur and in what files and +directories *) + +let collect i = + let info = ref [] in + let rec loop _ = + let l = input_line i in + (if String.length l > 2 && String.get l 0 = '+' + then info := (String.sub l 1 (String.length l - 1))::!info); + loop() in + try loop() + with End_of_file -> List.rev !info + +let split l = + let rec loop acc = function + [] -> acc + | x::xs -> + if String.get x 0 = '+' (* the start of a new file *) + then + (match Str.split (Str.regexp " ") x with + _::x::_ -> loop ((x,[])::acc) xs + | _ -> failwith ("no file: "^x)) + else + let acc = + match acc with + (file,instances)::rest -> (file,x::instances)::rest + | _ -> failwith "not possible" in + loop acc xs in + let res = List.rev (loop [] l) in + List.map (function (x,l) -> (x,List.rev l)) res + +let detect_alloc_free str l = + let try_add a f l = + let (same,diff) = List.partition (function (a1,f1) -> a = a1) l in + match same with + [(a1,f1)] -> if List.mem f f1 then l else (a1,f::f1) :: diff + | _ -> (a,[f])::l in + let rec loop acc = function + [] -> acc + | x::xs -> + match Str.split (Str.regexp (str^"\", ")) x with + _::matches -> + let acc = + List.fold_left + (function acc -> + function rest -> + (match Str.split (Str.regexp "[, )]+") rest with + alloc::free::_ -> try_add alloc free acc + | _ -> acc)) + acc matches in + loop acc xs + | _ -> loop acc xs in + List.sort compare + (List.map (function (a,f) -> (a,List.sort compare f)) (loop [] l)) + +let rec iterate str = function + [] -> [] + | (x,l)::xs -> + List.fold_left + (function rest -> + function info -> + let (same,diff) = + List.partition (function (x1,l1) -> l1 = info) rest in + match same with + [(files,info)] -> (x::files,info)::diff + | _ -> ([x],info)::diff) + (iterate str xs) (detect_alloc_free str l) + +(* ------------------------------------------------------------------------ *) + +let get_dir d = Filename.dirname d + +let get_subsystem d = + let pieces = Str.split (Str.regexp "/") d in + let front = List.hd(List.tl pieces) in + match front with + "arch" | "drivers" -> front ^ "/" ^ (List.hd(List.tl(List.tl pieces))) + | _ -> front + +let rec remdup = function + [] -> [] + | x::xs -> if List.mem x xs then remdup xs else x :: remdup xs + +let inc tbl key = + let cell = + (try let cell = Hashtbl.find tbl key in cell + with Not_found -> let c = ref 0 in Hashtbl.add tbl key c; c) in + cell := !cell + 1 + +let files_per_protocol = Hashtbl.create(10) +let dirs_per_protocol = Hashtbl.create(10) +let subsystems_per_protocol = Hashtbl.create(10) +let protocols_per_subsystem = Hashtbl.create(10) + +let collect_counts l = + List.iter + (function (files,(a,fs)) -> + let how_many_files = List.length files in + let how_many_dirs = remdup (List.map get_dir files) in + let how_many_subsystems = remdup (List.map get_subsystem files) in + let ct = + if how_many_files < 10 + then how_many_files + else ((how_many_files / 10) * 10) in + inc files_per_protocol ct; + inc dirs_per_protocol (List.length how_many_dirs); + inc subsystems_per_protocol (List.length how_many_subsystems); + List.iter (inc protocols_per_subsystem) how_many_subsystems) + l + +let print_hashtable f tbl = + let l = + Hashtbl.fold + (function key -> function vl -> function rest -> + (key,!vl) :: rest) + tbl [] in + let l = List.sort compare l in + List.iter + (function (key,vl) -> + Printf.printf " "; f key; Printf.printf ": %d\n" vl) + l + +let print_range_int_hashtable range = + print_hashtable + (function x -> + if x < range + then Printf.printf "%d" x + else Printf.printf "%d-%d" x (x + range - 1)) +let print_int_hashtable = + print_hashtable (function x -> Printf.printf "%d" x) +let print_string_hashtable = + print_hashtable (function x -> Printf.printf "%s" x) + +let histify _ = + Printf.printf "files per protocol:\n"; + print_range_int_hashtable 10 files_per_protocol; + Printf.printf "dirs per protocol:\n"; + print_int_hashtable dirs_per_protocol; + Printf.printf "subsystems per protocol:\n"; + print_int_hashtable subsystems_per_protocol; + Printf.printf "protocols per subsystem:\n"; + print_string_hashtable protocols_per_subsystem + +(* ------------------------------------------------------------------------ *) + +let dir = ref "p2" +let file = ref "" +let str = ref "detected allocator" + +let options = [] +let usage = "" + +let _ = + Arg.parse (Arg.align options) (fun x -> file := x) usage; + let i = open_in !file in + let l = collect i in + close_in i; + let l = split l in + let l = iterate !str l in + collect_counts l; + histify() + + diff --git a/tools/distributed/Makefile b/tools/distributed/Makefile new file mode 100644 index 0000000..e08d796 --- /dev/null +++ b/tools/distributed/Makefile @@ -0,0 +1,8 @@ +spatch_linux: spatch_linux.c + gcc -o spatch_linux spatch_linux.c + +install: spatch_linux cleanup + cp spatch_linux ~/bin + +cleanup: cleanup.ml + ocamlc -o cleanup str.cma cleanup.ml diff --git a/tools/distributed/README b/tools/distributed/README new file mode 100644 index 0000000..f8000ef --- /dev/null +++ b/tools/distributed/README @@ -0,0 +1,11 @@ +This directory contains code to distribute cpatch among multiple +processors. To adjust the actual call to spatch, modify the file +spatch_linux_script. + +spatch_linux.c has to be updated with the explicit path of the scripts +(spatch_linux_script and cleanup_script). + +Normally, after running make and make install, spatch_linux foo.cocci will +make 9 processes applying foo.cocci to the files in the directory mentioned +in spatch_linux_script. The result will be in foo. spatch_linux +-processes n foo.cocci will do the same, but for n processes rather than 9. diff --git a/tools/distributed/cleanup.ml b/tools/distributed/cleanup.ml new file mode 100644 index 0000000..4aa4b39 --- /dev/null +++ b/tools/distributed/cleanup.ml @@ -0,0 +1,71 @@ +let read_to_diff i = + let lines = ref [] in + let rec loop _ = + let l = input_line i in + if Str.string_match (Str.regexp "diff -u -p ") l 0 + then (List.rev !lines,Some l) + else (lines := l::!lines; loop ()) in + try loop() with End_of_file -> (List.rev !lines,None) + +let get_file l = (* l is a diff line *) + match Str.split (Str.regexp " ") l with + [_diff;_u;_p;old;_new] -> old + | _ -> failwith "bad diff line" + +let get_files prefix = + let files = Array.to_list(Sys.readdir(Sys.getcwd())) in + let is_number n = try let _ = int_of_string n in true with _ -> false in + let relevant name = + match Str.split (Str.regexp "\\.") name with + [pref;mid;ext] -> prefix = pref && is_number mid && ext = "out" + | _ -> false in + List.filter relevant files + +let process_file fl = + let i = open_in fl in + let elements = ref [] in + (match read_to_diff i with + (_,Some first_line) -> + let rec loop diff = + let (cur,more) = read_to_diff i in + elements := (get_file diff,diff::cur) :: !elements; + match more with + Some next_line -> loop next_line + | None -> () in + loop first_line + | _ -> ()); (* file is empty *) + close_in i; + !elements + +let process_all_files files out = + let elements = + List.sort compare (List.concat (List.map process_file files)) in + match elements with + [] -> (* only python output *) + let fl = String.concat " " (List.sort compare files) in + let _ = Sys.command (Printf.sprintf "cat %s > %s" fl out) in + () + | _ -> + let o = open_out out in + List.iter + (function (_,code) -> + List.iter + (function x -> Printf.fprintf o "%s\n" x) + code) + elements + +let _ = + let arg = List.hd(List.tl(Array.to_list Sys.argv)) in + Printf.printf "arg %s\n" arg; + let arg = Filename.chop_extension arg in + let files = get_files arg in + process_all_files files arg; + let tmp_files = + String.concat " " + (List.map (function x -> "tmp."^x) (List.sort compare files)) in + let _ = Sys.command (Printf.sprintf "cat %s > tmp.%s" tmp_files arg) in + List.iter + (function file -> + let _ = Sys.command (Printf.sprintf "/bin/rm %s" file) in + let _ = Sys.command (Printf.sprintf "/bin/rm tmp.%s" file) in ()) + files diff --git a/tools/distributed/cleanup_script b/tools/distributed/cleanup_script new file mode 100644 index 0000000..7f1e534 --- /dev/null +++ b/tools/distributed/cleanup_script @@ -0,0 +1,7 @@ +#!/bin/tcsh + +#cat ${1:r}.*.out > ${1:r} +#/bin/rm ${1:r}.*.out + +~/coccinelle/tools/distributed/cleanup $1 + diff --git a/tools/distributed/spatch_linux.c b/tools/distributed/spatch_linux.c new file mode 100644 index 0000000..cc0f6a1 --- /dev/null +++ b/tools/distributed/spatch_linux.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX 9 + +#define DONE_SEM 0 // index of the semaphore on which to wait for children + +#define HOME "/home/julia/coccinelle/tools/distributed/" + +int sem; + +void inc_sem(int sem, int sem_num, int inc) { + struct sembuf sops; + sops.sem_num = sem_num; + sops.sem_op = inc; + sops.sem_flg = 0; + semop(sem,&sops,1); +} + +void dec_sem(int sem, int sem_num) { + struct sembuf sops; + sops.sem_num = sem_num; + sops.sem_op = -1; + sops.sem_flg = 0; + semop(sem,&sops,1); +} + +void wait_sem(int sem, int sem_num) { + struct sembuf sops; + int err; + sops.sem_num = sem_num; + sops.sem_op = 0; + sops.sem_flg = 0; + err = semop(sem,&sops,1); + if (err < 0) {printf("error in %d\n",sem);perror("wait_sem");} +} + +void exit_sighandler(int x) { + semctl(sem,DONE_SEM,IPC_RMID); + exit(0); +} + +void do_child(int sem, int id, unsigned int argc, char **argv, int max, + char *script) { + int pid,status; + if (!(pid=fork())) { + // child + int i; + char **new_args = malloc(sizeof(char*) * (argc + 5)); + char string1[50],string2[50]; + for(i=1; i!=argc; i++) { + new_args[i+4] = argv[i]; + } + new_args[i+4] = NULL; + new_args[0] = "nothing"; + new_args[1] = new_args[5]; // cocci file must be first + new_args[2] = "-index"; + sprintf(string1, "%d", id); + new_args[3] = string1; // processor number must be third + new_args[4] = "-max"; + sprintf(string2, "%d", max); + new_args[5] = string2; + execvp(script,new_args); + printf("tried to execute %s\n",HOME "spatch_linux_script"); + perror("exec failure"); + exit(0); + } + wait(&status); + dec_sem(sem,DONE_SEM); // indicate that this child is done +} + +void cleanup(char **argv) { + char **new_args = malloc(sizeof(char*) * 3); + new_args[0] = "nothing"; + new_args[1] = argv[1]; + new_args[2] = NULL; + printf ("doing cleanup on %s\n",argv[1]); + execvp(HOME "cleanup_script",new_args); +} + +int main(unsigned int argc, char **argv) { + int pid, i, start=0, max; + char script[150]; + // initialize the semaphore + sem = semget(0,1/* only one sem */,(IPC_CREAT|0666)); + if (sem < 0) { perror("semget"); exit(0); } + // set up signal handlers so we can delete the semaphore + signal(SIGTERM,exit_sighandler); // kill + signal(SIGHUP,exit_sighandler); // kill -HUP / xterm closed + signal(SIGINT,exit_sighandler); // Interrupt from keyboard + signal(SIGQUIT,exit_sighandler); // Quit from keyboard + // interpret the arguments + max = MAX; + if (!strcmp(argv[1],"-processes")) {max = atoi(argv[2]); start = 2;} + if (!strcmp(argv[1],"-script")) { + strcpy(script,HOME); + strcat(script,argv[2]); + start = 2; + } else strcpy(script,HOME "spatch_linux_script"); + if (!strcmp(argv[1],"--help")) { + printf("spatch_linux [-processes n] foo.cocci ...\n"); + exit (0); + } + + inc_sem(sem,0,max); + + // run the child processes + for(i=0;i!=max;i++) { + if (!(pid=fork())) { + // child + do_child(sem,i,argc-start,&argv[start],max,script); + exit(0); + } + } + + wait_sem(sem,DONE_SEM); // wait for the children to end + int err = semctl(sem,DONE_SEM,IPC_RMID); + if (err < 0) perror ("couldn't remove"); + cleanup(&argv[start]); +} diff --git a/tools/distributed/spatch_linux_script b/tools/distributed/spatch_linux_script new file mode 100755 index 0000000..aea394c --- /dev/null +++ b/tools/distributed/spatch_linux_script @@ -0,0 +1,11 @@ +#!/bin/tcsh + +setenv PYTHONPATH ${HOME}/coccinelle/python +setenv LD_LIBRARY_PATH ${HOME}/coccinelle/pycaml +setenv COCCINELLE_HOME ${HOME}/coccinelle + +# -allow_inconsistent_paths + +(~/coccinelle/spatch.opt -quiet -timeout 120 \ +-dir /home/julia/linux-2.6 -use_glimpse -cocci_file $* > ${1:r}.${3}.out) \ +>& tmp.${1:r}.${3}.out diff --git a/tools/extract_c_and_res.ml b/tools/extract_c_and_res.ml new file mode 100644 index 0000000..41f7712 --- /dev/null +++ b/tools/extract_c_and_res.ml @@ -0,0 +1,49 @@ +open Common open Commonop + +(*****************************************************************************) +(* *) +(*****************************************************************************) +(* requirments: + * - extract from one git commit, or from a set of git commits + * - files from drivers/ and also from other directories now + * - .c and .h, local .h and also not local .h + * - files that were part of the patch, and so modified, but also + * other files (especially .h) to get more type information + * + *) + +(*****************************************************************************) +(* Flags *) +(*****************************************************************************) + +(*****************************************************************************) +(* Main entry point *) +(*****************************************************************************) + +let ex_kmallocmemset = "dd00cc486ab1c17049a535413d1751ef3482141c" +let ex_new_driver = "3faa1ffb4f4be7d10715f4b003ff7b27d14eae26" +let ex_delete_driver = "4d8506b806cc726c96db1c1a55edfb2da52217a9" + +let main () = + begin + let args = ref [] in + let options = [ + ] in + let usage_msg = + "Usage: " ^ basename Sys.argv.(0) ^ + " [options]" ^ "\n" ^ "Options are:" + in + + Arg.parse (Arg.align options) (fun x -> args := x::!args) usage_msg; + args := List.rev !args; + + (match (!args) with + | [x] -> pr x + | _ -> Arg.usage (Arg.align options) usage_msg; + ) + end + +(*****************************************************************************) +let _ = + main () + diff --git a/tools/generate_dependencies.ml b/tools/generate_dependencies.ml new file mode 100644 index 0000000..7dd22de --- /dev/null +++ b/tools/generate_dependencies.ml @@ -0,0 +1,100 @@ +open Common open Commonop + +(*****************************************************************************) +(* Flags *) +(*****************************************************************************) + +let generate_dependencies dir = + let c_info = + Common.glob (Filename.concat dir "*.[c]") + +> List.map (fun file -> + let (x,_) = Parse_c.parse_cache file in + let defined = C_info.defined_stuff x in + let used = C_info.used_stuff x in + let extra = C_info.extra_stuff x in + C_info.adjust_used_only_external used defined; + file, { C_info.used = used; defined = defined; is_module = extra} + ) in + let global = C_info.mk_global_definitions_index c_info in + c_info +> List.iter (fun (file, used_defined) -> + pr2 ("HANDLING : " ^ file); + C_info.print_entities used_defined.C_info.used; + ); + C_info.check_no_duplicate_global_definitions global; + let g = C_info.build_graph c_info global + (Filename.concat dir "depgraph.dot") in + C_info.generate_makefile g (Filename.concat dir "depcocci.dep") + + + + +(* + let path = + match xs with + | [] -> "/home/pad/kernels/git/linux-2.6/drivers/net" + | [x] -> x + | _ -> failwith "too much path" + in + + let dirs = + if dir + then Common.cmd_to_list ("find " ^ path ^ " -type d") +> Kbuild.adjust_dirs + else [path] + in + dirs +> List.iter (fun dir -> +*) + + +(* +let test_yyy () = + Sys.chdir "/home/pad/kernels/git/linux-2.6"; + let path="drivers/net" in + + let c_info = + Common.cmd_to_list ("find " ^ path ^ " -name \"*.c\" ") + +> List.map (fun file -> + let x = cprogram_of_file_cached file in + let defined = defined_stuff x in + let used = used_stuff x in + let extra = extra_stuff x in + adjust_used_only_external used defined; + file, { used = used; defined = defined; is_module = extra} + ) in + let global = mk_global_definitions_index c_info in + c_info +> List.iter (fun (file, used_defined) -> + pr2 ("HANDLING : " ^ file); + print_entities used_defined.used; + ); + check_no_duplicate_global_definitions global + (*build_graph c_info global (Filename.concat dir "depgraph.dot");*) +*) + + +(*****************************************************************************) +(* Main entry point *) +(*****************************************************************************) + +let main () = + begin + let args = ref [] in + let options = [ + ] in + let usage_msg = + "Usage: " ^ basename Sys.argv.(0) ^ + " [options]" ^ "\n" ^ "Options are:" + in + + Arg.parse (Arg.align options) (fun x -> args := x::!args) usage_msg; + args := List.rev !args; + + (match (!args) with + | [x] -> + generate_dependencies x + | _ -> Arg.usage (Arg.align options) usage_msg; + ) + end + +(*****************************************************************************) +let _ = + main () + diff --git a/tools/gitgrep.ml b/tools/gitgrep.ml new file mode 100644 index 0000000..0c9c59a --- /dev/null +++ b/tools/gitgrep.ml @@ -0,0 +1,187 @@ +(* adjust as convenient *) +let prefix = "/tmp/" +let prefix = "" + +(* The -grouped option means that all - and + code must appear in a +single contiguous block of - + code. This option has no effect on the +other kinds of patterns, ie Changelog (C) or Context (@) *) + +(* example: gitgrep -grouped -maxlen 25 - "[A-Z][A-Z]+" + "[A-Z][A-Z]+" +usb_21_22 *) + +type dir = Minus | Plus | Context | ChangeLog + +type res = Git of string | Block of int * string + +let grouped = ref false +let maxlen = ref None + +let space = Str.regexp " " + +let matches pattern line = + try let _ = Str.search_forward pattern line 0 in true + with Not_found -> false + +let res = ref [] + +let scan dir pattern i = + let rec loop skipping cl git = + let line = input_line i in + match Str.split space line with + ["commit";git] -> loop false true git + | "diff"::_ -> loop skipping false git + | _ -> + if String.length line > 0 && not skipping && + ((String.get line 0 = '-' && dir = Minus) or + (String.get line 0 = '+' && dir = Plus) or + (cl && dir = ChangeLog) or + (not (String.get line 0 = '-') && not (String.get line 0 = '+') && + dir = Context)) && + matches pattern line + then (res := Git(git)::!res; loop true cl git) + else loop skipping cl git in + loop false false "" + +(* for Minus and Plus directions only *) +let scan_grouped dir pattern i = + let block = ref 0 in + (* mp = true in minus-plus region *) + let rec loop mp git = + let line = input_line i in + match Str.split space line with + ["commit";git] -> loop false git + | "diff"::_ -> loop false git + | _ -> + if String.length line > 0 + then + let first_char = String.get line 0 in + let new_mp = + match first_char with + '-' | '+' -> (if not mp then block := !block + 1; true) + | _ -> false in + match (first_char,dir) with + ('-',Minus) | ('+',Plus) -> + let info = Block(!block,git) in + (if matches pattern line && not (List.mem info !res) + then res := info::!res); + loop new_mp git + | _ -> loop new_mp git + else loop mp git in + loop false "" + +let scan_line max i = + let rec loop skipping num git = + let line = input_line i in + match Str.split space line with + ["commit";git1] -> + loop false (-1) git1 + | "diff"::_ -> + if num > max && not skipping + then (res:=Git(git)::!res;loop true (num+1) git) + else loop skipping (if num = (-1) then 1 else num+1) git + | _ -> + if num > max && not skipping + then (res:=Git(git)::!res;loop true (num+1) git) + else loop skipping (if num = (-1) then num else num+1) git in + loop false (-1) "" + +let dot = Str.regexp "\\." + +let open_git file = + let tmp = prefix^file in + if Sys.file_exists tmp + then open_in tmp + else + match List.rev (Str.split dot file) with + last::rest -> + let last_int = int_of_string last in + if last_int = 0 + then + failwith + "can't go back one version from 0; make the log file by hand"; + let prev = + String.concat "." (List.rev ((string_of_int (last_int-1))::rest)) in + let _ = + Sys.command + (Printf.sprintf "git log -p v%s..v%s > %s" prev file tmp) in + open_in tmp + | _ -> open_in file + +let rec split_args = function + [] -> [] + | "-grouped"::rest -> grouped := true; split_args rest + | "-maxlen"::len::rest -> maxlen := Some (int_of_string len); split_args rest + | "-"::pattern::rest -> (Minus,Str.regexp pattern) :: split_args rest + | "+"::pattern::rest -> (Plus,Str.regexp pattern) :: split_args rest + | "@"::pattern::rest -> (Context,Str.regexp pattern) :: split_args rest + | "C"::pattern::rest -> (ChangeLog,Str.regexp pattern) :: split_args rest + | _ -> failwith "bad argument list" + +let process_one (dir,pattern) version = + res := []; + let i = open_git version in + try + if !grouped && (dir = Minus or dir = Plus) + then scan_grouped dir pattern i + else scan dir pattern i + with End_of_file -> (close_in i; List.rev !res) + +let process_len max version = + res := []; + let i = open_git version in + try scan_line max i + with End_of_file -> (close_in i; List.rev !res) + +let inter l1 l2 = + List.rev + (List.fold_left + (function prev -> + function + (Git(git)) as x -> + let rec loop = function + [] -> prev + | Git(git1)::rest when git = git1 -> x::prev + | Block(b1,git1)::rest when git = git1 -> Block(b1,git1)::prev + | _::rest -> loop rest in + loop l2 + | (Block(block,git)) as x -> + let rec loop = function + [] -> prev + | Git(git1)::rest when git = git1 -> x::prev + | Block(b1,git1)::rest when block = b1 && git = git1 -> + Block(b1,git1)::prev + | _::rest -> loop rest in + loop l2) + [] l1) + +let _ = + if Array.length Sys.argv < 4 + then failwith "arguments: -/+/@/C pattern -/+/@/C pattern ... version"; + let args = List.tl(Array.to_list Sys.argv) in + let version = List.hd(List.rev args) in + let pairs = List.rev(List.tl(List.rev args)) in + let requirements = split_args pairs in + let res = + List.map (function Git x -> x | Block (_,x) -> x) + (List.fold_left + (function all -> + function pattern -> + inter (process_one pattern version) all) + (process_one (List.hd requirements) version) + (List.tl requirements)) in + let res = + if !grouped + then + List.rev + (List.fold_left + (function prev -> + function x -> if List.mem x prev then prev else x::prev) + [] res) + else res in + let res = + match !maxlen with + None -> res + | Some max -> + let badgits = process_len max version in + List.filter (function x -> not(List.mem (Git(x)) badgits)) res in + List.iter (function name -> Printf.printf "%s\n" name) res diff --git a/tools/gitsort.ml b/tools/gitsort.ml new file mode 100644 index 0000000..4b7e256 --- /dev/null +++ b/tools/gitsort.ml @@ -0,0 +1,126 @@ +(* sort a list of git codes such that the most recent comes first *) + +let git_home = ref "/home/julia/linux-2.6" + +let unwind_protect f cleanup = + try f () + with e -> begin cleanup e; raise e end + +let (with_open_infile: string -> ((in_channel) -> 'a) -> 'a) = fun file f -> + let chan = open_in file in + unwind_protect (fun () -> + let res = f chan in + close_in chan; + res) + (fun e -> close_in chan) + +(* ----------------------------------------------------------------------- *) + +let months = + [("Jan",1);("Feb",2);("Mar",3);("Apr",4);("May",5);("Jun",6);("Jul",7); + ("Aug",8);("Sep",9);("Oct",10);("Nov",11);("Dec",12)] + +let antimonths = + [(1,31);(2,28);(3,31);(4,30);(5,31); (6,30);(7,31);(8,31);(9,30);(10,31); + (11,30);(12,31);(0,31)] + +let normalize (year,month,day,hour,minute,second) = + if hour < 0 + then + let (day,hour) = (day - 1,hour + 24) in + if day = 0 + then + let month = month - 1 in + let day = List.assoc month antimonths in + let day = + if month = 2 && year / 4 * 4 = year && not (year / 100 * 100 = year) + then 29 + else day in + if month = 0 + then (year-1,12,day,hour,minute,second) + else (year,month,day,hour,minute,second) + else (year,month,day,hour,minute,second) + else (year,month,day,hour,minute,second) + +exception Fail of string + +let read_info code = + let _ = + Sys.command + (Printf.sprintf + "pushd %s >& /dev/null ; git log %s^..%s | grep Date: > /tmp/gitsort_info ; popd >& /dev/null" + !git_home code code) in + with_open_infile "/tmp/gitsort_info" (fun i -> + let l = + try input_line i + with End_of_file -> raise (Fail "bad git file") in + match Str.split (Str.regexp " ") l with + [date;_;_;weekday;month;day;time;year;offset] -> + let day = int_of_string day in + let month = List.assoc month months in + let year = int_of_string year in + (match Str.split (Str.regexp ":") time with + [hour;minute;second] -> + let hour = int_of_string hour in + let minute = int_of_string minute in + let second = int_of_string second in + let modifier = + match String.get offset 0 with + '-' -> -1 + | '+' -> 1 + | _ -> raise (Fail "bad offset") in + (if not (String.sub offset 3 2 = "00") + then raise (Fail "require 0 minutes difference")); + let hour = + hour + (modifier * (int_of_string (String.sub offset 1 2))) in + normalize (year,month,day,hour,minute,second) + | _ -> raise (Fail "bad date2")) + | l -> raise (Fail ("bad date1: "^(String.concat "|" l)))) + +let rec get_dates = function + [] -> [] + | code::rest -> + let date = + try Some (read_info code) + with + Fail s -> Printf.printf "problem in %s: %s\n" code s; None + | _ -> Printf.printf "problem in %s\n" code; None in + match date with + Some date -> (date,code)::(get_dates rest) + | None -> get_dates rest + +let get_codes file = + let gits = ref ([] : string list) in + with_open_infile file (fun i -> + let rec loop _ = + let git = try Some (input_line i) with End_of_file -> None in + match git with + Some x -> gits := x :: !gits; loop() + | None -> () in + loop ()); + List.concat + (List.map + (function l -> + List.filter + (* all because I don't know how to make a backslash regexp...*) + (function x -> String.length x > 10) + (Str.split (Str.regexp "[ \t]+") l)) + !gits) + +let _ = + let args = Array.to_list Sys.argv in + let file = + match args with + [_;git_home_info;gits] -> git_home := git_home_info; gits + | [_;gits] -> gits + | _ -> failwith "args: [git home] git_codes_file" in + let codes = get_codes file in + let dates = get_dates codes in + match List.sort compare dates with + (_,last)::prev -> + List.iter (function (_,x) -> Printf.printf "%s \\\n" x) (List.rev prev); + Printf.printf "%s\n" last + | _ -> () + + + diff --git a/tools/licensify.ml b/tools/licensify.ml new file mode 100644 index 0000000..4c032d2 --- /dev/null +++ b/tools/licensify.ml @@ -0,0 +1,84 @@ +let lines = +["Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen"; +"Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller"; +"This file is part of Coccinelle."; +""; +"Coccinelle is free software: you can redistribute it and/or modify"; +"it under the terms of the GNU General Public License as published by"; +"the Free Software Foundation, according to version 2 of the License."; +""; +"Coccinelle is distributed in the hope that it will be useful,"; +"but WITHOUT ANY WARRANTY; without even the implied warranty of"; +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"; +"GNU General Public License for more details."; +""; +"You should have received a copy of the GNU General Public License"; +"along with Coccinelle. If not, see ."; +""; +"The authors reserve the right to distribute this or future versions of"; +"Coccinelle under other licenses." +] + +let c_lines = "/*" :: (List.map (function x -> "* "^x) lines) @ ["*/"] + +let ml_lines = "(*" :: (List.map (function x -> "* "^x) lines) @ ["*)"] + +let make_lines = (List.map (function x -> "# "^x) lines) + +let do_one file = + let lines = + if Filename.check_suffix file ".mly" then c_lines else + if Filename.check_suffix file ".ml" then ml_lines else + if Filename.check_suffix file ".mll" then ml_lines else + if Filename.basename file = "Makefile" then make_lines else + failwith (Printf.sprintf "unknown file type: %s" file) in + let _ = Sys.command (Printf.sprintf "cp %s /tmp/tmpfl" file) in + let o = open_out file in + List.iter (function l -> Printf.fprintf o "%s\n" l) lines; + Printf.fprintf o "\n"; + Printf.fprintf o "\n"; + close_out o; + let _ = Sys.command (Printf.sprintf "cat /tmp/tmpfl >> %s" file) in + () + +(* pad's modif *) +let (+>) o f = f o +let cat file = + let chan = open_in file in + let rec cat_aux acc () = + (* cant do input_line chan::aux() cos ocaml eval from right to left ! *) + let (b, l) = try (true, input_line chan) with End_of_file -> (false, "") in + if b + then cat_aux (l::acc) () + else acc + in + cat_aux [] () +> List.rev +> (fun x -> close_in chan; x) + + +let rec process dir = + let files = + try + List.map (function fl -> dir^"/"^fl) + (Array.to_list(Sys.readdir dir)) + with Sys_error _ -> [] in + List.iter (function file -> + try + let xs = cat file in + if List.exists (fun s -> + s = "* This file is part of Coccinelle." + || + s = "# This file is part of Coccinelle." + ) xs + then print_string ("already processed: " ^ file ^ "\n") + else begin + do_one file; + print_string ("processed: " ^ file ^ "\n"); + end + with _ -> + print_string ("skipped: " ^ file ^ "\n"); + () + ) files; + (* pad: no recursive call in directory List.iter process files *) + () + +let _ = process "." diff --git a/tools/process_isoprofile.ml b/tools/process_isoprofile.ml new file mode 100644 index 0000000..29027db --- /dev/null +++ b/tools/process_isoprofile.ml @@ -0,0 +1,147 @@ +(* This is for processing information created with the -profile_iso option. +Runs are assumed separated with a line beginning with =. +The first run is discarded *) + +let is_marker l = String.get l 0 = '=' +let is_nothing l = String.sub l 0 2 = "ls" + +let skip_start i = (* skip over the ========== at the beginning *) + let rec loop _ = + let l = input_line i in + if not (is_marker l) + then loop() in + loop() + +let get_data l = + match Str.split (Str.regexp ":") l with + [_;after] -> + (match Str.split (Str.regexp " sec") after with + [info;_] -> float_of_string info + | _ -> failwith "bad data") + | _ -> failwith (Printf.sprintf "bad data %s" l) + +type more = MORE | NOMORE | INFO of float * float * float * float | CONT + +let read_data_one i = + try + let start = input_line i in (* three lines of header *) + if is_marker start + then MORE + else if is_nothing start + then CONT + else + let _ = input_line i in + let _ = input_line i in + (match + List.sort compare + [input_line i;input_line i;input_line i;input_line i] + with + [asttoctl;full_engine;mysat;parse_cocci] -> + if String.get full_engine 0 = '*' + then (let _ = input_line i in CONT) (* hack!!! *) + else + let asttoctl = get_data asttoctl in + let full_engine = get_data full_engine in + let mysat = get_data mysat in + let parse_cocci = get_data parse_cocci in + INFO(full_engine,mysat,parse_cocci,asttoctl) + | _ -> failwith "not possible") + with End_of_file -> NOMORE + +let read_data i = + skip_start i; + let optcons x y = if x = [] then y else x::y in + let rec loop all_acc acc = + match read_data_one i with + NOMORE -> optcons acc all_acc + | MORE -> loop (optcons acc all_acc) [] + | CONT -> loop all_acc acc + | INFO(a,b,c,d) -> loop all_acc ((a,b,c,d)::acc) in + let table = loop [] [] in + let all_infos = (* a list with a list of information for each file *) + List.fold_left + (function all_infos -> + function one_run -> + List.map2 (function ainfo -> function orun -> orun::ainfo) + all_infos one_run) + (List.map (function _ -> []) (List.hd table)) + table in + let overheads = + List.concat + (List.map (List.map (function (_,x,y,z) -> x+.y+.z)) all_infos) in + let total_times = + List.concat + (List.map (List.map (function (x,_,_,_) -> x)) all_infos) in + let mysat_times = + List.concat + (List.map (List.map (function (_,x,_,_) -> x)) all_infos) in + let parse_time = + List.concat + (List.map (List.map (function (_,_,x,y) -> x +. y)) all_infos) in + (overheads,total_times,mysat_times,parse_time) + +let percent pct = (int_of_float ((100.0 *. pct) +. 0.5)) - 100 +let mpercent pct = (int_of_float ((100.0 *. pct) +. 0.5)) +let minf l = List.fold_left min (List.hd l) l +let maxf l = List.fold_left max (List.hd l) l + +let ave = function + [] -> 0.0 + | l -> + let total = List.fold_left (+.) 0.0 l in + total /. (float_of_int(List.length l)) + +let process_files iso_file noiso_file = + let i = open_in iso_file in + let (iso_over,iso_total,iso_mysat,iso_parse) = read_data i in + close_in i; + let i = open_in noiso_file in + let (noiso_over,noiso_total,noiso_mysat,noiso_parse) = read_data i in + close_in i; + Printf.printf "isos: min %f max %f ave %f\n" + (minf iso_total) (maxf iso_total) (ave iso_total); + Printf.printf "noisos: min %f max %f ave %f\n" + (minf noiso_total) (maxf noiso_total) (ave noiso_total); + Printf.printf "Overhead in total time %d%%: min %f max %f\n" + (percent (ave (List.map2 (/.) iso_total noiso_total))) + (minf (List.map2 (-.) iso_total noiso_total)) + (maxf (List.map2 (-.) iso_total noiso_total)); + Printf.printf "Portion of overhead due to parsing %d%%: min %f max %f\n" + (mpercent + (ave (List.fold_left2 + (function acc -> + (function (iso_total,iso_parse) -> + (function (noiso_total,noiso_parse) -> + let total_ovd = iso_total -. noiso_total in + let parse_ovd = iso_parse -. noiso_parse in + if total_ovd < 0.001 or parse_ovd > total_ovd or + parse_ovd < 0.0 + then acc + else (parse_ovd /. total_ovd) :: acc))) + [] + (List.combine iso_total iso_parse) + (List.combine noiso_total noiso_parse)))) + (minf (List.map2 (-.) iso_parse noiso_parse)) + (maxf (List.map2 (-.) iso_parse noiso_parse)); + Printf.printf "Portion of overhead due to matching %d%%: min %f max %f\n\n" + (mpercent + (ave (List.fold_left2 + (function acc -> + (function (iso_total,iso_mysat) -> + (function (noiso_total,noiso_mysat) -> + let total_ovd = iso_total -. noiso_total in + let mysat_ovd = iso_mysat -. noiso_mysat in + if total_ovd < 0.001 or mysat_ovd > total_ovd or + mysat_ovd < 0.0 + then acc + else (mysat_ovd /. total_ovd) :: acc))) + [] + (List.combine iso_total iso_mysat) + (List.combine noiso_total noiso_mysat)))) + (minf (List.map2 (-.) iso_mysat noiso_mysat)) + (maxf (List.map2 (-.) iso_mysat noiso_mysat)) + +let _ = + let iso = Array.get Sys.argv 1 in + let noiso = Array.get Sys.argv 2 in + process_files iso noiso diff --git a/tools/split_patch.ml b/tools/split_patch.ml new file mode 100644 index 0000000..f77e026 --- /dev/null +++ b/tools/split_patch.ml @@ -0,0 +1,264 @@ +open Common open Commonop + +module CP = Classic_patch + +(* ./split_patch ../demos/janitorings/patch-kzalloc-vnew3.patch /tmp/xx "0 -> NULL" ../bodymail.doc +./split_patch /tmp/badzero.patch /tmp/xx ../mailbody.doc ../kernel_dirs.meta + +update: see http://lwn.net/Articles/284469/ +for a script using git annotate to find automatically to who send +a patch (by looking at authors of lines close concerning the patch I guess +*) + +(*****************************************************************************) +(* Flags *) +(*****************************************************************************) + +let just_patch = ref false +let verbose = ref true + +let pr2 s = + if !verbose then pr2 s + +(*****************************************************************************) +(* Helpers *) +(*****************************************************************************) + +let print_header_patch patch = + patch +> List.iter (function CP.File (s, header, body) -> pr s) + + +(*****************************************************************************) +(* Grouping strategies *) +(*****************************************************************************) + +let group_patch_depth_2 patch = + let patch_with_dir = patch +> List.map (function (CP.File (s,header,body)) -> + Common.split "/" (Common.dirname s), + (CP.File (s, header, body)) + ) + in + let rec aux_patch xs = + match xs with + | [] -> [] + | (dir_elems,x)::xs -> + let cond, base = + if List.length dir_elems >= 2 then + let base = Common.take 2 dir_elems in + (fun dir_elems' -> + List.length dir_elems' >= 2 && Common.take 2 dir_elems' = base), + base + else + (fun dir_elems' -> dir_elems' = dir_elems), + dir_elems + in + + let (yes, no) = xs +> Common.partition_either (fun (dir_elems', x) -> + if cond dir_elems' + then Left x + else Right (dir_elems', x) + ) in + (Common.join "/" base, ["NOEMAIL"], (x::yes))::aux_patch no + in + aux_patch patch_with_dir + + + +let group_patch_subsystem_info patch subinfo = + let patch_with_dir = patch +> List.map (function (CP.File (s,header,body)) -> + (Common.dirname s), (CP.File (s, header, body)) + ) + in + let index = Maintainers.mk_inverted_index_subsystem subinfo in + let hash = Maintainers.subsystem_to_hash subinfo in + + let rec aux_patch xs = + match xs with + | [] -> [] + | ((dir,patchitem)::xs) as xs' -> + let leader = + try Hashtbl.find index dir + with Not_found -> failwith ("cant find leader for : " ^ dir) + in + let (emailsleader, subdirs) = + try Hashtbl.find hash leader + with Not_found -> failwith ("cant find subdirs of : " ^ leader) + in + + (match emailsleader with + | ["NOEMAIL"] | [] | [""] -> pr2 ("no leader maintainer for: "^leader); + | _ -> () + ); + + let emails = ref emailsleader in + let allsubdirs = (leader, emailsleader)::subdirs in + + let (yes, no) = xs' +> Common.partition_either (fun (dir',patchitem')-> + try ( + let emailsdir' = List.assoc dir' allsubdirs in + emails := !emails $+$ emailsdir'; + Left patchitem' + ) with Not_found -> Right (dir', patchitem') + (* + if List.mem dir' (leader::subdirs) + then Left x + else Right (dir', x) + *) + ) in + (leader, !emails, yes)::aux_patch no + in + aux_patch patch_with_dir + + +(*****************************************************************************) +(* Split patch *) +(*****************************************************************************) +let i_to_s_padded i total = + match i with + | i when i < 10 && total >= 10 -> "0" ^ i_to_s i + | i when i < 100 -> i_to_s i + | i -> i_to_s i + +let split_patch file prefix bodymail subinfofile = + let patch = CP.parse_patch file in + + let subsystem_info = Maintainers.parse_subsystem_info subinfofile in + let minipatches = group_patch_subsystem_info patch subsystem_info in + (* let minipatches = group_patch_depth_2 patch in *) + + let total = List.length minipatches in + let minipatches_indexed = Common.index_list_1 minipatches in + + let (subject, bodymail_rest) = + match Common.cat bodymail with + | x::y::xs -> + if x =~ "Subject: \\(.*\\)" + then + let subject = matched1 x in + if y =~ "[-]+$" + then + subject, xs + else failwith ("wrong format for mailbody in:" ^ bodymail) + else failwith ("wrong format for mailbody in:" ^ bodymail) + | _ -> failwith ("wrong format for mailbody in:" ^ bodymail) + in + + Common.command2_y_or_no ("rm -f " ^ prefix ^ "*"); + + + minipatches_indexed +> List.iter (fun ((dir,emails, minipatch), i) -> + let numpatch = i_to_s_padded i total in + let tmpfile = prefix ^ numpatch ^ ".mail" in + let patchfile = "/tmp/x.patch" in + pr2 ("generating :" ^ tmpfile ^ " for " ^ dir); + + CP.unparse_patch minipatch patchfile; + + let emails = + (match emails with + | ["NOEMAIL"] | [] | [""] -> + pr2 "no maintainer"; [] + | xs -> xs + ) @ ["akpm@linux-foundation.org"] + in + + + if !just_patch + then command2(sprintf "cat %s > %s" patchfile tmpfile) + else begin + Common.with_open_outfile tmpfile (fun (pr_no_nl, chan) -> + let pr s = pr_no_nl (s ^ "\n") in + pr "To: kernel-janitors@vger.kernel.org"; + pr (sprintf "Subject: [PATCH %s/%d] %s, for %s" + numpatch total subject dir); + pr ("Cc: " ^ (Common.join ", " (emails @ ["linux-kernel@vger.kernel.org"]))); + pr "BCC: padator@wanadoo.fr"; + pr "From: Yoann Padioleau "; + pr "--text follows this line--"; + + pr ""; + bodymail_rest +> List.iter pr; + pr ""; + pr "Signed-off-by: Yoann Padioleau "; + emails +> List.iter (fun s -> + pr ("Cc: " ^ s) + ); + pr "---"; + + pr ""; + ); + + command2(sprintf "diffstat -p1 %s >> %s" patchfile tmpfile); + command2(sprintf "echo >> %s" tmpfile); + command2(sprintf "cat %s >> %s" patchfile tmpfile); + end + ) + + + +(*****************************************************************************) +(* Test *) +(*****************************************************************************) + +let test_patch file = + let patch = CP.parse_patch file in + let groups = group_patch_depth_2 patch in + groups +> List.iter (fun (dir, email, minipatch) -> + print_header_patch minipatch; + pr "" + ) + + +(*****************************************************************************) +(* Main entry point *) +(*****************************************************************************) + +let main () = + begin + let args = ref [] in + let options = [ + "-just_patch", Arg.Set just_patch, ""; + "-no_verbose", Arg.Clear verbose, ""; + ] in + let usage_msg = + "Usage: " ^ basename Sys.argv.(0) ^ + " [options]" ^ "\n" + ^ "Options are:" + in + + Arg.parse (Arg.align options) (fun x -> args := x::!args) usage_msg; + args := List.rev !args; + + (match (!args) with + | [patch] -> test_patch patch + | [patch;prefix;bodymail;subinfofile] -> + split_patch patch prefix bodymail subinfofile; + + command2("rm -f /tmp/split_check*"); + let checkfile = "/tmp/split_check.all" in + let checkprefix = "/tmp/split_check-xx" in + save_excursion verbose (fun () -> + save_excursion just_patch (fun () -> + just_patch := true; + verbose := false; + split_patch patch checkprefix bodymail subinfofile; + )); + command2("cat /tmp/split_check*.mail > " ^ checkfile); + + let diff = Common.cmd_to_list (sprintf "diff %s %s " patch checkfile) + in + let samesize = Common.filesize patch = Common.filesize checkfile in + if (List.length diff <> 0) + then + if samesize + then pr2 "diff but at least same size" + else pr2 "PB: diff and not same size" + + | _ -> Arg.usage (Arg.align options) usage_msg; + ) + end + +(*****************************************************************************) +let _ = + main () + -- 2.20.1

    1z=0pN%< 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

    xo7?E+s!mF(=6X6>Lof{wlzS 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