packcr 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +21 -0
  3. data/README.md +73 -0
  4. data/lib/packcr/cli.rb +18 -16
  5. data/lib/packcr/code_block.rb +0 -1
  6. data/lib/packcr/context.rb +20 -18
  7. data/lib/packcr/generated/context.rb +483 -0
  8. data/lib/packcr/generated/node/action_node.rb +60 -0
  9. data/lib/packcr/generated/node/alternate_node.rb +98 -0
  10. data/lib/packcr/generated/node/capture_node.rb +39 -0
  11. data/lib/packcr/generated/node/charclass_node.rb +372 -0
  12. data/lib/packcr/generated/node/eof_node.rb +20 -0
  13. data/lib/packcr/generated/node/error_node.rb +67 -0
  14. data/lib/packcr/generated/node/expand_node.rb +30 -0
  15. data/lib/packcr/generated/node/predicate_node.rb +140 -0
  16. data/lib/packcr/generated/node/quantity_node.rb +166 -0
  17. data/lib/packcr/generated/node/reference_node.rb +70 -0
  18. data/lib/packcr/generated/node/rule_node.rb +63 -0
  19. data/lib/packcr/generated/node/sequence_node.rb +42 -0
  20. data/lib/packcr/generated/node/string_node.rb +60 -0
  21. data/lib/packcr/generator.rb +2 -1
  22. data/lib/packcr/node/action_node.rb +4 -2
  23. data/lib/packcr/node/alternate_node.rb +3 -1
  24. data/lib/packcr/node/capture_node.rb +3 -1
  25. data/lib/packcr/node/charclass_node.rb +24 -28
  26. data/lib/packcr/node/eof_node.rb +4 -2
  27. data/lib/packcr/node/error_node.rb +3 -1
  28. data/lib/packcr/node/expand_node.rb +8 -5
  29. data/lib/packcr/node/predicate_node.rb +4 -2
  30. data/lib/packcr/node/quantity_node.rb +12 -10
  31. data/lib/packcr/node/reference_node.rb +11 -5
  32. data/lib/packcr/node/root_node.rb +1 -0
  33. data/lib/packcr/node/rule_node.rb +7 -4
  34. data/lib/packcr/node/sequence_node.rb +3 -1
  35. data/lib/packcr/node/string_node.rb +9 -6
  36. data/lib/packcr/node.rb +3 -5
  37. data/lib/packcr/parser.rb +4389 -4064
  38. data/lib/packcr/stream.rb +17 -12
  39. data/lib/packcr/templates/context/header.c.erb +3 -3
  40. data/lib/packcr/templates/context/source.c.erb +481 -690
  41. data/lib/packcr/templates/context/source.rb.erb +123 -171
  42. data/lib/packcr/templates/node/action.c.erb +5 -5
  43. data/lib/packcr/templates/node/action.rb.erb +2 -2
  44. data/lib/packcr/templates/node/alternate.c.erb +9 -9
  45. data/lib/packcr/templates/node/alternate.rb.erb +4 -5
  46. data/lib/packcr/templates/node/capture.c.erb +7 -7
  47. data/lib/packcr/templates/node/capture.rb.erb +4 -4
  48. data/lib/packcr/templates/node/charclass.c.erb +12 -12
  49. data/lib/packcr/templates/node/charclass.rb.erb +6 -6
  50. data/lib/packcr/templates/node/charclass_any.c.erb +3 -3
  51. data/lib/packcr/templates/node/charclass_any.rb.erb +2 -2
  52. data/lib/packcr/templates/node/charclass_fail.c.erb +1 -1
  53. data/lib/packcr/templates/node/charclass_one.c.erb +10 -10
  54. data/lib/packcr/templates/node/charclass_one.rb.erb +6 -6
  55. data/lib/packcr/templates/node/charclass_utf8.c.erb +8 -8
  56. data/lib/packcr/templates/node/charclass_utf8.rb.erb +3 -3
  57. data/lib/packcr/templates/node/charclass_utf8_reverse.rb.erb +5 -5
  58. data/lib/packcr/templates/node/eof.c.erb +1 -1
  59. data/lib/packcr/templates/node/error.c.erb +11 -11
  60. data/lib/packcr/templates/node/error.rb.erb +2 -2
  61. data/lib/packcr/templates/node/expand.c.erb +5 -5
  62. data/lib/packcr/templates/node/expand.rb.erb +3 -3
  63. data/lib/packcr/templates/node/predicate.c.erb +10 -10
  64. data/lib/packcr/templates/node/predicate.rb.erb +6 -6
  65. data/lib/packcr/templates/node/predicate_neg.c.erb +8 -8
  66. data/lib/packcr/templates/node/predicate_neg.rb.erb +6 -6
  67. data/lib/packcr/templates/node/quantity_many.c.erb +47 -0
  68. data/lib/packcr/templates/node/{quantify_many.rb.erb → quantity_many.rb.erb} +9 -9
  69. data/lib/packcr/templates/node/quantity_one.c.erb +23 -0
  70. data/lib/packcr/templates/node/{quantify_one.rb.erb → quantity_one.rb.erb} +8 -8
  71. data/lib/packcr/templates/node/reference.c.erb +14 -2
  72. data/lib/packcr/templates/node/reference.rb.erb +16 -4
  73. data/lib/packcr/templates/node/reference_reverse.rb.erb +16 -4
  74. data/lib/packcr/templates/node/rule.c.erb +14 -7
  75. data/lib/packcr/templates/node/rule.rb.erb +26 -19
  76. data/lib/packcr/templates/node/string_many.c.erb +6 -6
  77. data/lib/packcr/templates/node/string_many.rb.erb +3 -3
  78. data/lib/packcr/templates/node/string_one.c.erb +5 -5
  79. data/lib/packcr/templates/node/string_one.rb.erb +3 -3
  80. data/lib/packcr/util.rb +21 -16
  81. data/lib/packcr/version.rb +1 -1
  82. data/lib/packcr.rb +8 -11
  83. metadata +40 -10
  84. data/lib/packcr/templates/node/quantify_many.c.erb +0 -45
  85. data/lib/packcr/templates/node/quantify_one.c.erb +0 -21
  86. data/lib/packcr/tokenizer.rb +0 -2948
@@ -0,0 +1,483 @@
1
+ class Packcr
2
+ class Context
3
+ def get_header_code(lang, stream)
4
+ case lang
5
+ when :c
6
+ erbout = +""
7
+ erbout << "/* A packrat parser generated by PackCR #{Packcr::VERSION} */\n\n".freeze
8
+
9
+ code(:eheader).each do |code|
10
+ erbout << "#{stream.get_code_block(code, 0, @iname)}".freeze
11
+ end
12
+ if !code(:eheader).empty?
13
+ erbout << "\n".freeze
14
+ end
15
+ erbout << "#ifndef PACKCR_INCLUDED_#{@hid}\n#define PACKCR_INCLUDED_#{@hid}\n\n".freeze
16
+
17
+ code(:header).each do |code|
18
+ erbout << "#{stream.get_code_block(code, 0, @iname)}".freeze
19
+ end
20
+ erbout << "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct #{prefix}_context_tag #{prefix}_context_t;\n\n#{prefix}_context_t *#{prefix}_create(#{auxil_def}auxil);\nint #{prefix}_parse(#{prefix}_context_t *ctx, #{value_def}*ret);\nvoid #{prefix}_destroy(#{prefix}_context_t *ctx);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* !PACKCR_INCLUDED_#{@hid} */\n".freeze
21
+
22
+ erbout
23
+ end
24
+ end
25
+
26
+ def get_source_code(lang, stream)
27
+ case lang
28
+ when :c
29
+ erbout = +""
30
+ erbout << "/* A packrat parser generated by PackCR #{Packcr::VERSION} */\n\n".freeze
31
+
32
+ code(:esource).each do |code|
33
+ erbout << "#{stream.get_code_block(code, 0, @iname)}".freeze
34
+ end
35
+ if !code(:esource).empty?
36
+ erbout << "\n".freeze
37
+ end
38
+ erbout << "#ifdef _MSC_VER\n#undef _CRT_SECURE_NO_WARNINGS\n#define _CRT_SECURE_NO_WARNINGS\n#endif /* _MSC_VER */\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#ifndef _MSC_VER\n#if defined __GNUC__ && defined _WIN32 /* MinGW */\n#ifndef PACKCR_USE_SYSTEM_STRNLEN\n#define strnlen(str, maxlen) packcr_strnlen(str, maxlen)\nstatic size_t packcr_strnlen(const char *str, size_t maxlen) {\n size_t i;\n for (i = 0; i < maxlen && str[i]; i++);\n return i;\n}\n#endif /* !PACKCR_USE_SYSTEM_STRNLEN */\n#endif /* defined __GNUC__ && defined _WIN32 */\n#endif /* !_MSC_VER */\n\n#include \"#{@hname}\"\n".freeze
39
+
40
+ if !code(:location).empty?
41
+ erbout << "\n".freeze
42
+
43
+ code(:location).each do |code|
44
+ erbout << "#{stream.get_code_block(code, 4, @iname)}".freeze
45
+ end
46
+ end
47
+ erbout << "\n".freeze
48
+
49
+ code(:source).each do |code|
50
+ erbout << "#{stream.get_code_block(code, 0, @iname)}".freeze
51
+ end
52
+ erbout << "#if !defined __has_attribute || defined _MSC_VER\n#define __attribute__(x)\n#endif\n\n#ifdef _MSC_VER\n#define MARK_FUNC_AS_USED __pragma(warning(suppress:4505))\n#else\n#define MARK_FUNC_AS_USED __attribute__((__unused__))\n#endif\n\n#ifndef PACKCR_BUFFER_MIN_SIZE\n#define PACKCR_BUFFER_MIN_SIZE 256\n#endif /* !PACKCR_BUFFER_MIN_SIZE */\n\n#ifndef PACKCR_ARRAY_MIN_SIZE\n#define PACKCR_ARRAY_MIN_SIZE 2\n#endif /* !PACKCR_ARRAY_MIN_SIZE */\n\n#ifndef PACKCR_POOL_MIN_SIZE\n#define PACKCR_POOL_MIN_SIZE 65536\n#endif /* !PACKCR_POOL_MIN_SIZE */\n\n#define PACKCR_DBG_EVALUATE 0\n#define PACKCR_DBG_MATCH 1\n#define PACKCR_DBG_NOMATCH 2\n\n#define PACKCR_VOID_VALUE (~(size_t)0)\n\ntypedef enum packcr_bool_tag {\n PACKCR_FALSE = 0,\n PACKCR_TRUE\n} packcr_bool_t;\n\ntypedef struct packcr_char_array_tag {\n char *buf;\n size_t max;\n size_t len;\n} packcr_char_array_t;\n\ntypedef struct packcr_range_tag {\n size_t start;\n size_t end;\n".freeze
53
+
54
+ if @location
55
+ erbout << " packcr_location_t start_loc;\n packcr_location_t end_loc;\n".freeze
56
+ end
57
+ erbout << "} packcr_range_t;\n\ntypedef #{value_def}packcr_value_t;\n\ntypedef #{auxil_def}packcr_auxil_t;\n\n".freeze
58
+
59
+ if prefix != "packcr"
60
+ erbout << "typedef #{prefix}_context_t packcr_context_t;\n\n".freeze
61
+ end
62
+ erbout << "typedef struct packcr_value_table_tag {\n packcr_value_t *buf;\n size_t max;\n size_t len;\n} packcr_value_table_t;\n\ntypedef struct packcr_value_refer_table_tag {\n packcr_value_t **buf;\n size_t max;\n size_t len;\n} packcr_value_refer_table_t;\n\ntypedef struct packcr_capture_tag {\n packcr_range_t range;\n char *string; /* mutable */\n} packcr_capture_t;\n\ntypedef struct packcr_capture_table_tag {\n packcr_capture_t *buf;\n size_t max;\n size_t len;\n} packcr_capture_table_t;\n\ntypedef struct packcr_capture_const_table_tag {\n const packcr_capture_t **buf;\n size_t max;\n size_t len;\n} packcr_capture_const_table_t;\n\ntypedef struct packcr_thunk_tag packcr_thunk_t;\ntypedef struct packcr_thunk_array_tag packcr_thunk_array_t;\n\ntypedef void (*packcr_action_t)(packcr_context_t *, packcr_thunk_t *, packcr_value_t *);\n\ntypedef enum packcr_thunk_type_tag {\n PACKCR_THUNK_LEAF,\n PACKCR_THUNK_NODE\n} packcr_thunk_type_t;\n\ntypedef struct packcr_thunk_leaf_tag {\n packcr_value_refer_table_t values;\n packcr_capture_const_table_t capts;\n packcr_capture_t capt0;\n packcr_action_t action;\n} packcr_thunk_leaf_t;\n\ntypedef struct packcr_thunk_node_tag {\n const packcr_thunk_array_t *thunks; /* just a reference */\n packcr_value_t *value; /* just a reference */\n} packcr_thunk_node_t;\n\ntypedef union packcr_thunk_data_tag {\n packcr_thunk_leaf_t leaf;\n packcr_thunk_node_t node;\n} packcr_thunk_data_t;\n\nstruct packcr_thunk_tag {\n packcr_thunk_type_t type;\n packcr_thunk_data_t data;\n};\n\nstruct packcr_thunk_array_tag {\n packcr_thunk_t **buf;\n size_t max;\n size_t len;\n};\n\ntypedef struct packcr_thunk_chunk_tag {\n packcr_value_table_t values;\n packcr_capture_table_t capts;\n packcr_thunk_array_t thunks;\n size_t pos; /* the starting position in the character buffer */\n".freeze
63
+
64
+ if @location
65
+ erbout << " packcr_location_t pos_loc;\n".freeze
66
+ end
67
+ erbout << "} packcr_thunk_chunk_t;\n\ntypedef struct packcr_lr_memo_tag packcr_lr_memo_t;\n\nstruct packcr_lr_memo_tag {\n size_t offset;\n".freeze
68
+
69
+ if @location
70
+ erbout << " packcr_location_t offset_loc;\n".freeze
71
+ end
72
+ erbout << " packcr_lr_memo_t *hold;\n packcr_thunk_chunk_t *chunk;\n packcr_bool_t fail;\n packcr_bool_t grow;\n};\n\ntypedef struct packcr_rule_set_tag packcr_rule_set_t;\n\ntypedef packcr_thunk_chunk_t *(*packcr_rule_t)(packcr_context_t *, size_t".freeze
73
+ if @location
74
+ erbout << ", packcr_location_t".freeze
75
+ end
76
+ erbout << ", packcr_rule_set_t*);\n\ntypedef struct packcr_rule_set_tag {\n packcr_rule_t *buf;\n size_t max;\n size_t len;\n} packcr_rule_set_t;\n\ntypedef struct packcr_lr_memo_map_entry_tag {\n packcr_rule_t rule;\n packcr_lr_memo_t *memo;\n} packcr_lr_memo_map_entry_t;\n\ntypedef struct packcr_lr_memo_map_tag {\n packcr_lr_memo_map_entry_t *buf;\n size_t max;\n size_t len;\n} packcr_lr_memo_map_t;\n\ntypedef struct packcr_lr_table_tag {\n packcr_lr_memo_map_t **buf;\n size_t max;\n size_t len;\n size_t ofs;\n} packcr_lr_table_t;\n\ntypedef struct packcr_memory_entry_tag packcr_memory_entry_t;\ntypedef struct packcr_memory_pool_tag packcr_memory_pool_t;\n\nstruct packcr_memory_entry_tag {\n packcr_memory_entry_t *next;\n};\n\nstruct packcr_memory_pool_tag {\n packcr_memory_pool_t *next;\n size_t allocated;\n size_t unused;\n};\n\ntypedef struct packcr_memory_recycler_tag {\n packcr_memory_pool_t *pool_list;\n packcr_memory_entry_t *entry_list;\n size_t element_size;\n} packcr_memory_recycler_t;\n\nstruct #{prefix}_context_tag {\n size_t buffer_start_position; /* the position in the input of the first character currently buffered */\n size_t position_offset; /* the current parsing position in the character buffer */\n".freeze
77
+
78
+ if @location
79
+ erbout << " packcr_location_t buffer_start_position_loc;\n packcr_location_t position_offset_loc;\n".freeze
80
+ end
81
+ erbout << " size_t level;\n packcr_char_array_t buffer;\n packcr_lr_table_t lrtable;\n packcr_thunk_array_t thunks;\n packcr_auxil_t auxil;\n packcr_memory_recycler_t thunk_chunk_recycler;\n packcr_memory_recycler_t lr_memo_recycler;\n};\n\n#ifndef PACKCR_ERROR\n#define PACKCR_ERROR(auxil) packcr_error()\nMARK_FUNC_AS_USED\nstatic void packcr_error(void) {\n fprintf(stderr, \"Syntax error\\n\");\n exit(1);\n}\n#endif /* !PACKCR_ERROR */\n\n#ifndef PACKCR_GETCHAR\n#define PACKCR_GETCHAR(auxil) getchar()\n#endif /* !PACKCR_GETCHAR */\n\n#ifndef PACKCR_MALLOC\n#define PACKCR_MALLOC(auxil, size) packcr_malloc_e(size)\nstatic void *packcr_malloc_e(size_t size) {\n void *const p = malloc(size);\n if (p == NULL) {\n fprintf(stderr, \"Out of memory\\n\");\n exit(1);\n }\n return p;\n}\n#endif /* !PACKCR_MALLOC */\n\n#ifndef PACKCR_REALLOC\n#define PACKCR_REALLOC(auxil, ptr, size) packcr_realloc_e(ptr, size)\nstatic void *packcr_realloc_e(void *ptr, size_t size) {\n void *const p = realloc(ptr, size);\n if (p == NULL) {\n fprintf(stderr, \"Out of memory\\n\");\n exit(1);\n }\n return p;\n}\n#endif /* !PACKCR_REALLOC */\n\n#ifndef PACKCR_FREE\n#define PACKCR_FREE(auxil, ptr) free(ptr)\n#endif /* !PACKCR_FREE */\n\n#ifndef PACKCR_DEBUG\n#define PACKCR_DEBUG(auxil, event, rule, level, pos, buffer, length) ((void)0)\n#endif /* !PACKCR_DEBUG */\n\nstatic char *packcr_strndup_e(packcr_auxil_t auxil, const char *str, size_t len) {\n const size_t m = strnlen(str, len);\n char *const s = (char *)PACKCR_MALLOC(auxil, m + 1);\n memcpy(s, str, m);\n s[m] = '\\0';\n return s;\n}\n\nstatic void packcr_char_array__init(packcr_auxil_t auxil, packcr_char_array_t *array) {\n array->len = 0;\n array->max = 0;\n array->buf = NULL;\n}\n\nstatic void packcr_char_array__add(packcr_auxil_t auxil, packcr_char_array_t *array, char ch) {\n if (array->max <= array->len) {\n const size_t n = array->len + 1;\n size_t m = array->max;\n if (m == 0) m = PACKCR_BUFFER_MIN_SIZE;\n while (m < n && m != 0) m <<= 1;\n if (m == 0) m = n;\n array->buf = (char *)PACKCR_REALLOC(auxil, array->buf, m);\n array->max = m;\n }\n array->buf[array->len++] = ch;\n}\n\nstatic void packcr_char_array__term(packcr_auxil_t auxil, packcr_char_array_t *array) {\n PACKCR_FREE(auxil, array->buf);\n}\n\nstatic void packcr_value_table__init(packcr_auxil_t auxil, packcr_value_table_t *table) {\n table->len = 0;\n table->max = 0;\n table->buf = NULL;\n}\n\nMARK_FUNC_AS_USED\nstatic void packcr_value_table__resize(packcr_auxil_t auxil, packcr_value_table_t *table, size_t len) {\n if (table->max < len) {\n size_t m = table->max;\n if (m == 0) m = PACKCR_ARRAY_MIN_SIZE;\n while (m < len && m != 0) m <<= 1;\n if (m == 0) m = len;\n table->buf = (packcr_value_t *)PACKCR_REALLOC(auxil, table->buf, sizeof(packcr_value_t) * m);\n table->max = m;\n }\n table->len = len;\n}\n\nMARK_FUNC_AS_USED\nstatic void packcr_value_table__clear(packcr_auxil_t auxil, packcr_value_table_t *table) {\n memset(table->buf, 0, sizeof(packcr_value_t) * table->len);\n}\n\nstatic void packcr_value_table__term(packcr_auxil_t auxil, packcr_value_table_t *table) {\n PACKCR_FREE(auxil, table->buf);\n}\n\nstatic void packcr_value_refer_table__init(packcr_auxil_t auxil, packcr_value_refer_table_t *table) {\n table->len = 0;\n table->max = 0;\n table->buf = NULL;\n}\n\nstatic void packcr_value_refer_table__resize(packcr_auxil_t auxil, packcr_value_refer_table_t *table, size_t len) {\n size_t i;\n if (table->max < len) {\n size_t m = table->max;\n if (m == 0) m = PACKCR_ARRAY_MIN_SIZE;\n while (m < len && m != 0) m <<= 1;\n if (m == 0) m = len;\n table->buf = (packcr_value_t **)PACKCR_REALLOC(auxil, table->buf, sizeof(packcr_value_t *) * m);\n table->max = m;\n }\n for (i = table->len; i < len; i++) table->buf[i] = NULL;\n table->len = len;\n}\n\nstatic void packcr_value_refer_table__term(packcr_auxil_t auxil, packcr_value_refer_table_t *table) {\n PACKCR_FREE(auxil, table->buf);\n}\n\nstatic void packcr_capture_table__init(packcr_auxil_t auxil, packcr_capture_table_t *table) {\n table->len = 0;\n table->max = 0;\n table->buf = NULL;\n}\n\nMARK_FUNC_AS_USED\nstatic void packcr_capture_table__resize(packcr_auxil_t auxil, packcr_capture_table_t *table, size_t len) {\n size_t i;\n for (i = len; i < table->len; i++) PACKCR_FREE(auxil, table->buf[i].string);\n if (table->max < len) {\n size_t m = table->max;\n if (m == 0) m = PACKCR_ARRAY_MIN_SIZE;\n while (m < len && m != 0) m <<= 1;\n if (m == 0) m = len;\n table->buf = (packcr_capture_t *)PACKCR_REALLOC(auxil, table->buf, sizeof(packcr_capture_t) * m);\n table->max = m;\n }\n for (i = table->len; i < len; i++) {\n table->buf[i].range.start = 0;\n table->buf[i].range.end = 0;\n".freeze
82
+
83
+ if @location
84
+ erbout << " packcr_location_init(&table->buf[i].range.start_loc);\n packcr_location_init(&table->buf[i].range.end_loc);\n".freeze
85
+ end
86
+ erbout << " table->buf[i].string = NULL;\n }\n table->len = len;\n}\n\nstatic void packcr_capture_table__term(packcr_auxil_t auxil, packcr_capture_table_t *table) {\n while (table->len > 0) {\n table->len--;\n PACKCR_FREE(auxil, table->buf[table->len].string);\n }\n PACKCR_FREE(auxil, table->buf);\n}\n\nstatic void packcr_capture_const_table__init(packcr_auxil_t auxil, packcr_capture_const_table_t *table) {\n table->len = 0;\n table->max = 0;\n table->buf = NULL;\n}\n\nstatic void packcr_capture_const_table__resize(packcr_auxil_t auxil, packcr_capture_const_table_t *table, size_t len) {\n size_t i;\n if (table->max < len) {\n size_t m = table->max;\n if (m == 0) m = PACKCR_ARRAY_MIN_SIZE;\n while (m < len && m != 0) m <<= 1;\n if (m == 0) m = len;\n table->buf = (const packcr_capture_t **)PACKCR_REALLOC(auxil, (packcr_capture_t **)table->buf, sizeof(const packcr_capture_t *) * m);\n table->max = m;\n }\n for (i = table->len; i < len; i++) table->buf[i] = NULL;\n table->len = len;\n}\n\nstatic void packcr_capture_const_table__term(packcr_auxil_t auxil, packcr_capture_const_table_t *table) {\n PACKCR_FREE(auxil, (void *)table->buf);\n}\n\nMARK_FUNC_AS_USED\nstatic packcr_thunk_t *packcr_thunk__create_leaf(packcr_auxil_t auxil, packcr_action_t action, size_t valuec, size_t captc) {\n packcr_thunk_t *const thunk = (packcr_thunk_t *)PACKCR_MALLOC(auxil, sizeof(packcr_thunk_t));\n thunk->type = PACKCR_THUNK_LEAF;\n packcr_value_refer_table__init(auxil, &thunk->data.leaf.values);\n packcr_value_refer_table__resize(auxil, &thunk->data.leaf.values, valuec);\n packcr_capture_const_table__init(auxil, &thunk->data.leaf.capts);\n packcr_capture_const_table__resize(auxil, &thunk->data.leaf.capts, captc);\n thunk->data.leaf.capt0.range.start = 0;\n thunk->data.leaf.capt0.range.end = 0;\n".freeze
87
+
88
+ if @location
89
+ erbout << " packcr_location_init(&thunk->data.leaf.capt0.range.start_loc);\n packcr_location_init(&thunk->data.leaf.capt0.range.end_loc);\n".freeze
90
+ end
91
+ erbout << " thunk->data.leaf.capt0.string = NULL;\n thunk->data.leaf.action = action;\n return thunk;\n}\n\nstatic packcr_thunk_t *packcr_thunk__create_node(packcr_auxil_t auxil, const packcr_thunk_array_t *thunks, packcr_value_t *value) {\n packcr_thunk_t *const thunk = (packcr_thunk_t *)PACKCR_MALLOC(auxil, sizeof(packcr_thunk_t));\n thunk->type = PACKCR_THUNK_NODE;\n thunk->data.node.thunks = thunks;\n thunk->data.node.value = value;\n return thunk;\n}\n\nstatic void packcr_thunk__destroy(packcr_auxil_t auxil, packcr_thunk_t *thunk) {\n if (thunk == NULL) return;\n switch (thunk->type) {\n case PACKCR_THUNK_LEAF:\n PACKCR_FREE(auxil, thunk->data.leaf.capt0.string);\n packcr_capture_const_table__term(auxil, &thunk->data.leaf.capts);\n packcr_value_refer_table__term(auxil, &thunk->data.leaf.values);\n break;\n case PACKCR_THUNK_NODE:\n break;\n default: /* unknown */\n break;\n }\n PACKCR_FREE(auxil, thunk);\n}\n\nstatic void packcr_thunk_array__init(packcr_auxil_t auxil, packcr_thunk_array_t *array) {\n array->len = 0;\n array->max = 0;\n array->buf = NULL;\n}\n\nstatic void packcr_thunk_array__add(packcr_auxil_t auxil, packcr_thunk_array_t *array, packcr_thunk_t *thunk) {\n if (array->max <= array->len) {\n const size_t n = array->len + 1;\n size_t m = array->max;\n if (m == 0) m = PACKCR_ARRAY_MIN_SIZE;\n while (m < n && m != 0) m <<= 1;\n if (m == 0) m = n;\n array->buf = (packcr_thunk_t **)PACKCR_REALLOC(auxil, array->buf, sizeof(packcr_thunk_t *) * m);\n array->max = m;\n }\n array->buf[array->len++] = thunk;\n}\n\nstatic void packcr_thunk_array__revert(packcr_auxil_t auxil, packcr_thunk_array_t *array, size_t len) {\n while (array->len > len) {\n array->len--;\n packcr_thunk__destroy(auxil, array->buf[array->len]);\n }\n}\n\nstatic void packcr_thunk_array__term(packcr_auxil_t auxil, packcr_thunk_array_t *array) {\n while (array->len > 0) {\n array->len--;\n packcr_thunk__destroy(auxil, array->buf[array->len]);\n }\n PACKCR_FREE(auxil, array->buf);\n}\n\nstatic void packcr_memory_recycler__init(packcr_auxil_t auxil, packcr_memory_recycler_t *recycler, size_t element_size) {\n recycler->pool_list = NULL;\n recycler->entry_list = NULL;\n recycler->element_size = element_size;\n}\n\nstatic void *packcr_memory_recycler__supply(packcr_auxil_t auxil, packcr_memory_recycler_t *recycler) {\n if (recycler->entry_list) {\n packcr_memory_entry_t *const tmp = recycler->entry_list;\n recycler->entry_list = tmp->next;\n return tmp;\n }\n if (!recycler->pool_list || recycler->pool_list->unused == 0) {\n size_t size = PACKCR_POOL_MIN_SIZE;\n if (recycler->pool_list) {\n size = recycler->pool_list->allocated << 1;\n if (size == 0) size = recycler->pool_list->allocated;\n }\n {\n packcr_memory_pool_t *const pool = (packcr_memory_pool_t *)PACKCR_MALLOC(\n auxil, sizeof(packcr_memory_pool_t) + recycler->element_size * size\n );\n pool->allocated = size;\n pool->unused = size;\n pool->next = recycler->pool_list;\n recycler->pool_list = pool;\n }\n }\n recycler->pool_list->unused--;\n return (char *)recycler->pool_list + sizeof(packcr_memory_pool_t) + recycler->element_size * recycler->pool_list->unused;\n}\n\nstatic void packcr_memory_recycler__recycle(packcr_auxil_t auxil, packcr_memory_recycler_t *recycler, void *ptr) {\n packcr_memory_entry_t *const tmp = (packcr_memory_entry_t *)ptr;\n tmp->next = recycler->entry_list;\n recycler->entry_list = tmp;\n}\n\nstatic void packcr_memory_recycler__term(packcr_auxil_t auxil, packcr_memory_recycler_t *recycler) {\n while (recycler->pool_list) {\n packcr_memory_pool_t *const tmp = recycler->pool_list;\n recycler->pool_list = tmp->next;\n PACKCR_FREE(auxil, tmp);\n }\n}\n\nMARK_FUNC_AS_USED\nstatic packcr_thunk_chunk_t *packcr_thunk_chunk__create(packcr_context_t *ctx) {\n packcr_thunk_chunk_t *const chunk = (packcr_thunk_chunk_t *)packcr_memory_recycler__supply(ctx->auxil, &ctx->thunk_chunk_recycler);\n packcr_value_table__init(ctx->auxil, &chunk->values);\n packcr_capture_table__init(ctx->auxil, &chunk->capts);\n packcr_thunk_array__init(ctx->auxil, &chunk->thunks);\n chunk->pos = 0;\n return chunk;\n}\n\nstatic void packcr_thunk_chunk__destroy(packcr_context_t *ctx, packcr_thunk_chunk_t *chunk) {\n if (chunk == NULL) return;\n packcr_thunk_array__term(ctx->auxil, &chunk->thunks);\n packcr_capture_table__term(ctx->auxil, &chunk->capts);\n packcr_value_table__term(ctx->auxil, &chunk->values);\n packcr_memory_recycler__recycle(ctx->auxil, &ctx->thunk_chunk_recycler, chunk);\n}\n\nstatic void packcr_rule_set__init(packcr_auxil_t auxil, packcr_rule_set_t *set) {\n set->len = 0;\n set->max = 0;\n set->buf = NULL;\n}\n\nstatic size_t packcr_rule_set__index(packcr_auxil_t auxil, const packcr_rule_set_t *set, packcr_rule_t rule) {\n size_t i;\n for (i = 0; i < set->len; i++) {\n if (set->buf[i] == rule) return i;\n }\n return PACKCR_VOID_VALUE;\n}\n\nstatic packcr_bool_t packcr_rule_set__add(packcr_auxil_t auxil, packcr_rule_set_t *set, packcr_rule_t rule) {\n const size_t i = packcr_rule_set__index(auxil, set, rule);\n if (i != PACKCR_VOID_VALUE) return PACKCR_FALSE;\n if (set->max <= set->len) {\n const size_t n = set->len + 1;\n size_t m = set->max;\n if (m == 0) m = PACKCR_ARRAY_MIN_SIZE;\n while (m < n && m != 0) m <<= 1;\n if (m == 0) m = n;\n set->buf = (packcr_rule_t *)PACKCR_REALLOC(auxil, set->buf, sizeof(packcr_rule_t) * m);\n set->max = m;\n }\n set->buf[set->len++] = rule;\n return PACKCR_TRUE;\n}\n\nstatic void packcr_rule_set__term(packcr_auxil_t auxil, packcr_rule_set_t *set) {\n PACKCR_FREE(auxil, set->buf);\n}\n\nstatic packcr_lr_memo_t *packcr_lr_memo__create(packcr_context_t *ctx, size_t offset".freeze
92
+ if @location
93
+ erbout << ", packcr_location_t offset_loc".freeze
94
+ end
95
+ erbout << ") {\n packcr_lr_memo_t *memo = (packcr_lr_memo_t *)packcr_memory_recycler__supply(ctx->auxil, &ctx->lr_memo_recycler);\n memo->offset = offset;\n".freeze
96
+
97
+ if @location
98
+ erbout << " memo->offset_loc = offset_loc;\n".freeze
99
+ end
100
+ erbout << " memo->chunk = NULL;\n memo->fail = PACKCR_TRUE;\n memo->grow = PACKCR_FALSE;\n memo->hold = NULL;\n return memo;\n}\n\nstatic void packcr_lr_memo__set_chunk(packcr_context_t *ctx, packcr_lr_memo_t *memo, packcr_thunk_chunk_t *chunk) {\n if (memo->chunk) {\n packcr_lr_memo_t *const new_hold_memo = packcr_lr_memo__create(ctx, memo->offset".freeze
101
+
102
+ if @location
103
+ erbout << ", memo->offset_loc".freeze
104
+ end
105
+ erbout << ");\n new_hold_memo->chunk = memo->chunk;\n new_hold_memo->hold = memo->hold;\n memo->hold = new_hold_memo;\n }\n memo->chunk = chunk;\n memo->fail = PACKCR_FALSE;\n}\n\nstatic void packcr_lr_memo__destroy(packcr_context_t *ctx, packcr_lr_memo_t *memo) {\n while (memo != NULL) {\n packcr_lr_memo_t *const hold_memo = memo->hold;\n packcr_thunk_chunk__destroy(ctx, memo->chunk);\n packcr_memory_recycler__recycle(ctx->auxil, &ctx->lr_memo_recycler, memo);\n memo = hold_memo;\n }\n}\n\nstatic void packcr_lr_memo_map__init(packcr_auxil_t auxil, packcr_lr_memo_map_t *map) {\n map->len = 0;\n map->max = 0;\n map->buf = NULL;\n}\n\nstatic size_t packcr_lr_memo_map__index(packcr_context_t *ctx, packcr_lr_memo_map_t *map, packcr_rule_t rule) {\n size_t i;\n for (i = 0; i < map->len; i++) {\n if (map->buf[i].rule == rule) return i;\n }\n return PACKCR_VOID_VALUE;\n}\n\nstatic void packcr_lr_memo_map__put(packcr_context_t *ctx, packcr_lr_memo_map_t *map, packcr_rule_t rule, packcr_lr_memo_t *memo) {\n const size_t i = packcr_lr_memo_map__index(ctx, map, rule);\n if (i != PACKCR_VOID_VALUE) {\n packcr_lr_memo__destroy(ctx, map->buf[i].memo);\n map->buf[i].memo = memo;\n }\n else {\n if (map->max <= map->len) {\n const size_t n = map->len + 1;\n size_t m = map->max;\n if (m == 0) m = PACKCR_ARRAY_MIN_SIZE;\n while (m < n && m != 0) m <<= 1;\n if (m == 0) m = n;\n map->buf = (packcr_lr_memo_map_entry_t *)PACKCR_REALLOC(ctx->auxil, map->buf, sizeof(packcr_lr_memo_map_entry_t) * m);\n map->max = m;\n }\n map->buf[map->len].rule = rule;\n map->buf[map->len].memo = memo;\n map->len++;\n }\n}\n\nstatic packcr_lr_memo_t *packcr_lr_memo_map__get(packcr_context_t *ctx, packcr_lr_memo_map_t *map, packcr_rule_t rule) {\n const size_t i = packcr_lr_memo_map__index(ctx, map, rule);\n return (i != PACKCR_VOID_VALUE) ? map->buf[i].memo : NULL;\n}\n\nstatic void packcr_lr_memo_map__term(packcr_context_t *ctx, packcr_lr_memo_map_t *map) {\n while (map->len > 0) {\n map->len--;\n packcr_lr_memo__destroy(ctx, map->buf[map->len].memo);\n }\n PACKCR_FREE(ctx->auxil, map->buf);\n}\n\nstatic packcr_lr_memo_map_t *packcr_lr_memo_map__create(packcr_context_t *ctx) {\n packcr_lr_memo_map_t *const memo = (packcr_lr_memo_map_t *)PACKCR_MALLOC(ctx->auxil, sizeof(packcr_lr_memo_map_t));\n packcr_lr_memo_map__init(ctx->auxil, memo);\n return memo;\n}\n\nstatic void packcr_lr_memo_map__destroy(packcr_context_t *ctx, packcr_lr_memo_map_t *memo) {\n if (memo == NULL) return;\n packcr_lr_memo_map__term(ctx, memo);\n PACKCR_FREE(ctx->auxil, memo);\n}\n\nstatic void packcr_lr_table__init(packcr_auxil_t auxil, packcr_lr_table_t *table) {\n table->ofs = 0;\n table->len = 0;\n table->max = 0;\n table->buf = NULL;\n}\n\nstatic void packcr_lr_table__resize(packcr_context_t *ctx, packcr_lr_table_t *table, size_t len) {\n size_t i;\n for (i = len; i < table->len; i++) packcr_lr_memo_map__destroy(ctx, table->buf[i]);\n if (table->max < len) {\n size_t m = table->max;\n if (m == 0) m = PACKCR_ARRAY_MIN_SIZE;\n while (m < len && m != 0) m <<= 1;\n if (m == 0) m = len;\n table->buf = (packcr_lr_memo_map_t **)PACKCR_REALLOC(ctx->auxil, table->buf, sizeof(packcr_lr_memo_map_t *) * m);\n table->max = m;\n }\n for (i = table->len; i < len; i++) table->buf[i] = NULL;\n table->len = len;\n}\n\nstatic void packcr_lr_table__set_memo(packcr_context_t *ctx, packcr_lr_table_t *table, size_t index, packcr_rule_t rule, packcr_lr_memo_t *memo) {\n index += table->ofs;\n if (index >= table->len) packcr_lr_table__resize(ctx, table, index + 1);\n if (table->buf[index] == NULL) table->buf[index] = packcr_lr_memo_map__create(ctx);\n packcr_lr_memo_map__put(ctx, table->buf[index], rule, memo);\n}\n\nstatic packcr_lr_memo_t *packcr_lr_table__get_memo(packcr_context_t *ctx, packcr_lr_table_t *table, size_t index, packcr_rule_t rule) {\n index += table->ofs;\n if (index >= table->len || table->buf[index] == NULL) return NULL;\n return packcr_lr_memo_map__get(ctx, table->buf[index], rule);\n}\n\nstatic void packcr_lr_table__shift(packcr_context_t *ctx, packcr_lr_table_t *table, size_t count) {\n size_t i;\n if (count > table->len - table->ofs) count = table->len - table->ofs;\n for (i = 0; i < count; i++) packcr_lr_memo_map__destroy(ctx, table->buf[table->ofs++]);\n if (table->ofs > (table->max >> 1)) {\n memmove(table->buf, table->buf + table->ofs, sizeof(packcr_lr_memo_map_t *) * (table->len - table->ofs));\n table->len -= table->ofs;\n table->ofs = 0;\n }\n}\n\nstatic void packcr_lr_table__term(packcr_context_t *ctx, packcr_lr_table_t *table) {\n while (table->len > table->ofs) {\n table->len--;\n packcr_lr_memo_map__destroy(ctx, table->buf[table->len]);\n }\n PACKCR_FREE(ctx->auxil, table->buf);\n}\n\nstatic packcr_context_t *packcr_context__create(packcr_auxil_t auxil) {\n packcr_context_t *const ctx = (packcr_context_t *)PACKCR_MALLOC(auxil, sizeof(packcr_context_t));\n ctx->buffer_start_position = 0;\n ctx->position_offset = 0;\n".freeze
106
+
107
+ if @location
108
+ erbout << " packcr_location_init(&ctx->buffer_start_position_loc);\n packcr_location_init(&ctx->position_offset_loc);\n".freeze
109
+ end
110
+ erbout << " ctx->level = 0;\n packcr_char_array__init(auxil, &ctx->buffer);\n packcr_lr_table__init(auxil, &ctx->lrtable);\n packcr_thunk_array__init(auxil, &ctx->thunks);\n packcr_memory_recycler__init(auxil, &ctx->thunk_chunk_recycler, sizeof(packcr_thunk_chunk_t));\n packcr_memory_recycler__init(auxil, &ctx->lr_memo_recycler, sizeof(packcr_lr_memo_t));\n ctx->auxil = auxil;\n return ctx;\n}\n\nstatic void packcr_context__destroy(packcr_context_t *ctx) {\n if (ctx == NULL) return;\n packcr_thunk_array__term(ctx->auxil, &ctx->thunks);\n packcr_lr_table__term(ctx, &ctx->lrtable);\n packcr_char_array__term(ctx->auxil, &ctx->buffer);\n packcr_memory_recycler__term(ctx->auxil, &ctx->thunk_chunk_recycler);\n packcr_memory_recycler__term(ctx->auxil, &ctx->lr_memo_recycler);\n PACKCR_FREE(ctx->auxil, ctx);\n}\n\nstatic size_t packcr_refill_buffer(packcr_context_t *ctx, size_t num) {\n if (ctx->buffer.len >= ctx->position_offset + num) return ctx->buffer.len - ctx->position_offset;\n while (ctx->buffer.len < ctx->position_offset + num) {\n const int c = PACKCR_GETCHAR(ctx->auxil);\n if (c < 0) break;\n packcr_char_array__add(ctx->auxil, &ctx->buffer, (char)c);\n }\n return ctx->buffer.len - ctx->position_offset;\n}\n\nMARK_FUNC_AS_USED\nstatic void packcr_commit_buffer(packcr_context_t *ctx) {\n memmove(ctx->buffer.buf, ctx->buffer.buf + ctx->position_offset, ctx->buffer.len - ctx->position_offset);\n ctx->buffer.len -= ctx->position_offset;\n ctx->buffer_start_position += ctx->position_offset;\n packcr_lr_table__shift(ctx, &ctx->lrtable, ctx->position_offset);\n ctx->position_offset = 0;\n".freeze
111
+
112
+ if @location
113
+ erbout << " ctx->buffer_start_position_loc = packcr_location_add(ctx->buffer_start_position_loc, ctx->position_offset_loc);\n packcr_location_init(&ctx->position_offset_loc);\n".freeze
114
+ end
115
+ erbout << "}\n\nMARK_FUNC_AS_USED\nstatic const char *packcr_get_capture_string(packcr_context_t *ctx, const packcr_capture_t *capt) {\n if (capt->string == NULL)\n ((packcr_capture_t *)capt)->string =\n packcr_strndup_e(ctx->auxil, ctx->buffer.buf + capt->range.start, capt->range.end - capt->range.start);\n return capt->string;\n}\n\n".freeze
116
+
117
+ if @utf8
118
+ erbout << "static size_t packcr_get_char_as_utf32(packcr_context_t *ctx, int *out) { /* with checking UTF-8 validity */\n int c, u;\n size_t n;\n if (packcr_refill_buffer(ctx, 1) < 1) return 0;\n c = (int)(unsigned char)ctx->buffer.buf[ctx->position_offset];\n n = (c < 0x80) ? 1 :\n ((c & 0xe0) == 0xc0) ? 2 :\n ((c & 0xf0) == 0xe0) ? 3 :\n ((c & 0xf8) == 0xf0) ? 4 : 0;\n if (n < 1) return 0;\n if (packcr_refill_buffer(ctx, n) < n) return 0;\n switch (n) {\n case 1:\n u = c;\n break;\n case 2:\n u = c & 0x1f;\n c = (int)(unsigned char)ctx->buffer.buf[ctx->position_offset + 1];\n if ((c & 0xc0) != 0x80) return 0;\n u <<= 6; u |= c & 0x3f;\n if (u < 0x80) return 0;\n break;\n case 3:\n u = c & 0x0f;\n c = (int)(unsigned char)ctx->buffer.buf[ctx->position_offset + 1];\n if ((c & 0xc0) != 0x80) return 0;\n u <<= 6; u |= c & 0x3f;\n c = (int)(unsigned char)ctx->buffer.buf[ctx->position_offset + 2];\n if ((c & 0xc0) != 0x80) return 0;\n u <<= 6; u |= c & 0x3f;\n if (u < 0x800) return 0;\n break;\n case 4:\n u = c & 0x07;\n c = (int)(unsigned char)ctx->buffer.buf[ctx->position_offset + 1];\n if ((c & 0xc0) != 0x80) return 0;\n u <<= 6; u |= c & 0x3f;\n c = (int)(unsigned char)ctx->buffer.buf[ctx->position_offset + 2];\n if ((c & 0xc0) != 0x80) return 0;\n u <<= 6; u |= c & 0x3f;\n c = (int)(unsigned char)ctx->buffer.buf[ctx->position_offset + 3];\n if ((c & 0xc0) != 0x80) return 0;\n u <<= 6; u |= c & 0x3f;\n if (u < 0x10000 || u > 0x10ffff) return 0;\n break;\n default:\n return 0;\n }\n if (out) *out = u;\n return n;\n}\n\n".freeze
119
+ end
120
+ erbout << "static void packcr_grow_lr(packcr_context_t *ctx, packcr_rule_t rule, size_t offset".freeze
121
+ if @location
122
+ erbout << ", packcr_location_t offset_loc".freeze
123
+ end
124
+ erbout << ") {\n while(1) {\n const size_t old_offset = ctx->position_offset;\n packcr_thunk_chunk_t *chunk;\n packcr_lr_memo_t *memo;\n packcr_rule_set_t limits;\n ctx->position_offset = offset;\n".freeze
125
+
126
+ if @location
127
+ erbout << " ctx->position_offset_loc = offset_loc;\n".freeze
128
+ end
129
+ erbout << " packcr_rule_set__init(ctx->auxil, &limits);\n packcr_rule_set__add(ctx->auxil, &limits, rule);\n chunk = rule(ctx, offset".freeze
130
+
131
+ if @location
132
+ erbout << ", offset_loc".freeze
133
+ end
134
+ erbout << ", &limits);\n packcr_rule_set__term(ctx->auxil, &limits);\n if (!chunk)\n break;\n if (ctx->position_offset <= old_offset) {\n packcr_thunk_chunk__destroy(ctx, chunk);\n break;\n }\n memo = packcr_lr_table__get_memo(ctx, &ctx->lrtable, offset, rule);\n packcr_lr_memo__set_chunk(ctx, memo, chunk);\n memo->offset = ctx->position_offset;\n".freeze
135
+
136
+ if @location
137
+ erbout << " memo->offset_loc = ctx->position_offset_loc;\n".freeze
138
+ end
139
+ erbout << " }\n}\n\nMARK_FUNC_AS_USED\nstatic packcr_thunk_chunk_t *packcr_get_rule_thunk_chunk(packcr_context_t *ctx, packcr_rule_t rule) {\n packcr_thunk_chunk_t *c = NULL;\n size_t offset = ctx->position_offset;\n".freeze
140
+
141
+ if @location
142
+ erbout << " packcr_location_t offset_loc = ctx->position_offset_loc;\n".freeze
143
+ end
144
+ erbout << " packcr_lr_memo_t *memo = packcr_lr_table__get_memo(ctx, &ctx->lrtable, offset, rule);\n\n if (memo == NULL) {\n memo = packcr_lr_memo__create(ctx, offset".freeze
145
+
146
+ if @location
147
+ erbout << ", offset_loc".freeze
148
+ end
149
+ erbout << ");\n packcr_lr_table__set_memo(ctx, &ctx->lrtable, offset, rule, memo);\n c = rule(ctx, offset".freeze
150
+
151
+ if @location
152
+ erbout << ", offset_loc".freeze
153
+ end
154
+ erbout << ", NULL);\n packcr_lr_memo__set_chunk(ctx, memo, c);\n memo->offset = ctx->position_offset;\n".freeze
155
+
156
+ if @location
157
+ erbout << " memo->offset_loc = ctx->position_offset_loc;\n".freeze
158
+ end
159
+ erbout << " if (memo->grow) {\n packcr_grow_lr(ctx, rule, offset".freeze
160
+
161
+ if @location
162
+ erbout << ", offset_loc".freeze
163
+ end
164
+ erbout << ");\n memo->grow = PACKCR_FALSE;\n ctx->position_offset = memo->offset;\n".freeze
165
+
166
+ if @location
167
+ erbout << " ctx->position_offset_loc = memo->offset_loc;\n".freeze
168
+ end
169
+ erbout << " return memo->chunk;\n }\n return c;\n } else if (memo->fail) {\n packcr_lr_memo__set_chunk(ctx, memo, NULL);\n memo->grow = PACKCR_TRUE;\n return NULL;\n }\n ctx->position_offset = memo->offset;\n".freeze
170
+
171
+ if @location
172
+ erbout << " ctx->position_offset_loc = memo->offset_loc;\n".freeze
173
+ end
174
+ erbout << " return memo->chunk;\n}\n\nMARK_FUNC_AS_USED\nstatic packcr_bool_t packcr_apply_rule(packcr_context_t *ctx, packcr_rule_t rule, packcr_thunk_array_t *thunks, packcr_value_t *value, size_t offset".freeze
175
+
176
+ if @location
177
+ erbout << ", packcr_location_t offset_loc".freeze
178
+ end
179
+ erbout << ", packcr_rule_set_t *limits) {\n static packcr_value_t null;\n packcr_thunk_chunk_t *c;\n if (limits != NULL) {\n packcr_lr_memo_t *memo;\n packcr_rule_set__add(ctx->auxil, limits, rule);\n c = rule(ctx, offset".freeze
180
+
181
+ if @location
182
+ erbout << ", offset_loc".freeze
183
+ end
184
+ erbout << ", limits);\n memo = packcr_lr_table__get_memo(ctx, &ctx->lrtable, offset, rule);\n if (memo == NULL || ctx->position_offset <= memo->offset) {\n if (memo) {\n c = memo->chunk;\n ctx->position_offset = memo->offset;\n".freeze
185
+
186
+ if @location
187
+ erbout << " ctx->position_offset_loc = memo->offset_loc;\n".freeze
188
+ end
189
+ erbout << " }\n } else {\n packcr_lr_memo__set_chunk(ctx, memo, c);\n memo->offset = ctx->position_offset;\n".freeze
190
+
191
+ if @location
192
+ erbout << " memo->offset_loc = ctx->position_offset_loc;\n".freeze
193
+ end
194
+ erbout << " }\n } else {\n c = packcr_get_rule_thunk_chunk(ctx, rule);\n }\n if (c == NULL) return PACKCR_FALSE;\n if (value == NULL) value = &null;\n memset(value, 0, sizeof(packcr_value_t)); /* in case */\n packcr_thunk_array__add(ctx->auxil, thunks, packcr_thunk__create_node(ctx->auxil, &c->thunks, value));\n return PACKCR_TRUE;\n}\n\nMARK_FUNC_AS_USED\nstatic void packcr_do_action(packcr_context_t *ctx, const packcr_thunk_array_t *thunks, packcr_value_t *value) {\n size_t i;\n for (i = 0; i < thunks->len; i++) {\n packcr_thunk_t *const thunk = thunks->buf[i];\n switch (thunk->type) {\n case PACKCR_THUNK_LEAF:\n thunk->data.leaf.action(ctx, thunk, value);\n break;\n case PACKCR_THUNK_NODE:\n packcr_do_action(ctx, thunk->data.node.thunks, thunk->data.node.value);\n break;\n default: /* unknown */\n break;\n }\n }\n}\n\n".freeze
195
+
196
+ @root.rules.each do |rule|
197
+ rule.codes.each do |code|
198
+ erbout << "static void packcr_action_#{rule.name}_#{code.index}(#{prefix}_context_t *__packcr_ctx, packcr_thunk_t *__packcr_in, packcr_value_t *__packcr_out) {\n#define auxil (__packcr_ctx->auxil)\n#define __ (*__packcr_out)\n".freeze
199
+
200
+ code.vars.each do |ref|
201
+ erbout << "#define #{ref.var} (*__packcr_in->data.leaf.values.buf[#{ref.index}])\n".freeze
202
+ end
203
+ erbout << "#define _0 packcr_get_capture_string(__packcr_ctx, &__packcr_in->data.leaf.capt0)\n#define _0s ((const size_t)(__packcr_ctx->buffer_start_position + __packcr_in->data.leaf.capt0.range.start))\n#define _0e ((const size_t)(__packcr_ctx->buffer_start_position + __packcr_in->data.leaf.capt0.range.end))\n".freeze
204
+
205
+ if @location
206
+ erbout << "#define _0sl ((const packcr_location_t)(packcr_location_add(__packcr_ctx->buffer_start_position_loc, __packcr_in->data.leaf.capt0.range.start_loc)))\n#define _0el ((const packcr_location_t)(packcr_location_add(__packcr_ctx->buffer_start_position_loc, __packcr_in->data.leaf.capt0.range.end_loc)))\n".freeze
207
+ end
208
+ if @capture_in_code
209
+ erbout << "#define _0c __packcr_in->data.leaf.capt0\n".freeze
210
+ end
211
+ code.capts.each do |capture|
212
+ erbout << "#define _#{capture.index + 1} packcr_get_capture_string(__packcr_ctx, __packcr_in->data.leaf.capts.buf[#{capture.index}])\n#define _#{capture.index + 1}s ((const size_t)(__packcr_ctx->buffer_start_position + __packcr_in->data.leaf.capts.buf[#{capture.index}]->range.start))\n#define _#{capture.index + 1}e ((const size_t)(__packcr_ctx->buffer_start_position + __packcr_in->data.leaf.capts.buf[#{capture.index}]->range.end))\n".freeze
213
+
214
+ if @location
215
+ erbout << "#define _#{capture.index + 1}sl ((const packcr_location_t)(packcr_location_add(__packcr_ctx->buffer_start_position_loc, __packcr_in->data.leaf.capts.buf[#{capture.index}]->range.start_loc)))\n#define _#{capture.index + 1}el ((const packcr_location_t)(packcr_location_add(__packcr_ctx->buffer_start_position_loc, __packcr_in->data.leaf.capts.buf[#{capture.index}]->range.end_loc)))\n".freeze
216
+ end
217
+ next unless @capture_in_code
218
+
219
+ erbout << "#define _#{capture.index + 1}c (*__packcr_in->data.leaf.capts.buf[#{capture.index}])\n".freeze
220
+ end
221
+ erbout << "#{stream.get_code_block(code.code, 4, @iname)}".freeze
222
+ code.capts.reverse_each do |capture|
223
+ if @location
224
+ erbout << "#undef _#{capture.index + 1}el\n#undef _#{capture.index + 1}sl\n".freeze
225
+ end
226
+ erbout << "#undef _#{capture.index + 1}e\n#undef _#{capture.index + 1}s\n#undef _#{capture.index + 1}\n".freeze
227
+ end
228
+ erbout << "#undef _0e\n#undef _0s\n#undef _0\n".freeze
229
+
230
+ code.vars.reverse_each do |ref|
231
+ erbout << "#undef #{ref.var}\n".freeze
232
+ end
233
+ erbout << "#undef __\n#undef auxil\n}\n\n".freeze
234
+ end
235
+ end
236
+ @root.rules.each do |rule|
237
+ erbout << "static packcr_thunk_chunk_t *packcr_evaluate_rule_#{rule.name}(packcr_context_t *ctx, size_t offset".freeze
238
+ if @location
239
+ erbout << ", packcr_location_t offset_loc".freeze
240
+ end
241
+ erbout << ", packcr_rule_set_t *limits);\n".freeze
242
+ end
243
+ erbout << "\n".freeze
244
+
245
+ @root.rules.each do |rule|
246
+ gen = ::Packcr::Generator.new(rule, @ascii, @location)
247
+ erbout << "#{gen.generate_code(rule, 0, 0, false)}\n".freeze
248
+ end
249
+ erbout << "#{prefix}_context_t *#{prefix}_create(#{auxil_def}auxil) {\n return packcr_context__create(auxil);\n}\n\nint #{prefix}_parse(#{prefix}_context_t *ctx, #{value_def}*ret) {\n size_t pos = ctx->buffer_start_position;\n".freeze
250
+
251
+ if !@root.rules.empty?
252
+ erbout << " if (packcr_apply_rule(ctx, packcr_evaluate_rule_#{@root.rules[0].name}, &ctx->thunks, ret, ctx->position_offset".freeze
253
+ if @location
254
+ erbout << ", ctx->position_offset_loc".freeze
255
+ end
256
+ erbout << ", NULL))\n packcr_do_action(ctx, &ctx->thunks, ret);\n else\n PACKCR_ERROR(ctx->auxil);\n packcr_commit_buffer(ctx);\n".freeze
257
+ end
258
+ erbout << " packcr_thunk_array__revert(ctx->auxil, &ctx->thunks, 0);\n return pos != ctx->buffer_start_position && packcr_refill_buffer(ctx, 1) >= 1;\n}\n\nvoid #{prefix}_destroy(#{prefix}_context_t *ctx) {\n packcr_context__destroy(ctx);\n}\n".freeze
259
+
260
+ if !code(:lsource).empty?
261
+ erbout << "\n".freeze
262
+
263
+ code(:lsource).each do |code|
264
+ erbout << "#{stream.get_code_block(code, 0, @iname)}".freeze
265
+ end
266
+ end
267
+ erbout
268
+ when :rb
269
+ erbout = +""
270
+ erbout << "# A packrat parser generated by PackCR #{Packcr::VERSION}\n".freeze
271
+
272
+ if !code(:esource).empty?
273
+ erbout << "\n".freeze
274
+
275
+ code(:esource).each do |code|
276
+ erbout << "#{stream.get_code_block(code, 0, @iname)}".freeze
277
+ end
278
+ end
279
+ erbout << "class #{class_name}\n".freeze
280
+
281
+ code(:location).each do |code|
282
+ erbout << "#{stream.get_code_block(code, 2, @iname)}\n".freeze
283
+ end
284
+ code(:source).each do |code|
285
+ erbout << " #{stream.get_code_block(code, 2, @iname)}\n".freeze
286
+ end
287
+ erbout << " def initialize(".freeze
288
+ if @auxil_type
289
+ erbout << "#{auxil_type}, ".freeze
290
+ end
291
+ erbout << "debug: false)\n".freeze
292
+
293
+ if @utf8
294
+ erbout << " @buffer = +\"\"\n".freeze
295
+
296
+ else
297
+ erbout << " @buffer = +\"\".b\n".freeze
298
+ end
299
+ erbout << "\n @buffer_start_position = 0\n @position_offset = 0\n @level = 0\n @thunk = ThunkNode.new([], nil, 0)\n @memos = LrMemoTable.new\n @debug = debug\n @global_values = {}\n".freeze
300
+
301
+ if @location
302
+ erbout << " @buffer_start_position_loc = Location.new\n @position_offset_loc = Location.new\n".freeze
303
+ end
304
+ code(:init).each do |code|
305
+ erbout << "#{stream.get_code_block(code, 4, @iname)}".freeze
306
+ end
307
+ erbout << " end\n\n def debug\n yield if @debug\n end\n\n def getc\n".freeze
308
+
309
+ if @utf8
310
+ erbout << " $stdin.getc\n".freeze
311
+
312
+ else
313
+ erbout << " $stdin.getc&.b\n".freeze
314
+ end
315
+ erbout << " end\n\n def refill_buffer(num, mode = nil)\n len = @buffer.length\n if len >= @position_offset + num\n return len - @position_offset\n end\n while len < @position_offset + num\n c = getc\n break if !c\n @buffer << c\n len = @buffer.length\n end\n return len - @position_offset\n end\n\n def commit_buffer\n @buffer = @buffer[@position_offset, @buffer.length - @position_offset]\n @buffer_start_position += @position_offset\n @memos.clear\n @position_offset = 0\n".freeze
316
+
317
+ if @location
318
+ erbout << " @buffer_start_position_loc = @buffer_start_position_loc + @position_offset_loc\n @position_offset_loc = Location.new\n".freeze
319
+ end
320
+ erbout << " end\n\n def parse\n pos = @buffer_start_position\n".freeze
321
+
322
+ if !@root.rules.empty?
323
+ erbout << " if apply_rule(:evaluate_rule_#{@root.rules[0].name}, @thunk.thunks, nil, 0, @buffer_start_position".freeze
324
+ if @location
325
+ erbout << ", @buffer_start_position_loc".freeze
326
+ end
327
+ erbout << ")\n @thunk.do_action(self, nil, 0)\n else\n raise SyntaxError, \"can't parse\"\n end\n commit_buffer\n".freeze
328
+ end
329
+ erbout << " @thunk.clear\n refill_buffer(1) >= 1 && pos != @buffer_start_position\n end\n\n def run\n nil while parse\n end\n\n".freeze
330
+
331
+ @root.rules.each do |rule|
332
+ rule.codes.each do |code|
333
+ erbout << " def action_#{rule.name}_#{code.index}(__packcr_in, __packcr_vars, __packcr_index)\n ____ = (__packcr_vars[__packcr_index] ||= Value.new).value if __packcr_vars\n".freeze
334
+
335
+ code.vars.each do |ref|
336
+ erbout << " #{ref.var} = (__packcr_in.value_refs[#{ref.index}] ||= Value.new).value\n".freeze
337
+ end
338
+ erbout << " __0 = __packcr_in.capt0.capture_string(@buffer)\n __0s = @buffer_start_position + __packcr_in.capt0.range_start\n __0e = @buffer_start_position + __packcr_in.capt0.range_end\n".freeze
339
+
340
+ if @location
341
+ erbout << " __0sl = @buffer_start_position_loc + __packcr_in.capt0.start_loc\n __0el = @buffer_start_position_loc + __packcr_in.capt0.end_loc\n".freeze
342
+ end
343
+ if @capture_in_code
344
+ erbout << " __0c = __packcr_in.capt0\n".freeze
345
+ end
346
+ code.capts.each do |capture|
347
+ erbout << " __#{capture.index + 1} = __packcr_in.capts[#{capture.index}].capture_string(@buffer)\n __#{capture.index + 1}s = @buffer_start_position + __packcr_in.capts[#{capture.index}].range_start\n __#{capture.index + 1}e = @buffer_start_position + __packcr_in.capts[#{capture.index}].range_end\n".freeze
348
+
349
+ if @location
350
+ erbout << " __#{capture.index + 1}sl = @buffer_start_position_loc + __packcr_in.capts[#{capture.index}].start_loc\n __#{capture.index + 1}el = @buffer_start_position_loc + __packcr_in.capts[#{capture.index}].end_loc\n".freeze
351
+ end
352
+ next unless @capture_in_code
353
+
354
+ erbout << " __#{capture.index + 1}c = __packcr_in.capts[#{capture.index}]\n".freeze
355
+ end
356
+
357
+ erbout << "#{stream.get_code_block(code.code, 4, @iname)}\n __packcr_vars[__packcr_index].value = ____ if __packcr_vars\n end\n\n".freeze
358
+ end
359
+ end
360
+ @root.rules.each do |rule|
361
+ gen = ::Packcr::Generator.new(rule, @ascii, @location, :rb)
362
+
363
+ erbout << "#{gen.generate_code(rule, 0, 2, false)}\n".freeze
364
+ end
365
+ erbout << " def grow_lr(rule, offset".freeze
366
+ if @location
367
+ erbout << ", offset_loc".freeze
368
+ end
369
+ erbout << ")\n while true\n old_offset = @position_offset\n @position_offset = offset\n".freeze
370
+
371
+ if @location
372
+ erbout << " @position_offset_loc = offset_loc\n".freeze
373
+ end
374
+ erbout << " answer = public_send(rule, offset".freeze
375
+ if @location
376
+ erbout << ", offset_loc".freeze
377
+ end
378
+ erbout << ", limits: {rule => true})\n if !answer || @position_offset <= old_offset\n break\n end\n memo = @memos[offset, rule]\n memo.answer = answer\n memo.offset = @position_offset\n".freeze
379
+
380
+ if @location
381
+ erbout << " memo.offset_loc = @position_offset_loc\n".freeze
382
+ end
383
+ erbout << " end\n end\n\n def rule_answer(rule)\n offset = @position_offset\n".freeze
384
+
385
+ if @location
386
+ erbout << " offset_loc = @position_offset_loc\n".freeze
387
+ end
388
+ erbout << " memo = @memos[offset, rule]\n\n if !memo\n memo = LrMemo.new(offset".freeze
389
+
390
+ if @location
391
+ erbout << ", offset_loc".freeze
392
+ end
393
+ erbout << ")\n @memos[offset, rule] = memo\n answer = public_send(rule, offset".freeze
394
+
395
+ if @location
396
+ erbout << ", offset_loc".freeze
397
+ end
398
+ erbout << ")\n memo.answer = answer\n memo.offset = @position_offset\n".freeze
399
+
400
+ if @location
401
+ erbout << " memo.offset_loc = @position_offset_loc\n".freeze
402
+ end
403
+ erbout << " if memo.grow\n grow_lr(rule, offset".freeze
404
+
405
+ if @location
406
+ erbout << ", offset_loc".freeze
407
+ end
408
+ erbout << ")\n memo.grow = false\n answer = memo.answer\n @position_offset = memo.offset\n".freeze
409
+
410
+ if @location
411
+ erbout << " @position_offset_loc = memo.offset_loc\n".freeze
412
+ end
413
+ erbout << " end\n return answer\n elsif memo.fail\n memo.answer = nil\n memo.grow = true\n return nil\n else\n @position_offset = memo.offset\n".freeze
414
+
415
+ if @location
416
+ erbout << " @position_offset_loc = memo.offset_loc\n".freeze
417
+ end
418
+ erbout << " return memo.answer\n end\n end\n\n def apply_rule(rule, thunks, values, index, offset".freeze
419
+ if @location
420
+ erbout << ", offset_loc".freeze
421
+ end
422
+ erbout << ", limits: nil)\n if limits\n limits = limits.merge(rule => true)\n answer = public_send(rule, offset".freeze
423
+
424
+ if @location
425
+ erbout << ", offset_loc".freeze
426
+ end
427
+ erbout << ", limits: limits)\n memo = @memos[offset, rule]\n if !answer || @position_offset <= memo.offset\n if memo\n answer = memo.answer\n @position_offset = memo.offset\n".freeze
428
+
429
+ if @location
430
+ erbout << " @position_offset_loc = memo.offset_loc\n".freeze
431
+ end
432
+ erbout << " end\n else\n memo.answer = answer\n memo.offset = @position_offset\n".freeze
433
+
434
+ if @location
435
+ erbout << " memo.offset_loc = @position_offset_loc\n".freeze
436
+ end
437
+ erbout << " end\n else\n answer = rule_answer(rule)\n end\n\n if !answer\n return false\n end\n values ||= @global_values\n thunks << ThunkNode.new(answer.thunks, values, index)\n return true\n end\n\n def do_action(thunks, values, index)\n thunks.each do |thunk|\n thunk.do_action(self, values, index)\n end\n end\n\n class LrMemoTable\n def initialize\n @memos = {}\n end\n\n def clear\n @memos.clear\n end\n\n def []=(index, rule_name, memo)\n entry = @memos[index] ||= {}\n entry[rule_name] = memo\n end\n\n def [](index, rule_name)\n @memos.dig(index, rule_name)\n end\n end\n\n class LrMemo\n attr_accessor :grow, :answer, :offset, :fail\n".freeze
438
+
439
+ if @location
440
+ erbout << " attr_accessor :offset_loc\n".freeze
441
+ end
442
+ erbout << "\n def initialize(offset".freeze
443
+ if @location
444
+ erbout << ", offset_loc".freeze
445
+ end
446
+ erbout << ")\n @offset = offset\n".freeze
447
+
448
+ if @location
449
+ erbout << " @offset_loc = offset_loc\n".freeze
450
+ end
451
+ erbout << " @fail = true\n @grow = false\n end\n\n def answer=(answer)\n @fail = nil\n @answer = answer\n end\n end\n\n class ThunkChunk\n attr_accessor :thunks, :capts, :pos, :values\n".freeze
452
+
453
+ if @location
454
+ erbout << " attr_accessor :pos_loc\n".freeze
455
+ end
456
+ erbout << "\n def initialize\n super\n @thunks = []\n @capts = {}\n @pos = 0\n @values = {}\n end\n\n def resize_captures(len)\n len.times do |i|\n @capts[i] = Capture.new\n end\n end\n end\n\n class ThunkLeaf\n attr_accessor :capt0, :capts, :value_refs, :action\n\n def initialize(action, capt0 = Capture.new, value_refs = {}, capts = {})\n @value_refs = value_refs\n @capts = capts\n @capt0 = capt0\n @action = action\n end\n\n def do_action(ctx, values, index)\n ctx.public_send(action, self, values, index)\n end\n end\n\n class ThunkNode\n attr_accessor :thunks, :values, :index\n\n def initialize(thunks, values, index)\n @thunks = thunks\n @values = values\n @index = index\n values[index] ||= Value.new if values\n end\n\n def do_action(ctx, _values, _index)\n @thunks.each do |thunk|\n thunk.do_action(ctx, @values, @index)\n end\n end\n\n def clear\n @thunks.clear\n end\n end\n\n class Capture\n attr_accessor :range_start, :range_end\n".freeze
457
+
458
+ if @location
459
+ erbout << " attr_accessor :start_loc, :end_loc\n".freeze
460
+ end
461
+ erbout << "\n def initialize(range_start = 0, range_end = 0".freeze
462
+ if @location
463
+ erbout << ", start_loc = nil, end_loc = nil".freeze
464
+ end
465
+ erbout << ")\n @range_start = range_start\n @range_end = range_end\n".freeze
466
+
467
+ if @location
468
+ erbout << " @start_loc = start_loc || Location.new\n @end_loc = end_loc || Location.new\n".freeze
469
+ end
470
+ erbout << " end\n\n def capture_string(buffer)\n @capture_string ||= buffer[@range_start, @range_end - @range_start]\n end\n end\n\n class Value\n attr_accessor :value\n end\nend\n".freeze
471
+
472
+ if !code(:lsource).empty?
473
+ erbout << "\n".freeze
474
+
475
+ code(:lsource).each do |code|
476
+ erbout << "#{stream.get_code_block(code, 0, @iname)}".freeze
477
+ end
478
+ end
479
+ erbout
480
+ end
481
+ end
482
+ end
483
+ end
@@ -0,0 +1,60 @@
1
+ class Packcr
2
+ class Node
3
+ class ActionNode
4
+ def get_code(gen, onfail, indent, bare, oncut)
5
+ case gen.lang
6
+ when :c
7
+ erbout = +""
8
+ erbout << "{\n packcr_thunk_t *const thunk = packcr_thunk__create_leaf(ctx->auxil, packcr_action_#{gen.rule.name}_#{index}, #{gen.rule.vars.length}, #{gen.rule.capts.length});\n".freeze
9
+
10
+ vars.each do |var|
11
+ erbout << " thunk->data.leaf.values.buf[#{var.index}] = &(chunk->values.buf[#{var.index}]);\n".freeze
12
+ end
13
+ capts.each do |capt|
14
+ erbout << " thunk->data.leaf.capts.buf[#{capt.index}] = &(chunk->capts.buf[#{capt.index}]);\n".freeze
15
+ end
16
+ erbout << " thunk->data.leaf.capt0.range.start = chunk->pos;\n thunk->data.leaf.capt0.range.end = ctx->position_offset;\n".freeze
17
+
18
+ if gen.location
19
+ erbout << " thunk->data.leaf.capt0.range.start_loc = chunk->pos_loc;\n thunk->data.leaf.capt0.range.end_loc = ctx->position_offset_loc;\n".freeze
20
+ end
21
+ erbout << " packcr_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);\n}\n".freeze
22
+
23
+ erbout
24
+ when :rb
25
+ erbout = +""
26
+ erbout << "answer.thunks.push(\n ThunkLeaf.new(\n :action_#{gen.rule.name}_#{index},\n Capture.new(\n answer.pos, @position_offset,\n".freeze
27
+
28
+ if gen.location
29
+ erbout << " answer.pos_loc, @position_offset_loc,\n".freeze
30
+ end
31
+ erbout << " ),\n".freeze
32
+
33
+ if vars.empty?
34
+ erbout << " {},\n".freeze
35
+
36
+ else
37
+ erbout << " answer.values.slice(".freeze
38
+ vars.each_with_index do |var, i|
39
+ erbout << "#{", " if i > 0}#{var.index}".freeze
40
+ end
41
+ erbout << "),\n".freeze
42
+ end
43
+ if capts.empty?
44
+ erbout << " {},\n".freeze
45
+
46
+ else
47
+ erbout << " answer.capts.slice(".freeze
48
+ capts.each_with_index do |capt, i|
49
+ erbout << "#{", " if i > 0}#{capt.index}".freeze
50
+ end
51
+ erbout << "),\n".freeze
52
+ end
53
+ erbout << " )\n)\n".freeze
54
+
55
+ erbout
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end