diff --git a/README.md b/README.md index e69de29..a8ea72e 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,68 @@ +# 甘棠约束条件编码器 + +## 使用方法 + +Linux 二进制已经编译好了,直接 ./encoder 即可。 + +自动读取当前目录 ./data 下的三个 csv 文件作为程序输入,如果需要修改输入数据,就改那三个 csv 文件(一定要UTF-8编码的,因为文件里有中文,Office Excel 转成的 csv 是 GBK 编码的,需要额外处理一下)。 + +```bash +约束条件可以使用任意数理逻辑表达式,包括 =>、<=、()、!、~、&、|、<=>,并且可以任意嵌套 +运算符默认优先级 (~|!) > (&) > (|) > (=>) = (<=) > (<=>) +``` + +程序的标准输出就是 CNF 格式的,并且包含合理的注释信息,直接重定向就可以: + +```bash +./encoder > result.cnf +``` + +## 如何编译 + +比较懒没有写 makefile,.h 和 .cpp 文件之间互相依赖太多了,基本改了一个就要全部重新编译,所以直接用脚本,每次重新全部编译。 + +```bash +./build.sh +``` + +没有使用系统调用,在 Windows 上编译也可以直接编译通过,也是同样的编译命令。 + +## 正确性 + +在给定的示例编码文件中,最终编码文件 result.cnf 在 appmc 和 projMC 的计算中,都为 36288,和给定的目标完全一致。 + +projMC 的程序好像是有数组越界的 BUG,需要稍微把 p cnf 中的变量数量改的比实际变量的范围和数量要大一点才不会报错,appmc 没有问题。 + +``` +> approxmc --epsilon 0.05 result.cnf +c Total time (this thread) : 0.67 +c [appmc+arjun] Total time: 0.67 +c [appmc] Number of solutions is: 4536*2**3 +s SATISFIABLE +s mc 36288 + +> ./binary/projMC_linux -fpv=name_nbvar.var result.cnf +c Projected Model Counter Information +c Number of recursive calls: 16 +c Number of decomposable AND nodes: 17 +c Number of UNSAT subproblems: 3 +c Number of positive hits: 2 +c +c Final time: 0.015772 +c +s 36288 +``` + +## 编码思路 + +对于基本可选特征值和特征族的编码,可以用传统方式直接编码,最麻烦的一个部分是约束条件的形式是一个没有任何特殊性质的数理逻辑表达式(&、|、~、=>、<=>、()、!),并且可以任意组合,因此需要构造一个通用的语法分析器。 + +### 语法分析 + +使用 LR(1)/LALR(1) 文法自动机对每个约束语句进行语法分析,按照数理逻辑的符号优先级定义规约顺序,并且规则设定为左结合优先,使二义性文法符合 LR(1) 文法,利用文法构造器,去生成语法分析代码框架。 + +### 语法制导 + +按照自底向上的语法制导方法,每次依次合并两个变量或者取反,用新的变量等价代替它,然后将新的变量压入栈中,这样会有状态数过多的问题。 + +实际上连续的析取和合取子句,只需要一个等价的变量去代替就可以了,因此构建一个新的类代表若干个子句的析取或合取式子,重载该类的所有操作,遇到必须合并的时候再整体等价为一个变量操作。 diff --git a/binary/projMC_linux b/binary/projMC_linux new file mode 100644 index 0000000..9fe22b7 Binary files /dev/null and b/binary/projMC_linux differ diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..74e4e2c --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +#!/bin/bash +g++ src/CalculatorParser.cpp src/Main.cpp src/Allocate.cpp src/CNF.cpp -O3 -std=c++17 -o encoder \ No newline at end of file diff --git a/data/是否必选特征族.csv b/data/是否必选特征族.csv new file mode 100644 index 0000000..060bc46 --- /dev/null +++ b/data/是否必选特征族.csv @@ -0,0 +1,238 @@ +序号,销售车型编码,特征族编码,是否必选 +1,TEST01,A8088382906,是 +2,TEST01,A8088382908,是 +3,TEST01,A8088382909,是 +4,TEST01,A8088382910,是 +5,TEST01,A8088382912,是 +6,TEST01,A8088382915,是 +7,TEST01,A8088382919,是 +8,TEST01,A8088382920,是 +9,TEST01,A8088382923,是 +10,TEST01,A8088382928,是 +11,TEST01,A8088382930,是 +12,TEST01,A8088382933,是 +13,TEST01,A8088382934,是 +14,TEST01,A8088382936,是 +15,TEST01,A8088382939,是 +16,TEST01,A8088382940,是 +17,TEST01,A8088382942,是 +18,TEST01,A8088382945,是 +19,TEST01,A8088382947,是 +20,TEST01,A8088382948,是 +21,TEST01,A8088382949,是 +22,TEST01,A8088382953,是 +23,TEST01,A8088382954,是 +24,TEST01,A8088382955,是 +25,TEST01,A8088382956,是 +26,TEST01,A8088382959,是 +27,TEST01,A8088382960,是 +28,TEST01,A8088382961,是 +29,TEST01,A8088382971,是 +30,TEST01,A8088382972,是 +31,TEST01,A8088382974,是 +32,TEST01,A8088382977,是 +33,TEST01,A8088382982,是 +34,TEST01,A8088382984,是 +35,TEST01,A8088382986,是 +36,TEST01,A8088382987,是 +37,TEST01,A8088382988,是 +38,TEST01,A8088382989,是 +39,TEST01,A8088382991,是 +40,TEST01,A8088382992,是 +41,TEST01,A8088382993,是 +42,TEST01,A8088382994,是 +43,TEST01,A8088382996,是 +44,TEST01,A8088382997,是 +45,TEST01,A8088383002,是 +46,TEST01,A8088383005,是 +47,TEST01,A8088383009,是 +48,TEST01,A8088383010,是 +49,TEST01,A8088383011,是 +50,TEST01,A8088383012,是 +51,TEST01,A8088383014,是 +52,TEST01,A8088383018,是 +53,TEST01,A8088383019,是 +54,TEST01,A8088383020,是 +55,TEST01,A8088383021,是 +56,TEST01,A8088383022,是 +57,TEST01,A8088383024,是 +58,TEST01,A8088383029,是 +59,TEST01,A8088383030,是 +60,TEST01,A8088383034,是 +61,TEST01,A8088383036,是 +62,TEST01,A8088383037,是 +63,TEST01,A8088383039,是 +64,TEST01,A8088383040,是 +65,TEST01,A8088383042,是 +66,TEST01,A8088383043,是 +67,TEST01,A8088383046,是 +68,TEST01,A8088383047,是 +69,TEST01,A8088383048,是 +70,TEST01,A8088383049,是 +71,TEST01,A8088383050,是 +72,TEST01,A8088383051,是 +73,TEST01,A8088383054,是 +74,TEST01,A8088383057,是 +75,TEST01,A8088383059,是 +76,TEST01,A8088383064,是 +77,TEST01,A8088383067,是 +78,TEST01,A8088383068,是 +79,TEST01,A8088383070,是 +80,TEST01,A8088383071,是 +81,TEST01,A8088383072,是 +82,TEST01,A8088383073,是 +83,TEST01,A8088383075,是 +84,TEST01,A8088383083,是 +85,TEST01,A8088383084,是 +86,TEST01,A8088383085_AP-1,是 +87,TEST01,A8088383085_AP-2,是 +88,TEST01,A8088383085_AP-3,是 +89,TEST01,A8088383086,是 +90,TEST01,A8088383089,是 +91,TEST01,A8088383090,是 +92,TEST01,A8088383091,是 +93,TEST01,A8088383092,是 +94,TEST01,A8088383093,是 +95,TEST01,A8088383094,是 +96,TEST01,A8088383096,是 +97,TEST01,A8088383099,是 +98,TEST01,A8088383105,是 +99,TEST01,A8088383107,是 +100,TEST01,A8088383108,是 +101,TEST01,A8088383109,是 +102,TEST01,A8088383118,是 +103,TEST01,A8088383120,是 +104,TEST01,A8088383122,是 +105,TEST01,A8088383130,是 +106,TEST01,A8088383133,是 +107,TEST01,A8088383139,是 +108,TEST01,A8088383143,是 +109,TEST01,A8088383144,是 +110,TEST01,A8088383145,是 +111,TEST01,A8088383146,是 +112,TEST01,A8088383149,是 +113,TEST01,A8088383150,是 +114,TEST01,A8088383151,是 +115,TEST01,A8088383152,是 +116,TEST01,A8088383153,是 +117,TEST01,A8088383154,是 +118,TEST01,A8088383155,是 +119,TEST01,A8088383159,是 +120,TEST01,A8088383160,是 +121,TEST01,A8088383163,是 +122,TEST01,A8088383165,是 +123,TEST01,A8088383169,是 +124,TEST01,A8088383170,是 +125,TEST01,A8088383176,是 +126,TEST01,A8088383181,是 +127,TEST01,A8088383182,是 +128,TEST01,A8088383183,是 +129,TEST01,A8088383184,是 +130,TEST01,A8088383185,是 +131,TEST01,A8088383189,是 +132,TEST01,A8088383190,是 +133,TEST01,A8088383191,是 +134,TEST01,A8088389461,是 +135,TEST01,A8129009430,是 +136,TEST01,A8130212104,是 +137,TEST01,A8130218285,是 +138,TEST01,A8132534722,是 +139,TEST01,A8132565715,是 +140,TEST01,A8133696776,是 +141,TEST01,A8133703916,是 +142,TEST01,A8133728830,是 +143,TEST01,A8134836166,是 +144,TEST01,A8134856799,是 +145,TEST01,A8147586459,是 +146,TEST01,A8150106844,是 +147,TEST01,A8218592989,是 +148,TEST01,A8235299888,是 +149,TEST01,A8236984717,是 +150,TEST01,A8238806396,是 +151,TEST01,A8238822364,是 +152,TEST01,A8240441229,是 +153,TEST01,A8242038029,是 +154,TEST01,A8245325114,是 +155,TEST01,A8247709306,是 +156,TEST01,A8247710572,是 +157,TEST01,A8247710818,是 +158,TEST01,A8249270116,是 +159,TEST01,A8249270719,是 +160,TEST01,A8249270825,是 +161,TEST01,A8249271073,是 +162,TEST01,A8276674900,是 +163,TEST01,A8387261123,是 +164,TEST01,A8405143036,是 +165,TEST01,A8408490681,是 +166,TEST01,A8408492609,是 +167,TEST01,A8486081323,是 +168,TEST01,A8565145791,是 +169,TEST01,A8565155034,是 +170,TEST01,A8583136039,是 +171,TEST01,A8583148769,是 +172,TEST01,A8583224847,是 +173,TEST01,A8688949972,是 +174,TEST01,A8770692605,是 +175,TEST01,A8770692765,是 +176,TEST01,A8833045633,是 +177,TEST01,MB_2FT,是 +178,TEST01,MB_CK,是 +179,TEST01,MB_CMF,是 +180,TEST01,MB_DO,是 +181,TEST01,MB_EF,是 +182,TEST01,MB_FW,是 +183,TEST01,MB_TR,是 +184,TEST01,A8088382964,否 +185,TEST01,A8088382995,否 +186,TEST01,A8088383001,否 +187,TEST01,A8088383027,否 +188,TEST01,A8088383062,否 +189,TEST01,A8088383066,否 +190,TEST01,A8088383079,否 +191,TEST01,A8088383085_AP-R,否 +192,TEST01,A8088383087,否 +193,TEST01,A8088383095,否 +194,TEST01,A8088383097,否 +195,TEST01,A8088383104,否 +196,TEST01,A8088383106,否 +197,TEST01,A8088383129,否 +198,TEST01,A8088383134,否 +199,TEST01,A8088383142,否 +200,TEST01,A8088383158,否 +201,TEST01,A8088383161,否 +202,TEST01,A8088383171,否 +203,TEST01,A8132543233,否 +204,TEST01,A8132543303,否 +205,TEST01,A8132543712,否 +206,TEST01,A8133704162,否 +207,TEST01,A8133718802,否 +208,TEST01,A8134840666,否 +209,TEST01,A8134896521,否 +210,TEST01,A8134902324,否 +211,TEST01,A8218505828,否 +212,TEST01,A8218621069,否 +213,TEST01,A8219533203,否 +214,TEST01,A8219534112,否 +215,TEST01,A8219554553,否 +216,TEST01,A8223795058,否 +217,TEST01,A8236984887,否 +218,TEST01,A8238604496,否 +219,TEST01,A8238849646,否 +220,TEST01,A8238851748,否 +221,TEST01,A8238871437,否 +222,TEST01,A8303611888,否 +223,TEST01,A8405138477,否 +224,TEST01,A8469783998,否 +225,TEST01,A8620459012,否 +226,TEST01,A8633749842,否 +227,TEST01,A8695503860,否 +228,TEST01,A8718209024,否 +229,TEST01,A8741776772,否 +230,TEST01,A8827994616,否 +231,TEST01,MB_EX,否 +232,TEST01,MB_LW,否 +233,TEST01,MB_MT,否 +234,TEST01,MB_RS,否 +235,TEST01,MB_SM,否 +236,TEST01,MB_SW,否 +237,TEST01,MB_WT,否 diff --git a/data/是否必选特征族.xls b/data/是否必选特征族.xls new file mode 100644 index 0000000..42eab97 Binary files /dev/null and b/data/是否必选特征族.xls differ diff --git a/data/销售配置表.csv b/data/销售配置表.csv new file mode 100644 index 0000000..ecac792 --- /dev/null +++ b/data/销售配置表.csv @@ -0,0 +1,318 @@ +序号,特征族编码,特征徝编码,TEST01,,,符合条件数量36288,参与穷举特征族 +1,A8088382906,F2H,S,,,,A8134836166 +2,A8088382908,D0S,S,,,,A8387261123 +3,A8088382909,D8L,S,,,,A8238851748 +4,A8088382910,M8Y,S,,,,A8088382936 +5,A8088382912,X3H,S,,,,A8633749842 +6,A8088382915,K0W,S,,,,A8088383105 +7,A8088382919,S1L,S,,,,A8088383027 +8,A8088382920,F5Y,S,,,,A8088383104 +9,A8088382923,M5D,S,,,,A8088382933 +10,A8088382928,Z4P,S,,,,A8088383153 +11,A8088382930,I6X,S,,,,A8219534112 +12,A8088382933,J5R,S,,,,A8088383154 +13,A8088382934,W2U,S,,,,A8129009430 +14,A8088382936,D4T,S,,,,A8695503860 +15,A8088382939,A1G,S,,,,A8238604496 +16,A8088382940,S8C,S,,,,A8088383085_AP-R +17,A8088382942,K0T,S,,,,A8132543303 +18,A8088382945,R1Q,S,,,,A8088382964 +19,A8088382945,R7S,O,,,,A8088383142 +20,A8088382947,U1S,S,,,,A8088383185 +21,A8088382948,Q0R,-,,,,A8088383064 +22,A8088382948,Q4K,S,,,,A8219554553 +23,A8088382949,D3F,S,,,,A8088383062 +24,A8088382953,Q5J,-,,,,A8134896521 +25,A8088382953,Q5U,S,,,,A8088383146 +26,A8088382954,M6M,S,,,,A8088383068 +27,A8088382955,C6K,S,,,,A8088383189 +28,A8088382956,Q1K,S,,,,A8088383067 +29,A8088382959,E1K,O,,,,A8088383143 +30,A8088382959,E1L,S,,,,A8088383066 +31,A8088382960,S5Z,S,,,,A8088382915 +32,A8088382961,S1D,S,,,,A8088382959 +33,A8088382964,D4Y,S,,,,A8827994616 +34,A8088382964,D4Z,O,,,,A8088383085_AP-1 +35,A8088382971,F4Y,S,,,,A8088383085_AP-2 +36,A8088382972,C6C,S,,,,A8088383085_AP-3 +37,A8088382974,H8X,S,,,,A8088382995 +38,A8088382977,Z5X,S,,,,A8088383005 +39,A8088382982,D6F,S,,,,A8088383049 +40,A8088382982,D6G,O,,,,A8088382994 +41,A8088382984,J1V,S,,,,A8132543712 +42,A8088382986,Y4Z,S,,,,A8620459012 +43,A8088382987,F4I,S,,,,A8132543233 +44,A8088382988,G1W,-,,,,A8088382997 +45,A8088382988,G1X,-,,,,A8088382953 +46,A8088382988,G2B,-,,,,A8088383129 +47,A8088382988,G2E,S,,,,A8088383097 +48,A8088382989,I1W,S,,,,A8088383095 +49,A8088382989,I2F,O,,,,A8132534722 +50,A8088382991,F2A,S,,,,A8088383134 +51,A8088382992,G5A,S,,,,A8150106844 +52,A8088382993,K3M,S,,,,A8088383176 +53,A8088382994,D1N,S,,,,A8088383094 +54,A8088382994,D2D,O,,,,A8088383171 +55,A8088382995,D6I,-,,,,A8088383050 +56,A8088382996,F2W,S,,,,A8088382948 +57,A8088382997,K2R,S,,,,A8088382908 +58,A8088382997,K8M,-,,,,A8088382909 +59,A8088382997,K8T,-,,,,A8303611888 +60,A8088383001,S8B,O,,,,A8133718802 +61,A8088383002,B1F,S,,,,A8088382982 +62,A8088383005,I1V,S,,,,A8134902324 +63,A8088383005,I2E,O,,,,A8088383158 +64,A8088383009,B4L,-,,,,A8218592989 +65,A8088383009,B4M,S,,,,A8088382945 +66,A8088383010,S1H,S,,,,A8088382989 +67,A8088383011,C8B,S,,,,A8223795058 +68,A8088383012,M4A,-,,,,A8088382986 +69,A8088383012,M4B,-,,,,A8088383087 +70,A8088383012,Z5E,S,,,,A8133703916 +71,A8088383014,M7I,S,,,,A8088383084 +72,A8088383018,F1R,S,,,,A8405138477 +73,A8088383019,IZY,S,,,,A8238806396 +74,A8088383020,E0P,S,,,,A8218621069 +75,A8088383021,O0A,S,,,,A8088383089 +76,A8088383022,O1X,S,,,,A8088383165 +77,A8088383024,C5P,S,,,,A8088383083 +78,A8088383027,U2I,O,,,, +79,A8088383029,G5G,S,,,, +80,A8088383030,F1I,S,,,, +81,A8088383034,U1W,S,,,, +82,A8088383036,F0X,S,,,, +83,A8088383037,Q6Z,S,,,, +84,A8088383039,F2P,S,,,, +85,A8088383040,F7A,S,,,, +86,A8088383042,O1Y,S,,,, +87,A8088383043,A5D,O,,,, +88,A8088383043,A6Y,S,,,, +89,A8088383046,I4I,S,,,, +90,A8088383047,D2Y,S,,,, +91,A8088383048,I6N,S,,,, +92,A8088383049,F3B,S,,,, +93,A8088383049,F3C,O,,,, +94,A8088383050,B1B,O,,,, +95,A8088383050,B1U,S,,,, +96,A8088383051,F6C,S,,,, +97,A8088383054,C7F,S,,,, +98,A8088383057,B2A,S,,,, +99,A8088383059,C1N,S,,,, +100,A8088383062,D6M,-,,,, +101,A8088383064,J2I,S,,,, +102,A8088383064,J2K,O,,,, +103,A8088383066,Q0A,O,,,, +104,A8088383067,Q0W,S,,,, +105,A8088383068,S1P,S,,,, +106,A8088383068,S1W,O,,,, +107,A8088383070,A1Z,S,,,, +108,A8088383071,I6K,S,,,, +109,A8088383072,J3V,S,,,, +110,A8088383073,B5I,S,,,, +111,A8088383075,E3L,S,,,, +112,A8088383079,B3J,-,,,, +113,A8088383083,Q6D,S,,,, +114,A8088383084,F3W,S,,,, +115,A8088383084,F3Y,O,,,, +116,A8088383085_AP-1,F38MEA 0C,O,,,, +117,A8088383085_AP-1,F58L96 81,-,,,, +118,A8088383085_AP-1,F58LFA 0C,-,,,, +119,A8088383085_AP-1,F58MEA 0C,-,,,, +120,A8088383085_AP-1,V18MEA 0C,S,,,, +121,A8088383085_AP-2,AP-2 F38MFA 0C,O,,,, +122,A8088383085_AP-2,AP-2 F58L96 81,-,,,, +123,A8088383085_AP-2,AP-2 F58L98 81,-,,,, +124,A8088383085_AP-2,AP-2 V18MFA 0C,S,,,, +125,A8088383085_AP-3,AP-3 F38MFA 0C,O,,,, +126,A8088383085_AP-3,AP-3 F58L96 81,-,,,, +127,A8088383085_AP-3,AP-3 F58L98 81,-,,,, +128,A8088383085_AP-3,AP-3 V18MFA 0C,S,,,, +129,A8088383085_AP-R,AP-B F38MEA 0C,O,,,, +130,A8088383085_AP-R,AP-B F38MFA 0C,-,,,, +131,A8088383085_AP-R,AP-B F58L96 81,-,,,, +132,A8088383085_AP-R,AP-B F58L98 81,-,,,, +133,A8088383085_AP-R,AP-B F58LFA 0C,-,,,, +134,A8088383085_AP-R,AP-B F58MEA 0C,-,,,, +135,A8088383085_AP-R,AP-B V18MEA 0C,O,,,, +136,A8088383085_AP-R,AP-B V18MFA 0C,-,,,, +137,A8088383086,C6I,S,,,, +138,A8088383087,D7J,O,,,, +139,A8088383089,Q4X,S,,,, +140,A8088383090,M5C,S,,,, +141,A8088383091,D3C,S,,,, +142,A8088383092,C5B,S,,,, +143,A8088383093,F7T,S,,,, +144,A8088383094,K4X,S,,,, +145,A8088383094,K8K,-,,,, +146,A8088383094,K8L,-,,,, +147,A8088383094,K8N,-,,,, +148,A8088383095,D7A,-,,,, +149,A8088383096,F7X,S,,,, +150,A8088383097,F5L,O,,,, +151,A8088383099,K5Q,S,,,, +152,A8088383104,L1H,O,,,, +153,A8088383105,J1H,S,,,, +154,A8088383106,M0E,-,,,, +155,A8088383107,B1G,S,,,, +156,A8088383108,M8B,S,,,, +157,A8088383109,Z2H,S,,,, +158,A8088383118,I6D,S,,,, +159,A8088383120,E6I,S,,,, +160,A8088383122,M7T,S,,,, +161,A8088383129,R8P,O,,,, +162,A8088383130,E1N,S,,,, +163,A8088383133,A2U,S,,,, +164,A8088383134,R8F,O,,,, +165,A8088383139,F8E,S,,,, +166,A8088383142,Y1X,O,,,, +167,A8088383143,Y4A,S,,,, +168,A8088383144,I5F,S,,,, +169,A8088383145,L3A,S,,,, +170,A8088383146,D1E,S,,,, +171,A8088383146,D1R,O,,,, +172,A8088383146,D2E,O,,,, +173,A8088383149,L1B,S,,,, +174,A8088383150,F7C,S,,,, +175,A8088383151,Z4M,-,,,, +176,A8088383151,Z5I,S,,,, +177,A8088383152,K7N,S,,,, +178,A8088383153,F5B,S,,,, +179,A8088383154,E7F,S,,,, +180,A8088383155,X2T,S,,,, +181,A8088383158,E0D,O,,,, +182,A8088383159,IZS,S,,,, +183,A8088383160,Z5Q,S,,,, +184,A8088383161,C8H,S,,,, +185,A8088383163,C5D,S,,,, +186,A8088383165,H1J,S,,,, +187,A8088383169,C6Q,S,,,, +188,A8088383170,Z5Y,S,,,, +189,A8088383171,Z4R,-,,,, +190,A8088383176,J6A,S,,,, +191,A8088383176,J6C,-,,,, +192,A8088383181,M5V,S,,,, +193,A8088383182,D7R,S,,,, +194,A8088383183,F6I,S,,,, +195,A8088383184,C8I,S,,,, +196,A8088383185,K5M,S,,,, +197,A8088383189,S5A,S,,,, +198,A8088383189,S5E,-,,,, +199,A8088383189,S5M,O,,,, +200,A8088383190,C0A,S,,,, +201,A8088383191,D2V,S,,,, +202,A8088389461,DUP0,S,,,, +203,A8129009430,B5C,S,,,, +204,A8130212104,C8Y,S,,,, +205,A8130218285,D0L,S,,,, +206,A8132534722,D4U,S,,,, +207,A8132543233,D5B,O,,,, +208,A8132543303,D5Z,O,,,, +209,A8132543712,D6C,-,,,, +210,A8132565715,D7G,S,,,, +211,A8133696776,E3Q,S,,,, +212,A8133703916,E5J,S,,,, +213,A8133704162,E5K,-,,,, +214,A8133718802,F0T,O,,,, +215,A8133728830,F4Z,S,,,, +216,A8134836166,F6Q,S,,,, +217,A8134836166,F6R,O,,,, +218,A8134840666,F6T,-,,,, +219,A8134856799,F8B,S,,,, +220,A8134896521,F8W,O,,,, +221,A8134902324,G0L,-,,,, +222,A8134902324,G0T,O,,,, +223,A8147586459,M5F,S,,,, +224,A8150106844,Q0X,S,,,, +225,A8218505828,A9X,-,,,, +226,A8218592989,Q0Y,S,,,, +227,A8218621069,S1I,O,,,, +228,A8219533203,S1R,O,,,, +229,A8219534112,S6G,O,,,, +230,A8219534112,S6H,O,,,, +231,A8219554553,S3A,O,,,, +232,A8223795058,L1G,O,,,, +233,A8235299888,S8E,S,,,, +234,A8236984717,Y4J,S,,,, +235,A8236984887,Y4W,-,,,, +236,A8238604496,D4N,O,,,, +237,A8238806396,E2Y,S,,,, +238,A8238822364,E8A,S,,,, +239,A8238849646,Q3V,-,,,, +240,A8238851748,R0Q,O,,,, +241,A8238871437,V5N,-,,,, +242,A8240441229,S2B,S,,,, +243,A8242038029,Z3H,S,,,, +244,A8245325114,X3D,S,,,, +245,A8245325114,X3E,-,,,, +246,A8247709306,I8R,S,,,, +247,A8247710572,IYY,S,,,, +248,A8247710818,IZG,S,,,, +249,A8249270116,M1U,-,,,, +250,A8249270116,M1V,-,,,, +251,A8249270116,M1W,-,,,, +252,A8249270116,M1X,-,,,, +253,A8249270116,M1Y,-,,,, +254,A8249270116,M3A,-,,,, +255,A8249270116,M3B,-,,,, +256,A8249270116,M3C,-,,,, +257,A8249270116,M3D,-,,,, +258,A8249270116,M3E,S,,,, +259,A8249270719,V2B,S,,,, +260,A8249270825,V1A,S,,,, +261,A8249271073,ZZT,S,,,, +262,A8276674900,O5Q,S,,,, +263,A8303611888,D0A,O,,,, +264,A8387261123,U3W,S,,,, +265,A8405138477,F8V,O,,,, +266,A8405143036,Z3J,S,,,, +267,A8408490681,J8O,S,,,, +268,A8408492609,J8Q,S,,,, +269,A8469783998,Z4J,-,,,, +270,A8486081323,G5L,S,,,, +271,A8565145791,U2G,S,,,, +272,A8565155034,U2S,S,,,, +273,A8583136039,G0K,S,,,, +274,A8583148769,U1E,S,,,, +275,A8583148769,U1F,O,,,, +276,A8583224847,U9Z,S,,,, +277,A8620459012,E3W,-,,,, +278,A8633749842,S1G,-,,,, +279,A8688949972,Z4K,S,,,, +280,A8695503860,S2M,O,,,, +281,A8718209024,M6E,-,,,, +282,A8741776772,C8M,O,,,, +283,A8770692605,I8M,S,,,, +284,A8770692605,I8N,-,,,, +285,A8770692765,I8O,-,,,, +286,A8770692765,I8P,S,,,, +287,A8827994616,F3Z,-,,,, +288,A8833045633,M0C,S,,,, +289,MB_2FT,MB_2FT_A42_B64/62/4,-,,,, +290,MB_2FT,MB_2FT_A64/62,S,,,, +291,MB_2FT,MB_2FT_WT_A64/62,-,,,, +292,MB_2FT,MB_2FT_WT_B64/62,-,,,, +293,MB_CK,MB_CK_C,S,,,, +294,MB_CMF,MB_CMF_C,S,,,, +295,MB_CMF,MB_CMF_T,O,,,, +296,MB_CMF,MB_CMF_TP,O,,,, +297,MB_DO,MB_DO_C,S,,,, +298,MB_DO,MB_DO_T,O,,,, +299,MB_EF,MB_EF_C,S,,,, +300,MB_EF,MB_EF_T_A,O,,,, +301,MB_EF,MB_EF_T_B,-,,,, +302,MB_EX,MB_EX_C,O,,,, +303,MB_EX,MB_EX_ST_A,O,,,, +304,MB_EX,MB_EX_T_A,O,,,, +305,MB_EX,MB_EX_T_B,-,,,, +306,MB_EX,MB_EX_T_B_B1,O,,,, +307,MB_FW,MB_FW_JO_6X4/6X2,S,,,, +308,MB_LW,MB_LW_A/B_B1,O,,,, +309,MB_MT,MB_MT_A/B,O,,,, +310,MB_RS,MB_RS_A/B,O,,,, +311,MB_SM,MB_SM_A/B,-,,,, +312,MB_SW,MB_SW_G70,O,,,, +313,MB_SW,MB_SW_G80,O,,,, +314,MB_TR,MB_TR_G70_6x4,O,,,, +315,MB_TR,MB_TR_G80_6x4,S,,,, +316,MB_WT,MB_WT_A_64/62,-,,,, +317,MB_WT,MB_WT_B_64/62,-,,,, diff --git a/data/销售配置表.xls b/data/销售配置表.xls new file mode 100644 index 0000000..b31bd61 Binary files /dev/null and b/data/销售配置表.xls differ diff --git a/data/销售配置表_约束规则.csv b/data/销售配置表_约束规则.csv new file mode 100644 index 0000000..ce6495c --- /dev/null +++ b/data/销售配置表_约束规则.csv @@ -0,0 +1,138 @@ +序号,规则 +1,M1W=>G1X&Z2H +2,AP-B F58MEA 0C=>R8P +3,G2B=>G5G +4,M3A=>(G2B|G2E) +5,M1X=>(G1X&M4A) +6,AP-B F58LFA 0C=>R8P +7,~(M7I&(D6C)) +8,J5R=>J6A +9,E1N=>Z5E +10,S1I=>(B1B&D2E&S1W&S2M&X3D&(G1W|G1X|G5G)) +11,AP-B V18MEA 0C=>R8P +12,AP-B F38MEA 0C=>R8P +13,E0D=>(E1K&(D6C|Y1X)) +14,Q0Y=>(Q0R|Q4K) +15,~(E5J&(V5N)) +16,K7N=>(Z2H|Z5E) +17,Z5E=>(M3A|M3B|M3C|M3D|M3E) +18,~(D6F&((D6C|D6I|D6M))) +19,M6E=>Z2H&(M5D&M7T&(M3A|M3B|M3C)) +20,Q5U=>(H1J&Q4K&Q4X&Q6D) +21,B3J=>(G1W|G1X) +22,J2K=>(J5R|J6C) +23,AP-B F38MFA 0C=>R8P +24,G5L=>G5G +25,S1P=>B1U +26,Q4X=>(Q5J|Q5U) +27,AP-B F58L98 81=>R8P +28,X3E=>(M4A|M4B) +29,U2G=>Z5E +30,I8P=>Z5E +31,D6I=>D6M +32,~(E1L&((D6C|D6M))) +33,J2I=>(J5R|J6C) +34,D6C=>(D6G&E0D&E1K) +35,M3C=>G2E +36,Q0W=>(Q5J|Q5U) +37,M1Y=>(G1X&M4A) +38,Y1X=>D7J +39,K2R=>Z4K +40,Q5J=>(H1J&Q0R&Q4X&Q6D) +41,Q6D=>(Q5J|Q5U) +42,S1W=>B1B +43,M6M=>(M5D&Z5E) +44,M7T=>Z5E +45,G5G=>(G2B|G2E) +46,Z4K=>(K2R|K4X|K8M) +47,H1J=>(Q5J|Q5U) +48,K8N=>(K0W&K8T&Z4R&Z5E) +49,~(G1X&(G5G)) +50,S6H=>B1B +51,L1G=>Z5E +52,J1H=>J6A +53,~(G1W&(G5G)) +54,M0E=>((M3C&(B3J|G2E))|((M3A|M3B)&(B3J|G2B|G2E))) +55,R8P=>R8F +56,M3B=>(G1X|G2E) +57,D6M=>(D6G&D6I&D7A&E1K) +58,U3W=>J6A&Z2H +59,S2M=>(B1B&S1W) +60,I8M=>Z5E +61,K8T=>(Z4R&((K8L&(M4A|M4B))|(K8N&Z5E))) +62,Q4K=>Q5U +63,K8L=>(K0W&K8T&Z4R&(M4A|M4B)) +64,R8F=>R8P +65,Z5Q=>(G2B|G2E) +66,K8M=>Z4K +67,S5M=>S1W +68,U2S=>U2G +69,Z5I=>Z5E +70,AP-B F58L96 81=>R8P +71,S3A=>(D0A&D2E&X3D) +72,I8N=>Z5E +73,M3E=>G2E +74,G0L=>(G1W|G1X) +75,S1G=>(B1B&S1W&S2M&(G1W|G1X)) +76,M3D=>G2E +77,M5V=>(M5D&Z5E) +78,M4A=>(M1W|M1X|M1Y) +79,G0K=>(Z5E&((B3J&(G1W|G1X))|(G5G&(B3J|G2B|G2E)))) +80,M1V=>(G1W&M4B) +81,Y4Z=>D0S +82,Q0R=>Q5J +83,S1R=>(B1B&S1W&S2M&Z5E) +84,K4X=>(K2R&Z5E)&(K0W&Z4K) +85,X3D=>Z5E +86,M1U=>(G1W&M4B) +87,M4B=>(M1U|M1V) +88,M5D=>Z5E +89,K0W=>(K4X|K8K|K8L|K8N) +90,AP-B V18MFA 0C=>R8P +91,I8O=>Z5E +92,K8K=>(K0W&K2R&Z4R&(M4A|M4B)) +93,S6G=>B1B +94,G2E=>G5G +95,MB_CMF_T=>D4T&D4U&D8L&E2Y&D0A&D4N&D5B&D5Z&D6G&D7J&F3C +96,MB_CMF_TP=>D4T&D4U&D8L&E2Y&D0A&D4N&D5B&D5Z&D6G&D7J&F3C&D2D&D4Z&E0D&E1K&Y1X +97,MB_DO_C=>B5C&D0S&E5J&K5M&Y4A&Y4Z&E7F +98,MB_DO_T=>B5C&D0S&E5J&K5M&Y4A&Y4Z&E7F&F3Y +99,MB_EF_C=>F5B +100,MB_EF_T_A=>G0T +101,MB_EF_T_B=>G0L +102,MB_EX_C=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I +103,MB_EX_ST_A=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I&F8V&F8W&L1H&S1I&L1G&S3A +104,MB_EX_T_A=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I&F8V&F8W&L1H&S1I +105,MB_EX_T_B=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I&F8V&F8W&L1H&S1G +106,MB_EX_T_B_B1=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I&F8V&F8W&L1H +107,MB_FW_JO_6X4/6X2=>Q5U&Q4K&Q6D&Q0W&Q0X&Q0Y&Q4X&H1J +108,MB_LW_A/B_B1=>Q0A&R7S +109,MB_MT_A/B=>L1H +110,MB_RS_A/B=>F0T&F5L&F6R +111,MB_SM_A/B=>D6C&D7A&E0D&E1K&D2E&D6G +112,MB_SW_G70=>R8F&R8P&AP-B F38MEA 0C +113,MB_SW_G80=>R8F&R8P&AP-B V18MEA 0C +114,MB_TR_G70_6x4=>I2E&I2F&F38MEA 0C&AP-2 F38MFA 0C&AP-3 F38MFA 0C +115,MB_TR_G80_6x4=>AP-2 V18MFA 0C&V18MEA 0C&I1V&I1W&AP-3 V18MFA 0C +116,MB_WT_A_64/62=>D6G&D6I&D6M&D7A&E1K&E3W&K8T&K8N&F3Z +117,MB_WT_B_64/62=>D6G&D6I&D6M&D7A&E1K&E3W&K8T&F3Z&K8L +118,MB_2FT_WT_A64/62=>K0W&K8T&K8N&Z4R +119,MB_2FT_WT_B64/62=>K0W&K8T&Z4R&K8L +120,MB_CK_C=>J6A&J1H&J5R&J2I&U3W +121,MB_2FT_A42_B64/62/4=>K0W&K8K&Z4R +122,MB_2FT_A64/62=>K0W&K4X +123,MB_CMF_C=>D4T&D4U&D8L&E2Y +124,MB_SW_G80=>MB_TR_G80_6x4 +125,MB_SW_G70=>MB_TR_G70_6x4 +126,(MB_DO_C|MB_DO_T)=>M7I +127,M1X|M3A=>!(B3J|A5D) +128,U1F<=>S1W +129,C8M&I2E&I2F=>MB_LW_A/B_B1 +130,MB_CMF_T|MB_CMF_TP=>D2E +131,M7I=>!MB_SM_A/B +132,G0T=>((G2B|G2E)&G5G)|((G1W|G1X)&B3J)&Z5E +133,MB_EX_ST_A=>S1R +134,MB_MT_A/B&X3E=>A5D&B3J +135,MB_EX_T_A|MB_EX_ST_A|MB_EX_T_B=>MB_CMF_TP|MB_CMF_T|MB_SM_A/B +136,MB_EX_T_A|MB_EX_ST_A=>MB_CMF_TP|MB_CMF_T|MB_SM_A/B +137,MB_MT_A/B&X3D=>A5D \ No newline at end of file diff --git a/data/销售配置表_约束规则.xls b/data/销售配置表_约束规则.xls new file mode 100644 index 0000000..30ae677 Binary files /dev/null and b/data/销售配置表_约束规则.xls differ diff --git a/encoder b/encoder new file mode 100644 index 0000000..f81dfe9 Binary files /dev/null and b/encoder differ diff --git a/name_nbvar.var b/name_nbvar.var new file mode 100644 index 0000000..9c3bace --- /dev/null +++ b/name_nbvar.var @@ -0,0 +1 @@ +1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539 \ No newline at end of file diff --git a/result.cnf b/result.cnf new file mode 100644 index 0000000..f61fc39 --- /dev/null +++ b/result.cnf @@ -0,0 +1,2089 @@ +c ind 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 0 +p cnf 600 1413 +c MAP: Q0R -> 1 +-1 0 +c MAP: Q5J -> 2 +-2 0 +c MAP: G1W -> 3 +-3 0 +c MAP: G1X -> 4 +-4 0 +c MAP: G2B -> 5 +-5 0 +c MAP: D6I -> 6 +-6 0 +c MAP: K8M -> 7 +-7 0 +c MAP: K8T -> 8 +-8 0 +c MAP: B4L -> 9 +-9 0 +c MAP: M4A -> 10 +-10 0 +c MAP: M4B -> 11 +-11 0 +c MAP: D6M -> 12 +-12 0 +c MAP: B3J -> 13 +-13 0 +c MAP: F58L96 81 -> 14 +-14 0 +c MAP: F58LFA 0C -> 15 +-15 0 +c MAP: F58MEA 0C -> 16 +-16 0 +c MAP: AP-2 F58L96 81 -> 17 +-17 0 +c MAP: AP-2 F58L98 81 -> 18 +-18 0 +c MAP: AP-3 F58L96 81 -> 19 +-19 0 +c MAP: AP-3 F58L98 81 -> 20 +-20 0 +c MAP: AP-B F38MFA 0C -> 21 +-21 0 +c MAP: AP-B F58L96 81 -> 22 +-22 0 +c MAP: AP-B F58L98 81 -> 23 +-23 0 +c MAP: AP-B F58LFA 0C -> 24 +-24 0 +c MAP: AP-B F58MEA 0C -> 25 +-25 0 +c MAP: AP-B V18MFA 0C -> 26 +-26 0 +c MAP: K8K -> 27 +-27 0 +c MAP: K8L -> 28 +-28 0 +c MAP: K8N -> 29 +-29 0 +c MAP: D7A -> 30 +-30 0 +c MAP: M0E -> 31 +-31 0 +c MAP: Z4M -> 32 +-32 0 +c MAP: Z4R -> 33 +-33 0 +c MAP: J6C -> 34 +-34 0 +c MAP: S5E -> 35 +-35 0 +c MAP: D6C -> 36 +-36 0 +c MAP: E5K -> 37 +-37 0 +c MAP: F6T -> 38 +-38 0 +c MAP: G0L -> 39 +-39 0 +c MAP: A9X -> 40 +-40 0 +c MAP: Y4W -> 41 +-41 0 +c MAP: Q3V -> 42 +-42 0 +c MAP: V5N -> 43 +-43 0 +c MAP: X3E -> 44 +-44 0 +c MAP: M1U -> 45 +-45 0 +c MAP: M1V -> 46 +-46 0 +c MAP: M1W -> 47 +-47 0 +c MAP: M1X -> 48 +-48 0 +c MAP: M1Y -> 49 +-49 0 +c MAP: M3A -> 50 +-50 0 +c MAP: M3B -> 51 +-51 0 +c MAP: M3C -> 52 +-52 0 +c MAP: M3D -> 53 +-53 0 +c MAP: Z4J -> 54 +-54 0 +c MAP: E3W -> 55 +-55 0 +c MAP: S1G -> 56 +-56 0 +c MAP: M6E -> 57 +-57 0 +c MAP: I8N -> 58 +-58 0 +c MAP: I8O -> 59 +-59 0 +c MAP: F3Z -> 60 +-60 0 +c MAP: MB_2FT_A42_B64/62/4 -> 61 +-61 0 +c MAP: MB_2FT_WT_A64/62 -> 62 +-62 0 +c MAP: MB_2FT_WT_B64/62 -> 63 +-63 0 +c MAP: MB_EF_T_B -> 64 +-64 0 +c MAP: MB_EX_T_B -> 65 +-65 0 +c MAP: MB_SM_A/B -> 66 +-66 0 +c MAP: MB_WT_A_64/62 -> 67 +-67 0 +c MAP: MB_WT_B_64/62 -> 68 +-68 0 +c MAP: F2H -> 69 +69 0 +c MAP: D0S -> 70 +70 0 +c MAP: D8L -> 71 +71 0 +c MAP: M8Y -> 72 +72 0 +c MAP: X3H -> 73 +73 0 +c MAP: K0W -> 74 +74 0 +c MAP: S1L -> 75 +75 0 +c MAP: F5Y -> 76 +76 0 +c MAP: M5D -> 77 +77 0 +c MAP: Z4P -> 78 +78 0 +c MAP: I6X -> 79 +79 0 +c MAP: J5R -> 80 +80 0 +c MAP: W2U -> 81 +81 0 +c MAP: D4T -> 82 +82 0 +c MAP: A1G -> 83 +83 0 +c MAP: S8C -> 84 +84 0 +c MAP: K0T -> 85 +85 0 +c MAP: R1Q -> 86 +c MAP: R7S -> 87 +86 87 0 +-86 -87 0 +c MAP: U1S -> 88 +88 0 +c MAP: Q4K -> 89 +1 89 0 +-1 -89 0 +c MAP: D3F -> 90 +90 0 +c MAP: Q5U -> 91 +2 91 0 +-2 -91 0 +c MAP: M6M -> 92 +92 0 +c MAP: C6K -> 93 +93 0 +c MAP: Q1K -> 94 +94 0 +c MAP: E1K -> 95 +c MAP: E1L -> 96 +95 96 0 +-95 -96 0 +c MAP: S5Z -> 97 +97 0 +c MAP: S1D -> 98 +98 0 +c MAP: D4Y -> 99 +c MAP: D4Z -> 100 +-99 -100 0 +c MAP: F4Y -> 101 +101 0 +c MAP: C6C -> 102 +102 0 +c MAP: H8X -> 103 +103 0 +c MAP: Z5X -> 104 +104 0 +c MAP: D6F -> 105 +c MAP: D6G -> 106 +105 106 0 +-105 -106 0 +c MAP: J1V -> 107 +107 0 +c MAP: Y4Z -> 108 +108 0 +c MAP: F4I -> 109 +109 0 +c MAP: G2E -> 110 +3 4 5 110 0 +-3 -4 0 +-3 -5 0 +-3 -110 0 +-4 -5 0 +-4 -110 0 +-5 -110 0 +c MAP: I1W -> 111 +c MAP: I2F -> 112 +111 112 0 +-111 -112 0 +c MAP: F2A -> 113 +113 0 +c MAP: G5A -> 114 +114 0 +c MAP: K3M -> 115 +115 0 +c MAP: D1N -> 116 +c MAP: D2D -> 117 +116 117 0 +-116 -117 0 +c MAP: F2W -> 118 +118 0 +c MAP: K2R -> 119 +119 7 8 0 +-119 -7 0 +-119 -8 0 +-7 -8 0 +c MAP: B1F -> 120 +120 0 +c MAP: I1V -> 121 +c MAP: I2E -> 122 +121 122 0 +-121 -122 0 +c MAP: B4M -> 123 +9 123 0 +-9 -123 0 +c MAP: S1H -> 124 +124 0 +c MAP: C8B -> 125 +125 0 +c MAP: Z5E -> 126 +10 11 126 0 +-10 -11 0 +-10 -126 0 +-11 -126 0 +c MAP: M7I -> 127 +127 0 +c MAP: F1R -> 128 +128 0 +c MAP: IZY -> 129 +129 0 +c MAP: E0P -> 130 +130 0 +c MAP: O0A -> 131 +131 0 +c MAP: O1X -> 132 +132 0 +c MAP: C5P -> 133 +133 0 +c MAP: G5G -> 134 +134 0 +c MAP: F1I -> 135 +135 0 +c MAP: U1W -> 136 +136 0 +c MAP: F0X -> 137 +137 0 +c MAP: Q6Z -> 138 +138 0 +c MAP: F2P -> 139 +139 0 +c MAP: F7A -> 140 +140 0 +c MAP: O1Y -> 141 +141 0 +c MAP: A5D -> 142 +c MAP: A6Y -> 143 +142 143 0 +-142 -143 0 +c MAP: I4I -> 144 +144 0 +c MAP: D2Y -> 145 +145 0 +c MAP: I6N -> 146 +146 0 +c MAP: F3B -> 147 +c MAP: F3C -> 148 +147 148 0 +-147 -148 0 +c MAP: B1B -> 149 +c MAP: B1U -> 150 +149 150 0 +-149 -150 0 +c MAP: F6C -> 151 +151 0 +c MAP: C7F -> 152 +152 0 +c MAP: B2A -> 153 +153 0 +c MAP: C1N -> 154 +154 0 +c MAP: J2I -> 155 +c MAP: J2K -> 156 +155 156 0 +-155 -156 0 +c MAP: Q0W -> 157 +157 0 +c MAP: S1P -> 158 +c MAP: S1W -> 159 +158 159 0 +-158 -159 0 +c MAP: A1Z -> 160 +160 0 +c MAP: I6K -> 161 +161 0 +c MAP: J3V -> 162 +162 0 +c MAP: B5I -> 163 +163 0 +c MAP: E3L -> 164 +164 0 +c MAP: Q6D -> 165 +165 0 +c MAP: F3W -> 166 +c MAP: F3Y -> 167 +166 167 0 +-166 -167 0 +c MAP: F38MEA 0C -> 168 +c MAP: V18MEA 0C -> 169 +168 14 15 16 169 0 +-168 -14 0 +-168 -15 0 +-168 -16 0 +-168 -169 0 +-14 -15 0 +-14 -16 0 +-14 -169 0 +-15 -16 0 +-15 -169 0 +-16 -169 0 +c MAP: AP-2 F38MFA 0C -> 170 +c MAP: AP-2 V18MFA 0C -> 171 +170 17 18 171 0 +-170 -17 0 +-170 -18 0 +-170 -171 0 +-17 -18 0 +-17 -171 0 +-18 -171 0 +c MAP: AP-3 F38MFA 0C -> 172 +c MAP: AP-3 V18MFA 0C -> 173 +172 19 20 173 0 +-172 -19 0 +-172 -20 0 +-172 -173 0 +-19 -20 0 +-19 -173 0 +-20 -173 0 +c MAP: AP-B F38MEA 0C -> 174 +-174 -21 0 +-174 -22 0 +-174 -23 0 +-174 -24 0 +-174 -25 0 +c MAP: AP-B V18MEA 0C -> 175 +-174 -175 0 +-174 -26 0 +-21 -22 0 +-21 -23 0 +-21 -24 0 +-21 -25 0 +-21 -175 0 +-21 -26 0 +-22 -23 0 +-22 -24 0 +-22 -25 0 +-22 -175 0 +-22 -26 0 +-23 -24 0 +-23 -25 0 +-23 -175 0 +-23 -26 0 +-24 -25 0 +-24 -175 0 +-24 -26 0 +-25 -175 0 +-25 -26 0 +-175 -26 0 +c MAP: C6I -> 176 +176 0 +c MAP: Q4X -> 177 +177 0 +c MAP: M5C -> 178 +178 0 +c MAP: D3C -> 179 +179 0 +c MAP: C5B -> 180 +180 0 +c MAP: F7T -> 181 +181 0 +c MAP: K4X -> 182 +182 27 28 29 0 +-182 -27 0 +-182 -28 0 +-182 -29 0 +-27 -28 0 +-27 -29 0 +-28 -29 0 +c MAP: F7X -> 183 +183 0 +c MAP: K5Q -> 184 +184 0 +c MAP: J1H -> 185 +185 0 +c MAP: B1G -> 186 +186 0 +c MAP: M8B -> 187 +187 0 +c MAP: Z2H -> 188 +188 0 +c MAP: I6D -> 189 +189 0 +c MAP: E6I -> 190 +190 0 +c MAP: M7T -> 191 +191 0 +c MAP: E1N -> 192 +192 0 +c MAP: A2U -> 193 +193 0 +c MAP: F8E -> 194 +194 0 +c MAP: Y4A -> 195 +195 0 +c MAP: I5F -> 196 +196 0 +c MAP: L3A -> 197 +197 0 +c MAP: D1E -> 198 +c MAP: D1R -> 199 +c MAP: D2E -> 200 +198 199 200 0 +-198 -199 0 +-198 -200 0 +-199 -200 0 +c MAP: L1B -> 201 +201 0 +c MAP: F7C -> 202 +202 0 +c MAP: Z5I -> 203 +32 203 0 +-32 -203 0 +c MAP: K7N -> 204 +204 0 +c MAP: F5B -> 205 +205 0 +c MAP: E7F -> 206 +206 0 +c MAP: X2T -> 207 +207 0 +c MAP: IZS -> 208 +208 0 +c MAP: Z5Q -> 209 +209 0 +c MAP: C5D -> 210 +210 0 +c MAP: H1J -> 211 +211 0 +c MAP: C6Q -> 212 +212 0 +c MAP: Z5Y -> 213 +213 0 +c MAP: J6A -> 214 +214 34 0 +-214 -34 0 +c MAP: M5V -> 215 +215 0 +c MAP: D7R -> 216 +216 0 +c MAP: F6I -> 217 +217 0 +c MAP: C8I -> 218 +218 0 +c MAP: K5M -> 219 +219 0 +c MAP: S5A -> 220 +c MAP: S5M -> 221 +220 35 221 0 +-220 -35 0 +-220 -221 0 +-35 -221 0 +c MAP: C0A -> 222 +222 0 +c MAP: D2V -> 223 +223 0 +c MAP: DUP0 -> 224 +224 0 +c MAP: B5C -> 225 +225 0 +c MAP: C8Y -> 226 +226 0 +c MAP: D0L -> 227 +227 0 +c MAP: D4U -> 228 +228 0 +c MAP: D7G -> 229 +229 0 +c MAP: E3Q -> 230 +230 0 +c MAP: E5J -> 231 +231 0 +c MAP: F4Z -> 232 +232 0 +c MAP: F6Q -> 233 +c MAP: F6R -> 234 +233 234 0 +-233 -234 0 +c MAP: F8B -> 235 +235 0 +c MAP: G0T -> 236 +-39 -236 0 +c MAP: M5F -> 237 +237 0 +c MAP: Q0X -> 238 +238 0 +c MAP: Q0Y -> 239 +239 0 +c MAP: S6G -> 240 +c MAP: S6H -> 241 +-240 -241 0 +c MAP: S8E -> 242 +242 0 +c MAP: Y4J -> 243 +243 0 +c MAP: E2Y -> 244 +244 0 +c MAP: E8A -> 245 +245 0 +c MAP: S2B -> 246 +246 0 +c MAP: Z3H -> 247 +247 0 +c MAP: X3D -> 248 +248 44 0 +-248 -44 0 +c MAP: I8R -> 249 +249 0 +c MAP: IYY -> 250 +250 0 +c MAP: IZG -> 251 +251 0 +c MAP: M3E -> 252 +45 46 47 48 49 50 51 52 53 252 0 +-45 -46 0 +-45 -47 0 +-45 -48 0 +-45 -49 0 +-45 -50 0 +-45 -51 0 +-45 -52 0 +-45 -53 0 +-45 -252 0 +-46 -47 0 +-46 -48 0 +-46 -49 0 +-46 -50 0 +-46 -51 0 +-46 -52 0 +-46 -53 0 +-46 -252 0 +-47 -48 0 +-47 -49 0 +-47 -50 0 +-47 -51 0 +-47 -52 0 +-47 -53 0 +-47 -252 0 +-48 -49 0 +-48 -50 0 +-48 -51 0 +-48 -52 0 +-48 -53 0 +-48 -252 0 +-49 -50 0 +-49 -51 0 +-49 -52 0 +-49 -53 0 +-49 -252 0 +-50 -51 0 +-50 -52 0 +-50 -53 0 +-50 -252 0 +-51 -52 0 +-51 -53 0 +-51 -252 0 +-52 -53 0 +-52 -252 0 +-53 -252 0 +c MAP: V2B -> 253 +253 0 +c MAP: V1A -> 254 +254 0 +c MAP: ZZT -> 255 +255 0 +c MAP: O5Q -> 256 +256 0 +c MAP: U3W -> 257 +257 0 +c MAP: Z3J -> 258 +258 0 +c MAP: J8O -> 259 +259 0 +c MAP: J8Q -> 260 +260 0 +c MAP: G5L -> 261 +261 0 +c MAP: U2G -> 262 +262 0 +c MAP: U2S -> 263 +263 0 +c MAP: G0K -> 264 +264 0 +c MAP: U1E -> 265 +c MAP: U1F -> 266 +265 266 0 +-265 -266 0 +c MAP: U9Z -> 267 +267 0 +c MAP: Z4K -> 268 +268 0 +c MAP: I8M -> 269 +269 58 0 +-269 -58 0 +c MAP: I8P -> 270 +59 270 0 +-59 -270 0 +c MAP: M0C -> 271 +271 0 +c MAP: MB_2FT_A64/62 -> 272 +61 272 62 63 0 +-61 -272 0 +-61 -62 0 +-61 -63 0 +-272 -62 0 +-272 -63 0 +-62 -63 0 +c MAP: MB_CK_C -> 273 +273 0 +c MAP: MB_CMF_C -> 274 +c MAP: MB_CMF_T -> 275 +c MAP: MB_CMF_TP -> 276 +274 275 276 0 +-274 -275 0 +-274 -276 0 +-275 -276 0 +c MAP: MB_DO_C -> 277 +c MAP: MB_DO_T -> 278 +277 278 0 +-277 -278 0 +c MAP: MB_EF_C -> 279 +c MAP: MB_EF_T_A -> 280 +279 280 64 0 +-279 -280 0 +-279 -64 0 +-280 -64 0 +c MAP: MB_EX_C -> 281 +c MAP: MB_EX_ST_A -> 282 +-281 -282 0 +c MAP: MB_EX_T_A -> 283 +-281 -283 0 +-281 -65 0 +c MAP: MB_EX_T_B_B1 -> 284 +-281 -284 0 +-282 -283 0 +-282 -65 0 +-282 -284 0 +-283 -65 0 +-283 -284 0 +-65 -284 0 +c MAP: MB_FW_JO_6X4/6X2 -> 285 +285 0 +c MAP: MB_SW_G70 -> 286 +c MAP: MB_SW_G80 -> 287 +-286 -287 0 +c MAP: MB_TR_G70_6x4 -> 288 +c MAP: MB_TR_G80_6x4 -> 289 +288 289 0 +-288 -289 0 +-67 -68 0 +c analyze: M1W=>G1X&Z2H +c MAP: 4 & 188 -> 290 +290 -4 -188 0 +4 -290 0 +188 -290 0 +c MAP: -47 | 290 -> 291 +-291 -47 290 0 +47 291 0 +-290 291 0 +291 0 +c analyze: AP-B F58MEA 0C=>R8P +c MAP: R8P -> 292 +c MAP: -25 | 292 -> 293 +-293 -25 292 0 +25 293 0 +-292 293 0 +293 0 +c analyze: G2B=>G5G +c MAP: -5 | 134 -> 294 +-294 -5 134 0 +5 294 0 +-134 294 0 +294 0 +c analyze: M3A=>(G2B|G2E) +c MAP: -50 | 5 | 110 -> 295 +-295 -50 5 110 0 +50 295 0 +-5 295 0 +-110 295 0 +295 0 +c analyze: M1X=>(G1X&M4A) +c MAP: 4 & 10 -> 296 +296 -4 -10 0 +4 -296 0 +10 -296 0 +c MAP: -48 | 296 -> 297 +-297 -48 296 0 +48 297 0 +-296 297 0 +297 0 +c analyze: AP-B F58LFA 0C=>R8P +c MAP: -24 | 292 -> 298 +-298 -24 292 0 +24 298 0 +-292 298 0 +298 0 +c analyze: ~(M7I&(D6C)) +c MAP: -127 | -36 -> 299 +-299 -127 -36 0 +127 299 0 +36 299 0 +299 0 +c analyze: J5R=>J6A +c MAP: -80 | 214 -> 300 +-300 -80 214 0 +80 300 0 +-214 300 0 +300 0 +c analyze: E1N=>Z5E +c MAP: -192 | 126 -> 301 +-301 -192 126 0 +192 301 0 +-126 301 0 +301 0 +c analyze: S1I=>(B1B&D2E&S1W&S2M&X3D&(G1W|G1X|G5G)) +c MAP: S1I -> 302 +c MAP: S2M -> 303 +c MAP: 3 | 4 | 134 -> 304 +-304 3 4 134 0 +-3 304 0 +-4 304 0 +-134 304 0 +c MAP: 149 & 200 & 159 & 303 & 248 & 304 -> 305 +305 -149 -200 -159 -303 -248 -304 0 +149 -305 0 +200 -305 0 +159 -305 0 +303 -305 0 +248 -305 0 +304 -305 0 +c MAP: -302 | 305 -> 306 +-306 -302 305 0 +302 306 0 +-305 306 0 +306 0 +c analyze: AP-B V18MEA 0C=>R8P +c MAP: -175 | 292 -> 307 +-307 -175 292 0 +175 307 0 +-292 307 0 +307 0 +c analyze: AP-B F38MEA 0C=>R8P +c MAP: -174 | 292 -> 308 +-308 -174 292 0 +174 308 0 +-292 308 0 +308 0 +c analyze: E0D=>(E1K&(D6C|Y1X)) +c MAP: E0D -> 309 +c MAP: Y1X -> 310 +c MAP: 36 | 310 -> 311 +-311 36 310 0 +-36 311 0 +-310 311 0 +c MAP: 95 & 311 -> 312 +312 -95 -311 0 +95 -312 0 +311 -312 0 +c MAP: -309 | 312 -> 313 +-313 -309 312 0 +309 313 0 +-312 313 0 +313 0 +c analyze: Q0Y=>(Q0R|Q4K) +c MAP: -239 | 1 | 89 -> 314 +-314 -239 1 89 0 +239 314 0 +-1 314 0 +-89 314 0 +314 0 +c analyze: ~(E5J&(V5N)) +c MAP: -231 | -43 -> 315 +-315 -231 -43 0 +231 315 0 +43 315 0 +315 0 +c analyze: K7N=>(Z2H|Z5E) +c MAP: -204 | 188 | 126 -> 316 +-316 -204 188 126 0 +204 316 0 +-188 316 0 +-126 316 0 +316 0 +c analyze: Z5E=>(M3A|M3B|M3C|M3D|M3E) +c MAP: -126 | 50 | 51 | 52 | 53 | 252 -> 317 +-317 -126 50 51 52 53 252 0 +126 317 0 +-50 317 0 +-51 317 0 +-52 317 0 +-53 317 0 +-252 317 0 +317 0 +c analyze: ~(D6F&((D6C|D6I|D6M))) +c MAP: 36 | 6 | 12 -> 318 +-318 36 6 12 0 +-36 318 0 +-6 318 0 +-12 318 0 +c MAP: -105 | -318 -> 319 +-319 -105 -318 0 +105 319 0 +318 319 0 +319 0 +c analyze: M6E=>Z2H&(M5D&M7T&(M3A|M3B|M3C)) +c MAP: 50 | 51 | 52 -> 320 +-320 50 51 52 0 +-50 320 0 +-51 320 0 +-52 320 0 +c MAP: 188 & 77 & 191 & 320 -> 321 +321 -188 -77 -191 -320 0 +188 -321 0 +77 -321 0 +191 -321 0 +320 -321 0 +c MAP: -57 | 321 -> 322 +-322 -57 321 0 +57 322 0 +-321 322 0 +322 0 +c analyze: Q5U=>(H1J&Q4K&Q4X&Q6D) +c MAP: 211 & 89 & 177 & 165 -> 323 +323 -211 -89 -177 -165 0 +211 -323 0 +89 -323 0 +177 -323 0 +165 -323 0 +c MAP: -91 | 323 -> 324 +-324 -91 323 0 +91 324 0 +-323 324 0 +324 0 +c analyze: B3J=>(G1W|G1X) +c MAP: -13 | 3 | 4 -> 325 +-325 -13 3 4 0 +13 325 0 +-3 325 0 +-4 325 0 +325 0 +c analyze: J2K=>(J5R|J6C) +c MAP: -156 | 80 | 34 -> 326 +-326 -156 80 34 0 +156 326 0 +-80 326 0 +-34 326 0 +326 0 +c analyze: AP-B F38MFA 0C=>R8P +c MAP: -21 | 292 -> 327 +-327 -21 292 0 +21 327 0 +-292 327 0 +327 0 +c analyze: G5L=>G5G +c MAP: -261 | 134 -> 328 +-328 -261 134 0 +261 328 0 +-134 328 0 +328 0 +c analyze: S1P=>B1U +c MAP: -158 | 150 -> 329 +-329 -158 150 0 +158 329 0 +-150 329 0 +329 0 +c analyze: Q4X=>(Q5J|Q5U) +c MAP: -177 | 2 | 91 -> 330 +-330 -177 2 91 0 +177 330 0 +-2 330 0 +-91 330 0 +330 0 +c analyze: AP-B F58L98 81=>R8P +c MAP: -23 | 292 -> 331 +-331 -23 292 0 +23 331 0 +-292 331 0 +331 0 +c analyze: X3E=>(M4A|M4B) +c MAP: -44 | 10 | 11 -> 332 +-332 -44 10 11 0 +44 332 0 +-10 332 0 +-11 332 0 +332 0 +c analyze: U2G=>Z5E +c MAP: -262 | 126 -> 333 +-333 -262 126 0 +262 333 0 +-126 333 0 +333 0 +c analyze: I8P=>Z5E +c MAP: -270 | 126 -> 334 +-334 -270 126 0 +270 334 0 +-126 334 0 +334 0 +c analyze: D6I=>D6M +c MAP: -6 | 12 -> 335 +-335 -6 12 0 +6 335 0 +-12 335 0 +335 0 +c analyze: ~(E1L&((D6C|D6M))) +c MAP: 36 | 12 -> 336 +-336 36 12 0 +-36 336 0 +-12 336 0 +c MAP: -96 | -336 -> 337 +-337 -96 -336 0 +96 337 0 +336 337 0 +337 0 +c analyze: J2I=>(J5R|J6C) +c MAP: -155 | 80 | 34 -> 338 +-338 -155 80 34 0 +155 338 0 +-80 338 0 +-34 338 0 +338 0 +c analyze: D6C=>(D6G&E0D&E1K) +c MAP: 106 & 309 & 95 -> 339 +339 -106 -309 -95 0 +106 -339 0 +309 -339 0 +95 -339 0 +c MAP: -36 | 339 -> 340 +-340 -36 339 0 +36 340 0 +-339 340 0 +340 0 +c analyze: M3C=>G2E +c MAP: -52 | 110 -> 341 +-341 -52 110 0 +52 341 0 +-110 341 0 +341 0 +c analyze: Q0W=>(Q5J|Q5U) +c MAP: -157 | 2 | 91 -> 342 +-342 -157 2 91 0 +157 342 0 +-2 342 0 +-91 342 0 +342 0 +c analyze: M1Y=>(G1X&M4A) +c MAP: 4 & 10 -> 343 +343 -4 -10 0 +4 -343 0 +10 -343 0 +c MAP: -49 | 343 -> 344 +-344 -49 343 0 +49 344 0 +-343 344 0 +344 0 +c analyze: Y1X=>D7J +c MAP: D7J -> 345 +c MAP: -310 | 345 -> 346 +-346 -310 345 0 +310 346 0 +-345 346 0 +346 0 +c analyze: K2R=>Z4K +c MAP: -119 | 268 -> 347 +-347 -119 268 0 +119 347 0 +-268 347 0 +347 0 +c analyze: Q5J=>(H1J&Q0R&Q4X&Q6D) +c MAP: 211 & 1 & 177 & 165 -> 348 +348 -211 -1 -177 -165 0 +211 -348 0 +1 -348 0 +177 -348 0 +165 -348 0 +c MAP: -2 | 348 -> 349 +-349 -2 348 0 +2 349 0 +-348 349 0 +349 0 +c analyze: Q6D=>(Q5J|Q5U) +c MAP: -165 | 2 | 91 -> 350 +-350 -165 2 91 0 +165 350 0 +-2 350 0 +-91 350 0 +350 0 +c analyze: S1W=>B1B +c MAP: -159 | 149 -> 351 +-351 -159 149 0 +159 351 0 +-149 351 0 +351 0 +c analyze: M6M=>(M5D&Z5E) +c MAP: 77 & 126 -> 352 +352 -77 -126 0 +77 -352 0 +126 -352 0 +c MAP: -92 | 352 -> 353 +-353 -92 352 0 +92 353 0 +-352 353 0 +353 0 +c analyze: M7T=>Z5E +c MAP: -191 | 126 -> 354 +-354 -191 126 0 +191 354 0 +-126 354 0 +354 0 +c analyze: G5G=>(G2B|G2E) +c MAP: -134 | 5 | 110 -> 355 +-355 -134 5 110 0 +134 355 0 +-5 355 0 +-110 355 0 +355 0 +c analyze: Z4K=>(K2R|K4X|K8M) +c MAP: -268 | 119 | 182 | 7 -> 356 +-356 -268 119 182 7 0 +268 356 0 +-119 356 0 +-182 356 0 +-7 356 0 +356 0 +c analyze: H1J=>(Q5J|Q5U) +c MAP: -211 | 2 | 91 -> 357 +-357 -211 2 91 0 +211 357 0 +-2 357 0 +-91 357 0 +357 0 +c analyze: K8N=>(K0W&K8T&Z4R&Z5E) +c MAP: 74 & 8 & 33 & 126 -> 358 +358 -74 -8 -33 -126 0 +74 -358 0 +8 -358 0 +33 -358 0 +126 -358 0 +c MAP: -29 | 358 -> 359 +-359 -29 358 0 +29 359 0 +-358 359 0 +359 0 +c analyze: ~(G1X&(G5G)) +c MAP: -4 | -134 -> 360 +-360 -4 -134 0 +4 360 0 +134 360 0 +360 0 +c analyze: S6H=>B1B +c MAP: -241 | 149 -> 361 +-361 -241 149 0 +241 361 0 +-149 361 0 +361 0 +c analyze: L1G=>Z5E +c MAP: L1G -> 362 +c MAP: -362 | 126 -> 363 +-363 -362 126 0 +362 363 0 +-126 363 0 +363 0 +c analyze: J1H=>J6A +c MAP: -185 | 214 -> 364 +-364 -185 214 0 +185 364 0 +-214 364 0 +364 0 +c analyze: ~(G1W&(G5G)) +c MAP: -3 | -134 -> 365 +-365 -3 -134 0 +3 365 0 +134 365 0 +365 0 +c analyze: M0E=>((M3C&(B3J|G2E))|((M3A|M3B)&(B3J|G2B|G2E))) +c MAP: 13 | 110 -> 366 +-366 13 110 0 +-13 366 0 +-110 366 0 +c MAP: 50 | 51 -> 367 +-367 50 51 0 +-50 367 0 +-51 367 0 +c MAP: 13 | 5 | 110 -> 368 +-368 13 5 110 0 +-13 368 0 +-5 368 0 +-110 368 0 +c MAP: 52 & 366 -> 369 +369 -52 -366 0 +52 -369 0 +366 -369 0 +c MAP: 367 & 368 -> 370 +370 -367 -368 0 +367 -370 0 +368 -370 0 +c MAP: -31 | 369 | 370 -> 371 +-371 -31 369 370 0 +31 371 0 +-369 371 0 +-370 371 0 +371 0 +c analyze: R8P=>R8F +c MAP: R8F -> 372 +c MAP: -292 | 372 -> 373 +-373 -292 372 0 +292 373 0 +-372 373 0 +373 0 +c analyze: M3B=>(G1X|G2E) +c MAP: -51 | 4 | 110 -> 374 +-374 -51 4 110 0 +51 374 0 +-4 374 0 +-110 374 0 +374 0 +c analyze: D6M=>(D6G&D6I&D7A&E1K) +c MAP: 106 & 6 & 30 & 95 -> 375 +375 -106 -6 -30 -95 0 +106 -375 0 +6 -375 0 +30 -375 0 +95 -375 0 +c MAP: -12 | 375 -> 376 +-376 -12 375 0 +12 376 0 +-375 376 0 +376 0 +c analyze: U3W=>J6A&Z2H +c MAP: 214 & 188 -> 377 +377 -214 -188 0 +214 -377 0 +188 -377 0 +c MAP: -257 | 377 -> 378 +-378 -257 377 0 +257 378 0 +-377 378 0 +378 0 +c analyze: S2M=>(B1B&S1W) +c MAP: 149 & 159 -> 379 +379 -149 -159 0 +149 -379 0 +159 -379 0 +c MAP: -303 | 379 -> 380 +-380 -303 379 0 +303 380 0 +-379 380 0 +380 0 +c analyze: I8M=>Z5E +c MAP: -269 | 126 -> 381 +-381 -269 126 0 +269 381 0 +-126 381 0 +381 0 +c analyze: K8T=>(Z4R&((K8L&(M4A|M4B))|(K8N&Z5E))) +c MAP: 10 | 11 -> 382 +-382 10 11 0 +-10 382 0 +-11 382 0 +c MAP: 28 & 382 -> 383 +383 -28 -382 0 +28 -383 0 +382 -383 0 +c MAP: 29 & 126 -> 384 +384 -29 -126 0 +29 -384 0 +126 -384 0 +c MAP: 383 | 384 -> 385 +-385 383 384 0 +-383 385 0 +-384 385 0 +c MAP: 33 & 385 -> 386 +386 -33 -385 0 +33 -386 0 +385 -386 0 +c MAP: -8 | 386 -> 387 +-387 -8 386 0 +8 387 0 +-386 387 0 +387 0 +c analyze: Q4K=>Q5U +c MAP: -89 | 91 -> 388 +-388 -89 91 0 +89 388 0 +-91 388 0 +388 0 +c analyze: K8L=>(K0W&K8T&Z4R&(M4A|M4B)) +c MAP: 10 | 11 -> 389 +-389 10 11 0 +-10 389 0 +-11 389 0 +c MAP: 74 & 8 & 33 & 389 -> 390 +390 -74 -8 -33 -389 0 +74 -390 0 +8 -390 0 +33 -390 0 +389 -390 0 +c MAP: -28 | 390 -> 391 +-391 -28 390 0 +28 391 0 +-390 391 0 +391 0 +c analyze: R8F=>R8P +c MAP: -372 | 292 -> 392 +-392 -372 292 0 +372 392 0 +-292 392 0 +392 0 +c analyze: Z5Q=>(G2B|G2E) +c MAP: -209 | 5 | 110 -> 393 +-393 -209 5 110 0 +209 393 0 +-5 393 0 +-110 393 0 +393 0 +c analyze: K8M=>Z4K +c MAP: -7 | 268 -> 394 +-394 -7 268 0 +7 394 0 +-268 394 0 +394 0 +c analyze: S5M=>S1W +c MAP: -221 | 159 -> 395 +-395 -221 159 0 +221 395 0 +-159 395 0 +395 0 +c analyze: U2S=>U2G +c MAP: -263 | 262 -> 396 +-396 -263 262 0 +263 396 0 +-262 396 0 +396 0 +c analyze: Z5I=>Z5E +c MAP: -203 | 126 -> 397 +-397 -203 126 0 +203 397 0 +-126 397 0 +397 0 +c analyze: AP-B F58L96 81=>R8P +c MAP: -22 | 292 -> 398 +-398 -22 292 0 +22 398 0 +-292 398 0 +398 0 +c analyze: S3A=>(D0A&D2E&X3D) +c MAP: S3A -> 399 +c MAP: D0A -> 400 +c MAP: 400 & 200 & 248 -> 401 +401 -400 -200 -248 0 +400 -401 0 +200 -401 0 +248 -401 0 +c MAP: -399 | 401 -> 402 +-402 -399 401 0 +399 402 0 +-401 402 0 +402 0 +c analyze: I8N=>Z5E +c MAP: -58 | 126 -> 403 +-403 -58 126 0 +58 403 0 +-126 403 0 +403 0 +c analyze: M3E=>G2E +c MAP: -252 | 110 -> 404 +-404 -252 110 0 +252 404 0 +-110 404 0 +404 0 +c analyze: G0L=>(G1W|G1X) +c MAP: -39 | 3 | 4 -> 405 +-405 -39 3 4 0 +39 405 0 +-3 405 0 +-4 405 0 +405 0 +c analyze: S1G=>(B1B&S1W&S2M&(G1W|G1X)) +c MAP: 3 | 4 -> 406 +-406 3 4 0 +-3 406 0 +-4 406 0 +c MAP: 149 & 159 & 303 & 406 -> 407 +407 -149 -159 -303 -406 0 +149 -407 0 +159 -407 0 +303 -407 0 +406 -407 0 +c MAP: -56 | 407 -> 408 +-408 -56 407 0 +56 408 0 +-407 408 0 +408 0 +c analyze: M3D=>G2E +c MAP: -53 | 110 -> 409 +-409 -53 110 0 +53 409 0 +-110 409 0 +409 0 +c analyze: M5V=>(M5D&Z5E) +c MAP: 77 & 126 -> 410 +410 -77 -126 0 +77 -410 0 +126 -410 0 +c MAP: -215 | 410 -> 411 +-411 -215 410 0 +215 411 0 +-410 411 0 +411 0 +c analyze: M4A=>(M1W|M1X|M1Y) +c MAP: -10 | 47 | 48 | 49 -> 412 +-412 -10 47 48 49 0 +10 412 0 +-47 412 0 +-48 412 0 +-49 412 0 +412 0 +c analyze: G0K=>(Z5E&((B3J&(G1W|G1X))|(G5G&(B3J|G2B|G2E)))) +c MAP: 3 | 4 -> 413 +-413 3 4 0 +-3 413 0 +-4 413 0 +c MAP: 13 | 5 | 110 -> 414 +-414 13 5 110 0 +-13 414 0 +-5 414 0 +-110 414 0 +c MAP: 13 & 413 -> 415 +415 -13 -413 0 +13 -415 0 +413 -415 0 +c MAP: 134 & 414 -> 416 +416 -134 -414 0 +134 -416 0 +414 -416 0 +c MAP: 415 | 416 -> 417 +-417 415 416 0 +-415 417 0 +-416 417 0 +c MAP: 126 & 417 -> 418 +418 -126 -417 0 +126 -418 0 +417 -418 0 +c MAP: -264 | 418 -> 419 +-419 -264 418 0 +264 419 0 +-418 419 0 +419 0 +c analyze: M1V=>(G1W&M4B) +c MAP: 3 & 11 -> 420 +420 -3 -11 0 +3 -420 0 +11 -420 0 +c MAP: -46 | 420 -> 421 +-421 -46 420 0 +46 421 0 +-420 421 0 +421 0 +c analyze: Y4Z=>D0S +c MAP: -108 | 70 -> 422 +-422 -108 70 0 +108 422 0 +-70 422 0 +422 0 +c analyze: Q0R=>Q5J +c MAP: -1 | 2 -> 423 +-423 -1 2 0 +1 423 0 +-2 423 0 +423 0 +c analyze: S1R=>(B1B&S1W&S2M&Z5E) +c MAP: S1R -> 424 +c MAP: 149 & 159 & 303 & 126 -> 425 +425 -149 -159 -303 -126 0 +149 -425 0 +159 -425 0 +303 -425 0 +126 -425 0 +c MAP: -424 | 425 -> 426 +-426 -424 425 0 +424 426 0 +-425 426 0 +426 0 +c analyze: K4X=>(K2R&Z5E)&(K0W&Z4K) +c MAP: 119 & 126 & 74 & 268 -> 427 +427 -119 -126 -74 -268 0 +119 -427 0 +126 -427 0 +74 -427 0 +268 -427 0 +c MAP: -182 | 427 -> 428 +-428 -182 427 0 +182 428 0 +-427 428 0 +428 0 +c analyze: X3D=>Z5E +c MAP: -248 | 126 -> 429 +-429 -248 126 0 +248 429 0 +-126 429 0 +429 0 +c analyze: M1U=>(G1W&M4B) +c MAP: 3 & 11 -> 430 +430 -3 -11 0 +3 -430 0 +11 -430 0 +c MAP: -45 | 430 -> 431 +-431 -45 430 0 +45 431 0 +-430 431 0 +431 0 +c analyze: M4B=>(M1U|M1V) +c MAP: -11 | 45 | 46 -> 432 +-432 -11 45 46 0 +11 432 0 +-45 432 0 +-46 432 0 +432 0 +c analyze: M5D=>Z5E +c MAP: -77 | 126 -> 433 +-433 -77 126 0 +77 433 0 +-126 433 0 +433 0 +c analyze: K0W=>(K4X|K8K|K8L|K8N) +c MAP: -74 | 182 | 27 | 28 | 29 -> 434 +-434 -74 182 27 28 29 0 +74 434 0 +-182 434 0 +-27 434 0 +-28 434 0 +-29 434 0 +434 0 +c analyze: AP-B V18MFA 0C=>R8P +c MAP: -26 | 292 -> 435 +-435 -26 292 0 +26 435 0 +-292 435 0 +435 0 +c analyze: I8O=>Z5E +c MAP: -59 | 126 -> 436 +-436 -59 126 0 +59 436 0 +-126 436 0 +436 0 +c analyze: K8K=>(K0W&K2R&Z4R&(M4A|M4B)) +c MAP: 10 | 11 -> 437 +-437 10 11 0 +-10 437 0 +-11 437 0 +c MAP: 74 & 119 & 33 & 437 -> 438 +438 -74 -119 -33 -437 0 +74 -438 0 +119 -438 0 +33 -438 0 +437 -438 0 +c MAP: -27 | 438 -> 439 +-439 -27 438 0 +27 439 0 +-438 439 0 +439 0 +c analyze: S6G=>B1B +c MAP: -240 | 149 -> 440 +-440 -240 149 0 +240 440 0 +-149 440 0 +440 0 +c analyze: G2E=>G5G +c MAP: -110 | 134 -> 441 +-441 -110 134 0 +110 441 0 +-134 441 0 +441 0 +c analyze: MB_CMF_T=>D4T&D4U&D8L&E2Y&D0A&D4N&D5B&D5Z&D6G&D7J&F3C +c MAP: D4N -> 442 +c MAP: D5B -> 443 +c MAP: D5Z -> 444 +c MAP: 82 & 228 & 71 & 244 & 400 & 442 & 443 & 444 & 106 & 345 & 148 -> 445 +445 -82 -228 -71 -244 -400 -442 -443 -444 -106 -345 -148 0 +82 -445 0 +228 -445 0 +71 -445 0 +244 -445 0 +400 -445 0 +442 -445 0 +443 -445 0 +444 -445 0 +106 -445 0 +345 -445 0 +148 -445 0 +c MAP: -275 | 445 -> 446 +-446 -275 445 0 +275 446 0 +-445 446 0 +446 0 +c analyze: MB_CMF_TP=>D4T&D4U&D8L&E2Y&D0A&D4N&D5B&D5Z&D6G&D7J&F3C&D2D&D4Z&E0D&E1K&Y1X +c MAP: 82 & 228 & 71 & 244 & 400 & 442 & 443 & 444 & 106 & 345 & 148 & 117 & 100 & 309 & 95 & 310 -> 447 +447 -82 -228 -71 -244 -400 -442 -443 -444 -106 -345 -148 -117 -100 -309 -95 -310 0 +82 -447 0 +228 -447 0 +71 -447 0 +244 -447 0 +400 -447 0 +442 -447 0 +443 -447 0 +444 -447 0 +106 -447 0 +345 -447 0 +148 -447 0 +117 -447 0 +100 -447 0 +309 -447 0 +95 -447 0 +310 -447 0 +c MAP: -276 | 447 -> 448 +-448 -276 447 0 +276 448 0 +-447 448 0 +448 0 +c analyze: MB_DO_C=>B5C&D0S&E5J&K5M&Y4A&Y4Z&E7F +c MAP: 225 & 70 & 231 & 219 & 195 & 108 & 206 -> 449 +449 -225 -70 -231 -219 -195 -108 -206 0 +225 -449 0 +70 -449 0 +231 -449 0 +219 -449 0 +195 -449 0 +108 -449 0 +206 -449 0 +c MAP: -277 | 449 -> 450 +-450 -277 449 0 +277 450 0 +-449 450 0 +450 0 +c analyze: MB_DO_T=>B5C&D0S&E5J&K5M&Y4A&Y4Z&E7F&F3Y +c MAP: 225 & 70 & 231 & 219 & 195 & 108 & 206 & 167 -> 451 +451 -225 -70 -231 -219 -195 -108 -206 -167 0 +225 -451 0 +70 -451 0 +231 -451 0 +219 -451 0 +195 -451 0 +108 -451 0 +206 -451 0 +167 -451 0 +c MAP: -278 | 451 -> 452 +-452 -278 451 0 +278 452 0 +-451 452 0 +452 0 +c analyze: MB_EF_C=>F5B +c MAP: -279 | 205 -> 453 +-453 -279 205 0 +279 453 0 +-205 453 0 +453 0 +c analyze: MB_EF_T_A=>G0T +c MAP: -280 | 236 -> 454 +-454 -280 236 0 +280 454 0 +-236 454 0 +454 0 +c analyze: MB_EF_T_B=>G0L +c MAP: -64 | 39 -> 455 +-455 -64 39 0 +64 455 0 +-39 455 0 +455 0 +c analyze: MB_EX_C=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I +c MAP: R0Q -> 456 +c MAP: U2I -> 457 +c MAP: 149 & 456 & 159 & 303 & 240 & 221 & 457 -> 458 +458 -149 -456 -159 -303 -240 -221 -457 0 +149 -458 0 +456 -458 0 +159 -458 0 +303 -458 0 +240 -458 0 +221 -458 0 +457 -458 0 +c MAP: -281 | 458 -> 459 +-459 -281 458 0 +281 459 0 +-458 459 0 +459 0 +c analyze: MB_EX_ST_A=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I&F8V&F8W&L1H&S1I&L1G&S3A +c MAP: F8V -> 460 +c MAP: F8W -> 461 +c MAP: L1H -> 462 +c MAP: 149 & 456 & 159 & 303 & 240 & 221 & 457 & 460 & 461 & 462 & 302 & 362 & 399 -> 463 +463 -149 -456 -159 -303 -240 -221 -457 -460 -461 -462 -302 -362 -399 0 +149 -463 0 +456 -463 0 +159 -463 0 +303 -463 0 +240 -463 0 +221 -463 0 +457 -463 0 +460 -463 0 +461 -463 0 +462 -463 0 +302 -463 0 +362 -463 0 +399 -463 0 +c MAP: -282 | 463 -> 464 +-464 -282 463 0 +282 464 0 +-463 464 0 +464 0 +c analyze: MB_EX_T_A=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I&F8V&F8W&L1H&S1I +c MAP: 149 & 456 & 159 & 303 & 240 & 221 & 457 & 460 & 461 & 462 & 302 -> 465 +465 -149 -456 -159 -303 -240 -221 -457 -460 -461 -462 -302 0 +149 -465 0 +456 -465 0 +159 -465 0 +303 -465 0 +240 -465 0 +221 -465 0 +457 -465 0 +460 -465 0 +461 -465 0 +462 -465 0 +302 -465 0 +c MAP: -283 | 465 -> 466 +-466 -283 465 0 +283 466 0 +-465 466 0 +466 0 +c analyze: MB_EX_T_B=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I&F8V&F8W&L1H&S1G +c MAP: 149 & 456 & 159 & 303 & 240 & 221 & 457 & 460 & 461 & 462 & 56 -> 467 +467 -149 -456 -159 -303 -240 -221 -457 -460 -461 -462 -56 0 +149 -467 0 +456 -467 0 +159 -467 0 +303 -467 0 +240 -467 0 +221 -467 0 +457 -467 0 +460 -467 0 +461 -467 0 +462 -467 0 +56 -467 0 +c MAP: -65 | 467 -> 468 +-468 -65 467 0 +65 468 0 +-467 468 0 +468 0 +c analyze: MB_EX_T_B_B1=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I&F8V&F8W&L1H +c MAP: 149 & 456 & 159 & 303 & 240 & 221 & 457 & 460 & 461 & 462 -> 469 +469 -149 -456 -159 -303 -240 -221 -457 -460 -461 -462 0 +149 -469 0 +456 -469 0 +159 -469 0 +303 -469 0 +240 -469 0 +221 -469 0 +457 -469 0 +460 -469 0 +461 -469 0 +462 -469 0 +c MAP: -284 | 469 -> 470 +-470 -284 469 0 +284 470 0 +-469 470 0 +470 0 +c analyze: MB_FW_JO_6X4/6X2=>Q5U&Q4K&Q6D&Q0W&Q0X&Q0Y&Q4X&H1J +c MAP: 91 & 89 & 165 & 157 & 238 & 239 & 177 & 211 -> 471 +471 -91 -89 -165 -157 -238 -239 -177 -211 0 +91 -471 0 +89 -471 0 +165 -471 0 +157 -471 0 +238 -471 0 +239 -471 0 +177 -471 0 +211 -471 0 +c MAP: -285 | 471 -> 472 +-472 -285 471 0 +285 472 0 +-471 472 0 +472 0 +c analyze: MB_LW_A/B_B1=>Q0A&R7S +c MAP: MB_LW_A/B_B1 -> 473 +c MAP: Q0A -> 474 +c MAP: 474 & 87 -> 475 +475 -474 -87 0 +474 -475 0 +87 -475 0 +c MAP: -473 | 475 -> 476 +-476 -473 475 0 +473 476 0 +-475 476 0 +476 0 +c analyze: MB_MT_A/B=>L1H +c MAP: MB_MT_A/B -> 477 +c MAP: -477 | 462 -> 478 +-478 -477 462 0 +477 478 0 +-462 478 0 +478 0 +c analyze: MB_RS_A/B=>F0T&F5L&F6R +c MAP: MB_RS_A/B -> 479 +c MAP: F0T -> 480 +c MAP: F5L -> 481 +c MAP: 480 & 481 & 234 -> 482 +482 -480 -481 -234 0 +480 -482 0 +481 -482 0 +234 -482 0 +c MAP: -479 | 482 -> 483 +-483 -479 482 0 +479 483 0 +-482 483 0 +483 0 +c analyze: MB_SM_A/B=>D6C&D7A&E0D&E1K&D2E&D6G +c MAP: 36 & 30 & 309 & 95 & 200 & 106 -> 484 +484 -36 -30 -309 -95 -200 -106 0 +36 -484 0 +30 -484 0 +309 -484 0 +95 -484 0 +200 -484 0 +106 -484 0 +c MAP: -66 | 484 -> 485 +-485 -66 484 0 +66 485 0 +-484 485 0 +485 0 +c analyze: MB_SW_G70=>R8F&R8P&AP-B F38MEA 0C +c MAP: 372 & 292 & 174 -> 486 +486 -372 -292 -174 0 +372 -486 0 +292 -486 0 +174 -486 0 +c MAP: -286 | 486 -> 487 +-487 -286 486 0 +286 487 0 +-486 487 0 +487 0 +c analyze: MB_SW_G80=>R8F&R8P&AP-B V18MEA 0C +c MAP: 372 & 292 & 175 -> 488 +488 -372 -292 -175 0 +372 -488 0 +292 -488 0 +175 -488 0 +c MAP: -287 | 488 -> 489 +-489 -287 488 0 +287 489 0 +-488 489 0 +489 0 +c analyze: MB_TR_G70_6x4=>I2E&I2F&F38MEA 0C&AP-2 F38MFA 0C&AP-3 F38MFA 0C +c MAP: 122 & 112 & 168 & 170 & 172 -> 490 +490 -122 -112 -168 -170 -172 0 +122 -490 0 +112 -490 0 +168 -490 0 +170 -490 0 +172 -490 0 +c MAP: -288 | 490 -> 491 +-491 -288 490 0 +288 491 0 +-490 491 0 +491 0 +c analyze: MB_TR_G80_6x4=>AP-2 V18MFA 0C&V18MEA 0C&I1V&I1W&AP-3 V18MFA 0C +c MAP: 171 & 169 & 121 & 111 & 173 -> 492 +492 -171 -169 -121 -111 -173 0 +171 -492 0 +169 -492 0 +121 -492 0 +111 -492 0 +173 -492 0 +c MAP: -289 | 492 -> 493 +-493 -289 492 0 +289 493 0 +-492 493 0 +493 0 +c analyze: MB_WT_A_64/62=>D6G&D6I&D6M&D7A&E1K&E3W&K8T&K8N&F3Z +c MAP: 106 & 6 & 12 & 30 & 95 & 55 & 8 & 29 & 60 -> 494 +494 -106 -6 -12 -30 -95 -55 -8 -29 -60 0 +106 -494 0 +6 -494 0 +12 -494 0 +30 -494 0 +95 -494 0 +55 -494 0 +8 -494 0 +29 -494 0 +60 -494 0 +c MAP: -67 | 494 -> 495 +-495 -67 494 0 +67 495 0 +-494 495 0 +495 0 +c analyze: MB_WT_B_64/62=>D6G&D6I&D6M&D7A&E1K&E3W&K8T&F3Z&K8L +c MAP: 106 & 6 & 12 & 30 & 95 & 55 & 8 & 60 & 28 -> 496 +496 -106 -6 -12 -30 -95 -55 -8 -60 -28 0 +106 -496 0 +6 -496 0 +12 -496 0 +30 -496 0 +95 -496 0 +55 -496 0 +8 -496 0 +60 -496 0 +28 -496 0 +c MAP: -68 | 496 -> 497 +-497 -68 496 0 +68 497 0 +-496 497 0 +497 0 +c analyze: MB_2FT_WT_A64/62=>K0W&K8T&K8N&Z4R +c MAP: 74 & 8 & 29 & 33 -> 498 +498 -74 -8 -29 -33 0 +74 -498 0 +8 -498 0 +29 -498 0 +33 -498 0 +c MAP: -62 | 498 -> 499 +-499 -62 498 0 +62 499 0 +-498 499 0 +499 0 +c analyze: MB_2FT_WT_B64/62=>K0W&K8T&Z4R&K8L +c MAP: 74 & 8 & 33 & 28 -> 500 +500 -74 -8 -33 -28 0 +74 -500 0 +8 -500 0 +33 -500 0 +28 -500 0 +c MAP: -63 | 500 -> 501 +-501 -63 500 0 +63 501 0 +-500 501 0 +501 0 +c analyze: MB_CK_C=>J6A&J1H&J5R&J2I&U3W +c MAP: 214 & 185 & 80 & 155 & 257 -> 502 +502 -214 -185 -80 -155 -257 0 +214 -502 0 +185 -502 0 +80 -502 0 +155 -502 0 +257 -502 0 +c MAP: -273 | 502 -> 503 +-503 -273 502 0 +273 503 0 +-502 503 0 +503 0 +c analyze: MB_2FT_A42_B64/62/4=>K0W&K8K&Z4R +c MAP: 74 & 27 & 33 -> 504 +504 -74 -27 -33 0 +74 -504 0 +27 -504 0 +33 -504 0 +c MAP: -61 | 504 -> 505 +-505 -61 504 0 +61 505 0 +-504 505 0 +505 0 +c analyze: MB_2FT_A64/62=>K0W&K4X +c MAP: 74 & 182 -> 506 +506 -74 -182 0 +74 -506 0 +182 -506 0 +c MAP: -272 | 506 -> 507 +-507 -272 506 0 +272 507 0 +-506 507 0 +507 0 +c analyze: MB_CMF_C=>D4T&D4U&D8L&E2Y +c MAP: 82 & 228 & 71 & 244 -> 508 +508 -82 -228 -71 -244 0 +82 -508 0 +228 -508 0 +71 -508 0 +244 -508 0 +c MAP: -274 | 508 -> 509 +-509 -274 508 0 +274 509 0 +-508 509 0 +509 0 +c analyze: MB_SW_G80=>MB_TR_G80_6x4 +c MAP: -287 | 289 -> 510 +-510 -287 289 0 +287 510 0 +-289 510 0 +510 0 +c analyze: MB_SW_G70=>MB_TR_G70_6x4 +c MAP: -286 | 288 -> 511 +-511 -286 288 0 +286 511 0 +-288 511 0 +511 0 +c analyze: (MB_DO_C|MB_DO_T)=>M7I +c MAP: -277 & -278 -> 512 +512 277 278 0 +-277 -512 0 +-278 -512 0 +c MAP: 512 | 127 -> 513 +-513 512 127 0 +-512 513 0 +-127 513 0 +513 0 +c analyze: M1X|M3A=>!(B3J|A5D) +c MAP: -48 & -50 -> 514 +514 48 50 0 +-48 -514 0 +-50 -514 0 +c MAP: -13 & -142 -> 515 +515 13 142 0 +-13 -515 0 +-142 -515 0 +c MAP: 514 | 515 -> 516 +-516 514 515 0 +-514 516 0 +-515 516 0 +516 0 +c analyze: U1F<=>S1W +c MAP: -266 | 159 -> 517 +-517 -266 159 0 +266 517 0 +-159 517 0 +c MAP: -159 | 266 -> 518 +-518 -159 266 0 +159 518 0 +-266 518 0 +c MAP: 517 & 518 -> 519 +519 -517 -518 0 +517 -519 0 +518 -519 0 +519 0 +c analyze: C8M&I2E&I2F=>MB_LW_A/B_B1 +c MAP: C8M -> 520 +c MAP: -520 | -122 | -112 | 473 -> 521 +-521 -520 -122 -112 473 0 +520 521 0 +122 521 0 +112 521 0 +-473 521 0 +521 0 +c analyze: MB_CMF_T|MB_CMF_TP=>D2E +c MAP: -275 & -276 -> 522 +522 275 276 0 +-275 -522 0 +-276 -522 0 +c MAP: 522 | 200 -> 523 +-523 522 200 0 +-522 523 0 +-200 523 0 +523 0 +c analyze: M7I=>!MB_SM_A/B +c MAP: -127 | -66 -> 524 +-524 -127 -66 0 +127 524 0 +66 524 0 +524 0 +c analyze: G0T=>((G2B|G2E)&G5G)|((G1W|G1X)&B3J)&Z5E +c MAP: 5 | 110 -> 525 +-525 5 110 0 +-5 525 0 +-110 525 0 +c MAP: 3 | 4 -> 526 +-526 3 4 0 +-3 526 0 +-4 526 0 +c MAP: 525 & 134 -> 527 +527 -525 -134 0 +525 -527 0 +134 -527 0 +c MAP: 526 & 13 & 126 -> 528 +528 -526 -13 -126 0 +526 -528 0 +13 -528 0 +126 -528 0 +c MAP: -236 | 527 | 528 -> 529 +-529 -236 527 528 0 +236 529 0 +-527 529 0 +-528 529 0 +529 0 +c analyze: MB_EX_ST_A=>S1R +c MAP: -282 | 424 -> 530 +-530 -282 424 0 +282 530 0 +-424 530 0 +530 0 +c analyze: MB_MT_A/B&X3E=>A5D&B3J +c MAP: 142 & 13 -> 531 +531 -142 -13 0 +142 -531 0 +13 -531 0 +c MAP: -477 | -44 | 531 -> 532 +-532 -477 -44 531 0 +477 532 0 +44 532 0 +-531 532 0 +532 0 +c analyze: MB_EX_T_A|MB_EX_ST_A|MB_EX_T_B=>MB_CMF_TP|MB_CMF_T|MB_SM_A/B +c MAP: -283 & -282 & -65 -> 533 +533 283 282 65 0 +-283 -533 0 +-282 -533 0 +-65 -533 0 +c MAP: 533 | 276 | 275 | 66 -> 534 +-534 533 276 275 66 0 +-533 534 0 +-276 534 0 +-275 534 0 +-66 534 0 +534 0 +c analyze: MB_EX_T_A|MB_EX_ST_A=>MB_CMF_TP|MB_CMF_T|MB_SM_A/B +c MAP: -283 & -282 -> 535 +535 283 282 0 +-283 -535 0 +-282 -535 0 +c MAP: 535 | 276 | 275 | 66 -> 536 +-536 535 276 275 66 0 +-535 536 0 +-276 536 0 +-275 536 0 +-66 536 0 +536 0 +c analyze: MB_MT_A/B&X3D=>A5D +c MAP: -477 | -248 | 142 -> 537 +-537 -477 -248 142 0 +477 537 0 +248 537 0 +-142 537 0 +537 0 diff --git a/src/Allocate.cpp b/src/Allocate.cpp new file mode 100644 index 0000000..efaf177 --- /dev/null +++ b/src/Allocate.cpp @@ -0,0 +1,21 @@ +#include "Allocate.h" + +int IDManager::id = 0; +std::map IDManager::idToName; +std::map IDManager::nameToID; + + +int IDManager::allocate() { + return ++id; +} + +int IDManager::getOrAllocate(std::string name) { + if(nameToID.count(name)) + return nameToID[name]; + int tid = allocate(); + nameToID[name] = tid; + idToName[tid] = name; + + CNF::comment("MAP: " + name + " -> " + std::to_string(tid)); + return tid; +} \ No newline at end of file diff --git a/src/Allocate.h b/src/Allocate.h new file mode 100644 index 0000000..f9ad0f7 --- /dev/null +++ b/src/Allocate.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include +#include "CNF.h" + +class IDManager { +public: + static int allocate(); + static int getOrAllocate(std::string name); + + static std::map idToName; + static std::map nameToID; + static int id; +}; \ No newline at end of file diff --git a/src/CNF.cpp b/src/CNF.cpp new file mode 100644 index 0000000..44a653e --- /dev/null +++ b/src/CNF.cpp @@ -0,0 +1,37 @@ +#include "CNF.h" + +std::vector> CNF::vec; +std::vector CNF::tmp; +std::set CNF::el; +std::queue> CNF::cq; + +void CNF::add(int x) { + if(x == 0) { + vec.push_back(tmp); + tmp.clear(); + } else { + el.insert(abs(x)); + tmp.push_back(x); + } +} + +void CNF::comment(std::string str) { + cq.push(make_pair(vec.size(), str)); +} + +void CNF::print() { + printf("p cnf %d %d\n", IDManager::id, vec.size()); + + for(int i=0; i= cq.front().first) { + printf("c %s\n", cq.front().second.c_str()); + cq.pop(); + } + + for(auto& lit : vec[i]) { + printf("%d ", lit); + } + printf("0\n"); + } +} \ No newline at end of file diff --git a/src/CNF.h b/src/CNF.h new file mode 100644 index 0000000..3599a65 --- /dev/null +++ b/src/CNF.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "Allocate.h" + +class CNF { +public: + static void add(int x); + static void comment(std::string str); + static void print(); + +private: + static std::set el; + static std::vector tmp; + static std::vector> vec; + static std::queue> cq; +}; \ No newline at end of file diff --git a/src/Calculator.p b/src/Calculator.p new file mode 100644 index 0000000..92b232e --- /dev/null +++ b/src/Calculator.p @@ -0,0 +1,28 @@ +term And assoc(left) prec(4); // + +term Or assoc(left) prec(3); // - +term Entail assoc(left) prec(2); // * +term rEntail assoc(left) prec(2); // * +term Equal assoc(left) prec(1); // / +term Not; +term LeftParen; // ( +term RightParen; // ) +term LiteralNumber {% Clause %}; + +nonterm exp {% Clause %}; + +grammar { + exp -> LiteralNumber(value) {% return value; %}; + exp -> LeftParen exp(exp) RightParen {% return exp; %}; + exp -> Not exp(rhs) prec(10) {% return ~rhs; %}; + exp -> exp(lhs) And exp(rhs) {% return lhs & rhs; %}; + exp -> exp(lhs) Or exp(rhs) {% return lhs | rhs; %}; + exp -> exp(lhs) Entail exp(rhs) {% return (~lhs)|rhs; %}; + exp -> exp(lhs) rEntail exp(rhs) {% return (~rhs)|lhs; %}; + exp -> exp(lhs) Equal exp(rhs) {% return ((~lhs)|rhs)&((~rhs)|lhs); %}; +}; + +generator {% + { + "class_name": "CalculatorParser" + } +%}; \ No newline at end of file diff --git a/src/CalculatorParser.cpp b/src/CalculatorParser.cpp new file mode 100644 index 0000000..58a521e --- /dev/null +++ b/src/CalculatorParser.cpp @@ -0,0 +1,344 @@ +/** + * @file + * @date 2022-09-01 + * + * Auto generated code by 9chu/parser_gen. + */ +#include "CalculatorParser.hpp" + +#include + + +#define ACTION_ERROR 0 +#define ACTION_ACCEPT 1 +#define ACTION_GOTO 2 +#define ACTION_REDUCE 3 + +namespace { + CalculatorParser::ProductionValues Reduce0(std::vector& stack_) + { + // binding values + assert(stack_.size() >= 1); + auto value = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 1]) + ) + )); + + // user code + auto ret = [&]() { +return value; }(); + return CalculatorParser::ProductionValues { std::move(ret) }; + } + + CalculatorParser::ProductionValues Reduce1(std::vector& stack_) + { + // binding values + assert(stack_.size() >= 3); + auto exp = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 2]) + ) + )); + + + // user code + auto ret = [&]() { +return exp; }(); + return CalculatorParser::ProductionValues { std::move(ret) }; + } + + CalculatorParser::ProductionValues Reduce2(std::vector& stack_) + { + // binding values + assert(stack_.size() >= 2); + auto rhs = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 1]) + ) + )); + + + // user code + auto ret = [&]() { +return ~rhs; }(); + return CalculatorParser::ProductionValues { std::move(ret) }; + } + + CalculatorParser::ProductionValues Reduce3(std::vector& stack_) + { + // binding values + assert(stack_.size() >= 3); + auto lhs = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 3]) + ) + )); + + auto rhs = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 1]) + ) + )); + + + // user code + auto ret = [&]() { +return lhs & rhs; }(); + return CalculatorParser::ProductionValues { std::move(ret) }; + } + + CalculatorParser::ProductionValues Reduce4(std::vector& stack_) + { + // binding values + assert(stack_.size() >= 3); + auto lhs = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 3]) + ) + )); + + auto rhs = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 1]) + ) + )); + + + // user code + auto ret = [&]() { +return lhs | rhs; }(); + return CalculatorParser::ProductionValues { std::move(ret) }; + } + + CalculatorParser::ProductionValues Reduce5(std::vector& stack_) + { + // binding values + assert(stack_.size() >= 3); + auto lhs = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 3]) + ) + )); + + auto rhs = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 1]) + ) + )); + + + // user code + auto ret = [&]() { +return (~lhs)|rhs; }(); + return CalculatorParser::ProductionValues { std::move(ret) }; + } + + CalculatorParser::ProductionValues Reduce6(std::vector& stack_) + { + // binding values + assert(stack_.size() >= 3); + auto lhs = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 3]) + ) + )); + + auto rhs = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 1]) + ) + )); + + + // user code + auto ret = [&]() { +return (~rhs)|lhs; }(); + return CalculatorParser::ProductionValues { std::move(ret) }; + } + + CalculatorParser::ProductionValues Reduce7(std::vector& stack_) + { + // binding values + assert(stack_.size() >= 3); + auto lhs = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 3]) + ) + )); + + auto rhs = + std::move(std::get( + std::get( + std::move(stack_[stack_.size() - 1]) + ) + )); + + + // user code + auto ret = [&]() { +return ((~lhs)|rhs)&((~rhs)|lhs); }(); + return CalculatorParser::ProductionValues { std::move(ret) }; + } + +} + +using ReduceFunction = CalculatorParser::ProductionValues(*)(std::vector&); + +struct ProductionInfo +{ + uint32_t NonTerminal; + uint32_t SymbolCount; + ReduceFunction Callback; +}; + +struct ActionInfo +{ + uint8_t Action; + uint32_t Arg; +}; + +static const ProductionInfo kProductions[8] = { + { 10, 1, ::Reduce0 }, + { 10, 3, ::Reduce1 }, + { 10, 2, ::Reduce2 }, + { 10, 3, ::Reduce3 }, + { 10, 3, ::Reduce4 }, + { 10, 3, ::Reduce5 }, + { 10, 3, ::Reduce6 }, + { 10, 3, ::Reduce7 }, +}; + +static const ActionInfo kActions[34][11] = { + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 3 },{ 2, 2 },{ 2, 4 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 1 }, }, + { { 1, 0 },{ 2, 8 },{ 2, 7 },{ 2, 9 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 6 },{ 0, 0 },{ 2, 5 },{ 0, 0 }, }, + { { 3, 0 },{ 3, 0 },{ 3, 0 },{ 3, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 3, 0 },{ 0, 0 },{ 3, 0 },{ 0, 0 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 12 },{ 2, 11 },{ 2, 13 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 10 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 3 },{ 2, 2 },{ 2, 4 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 14 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 3 },{ 2, 2 },{ 2, 4 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 15 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 3 },{ 2, 2 },{ 2, 4 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 16 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 3 },{ 2, 2 },{ 2, 4 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 17 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 3 },{ 2, 2 },{ 2, 4 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 18 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 3 },{ 2, 2 },{ 2, 4 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 19 }, }, + { { 0, 0 },{ 2, 23 },{ 2, 22 },{ 2, 25 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 21 },{ 2, 24 },{ 2, 20 },{ 0, 0 }, }, + { { 0, 0 },{ 3, 0 },{ 3, 0 },{ 3, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 3, 0 },{ 3, 0 },{ 3, 0 },{ 0, 0 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 12 },{ 2, 11 },{ 2, 13 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 26 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 12 },{ 2, 11 },{ 2, 13 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 27 }, }, + { { 3, 2 },{ 3, 2 },{ 3, 2 },{ 3, 2 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 3, 2 },{ 0, 0 },{ 3, 2 },{ 0, 0 }, }, + { { 3, 6 },{ 2, 8 },{ 3, 6 },{ 3, 6 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 6 },{ 0, 0 },{ 3, 6 },{ 0, 0 }, }, + { { 3, 4 },{ 2, 8 },{ 3, 4 },{ 3, 4 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 3, 4 },{ 0, 0 },{ 3, 4 },{ 0, 0 }, }, + { { 3, 5 },{ 2, 8 },{ 3, 5 },{ 3, 5 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 6 },{ 0, 0 },{ 3, 5 },{ 0, 0 }, }, + { { 3, 3 },{ 3, 3 },{ 3, 3 },{ 3, 3 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 3, 3 },{ 0, 0 },{ 3, 3 },{ 0, 0 }, }, + { { 3, 7 },{ 2, 8 },{ 2, 7 },{ 3, 7 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 6 },{ 0, 0 },{ 2, 5 },{ 0, 0 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 12 },{ 2, 11 },{ 2, 13 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 28 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 12 },{ 2, 11 },{ 2, 13 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 29 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 12 },{ 2, 11 },{ 2, 13 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 30 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 12 },{ 2, 11 },{ 2, 13 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 31 }, }, + { { 3, 1 },{ 3, 1 },{ 3, 1 },{ 3, 1 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 3, 1 },{ 0, 0 },{ 3, 1 },{ 0, 0 }, }, + { { 0, 0 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 12 },{ 2, 11 },{ 2, 13 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 32 }, }, + { { 0, 0 },{ 2, 23 },{ 2, 22 },{ 2, 25 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 21 },{ 2, 33 },{ 2, 20 },{ 0, 0 }, }, + { { 0, 0 },{ 3, 2 },{ 3, 2 },{ 3, 2 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 3, 2 },{ 3, 2 },{ 3, 2 },{ 0, 0 }, }, + { { 0, 0 },{ 2, 23 },{ 3, 6 },{ 3, 6 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 21 },{ 3, 6 },{ 3, 6 },{ 0, 0 }, }, + { { 0, 0 },{ 2, 23 },{ 3, 4 },{ 3, 4 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 3, 4 },{ 3, 4 },{ 3, 4 },{ 0, 0 }, }, + { { 0, 0 },{ 2, 23 },{ 3, 5 },{ 3, 5 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 21 },{ 3, 5 },{ 3, 5 },{ 0, 0 }, }, + { { 0, 0 },{ 3, 3 },{ 3, 3 },{ 3, 3 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 3, 3 },{ 3, 3 },{ 3, 3 },{ 0, 0 }, }, + { { 0, 0 },{ 2, 23 },{ 2, 22 },{ 3, 7 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 2, 21 },{ 3, 7 },{ 2, 20 },{ 0, 0 }, }, + { { 0, 0 },{ 3, 1 },{ 3, 1 },{ 3, 1 },{ 0, 0 },{ 0, 0 },{ 0, 0 },{ 3, 1 },{ 3, 1 },{ 3, 1 },{ 0, 0 }, }, +}; + +CalculatorParser::CalculatorParser() +{ + Reset(); +} + +CalculatorParser::ParseResult CalculatorParser::operator()(TokenTypes token, const TokenValues& value) +{ + while (true) + { + assert(!m_stStack.empty()); + assert(static_cast(token) < 10); + + const ActionInfo& act = kActions[m_stStack.back()][static_cast(token)]; + if (act.Action == ACTION_ACCEPT) + { + // store the result + assert(!m_stValueStack.empty()); + m_stResult = + std::move(std::get( + std::get(std::move(m_stValueStack.back())) + )); + + Reset(); + return ParseResult::Accepted; + } + else if (act.Action == ACTION_ERROR) + { + Reset(); + return ParseResult::Rejected; + } + else if (act.Action == ACTION_GOTO) + { + m_stStack.push_back(static_cast(token)); + m_stStack.push_back(act.Arg); + assert(m_stStack.back() < 34); + + m_stValueStack.push_back(value); + } + else + { + assert(act.Action == ACTION_REDUCE); + assert(act.Arg < 8); + + const ProductionInfo& info = kProductions[act.Arg]; + auto val = info.Callback(m_stValueStack); + + assert(m_stStack.size() >= info.SymbolCount * 2); + m_stStack.resize(m_stStack.size() - info.SymbolCount * 2); + + assert(m_stValueStack.size() >= info.SymbolCount); + m_stValueStack.resize(m_stValueStack.size() - info.SymbolCount); + + m_stValueStack.emplace_back(std::move(val)); + assert(!m_stStack.empty()); + + const ActionInfo& act2 = kActions[m_stStack.back()][info.NonTerminal]; + if (act2.Action == ACTION_GOTO) + { + m_stStack.push_back(info.NonTerminal); + m_stStack.push_back(act2.Arg); + } + else + { + assert(false); + Reset(); + return ParseResult::Rejected; + } + + continue; + } + break; + } + + return ParseResult::Undecided; +} + +void CalculatorParser::Reset()noexcept +{ + m_stStack.clear(); + m_stValueStack.clear(); + + // initial state + m_stStack.push_back(0); +} diff --git a/src/CalculatorParser.hpp b/src/CalculatorParser.hpp new file mode 100644 index 0000000..8c0e22b --- /dev/null +++ b/src/CalculatorParser.hpp @@ -0,0 +1,66 @@ +/** + * @file + * @date 2022-09-01 + * + * Auto generated code by 9chu/parser_gen. + */ +#pragma once +#include +#include +#include +#include "ValueType.hpp" + + +// namespace { + class CalculatorParser + { + public: + enum class ParseResult + { + Undecided = 0, + Accepted = 1, + Rejected = 2, + }; + + enum class TokenTypes + { + _ = 0, + And = 1, + Entail = 2, + Equal = 3, + LeftParen = 4, + LiteralNumber = 5, + Not = 6, + Or = 7, + RightParen = 8, + rEntail = 9, + }; + + using TokenValues = std::variant< + std::monostate, + Clause + >; + + using ProductionValues = std::variant< + Clause + >; + + using UnionValues = std::variant; + + public: + CalculatorParser(); + + public: + ParseResult operator()(TokenTypes token, const TokenValues& value); + void Reset()noexcept; + + const Clause& Result()const noexcept { return m_stResult; } + Clause& Result()noexcept { return m_stResult; } + + private: + std::vector m_stStack; + std::vector m_stValueStack; + + Clause m_stResult {}; + }; +// } diff --git a/src/Main.cpp b/src/Main.cpp new file mode 100644 index 0000000..a61a93a --- /dev/null +++ b/src/Main.cpp @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include + +#include "ValueType.hpp" +#include "CalculatorParser.hpp" +#include "rapidcsv.h" +#include "Allocate.h" +#include "CNF.h" + +class Tokenizer { +public: + Tokenizer(const char* buffer) + : m_pBuffer(buffer) {} +public: + std::tuple Advance() { + using TokenTypes = CalculatorParser::TokenTypes; + using TokenValues = CalculatorParser::TokenValues; + while (true) { + if (*m_pBuffer == '\0') + return { TokenTypes::_, TokenValues {} }; + + char c; + switch (c = *(m_pBuffer++)) { + case '&': return { TokenTypes::And, TokenValues {} }; + case '|': return { TokenTypes::Or, TokenValues {} }; + case '(': return { TokenTypes::LeftParen, TokenValues {} }; + case ')': return { TokenTypes::RightParen, TokenValues {} }; + case '~': return { TokenTypes::Not, TokenValues {} }; + case '!': return { TokenTypes::Not, TokenValues {} }; + case '=': + c = *(m_pBuffer++); + if(c != '>') throw std::runtime_error("Bad input"); + return { TokenTypes::Entail, TokenValues {} }; + case '<': + c = *(m_pBuffer++); + if(c != '=') throw std::runtime_error("Bad input"); + c = *(m_pBuffer++); + if(c != '>') { + m_pBuffer--; + return { TokenTypes::rEntail, TokenValues {} }; + } + return { TokenTypes::Equal, TokenValues {} }; + default: + std::string str; + str += c; + while (!isReservedSymbol(*m_pBuffer) && *m_pBuffer != '\0') + str = str + *(m_pBuffer++); + //std::cout << str << std::endl; + Clause clause; + clause.positive = true; + clause.type = Clause::TYPE::UNIT; + clause.vec.push_back(IDManager::getOrAllocate(str)); + return { TokenTypes::LiteralNumber, TokenValues { clause } }; + } + } + } +private: + const char* m_pBuffer; + bool isReservedSymbol(char c) { + return c == '&' || c == '|' || c == '(' + || c == ')' || c == '~' || c == '<' + || c == '=' || c == '>' || c == '!'; + } +}; + +int main() { + try { + rapidcsv::Document doc_1("data/是否必选特征族.csv"); + std::set familyMustChoose; + + for(int i=0; i(i); + + std::string familyName = row[2]; + std::string value = row[3]; + + if(value == "是") { + familyMustChoose.insert(familyName); + } + } + + + rapidcsv::Document doc_2("data/销售配置表.csv"); + + std::map> valuesByFamily; + std::map> valuesByNotForceFamily; + + + for(int i=0; i(i); + + std::string familyName = row[1]; + std::string valueName = row[2]; + std::string chooseFlag = row[3]; + + if(chooseFlag == "-") { + CNF::add(-IDManager::getOrAllocate(valueName)); + CNF::add(0); + } + valuesByFamily[familyName].push_back(valueName); + } + + + + for(auto& [family, vec] : valuesByFamily) { + if(familyMustChoose.find(family) != familyMustChoose.end()) { + for(auto v : vec) { + CNF::add(IDManager::getOrAllocate(v)); + } + CNF::add(0); + } + for(int i=0; i(1); + for(auto& str : constraint) { + if(str == "") continue; + CNF::comment("analyze: " + str); + + Tokenizer tokenizer(str.c_str()); + CalculatorParser parser; + while (true) { + auto [t, v] = tokenizer.Advance(); + + auto ret = parser(t, v); + if (ret == CalculatorParser::ParseResult::Rejected) + throw std::runtime_error("Parse error"); + else if (ret == CalculatorParser::ParseResult::Accepted) { + parser.Result().mergeIntoUNIT(); + CNF::add(parser.Result().vec[0]); + CNF::add(0); + } + + if (t == CalculatorParser::TokenTypes::_) + break; + } + } + + + std::set list; + + auto inf = doc_2.GetColumn(7); + + for(auto& family : inf) { + list.insert(family); + } + + printf("c ind "); + // for(auto& [family, vec] : valuesByFamily) { + // //if(list.find(family) != list.end()) continue; + // for(auto &v : valuesByFamily[family]) { + // printf("%d ", IDManager::getOrAllocate(v)); + // } + // } + for(int i=1; i<=539; i++) { + printf("%d ", i); + } + printf("0\n"); + + CNF::print(); + } + catch (const std::exception& ex) { + std::cerr << ex.what() << std::endl; + return 1; + } + return 0; +} diff --git a/src/ValueType.hpp b/src/ValueType.hpp new file mode 100644 index 0000000..a2cd3ba --- /dev/null +++ b/src/ValueType.hpp @@ -0,0 +1,109 @@ +#pragma once + +#include +#include "Allocate.h" +#include "CNF.h" + +class Clause { +public: + enum class TYPE { + UNIT = 0, + AND = 1, + OR = 2, + }; + + std::vector vec; + TYPE type; + bool positive; + + Clause(): type() { + positive = true; + } + + void mergeIntoUNIT() { + if(type == TYPE::UNIT) return; + + int newId = IDManager::allocate(); + + + std::string output = "MAP: "; + for(int i=0; i +# +# 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 sys +import json +import argparse +import datetime +from typing import List, Set, Dict, Tuple, Optional + + +# ---------------------------------------- 文法解析器部分 ---------------------------------------- +# 文法解析器用于解析文法文件,一个文法文件包含语法的终极符、非终结符和对应的产生式及相关的属性。 +# +# 终结符使用下述方式声明: +# term 标识符 {% 替换 %} ; +# 其中,标识符用于指定终结符的名称,可以由非数字开头的若干数字、字母或者下划线构成(下同),需要注意的是单独的_会被识别为关键词。 +# 替换部分应当填写一个C/C++类型,当语法制导翻译遇到一个标识符时可以给出对应的C/C++类型的值供用户代码使用。 +# 若替换部分留空,则该标识符的值不可在翻译过程中被使用。 +# 此外,为了支撑算符优先冲突解决规则,可以在标识符后面使用关键字 assoc 和 prec 来指定左结合或右结合以及对应的优先级,例如: +# term minus assoc(left) prec(1) {% Tokenizer::Token %}; +# 其中 assoc 可以接 left、right 或者 none,表明左结合、右结合或者无结合性。 +# 需要注意的是,在解决冲突时,如果发现算符无结合性则会产生错误,若不指定结合性,则会按照其他规约规则自动解决冲突。 +# 其中 prec 用于指定算符优先级,算符优先级高的表达式会在移进-规约冲突中被优先选择。 +# +# 非终结符使用下述方式声明: +# nonterm 标识符 {% 替换 %}; +# 具体规则和终结符一致,但是不可以声明结合性或者优先级,其他内容不再赘述。 +# +# 声明完终结符和非终结符后可以声明语法规则,举例如下: +# grammar { +# BinExp -> Exp(lhs) BinOp(op) Exp(rhs) {% return Ast::BinExp(lhs, rhs, op); %}; +# BinOp -> minus {% +# return Ast::BinOp::Minus; +# %}; +# BinOp -> plus {% +# return Ast::BinOp::Plus; +# %}; +# } +# 语法规则定义在Grammar块中,一个产生式具备下述形式: +# 非终结符 -> 符号1 ( 标识符1 ) 符号2 ( 标识符2 ) ... {% 替换 %} ; +# 其中,非终结符指示从哪个终结符推导而来,整个产生式在规约后将会具备该终结符对应的类型。 +# 符号1..n 指示产生式的构成,每个符号可以接一个标识符,将会在生成代码中使用符号对应的类型捕获值给解析器代码使用。 +# 需要注意,首条规则被作为入口规则产生文法。此外如果产生式不规约任何符号,需要使用特殊的语法来声明: +# 非终结符 -> _ {% 替换 %}; +# 另外,为了支持单目运算符的特殊优先级,产生式本身可以指定一个独立的优先级,例如: +# grammar { +# UnaryExp -> minus Exp(rhs) prec(10) {% ... %}; +# } +# 此时,prec 必须在产生式末尾,当生成器在解决 BinExp 和 UnaryExp 的冲突时会优先匹配 UnaryExp。 +# +# 最后,在进行代码生成时,你可以使用 Json 来向生成器传递参数,这些参数会被用于在模板中替换对应的变量: +# generator {% +# { +# "namespace": "Test", +# "class_name": "MyParser" +# } +# %} +# +# 附录:关键词表 +# _ term nonterm grammar generator assoc prec left right none +# +# 附录:规约/移进冲突解决规则: +# 下述规则被依次用于解决规约/移进冲突: +# 1. 尝试使用算符优先和结合性规则进行解决; +# 2. 采取移进规则解决; +# 下述规则被依次用于解决规约/规约冲突: +# 1. 依照生成式的定义顺序解决,先定义的生成式会先被用于解决冲突; +# + +class Symbol: + """ + 符号 + + 标识一个终结符或者非终结符。 + 符号不覆盖__eq__和__hash__,因为在一个实例中应该是唯一的。 + """ + def __init__(self, t: int, id: str, replace: Optional[str] = None, assoc: int = 0, prec: int = 0, line: int=0): + self._type = t + self._id = id + self._replace = None if replace is None else replace.strip() + self._assoc = assoc + self._prec = prec + self._line = line + + def __repr__(self): + return self._id + + def type(self) -> int: + """ + 获取符号类型 + :return: 符号类型 + """ + return self._type + + def id(self) -> str: + """ + 获取标识符 + :return: 标识符 + """ + return self._id + + def replace(self) -> Optional[str]: + """ + 获取替换文本 + :return: 替换文本 + """ + return self._replace + + def associativity(self) -> int: + """ + 获取结合性 + :return: 结合性 + """ + return self._assoc + + def precedence(self) -> int: + """ + 获取优先级 + :return: 优先级 + """ + return self._prec + + def line_defined(self) -> int: + """ + 获取符号在源码中定义的行号 + :return: 行号 + """ + return self._line + + +SYMBOL_TESTER = -2 # special symbol '#', for generating LALR parser +SYMBOL_ENTRY = -1 # special symbol '@', for extending the grammar +SYMBOL_EOF = 0 # special symbol '$' +SYMBOL_TERMINAL = 1 # terminal symbol +SYMBOL_NON_TERMINAL = 2 # non-terminal symbol + +ASSOC_UNDEF = 0 +ASSOC_LEFT = 1 +ASSOC_RIGHT = 2 +ASSOC_NONE = 3 + +kEofSymbol = Symbol(SYMBOL_EOF, "$", "") +kEntrySymbol = Symbol(SYMBOL_ENTRY, "@", "") +kTesterSymbol = Symbol(SYMBOL_TESTER, "#", "") + + +class Production: + """ + 产生式 + + 由一系列符号构成。 + """ + def __init__(self, left: Symbol, right: List[Symbol], binding: Dict[int, str], replace: Optional[str] = None, + prec: int = 0, line: int = -1, index: int = -1): + self._left = left + self._right = right + self._binding = binding + self._replace = replace + self._prec = prec + self._line = line + self._index = index + + def __repr__(self): + if self._prec != 0: + return "%s -> %s prec(%d)" % (repr(self._left), " ".join([repr(x) for x in self._right]), self._prec) + return "%s -> %s" % (repr(self._left), " ".join([repr(x) for x in self._right])) + + def __len__(self): + return len(self._right) + + def __getitem__(self, item): + assert isinstance(item, int) + return self._right[item] + + def __eq__(self, obj) -> bool: # binding, replace, prec, line 不参与比较 + if not isinstance(obj, Production): + return False + if self._left != obj._left: + return False + if len(self._right) != len(obj._right): + return False + for i in range(0, len(self._right)): + if self._right[i] != obj._right[i]: + return False + return True + + def __ne__(self, obj) -> bool: + return not self == obj + + def __hash__(self) -> int: + ret = hash(self._left) + for i in range(0, len(self._right)): + ret = ret ^ hash(self._right[i]) + return ret + + def left(self) -> Symbol: + """ + 获取产生式对应的非终结符 + :return: 非终结符 + """ + return self._left + + def binding(self) -> Dict[int, str]: + """ + 获取绑定参数名的映射情况 + :return: 绑定参数映射表 + """ + return self._binding + + def replace(self) -> Optional[str]: + """ + 获取产生式对应的替代文本 + :return: 替代文本 + """ + return self._replace + + def precedence(self) -> int: + """ + 获取优先级 + :return: 优先级 + """ + return self._prec + + def line_defined(self) -> int: + """ + 获取符号在源码中定义的行号 + :return: 行号 + """ + return self._line + + def index(self) -> int: + """ + 获取产生式在源码中的索引 + :return: 索引 + """ + return self._index + + +class ParseError(Exception): + """ + 解析错误 + """ + def __init__(self, message: str, line: int, col: Optional[int] = None): + Exception.__init__(self, message) + self._message = message + self._line = line + self._col = col + + def __str__(self): + if self._col is not None: + return f"{self._message} (line {self._line}, col {self._col})" + return f"{self._message} (line {self._line})" + + def message(self): + return self._message + + def line(self): + return self._line + + def col(self): + return self._col + + +class SourceReader: + """ + 源代码读取器 + """ + def __init__(self, filename): + with open(filename, "r", encoding="utf-8") as f: + self._content = f.read() + self._pos = 0 + self._line = 1 + self._col = 0 + + def pos(self): + return self._pos + + def line(self): + return self._line + + def col(self): + return self._col + + def peek(self): + if self._pos >= len(self._content): + return '\0' + return self._content[self._pos] + + def read(self): + ch = self.peek() + if ch == '\0': + return ch + self._pos = self._pos + 1 + self._col = self._col + 1 + if ch == '\n': + self._line = self._line + 1 + self._col = 0 + return ch + + def raise_error(self, msg): + raise ParseError(msg, self._line, self._col) + + +TOKEN_EOF = 0 +TOKEN_IDENTIFIER = 1 # 标识符 +TOKEN_LITERAL = 2 # 替换用文本 +TOKEN_INTEGER = 3 # 整数 +TOKEN_EOD = 4 # 分号 ; +TOKEN_DEDUCE = 5 # 推导符号 -> +TOKEN_BEGIN_BLOCK = 6 # { +TOKEN_END_BLOCK = 7 # } +TOKEN_BEGIN_ARG = 8 # ( +TOKEN_END_ARG = 9 # ) +TOKEN_EMPTY = 10 # 关键词 _ +TOKEN_TERM = 11 # 关键词 term +TOKEN_NON_TERM = 12 # 关键词 nonterm +TOKEN_GRAMMAR = 13 # 关键词 grammar +TOKEN_GENERATOR = 14 # 关键词 generator +TOKEN_ASSOC = 15 # 关键词 assoc +TOKEN_PREC = 16 # 关键词 prec +TOKEN_LEFT = 17 # 关键词 left +TOKEN_RIGHT = 18 # 关键词 right +TOKEN_NONE = 19 # 关键词 none + + +class GrammarDocument: + """ + 语法文件 + + 存储语法文件内容并提供解析功能。 + 使用手写的递归下降来实现解析。 + + @mq + - 没有parser gen,要怎么解析语法文件 + - 写parser啊 + - 没有parser gen怎么写parser + - 那就写parser gen + - 写parser gen怎么解析语法规则!! + - 写parser!!! + """ + def __init__(self): + self._productions = [] # type: List[Production] + self._symbols = set() # type: Set[Symbol] + self._terminals = set() # type: Set[Symbol] + self._non_terminals = set() # type: Set[Symbol] + self._generator_args = None # type: Optional[Dict] + + def clear(self): + self._productions = [] # type: List[Production] + self._symbols = set() # type: Set[Symbol] + self._terminals = set() # type: Set[Symbol] + self._non_terminals = set() # type: Set[Symbol] + self._generator_args = None # type: Optional[Dict] + + def productions(self) -> List[Production]: + """ + 获取所有产生式 + :return: 产生式列表 + """ + return self._productions + + def symbols(self) -> Set[Symbol]: + """ + 获取所有符号 + :return: 符号集合 + """ + return self._symbols + + def terminals(self) -> Set[Symbol]: + """ + 获取终结符号 + :return: 终结符号集合 + """ + return self._terminals + + def non_terminals(self) -> Set[Symbol]: + """ + 获取非终结符号 + :return: 非终结符号集合 + """ + return self._non_terminals + + def generator_args(self) -> Optional[Dict]: + """ + 获取生成器参数 + :return: 参数 + """ + return self._generator_args + + @staticmethod + def _advance(reader: SourceReader): + while True: + if reader.peek() == '\0': + return TOKEN_EOF, None, reader.line() + + # 跳过空白 + if reader.peek().isspace(): + while reader.peek().isspace(): + reader.read() + continue + + # 跳过注释 + if reader.peek() == '/': + reader.read() + if reader.peek() != '/': # 当前语法只有'//'的可能 + reader.raise_error(f"'/' expected, but found {repr(reader.peek())}") + reader.read() + while reader.peek() != '\0' and reader.peek() != '\n': # 读到末尾 + reader.read() + continue + + # 符号 + if reader.peek() == ';': + line = reader.line() + reader.read() + return TOKEN_EOD, None, line + elif reader.peek() == '-': + line = reader.line() + reader.read() + if reader.peek() != '>': # 当前语法只有'->'可能 + reader.raise_error(f"'>' expected, but found {repr(reader.peek())}") + reader.read() + return TOKEN_DEDUCE, None, line + elif reader.peek() == '{': + line = reader.line() + reader.read() + if reader.peek() == '%': + reader.read() + content = [] + while True: + if reader.peek() == '%': + reader.read() + if reader.peek() == '}': + reader.read() + break + elif reader.peek() == '%': + reader.read() + content.append('%') + else: + reader.raise_error(f"'%' or '}}' expected, but found {repr(reader.peek())}") + elif reader.peek() == '\0': + reader.raise_error("Unexpected eof") + else: + content.append(reader.read()) + return TOKEN_LITERAL, "".join(content), line + else: + return TOKEN_BEGIN_BLOCK, None, line + elif reader.peek() == '}': + line = reader.line() + reader.read() + return TOKEN_END_BLOCK, None, line + elif reader.peek() == '(': + line = reader.line() + reader.read() + return TOKEN_BEGIN_ARG, None, line + elif reader.peek() == ')': + line = reader.line() + reader.read() + return TOKEN_END_ARG, None, line + + # 关键词/Identifier/数字 + content = [] + if reader.peek().isalpha() or reader.peek() == '_': + line = reader.line() + while reader.peek().isalnum() or reader.peek() == '_': + content.append(reader.read()) + identifier = "".join(content) + if identifier == "_": + return TOKEN_EMPTY, identifier, line + elif identifier == "term": + return TOKEN_TERM, identifier, line + elif identifier == "nonterm": + return TOKEN_NON_TERM, identifier, line + elif identifier == "grammar": + return TOKEN_GRAMMAR, identifier, line + elif identifier == "generator": + return TOKEN_GENERATOR, identifier, line + elif identifier == "assoc": + return TOKEN_ASSOC, identifier, line + elif identifier == "prec": + return TOKEN_PREC, identifier, line + elif identifier == "left": + return TOKEN_LEFT, identifier, line + elif identifier == "right": + return TOKEN_RIGHT, identifier, line + elif identifier == "none": + return TOKEN_NONE, identifier, line + return TOKEN_IDENTIFIER, identifier, line + if reader.peek().isnumeric(): + line = reader.line() + while reader.peek().isnumeric(): + content.append(reader.read()) + return TOKEN_INTEGER, int("".join(content)), line + reader.raise_error(f"Unexpected character '{repr(reader.peek())}'") + + def parse(self, filename): + reader = SourceReader(filename) + symbols = {} + productions = [] + production_set = set() + generator_args = None + while True: + token, value, line = GrammarDocument._advance(reader) + if token == TOKEN_EOF: + break + elif token == TOKEN_TERM: + # read identifier + token, identifier, line = GrammarDocument._advance(reader) + if token != TOKEN_IDENTIFIER: + raise ParseError("Identifier required parsing term statement", line) + if identifier in symbols: + raise ParseError(f"Terminated symbol \"{identifier}\" redefined", line) + replace = None + def_line = line + # read assoc or prec + assoc = None + prec = None + while True: + token, value, line = GrammarDocument._advance(reader) + if token == TOKEN_ASSOC: + if assoc is not None: + raise ParseError("Associate type redefined", line) + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_BEGIN_ARG: + raise ParseError("'(' expected parsing associate type", line) + token, _, line = GrammarDocument._advance(reader) + if token == TOKEN_LEFT: + assoc = ASSOC_LEFT + elif token == TOKEN_RIGHT: + assoc = ASSOC_RIGHT + elif token == TOKEN_NONE: + assoc = ASSOC_NONE + else: + raise ParseError("'left', 'right' or 'none' expected parsing associate type", line) + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_END_ARG: + raise ParseError("')' expected parsing associate type", line) + elif token == TOKEN_PREC: + if prec is not None: + raise ParseError("Precedence redefined", line) + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_BEGIN_ARG: + raise ParseError("'(' expected parsing precedence", line) + token, prec, line = GrammarDocument._advance(reader) + if token != TOKEN_INTEGER: + raise ParseError("Integer expected parsing precedence", line) + if prec == 0: + raise ParseError("Precedence must large than zero", line) + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_END_ARG: + raise ParseError("')' expected parsing associate type", line) + else: + break + # replace + if token == TOKEN_LITERAL: + replace = value + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_EOD: + raise ParseError("End of definition required", line) + if (assoc is not None) and (prec is None): + raise ParseError("Precedence must be defined while associativity defined", def_line) + symbols[identifier] = Symbol(SYMBOL_TERMINAL, identifier, replace, + ASSOC_UNDEF if assoc is None else assoc, + 0 if prec is None else prec, + def_line) + elif token == TOKEN_NON_TERM: + # read identifier + token, identifier, line = GrammarDocument._advance(reader) + if token != TOKEN_IDENTIFIER: + raise ParseError("Identifier required parsing term statement", line) + if identifier in symbols: + raise ParseError(f"Non-terminated symbol \"{identifier}\" redefined", line) + replace = None + def_line = line + # replace + token, value, line = GrammarDocument._advance(reader) + if token == TOKEN_LITERAL: + replace = value + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_EOD: + raise ParseError("End of definition required", line) + symbols[identifier] = Symbol(SYMBOL_NON_TERMINAL, identifier, replace, ASSOC_UNDEF, 0, def_line) + elif token == TOKEN_GRAMMAR: + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_BEGIN_BLOCK: + raise ParseError("'{' required parsing grammar block", line) + while True: + token, identifier, line = GrammarDocument._advance(reader) + if token == TOKEN_END_BLOCK: # } + break + elif token != TOKEN_IDENTIFIER: + raise ParseError("Identifier required parsing production expression", line) + + # identifier + if identifier not in symbols: + raise ParseError(f"Undefined symbol \"{identifier}\" parsing production expression", line) + # -> + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_DEDUCE: + raise ParseError("Deduce operator required parsing production expression", line) + right = [] + replace = None + prec = None + empty_production = False + def_line = line + binding = {} + while True: + token, value, line = GrammarDocument._advance(reader) + if token == TOKEN_EOD: # ; + if not empty_production and len(right) == 0: + raise ParseError("Symbol expected but found ';' parsing production expression", line) + break + elif token == TOKEN_LITERAL: + if not empty_production and len(right) == 0: + raise ParseError("Symbol expected but found replacement literal", line) + replace = value + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_EOD: + raise ParseError("End of definition required parsing production expression", line) + break + elif token == TOKEN_EMPTY: + if len(right) != 0 or (prec is not None): + raise ParseError("Epsilon symbol cannot be placed here parsing production expression", + line) + empty_production = True + elif token == TOKEN_PREC: + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_BEGIN_ARG: + raise ParseError("'(' required parsing precedence", line) + token, prec, line = GrammarDocument._advance(reader) + if token != TOKEN_INTEGER: + raise ParseError("Integer expected parsing precedence", line) + if prec == 0: + raise ParseError("Precedence must large than zero", line) + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_END_ARG: + raise ParseError("')' required parsing precedence", line) + elif token == TOKEN_IDENTIFIER: + if empty_production or (prec is not None): + raise ParseError("Identifier cannot be placed here", line) + if value not in symbols: + raise ParseError(f"Undefined symbol \"{value}\"", line) + right.append(symbols[value]) + elif token == TOKEN_BEGIN_ARG: + if len(right) == 0: + raise ParseError("Symbol required for binding argument name", line) + if right[len(right) - 1].replace() is None: + raise ParseError("Symbol don't have type for binding", line) + token, arg_id, line = GrammarDocument._advance(reader) + if token != TOKEN_IDENTIFIER: + raise ParseError("Identifier required parsing binding argument", line) + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_END_ARG: + raise ParseError("')' expected parsing binding argument", line) + binding[len(right) - 1] = arg_id + else: + raise ParseError("Unexpected token", line) + assert len(right) > 0 or empty_production + # calc prec if user not defined + if prec is None: + for e in reversed(right): + if e.type() == SYMBOL_TERMINAL: + prec = e.precedence() + if prec is None: + prec = 0 + production = Production(symbols[identifier], right, binding, replace, prec, def_line, + len(productions)) + if production in production_set: + raise ParseError(f"Production \"{production}\" redefined", def_line) + if (production.left().replace() is not None) and (production.replace() is None): + raise ParseError(f"Action body expected for production \"{production}\"", def_line) + productions.append(production) + production_set.add(production) + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_EOD: + raise ParseError("End of definition required parsing grammar block", line) + elif token == TOKEN_GENERATOR: + if generator_args is not None: + raise ParseError("Generator arguments is redefined", line) + try: + token, json_args, line = GrammarDocument._advance(reader) + except Exception as ex: + raise ParseError(f"Parsing json error parsing generator block: {ex}", line) + if token != TOKEN_LITERAL: + raise ParseError("String literal required parsing generator block", line) + token, _, line = GrammarDocument._advance(reader) + if token != TOKEN_EOD: + raise ParseError("';' expected parsing generator block", line) + generator_args = json.loads(json_args) + else: + raise ParseError("Unexpected token", line) + self._productions = productions + self._symbols = set([symbols[s] for s in symbols]) + self._terminals = set([s for s in self._symbols if s.type() == SYMBOL_TERMINAL]) + self._non_terminals = set([s for s in self._symbols if s.type() == SYMBOL_NON_TERMINAL]) + self._generator_args = generator_args + +# ---------------------------------------- LR(1)/LALR分析器部分 ---------------------------------------- +# LR(1)/LALR分析器用于解算状态转移矩阵。 +# 通过对文法进行LR分析,可以得到类似下图的转换矩阵: +# x opt eq $ | S E V +# 0 s2 s4 | +# 1 a | +# 2 r3 r3 | +# 3 s2 s4 | g8 g7 +# ……下略 +# 其中,表头表示向前看符号,每一行代表一个解析器状态,每一个格表明在看到下一个输入符号时需要进行的动作: +# sX 表明一个移进操作,在移入下一个符号后跳转到状态X +# rX 表明一个规约操作,在看到当前符号时按照产生式X进行规约,弹出解析栈顶部的|X|个元素 +# gX 表明在规约操作后,在看到栈顶符号为这个格子对应的符号时,转移状态到X状态 +# 同时分析器会依据之前的规则对 SR冲突、RR冲突 进行解决 + + +class ExtendProduction: + """ + 扩展生成式(项) + + 增加当前位置和向前看符号来计算闭包。 + """ + def __init__(self, raw: Production, pos: int, lookahead: Set[Symbol]): + assert len(raw) >= pos + self._production = raw + self._pos = pos + self._lookahead = lookahead + + def __repr__(self): + right = [repr(x) for x in self._production] + right.insert(self._pos, "·") + return "(%s -> %s, %s)" % (repr(self._production.left()), " ".join(right), self._lookahead) + + def __len__(self): + return len(self._production) + + def __getitem__(self, item): + assert isinstance(item, int) + return self._production[item] + + def __eq__(self, obj) -> bool: + if not isinstance(obj, ExtendProduction): + return False + if self._pos != obj._pos: + return False + if self._production != obj._production: + return False + if self._lookahead != obj._lookahead: + return False + return True + + def __ne__(self, obj) -> bool: + return not self == obj + + def __hash__(self) -> int: + ret = hash(self._pos) + for x in self._lookahead: + ret = ret ^ hash(x) + ret = ret ^ hash(self._production) + return ret + + def production(self) -> Production: + """ + 获取原始产生式 + :return: 产生式 + """ + return self._production + + def pos(self) -> int: + """ + 获取当前分析位置 + :return: 位置 + """ + return self._pos + + def lookahead(self) -> Set[Symbol]: + """ + 关联的向前看符号 + :return: 符号 + """ + return self._lookahead + + +class ExtendProductionSet: + """ + 扩展生成式集合(项集) + """ + def __init__(self, s: Set[ExtendProduction], state_id: Optional[int]): + self._set = s + self._state = state_id + + def __len__(self): + return len(self._set) + + def __eq__(self, obj) -> bool: # state_id不参与比较 + if not isinstance(obj, ExtendProductionSet): + return False + return self._set == obj._set + + def __ne__(self, obj) -> bool: + return not self == obj + + def __hash__(self) -> int: + ret = 0 + for x in self._set: + ret = ret ^ hash(x) + return ret + + def __iter__(self): + return iter(self._set) + + def __repr__(self): + ret = ["["] + for e in self._set: + ret.append(f" {repr(e)}") + ret.append("]") + return "\n".join(ret) + + def state(self): + """ + 获取状态ID + :return: 状态ID + """ + return self._state + + def set_state(self, state): + """ + 设置状态ID + """ + self._state = state + + def add(self, x: ExtendProduction): + """ + 向集合添加产生式 + :param x: 产生式 + """ + self._set.add(x) + + def union(self, x): + """ + 合并其他集合 + :param x: 集合 + """ + if isinstance(x, set): + self._set = self._set.union(x) + else: + assert isinstance(x, ExtendProductionSet) + self._set = self._set.union(x._set) + + def clone(self): + """ + 产生副本 + :return: 项集 + """ + return ExtendProductionSet(set(self._set), self._state) + + +ACTION_ACCEPT = 1 +ACTION_GOTO = 2 # Shift和Goto可以用一个动作表示,因为对于非终结符总是Goto的,对于终结符总是Shift的 +ACTION_REDUCE = 3 # 规约动作 + + +class Action: + """ + 语法动作 + """ + def __init__(self, action: int, arg, ref_state: ExtendProductionSet, ref_symbol: Symbol, + ref_prod: Optional[ExtendProduction]): + self._action = action + self._arg = arg + self._ref_state = ref_state + self._ref_symbol = ref_symbol + self._ref_prod = ref_prod + + # 参数检查 + if action == ACTION_GOTO: + assert isinstance(arg, ExtendProductionSet) + elif action == ACTION_REDUCE: + assert isinstance(arg, Production) + assert arg.index() >= 0 + + def __repr__(self): + if self._action == ACTION_ACCEPT: + return "a" + elif self._action == ACTION_GOTO: + assert isinstance(self._arg, ExtendProductionSet) + if self._ref_symbol.type() == SYMBOL_NON_TERMINAL: + return f"g{self._arg.state()}" + else: + return f"s{self._arg.state()}" + elif self._action == ACTION_REDUCE: + assert isinstance(self._arg, Production) + return f"r{self._arg.index()}" + return "" + + def action(self) -> int: + """ + 获取动作 + :return: 动作 + """ + return self._action + + def arg(self): + """ + 获取动作参数 + :return: 参数 + """ + return self._arg + + def ref_state(self) -> ExtendProductionSet: + """ + 获取关联的状态集合 + :return: 项集 + """ + return self._ref_state + + def ref_symbol(self) -> Symbol: + """ + 获取关联的符号 + :return: 符号 + """ + return self._ref_symbol + + def ref_prod(self) -> Optional[ExtendProduction]: + """ + 获取关联的生成式 + + 对于Shift操作不存在关联的生成式。 + :return: 项 + """ + return self._ref_prod + + +class GrammarError(Exception): + """ + 解析错误 + """ + def __init__(self, message: str): + Exception.__init__(self, message) + self._message = message + + def message(self): + return self._message + + +GRAMMAR_MODE_LR1 = 0 +GRAMMAR_MODE_LALR = 1 + + +class GrammarAnalyzer: + def __init__(self, document: GrammarDocument): + self._doc = document + + # 初始化 NullableSet、FirstSet 和 FollowSet 并计算 + # 注意这个 Set 会包含 kEofSymbol + self._nullable_set = {} # type: Dict[Symbol, bool] + self._first_set = {} # type: Dict[Symbol, Set[Symbol]] + self._follow_set = {} # type: Dict[Symbol, Set[Symbol]] + self._analyze_nullable_first_follow_set() + + # 初始化扩展符号表 + self._extend_symbols = set(self._doc.symbols()) # type: Set[Symbol] + self._extend_symbols.add(kEofSymbol) + + # 初始化分析动作表 + self._actions = {} # type: Dict[Symbol, Dict[int, Action]] + self._max_state = 0 # 最大的状态ID + self._resolve_rr_conflict = 0 # 解决Reduce/Reduce冲突的次数 + self._resolve_sr_conflict_by_prec = 0 # 解决Reduce/Shift冲突的次数(通过算符优先) + self._resolve_sr_conflict_by_shift = 0 # 解决Reduce/Shift冲突的次数(通过Shift优先) + self._reset_actions() + + def _analyze_nullable_first_follow_set(self): + # 对所有产生式执行拓扑排序的计算,并按照出度从小到大排序 + toposort_states = {} # type: Dict[Symbol, Dict] + toposort_results = [] # type: List[Production] + + # 初始化数据集 + for s in self._doc.non_terminals(): + toposort_states[s] = { + "out": 0, # 出度 + "from": [], # 入度 + "visited": False, # 是否已处理 + "productions": [], # 从当前非终结符号导出的产生式 + } + for p in self._doc.productions(): + toposort_states[p.left()]["productions"].append(p) + for i in range(0, len(p)): + if p[i].type() == SYMBOL_NON_TERMINAL: + toposort_states[p.left()]["out"] += 1 + toposort_states[p[i]]["from"].append(toposort_states[p.left()]) + + # 迭代进行拓扑排序直到集合为空 + while len(toposort_results) < len(self._doc.productions()): + refs_min = None + for k in toposort_states: # 寻找一个出度最小节点 + state = toposort_states[k] + if state["visited"]: + continue + if refs_min is None or state["out"] < refs_min["out"]: + refs_min = state + assert refs_min is not None + toposort_results.extend(refs_min["productions"]) # 将当前节点的产生式放入队列 + # 从集合中隐藏当前节点 + refs_min["visited"] = True + for e in refs_min["from"]: + e["out"] -= 1 + assert e["out"] >= 0 + assert len(toposort_results) == len(self._doc.productions()) + + # 初始化集合 + nullable_set = {kEofSymbol: False} # type: Dict[Symbol, bool] + first_set = {kEofSymbol: {kEofSymbol}} # type: Dict[Symbol, Set[Symbol]] + follow_set = {kEofSymbol: set()} # type: Dict[Symbol, Set[Symbol]] + for s in self._doc.symbols(): + nullable_set[s] = False + first_set[s] = {s} if s.type() == SYMBOL_TERMINAL else set() + follow_set[s] = set() + + # 迭代到不动点计算NULLABLE、FIRST集合和FOLLOW集合 + while True: + stopped = True + for p in toposort_results: + s = p.left() + + # 检查产生式是否可空,即产生式中所有项都可空能推导出当前的非终结符可空 + if not nullable_set[s]: # 对于已经认为可空的永远不会变为非可空 + nullable = True + for i in range(0, len(p)): + if not nullable_set[p[i]]: # 非空 + nullable = False + break + if nullable_set[s] != nullable: + nullable_set[s] = nullable + stopped = False + + # 计算FIRST集 + first = set(first_set[s]) + for i in range(0, len(p)): + # 若 p[0..i] 都可空,那么 first[s] = first[s] ∪ first[p[i]] + prefix_nullable = True + for j in range(0, i): + if not nullable_set[p[j]]: + prefix_nullable = False + break + if prefix_nullable: + first = first.union(first_set[p[i]]) + else: + break # 如果中间出现过不可空的,则无需继续看 + if first_set[s] != first: + first_set[s] = first + stopped = False + + # 计算FOLLOW集 + for i in range(0, len(p)): + x = p[i] # 注意此时计算的目标是产生式中的每个项 + follow = set(follow_set[x]) # copy + # 若 p[i+1..len(p)] 都可空,那么 follow[x] = follow[x] ∪ follow[s] + postfix_nullable = True + for j in range(i + 1, len(p)): + if not nullable_set[p[j]]: + postfix_nullable = False + break + if postfix_nullable: + follow = follow.union(follow_set[s]) + # 若 p[i+1..j] 都可空,那么 follow[x] = follow[x] ∪ first[j] + for j in range(i + 1, len(p)): + inner_nullable = True + for k in range(i + 1, j): + if not nullable_set[p[k]]: + inner_nullable = False + break + if inner_nullable: + follow = follow.union(first_set[p[j]]) + if follow_set[x] != follow: + follow_set[x] = follow + stopped = False + if stopped: + break + self._nullable_set = nullable_set + self._first_set = first_set + self._follow_set = follow_set + + def _reset_actions(self): + for s in self._extend_symbols: + self._actions[s] = {} + self._max_state = 0 + self._resolve_rr_conflict = 0 + self._resolve_sr_conflict_by_prec = 0 + self._resolve_sr_conflict_by_shift = 0 + + def _closure(self, org: ExtendProductionSet) -> ExtendProductionSet: + """ + 求项集的闭包 + :param org: 原始项集 + :return: 项集的闭包 + """ + ret = org.clone() # copy + ret.set_state(-1) # 需要外部重新赋予状态ID + add = set() + while True: + for e in ret: + if e.pos() >= len(e.production()): + continue + + x = e.production()[e.pos()] + if x.type() == SYMBOL_TERMINAL: + continue + if x.type() == SYMBOL_EOF: + assert (len(e.lookahead()) == 0) + continue + assert(x.type() != SYMBOL_ENTRY) + + # 计算 FIRST 集 + first = set() + for i in range(e.pos() + 1, len(e.production()) + 1): + # 若 p[cur+1..i] 都可空,那么 first[X] = first[X] ∪ first[p[i]] + prefix_nullable = True + for j in range(e.pos() + 1, i): + if not self._nullable_set[e.production()[j]]: + prefix_nullable = False + break + if prefix_nullable: + if i == len(e.production()): + first = first.union(e.lookahead()) + else: + first = first.union(self._first_set[e.production()[i]]) + else: + break # 如果中间出现过不可空的,则无需继续看 + + # 展开终结符 + for p in self._doc.productions(): + if p.left() == x: + for w in first: + item = ExtendProduction(p, 0, {w}) + if item not in ret and item not in add: + add.add(item) + + if len(add) == 0: + break + ret.union(add) + add.clear() + return ret + + def _goto(self, org: ExtendProductionSet, x: Symbol) -> ExtendProductionSet: + """ + 求项集在符号 X 下可以转移到的状态 + :param org: 原始项集 + :param x: 转移符号 + :return: 输出状态 + """ + ret = set() + for e in org: + if e.pos() >= len(e.production()): + continue + s = e.production()[e.pos()] + if s != x: + continue + p = ExtendProduction(e.production(), e.pos() + 1, e.lookahead()) + if p not in ret: + ret.add(p) + return self._closure(ExtendProductionSet(ret, -1)) # 需要外部重新赋予状态ID + + def _populate_action(self, s: Symbol, state: int, act: Action): + if state in self._actions[s]: # 冲突解决 + raise_error = True + conflict_type = 0 # 0: unknown 1: shift/shift冲突 2:shift/reduce冲突 3:reduce/reduce冲突 + conflict_args = () + org_action = self._actions[s][state] + assert state == org_action.ref_state().state() + + # 如果存在Shift/Shift冲突,则抛出错误 + if org_action.action() == ACTION_GOTO and act.action() == ACTION_GOTO: + assert isinstance(org_action.arg(), ExtendProductionSet) + assert isinstance(act.arg(), ExtendProductionSet) + conflict_type = 1 + conflict_args = (s, org_action.ref_state().state(), org_action.arg(), act.arg()) + + # 针对Reduce/Reduce的情况,选择优先出现的规则 + if org_action.action() == ACTION_REDUCE and act.action() == ACTION_REDUCE: + assert isinstance(org_action.arg(), Production) + assert isinstance(act.arg(), Production) + assert org_action.arg().index() != act.arg().index() + conflict_type = 3 + conflict_args = (s, org_action.ref_state().state(), org_action.arg(), act.arg()) + raise_error = False + self._resolve_rr_conflict += 1 + if act.arg().index() > org_action.arg().index(): + return # 不接受在后面的产生式 + + # 针对Reduce/Shift的情况 + if (org_action.action() == ACTION_REDUCE and act.action() == ACTION_GOTO) or \ + (org_action.action() == ACTION_GOTO and act.action() == ACTION_REDUCE): + if org_action.action() == ACTION_REDUCE: + reduce_action = org_action + shift_action = act + else: + reduce_action = act + shift_action = org_action + reduce_production = reduce_action.arg() # type: Production + shift_state = shift_action.arg() # type: ExtendProductionSet + assert isinstance(reduce_production, Production) + assert isinstance(shift_state, ExtendProductionSet) + assert shift_action.ref_symbol() == s + assert s.type() != SYMBOL_NON_TERMINAL # 非终结符不可能出现SR冲突 + conflict_type = 2 + conflict_args = (s, org_action.ref_state().state(), reduce_production) + + accept_reduce = None + raise_error = False + + # 首先尝试算符优先 + # 语法规则保证定义了结合性时必然定义了算符优先级,对于没有定义算符优先级的表达式/符号不会通过算符优先方式解决 + if s.type() == SYMBOL_TERMINAL and s.precedence() > 0 and reduce_production.precedence() > 0: + # 如果优先级一致,则考虑结合性 + if s.precedence() == reduce_production.precedence(): + # 找到Reduce产生式的符号获取结合性 + reduce_symbol = None + for i in range(len(reduce_production) - 1, -1, -1): + if reduce_production[i].type() == SYMBOL_TERMINAL: + reduce_symbol = reduce_production[i] + break + assert reduce_symbol is not None + + if reduce_symbol.associativity() == ASSOC_NONE or s.associativity() == ASSOC_NONE: + # 没有结合性,报错 + raise_error = True + elif reduce_symbol.associativity() == ASSOC_UNDEF or s.associativity() == ASSOC_UNDEF: + # 未定义结合性,回退到Shift优先规则 + pass + elif reduce_symbol.associativity() != s.associativity(): + # 结合性不一致,报错 + raise_error = True + else: + # 结合性一致,按照结合性解决SR冲突 + assert reduce_symbol.associativity() == s.associativity() + + # 如果为左结合,则采取Reduce操作,否则采取Shift操作 + if s.associativity() == ASSOC_LEFT: + accept_reduce = True + else: + assert s.associativity() == ASSOC_RIGHT + accept_reduce = False + self._resolve_sr_conflict_by_prec += 1 + else: # 优先级不一致,选择优先级高的进行reduce/shift + if reduce_production.precedence() > s.precedence(): + accept_reduce = True + else: + accept_reduce = False + self._resolve_sr_conflict_by_prec += 1 + + # 在算符优先也没有解决的情况下,优先使用Shift规则 + if (accept_reduce is None) and (not raise_error): + accept_reduce = False + self._resolve_sr_conflict_by_shift += 1 + + # 最终决定是否接受覆盖 + if accept_reduce is not None: + assert not raise_error + if accept_reduce and reduce_action == org_action: + return + elif not accept_reduce and reduce_action == act: + return + + assert conflict_type != 0 + if raise_error: # 未能解决冲突 + if conflict_type == 1: + raise GrammarError(f"Shift/shift conflict detected, symbol {repr(conflict_args[0])}, state: " + f"{repr(conflict_args[1])}, shift state 1: {repr(conflict_args[2])}, " + f"shift state 2: {repr(conflict_args[3])}") + elif conflict_type == 2: + raise GrammarError(f"Shift/reduce conflict detected, state: {repr(conflict_args[1])}, " + f"shift symbol: {repr(conflict_args[0])}, reduce production: " + f"{repr(conflict_args[2])}") + elif conflict_type == 3: + assert False # Reduce/reduce冲突总能被解决 + self._actions[s][state] = act # 覆盖状态 + + def _process_lr1(self): + # 以首个规则作为入口 + entry_production = Production(kEntrySymbol, [self._doc.productions()[0].left(), kEofSymbol], {}) + entry_production_ex = ExtendProduction(entry_production, 0, set()) + entry_item_set = self._closure(ExtendProductionSet({entry_production_ex}, -1)) + entry_item_set.set_state(0) # 首个状态 + + # 初始化状态 + next_state = 1 + states = {entry_item_set: entry_item_set.state()} # type: Dict[ExtendProductionSet, int] + q = [entry_item_set] # type: List[ExtendProductionSet] + + # 计算动作表 + while len(q) > 0: + state = q.pop(0) + assert states[state] == state.state() + + # 填写规约动作 + for p in state: + if p.pos() >= len(p.production()): + for x in p.lookahead(): + action = Action(ACTION_REDUCE, p.production(), state, x, p) + self._populate_action(x, state.state(), action) + + # 计算Shift/Goto/Accept + for x in self._extend_symbols: + goto = self._goto(state, x) + if len(goto) == 0: + continue + if x == kEofSymbol: + for p in goto: + if p.pos() >= len(p.production()): + action = Action(ACTION_ACCEPT, None, state, x, p) + self._populate_action(x, state.state(), action) + else: + assert False # 经由Eof推导出的状态只能是Reduce,不可能出现其他情况 + else: + if goto in states: + goto.set_state(states[goto]) + else: + goto.set_state(next_state) + next_state += 1 + states[goto] = goto.state() + q.append(goto) + assert goto.state() != -1 + action = Action(ACTION_GOTO, goto, state, x, None) + self._populate_action(x, state.state(), action) + self._max_state = next_state - 1 + + def document(self): + """ + 获取原始语法文件 + :return: 文档对象 + """ + return self._doc + + def actions(self): + """ + 获取计算后的动作表 + :return: 动作转换表 + """ + return self._actions + + def max_state(self): + """ + 获取最大的状态ID + """ + return self._max_state + + def printable_actions(self) -> str: + """ + 获取可打印动作表 + :return: 字符串结果 + """ + ret = [] + header = [None] # 表头 + for s in self._doc.terminals(): + header.append(s) + header.append(kEofSymbol) + for s in self._doc.non_terminals(): + header.append(s) + min_width = len(str(self._max_state)) + 1 + header_width = [max(min_width, len(s.id()) if s is not None else 0) for s in header] + + # 打印表头 + ret.append(" | ".join([header[i].id().rjust(header_width[i]) if header[i] is not None else + "".rjust(header_width[i]) for i in range(0, len(header))])) + + # 打印所有行 + for s in range(0, self._max_state + 1): + empty = True + data = [] + for i in range(0, len(header)): + if i == 0: + data.append(str(s).rjust(header_width[i])) + else: + if s in self._actions[header[i]]: + data.append(repr(self._actions[header[i]][s]).rjust(header_width[i])) + empty = False + else: + data.append("".rjust(header_width[i])) + if not empty: + ret.append(" | ".join(data)) + return "\n".join(ret) + + def process(self, mode): + """ + 处理语法 + :param mode: 语法模式 + """ + self._reset_actions() + if mode == GRAMMAR_MODE_LR1: + self._process_lr1() + else: + assert mode == GRAMMAR_MODE_LALR + # TODO + raise NotImplementedError() + + def resolve_stat(self) -> Tuple[int, int, int]: + return self._resolve_rr_conflict, self._resolve_sr_conflict_by_prec, self._resolve_sr_conflict_by_shift + +# ---------------------------------------- 模板渲染器 ---------------------------------------- +# 见 https://github.com/9chu/et-py + + +class TemplateNode: + def __init__(self, parent): + self.parent = parent + self.nodes = [] + + def render(self, context): + pass + + +class TemplateForNode(TemplateNode): + def __init__(self, parent, identifier, expression): + TemplateNode.__init__(self, parent) + self.identifier = identifier + self.expression = expression + + def render(self, context): + result = eval(self.expression, None, context) + origin = context[self.identifier] if self.identifier in context else None + for i in result: + context[self.identifier] = i + yield iter(self.nodes) + if origin: + context[self.identifier] = origin + + +class TemplateIfNode(TemplateNode): + def __init__(self, parent, expression): + TemplateNode.__init__(self, parent) + self.expression = expression + self.true_branch = self.nodes + + def render(self, context): + test = eval(self.expression, None, context) + if test: + yield iter(self.true_branch) + + +class TemplateIfElseNode(TemplateNode): + def __init__(self, parent, if_node): # extent from IfNode + TemplateNode.__init__(self, parent) + self.expression = if_node.expression + self.true_branch = if_node.true_branch + self.false_branch = self.nodes + + def render(self, context): + test = eval(self.expression, None, context) + if test: + yield iter(self.true_branch) + else: + yield iter(self.false_branch) + + +class TemplateExpressionNode(TemplateNode): + def __init__(self, parent, expression): + TemplateNode.__init__(self, parent) + self.expression = expression + + def render(self, context): + return eval(self.expression, None, context) + + +class TextConsumer: + def __init__(self, text): + self._text = text + self._len = len(text) + self._pos = 0 + self._line = 1 + self._row = 0 + + def get_pos(self): + return self._pos + + def get_line(self): + return self._line + + def get_row(self): + return self._row + + def read(self): + if self._pos >= self._len: + return '\0' + ch = self._text[self._pos] + self._pos += 1 + self._row += 1 + if ch == '\n': + self._line += 1 + self._row = 0 + return ch + + def peek(self, advance=0): + if self._pos + advance >= self._len: + return '\0' + return self._text[self._pos + advance] + + def substr(self, begin, end): + return self._text[begin:end] + + +class TemplateParser: + OUTER_TOKEN_LITERAL = 1 + OUTER_TOKEN_EXPRESS = 2 + + RESERVED = ["and", "as", "assert", "break", "class", "continue", "def", "del", "elif", "else", "except", "exec", + "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", "not", "or", "pass", "print", + "raise", "return", "try", "while", "with", "yield"] + + def __init__(self, text): + self._text = text + self._consumer = TextConsumer(text) + + @staticmethod + def _is_starting_by_new_line(text): + for i in range(0, len(text)): + ch = text[i:i + 1] + if ch == '\n': + return True + elif not ch.isspace(): + break + return False + + @staticmethod + def _is_ending_by_new_line(text): + for i in range(len(text) - 1, -1, -1): + ch = text[i:i + 1] + if ch == '\n': + return True + elif not ch.isspace(): + break + return False + + @staticmethod + def _trim_left_until_new_line(text): + for i in range(0, len(text)): + ch = text[i:i+1] + if ch == '\n': + return text[i+1:] + elif not ch.isspace(): + break + return text + + @staticmethod + def _trim_right_until_new_line(text): + for i in range(len(text) - 1, -1, -1): + ch = text[i:i+1] + if ch == '\n': + return text[0:i+1] # save right \n + elif not ch.isspace(): + break + return text + + @staticmethod + def _parse_blank(consumer): + while consumer.peek().isspace(): # 跳过所有空白 + consumer.read() + + @staticmethod + def _parse_identifier(consumer): + ch = consumer.peek() + if not (ch.isalpha() or ch == '_'): + return "" + chars = [consumer.read()] # ch + ch = consumer.peek() + while ch.isalnum() or ch == '_': + chars.append(consumer.read()) # ch + ch = consumer.peek() + return "".join(chars) + + @staticmethod + def _parse_inner(content, line, row): + """内层解析函数 + 考虑到表达式解析非常费力不讨好,这里采用偷懒方式进行。 + 表达式全部交由python自行解决,匹配仅匹配开头,此外不处理注释(意味着不能在表达式中包含注释内容)。 + 当满足 for in <...> 时产生 for节点 + 当满足 if <...> 时产生 if节点 + 当满足 elif <...> 时产生 elif节点 + 当满足 else 时产生 else节点 + 当满足 end 时产生 end节点 + :param content: 内层内容 + :param line: 起始行 + :param row: 起始列 + :return: 节点名称, 表达式部分, 可选的Identifier + """ + consumer = TextConsumer(content) + TemplateParser._parse_blank(consumer) + operator = TemplateParser._parse_identifier(consumer) + identifier = None + if operator == "for": + TemplateParser._parse_blank(consumer) + identifier = TemplateParser._parse_identifier(consumer) + if identifier == "" or (identifier in TemplateParser.RESERVED): + raise ParseError("Identifier expected", consumer.get_line() + line - 1, + consumer.get_row() + row if consumer.get_line() == 1 else consumer.get_row()) + TemplateParser._parse_blank(consumer) + if TemplateParser._parse_identifier(consumer) != "in": + raise ParseError("Keyword 'in' expected", consumer.get_line() + line - 1, + consumer.get_row() + row if consumer.get_line() == 1 else consumer.get_row()) + TemplateParser._parse_blank(consumer) + expression = content[consumer.get_pos():] + if expression == "": + raise ParseError("Expression expected", consumer.get_line() + line - 1, + consumer.get_row() + row if consumer.get_line() == 1 else consumer.get_row()) + elif operator == "if" or operator == "elif": + TemplateParser._parse_blank(consumer) + expression = content[consumer.get_pos():] + if expression == "": + raise ParseError("Expression expected", consumer.get_line() + line - 1, + consumer.get_row() + row if consumer.get_line() == 1 else consumer.get_row()) + elif operator == "end" or operator == "else": + TemplateParser._parse_blank(consumer) + expression = content[consumer.get_pos():] + if expression != '': + raise ParseError("Unexpected content", consumer.get_line() + line - 1, + consumer.get_row() + row if consumer.get_line() == 1 else consumer.get_row()) + else: + operator = "" + expression = content + return operator, expression.strip(), identifier + + def _parse_outer(self): + """外层解析函数 + 将输入拆分成字符串(Literal)和表达式(Expression)两个组成。 + 遇到'{%'开始解析Expression,在解析Expression时允许使用'%%'转义,即'%%'->'%',这使得'%%>'->'%>'而不会结束表达式。 + :return: 类型, 内容, 起始行, 起始列 + """ + begin = self._consumer.get_pos() + end = begin # [begin, end) + begin_line = self._consumer.get_line() + begin_row = self._consumer.get_row() + ch = self._consumer.peek() + while ch != '\0': + if ch == '{': + ahead = self._consumer.peek(1) + if ahead == '%': + if begin != end: + return TemplateParser.OUTER_TOKEN_LITERAL, self._consumer.substr(begin, end), begin_line, \ + begin_row + self._consumer.read() # { + self._consumer.read() # % + begin_line = self._consumer.get_line() + begin_row = self._consumer.get_row() + chars = [] + while True: + ch = self._consumer.read() + if ch == '\0': + raise ParseError("Unexpected eof", self._consumer.get_line(), self._consumer.get_row()) + elif ch == '%': + if self._consumer.peek() == '}': # '%}' + self._consumer.read() + return TemplateParser.OUTER_TOKEN_EXPRESS, "".join(chars), begin_line, begin_row + elif self._consumer.peek() == '%': # '%%' -> '%' + self._consumer.read() + chars.append(ch) + self._consumer.read() + ch = self._consumer.peek() + end = self._consumer.get_pos() + return TemplateParser.OUTER_TOKEN_LITERAL, self._consumer.substr(begin, end), begin_line, begin_row + + @staticmethod + def _trim_empty_line(result): + state = 0 + left = None # 需要剔除右边的元素 + for i in range(0, len(result)): + cur = result[i] + p = result[i - 1] if i != 0 else None + n = result[i + 1] if i != len(result) - 1 else None + if state == 0: + # 当前是表达式,且上一个是文本 + if cur[0] == TemplateParser.OUTER_TOKEN_EXPRESS: + if p is None or (p[0] == TemplateParser.OUTER_TOKEN_LITERAL and + TemplateParser._is_ending_by_new_line(p[1])): + left = i - 1 if p else None + state = 1 + if state == 1: + if n is None or (n[0] == TemplateParser.OUTER_TOKEN_LITERAL and + TemplateParser._is_starting_by_new_line(n[1])): + right = i + 1 if n else None + if left is not None: + result[left] = (result[left][0], + TemplateParser._trim_right_until_new_line(result[left][1]), + result[left][2], + result[left][3]) + if right is not None: + result[right] = (result[right][0], + TemplateParser._trim_left_until_new_line(result[right][1]), + result[right][2], + result[right][3]) + state = 0 + elif cur[0] != TemplateParser.OUTER_TOKEN_EXPRESS: # 行中有其他文本,不进行剔除 + state = 0 + + def process(self): + root = [] # 根 + nodes = [] # 未闭合节点队列 + outer_results = [] + while True: # 为了剔除空行,需要先解析完所有的根元素做预处理 + ret = self._parse_outer() + if ret[0] == TemplateParser.OUTER_TOKEN_LITERAL and ret[1] == "": # EOF + break + outer_results.append(ret) + TemplateParser._trim_empty_line(outer_results) + for i in outer_results: + (t, content, line, row) = i + back = None if len(nodes) == 0 else nodes[len(nodes) - 1] + if t == TemplateParser.OUTER_TOKEN_LITERAL: + root.append(content) if back is None else back.nodes.append(content) + else: + assert t == TemplateParser.OUTER_TOKEN_EXPRESS + (operator, expression, identifier) = self._parse_inner(content, line, row) + if operator == "for": + node = TemplateForNode(back, identifier, expression) + root.append(node) if back is None else back.nodes.append(node) + nodes.append(node) + elif operator == "if": + node = TemplateIfNode(back, expression) + root.append(node) if back is None else back.nodes.append(node) + nodes.append(node) + elif operator == "else": + if not isinstance(back, TemplateIfNode): + raise ParseError("Unexpected else branch", line, row) + node = TemplateIfElseNode(back.parent, back) + # 从root或者父节点中删除back + if back.parent is None: + assert root[len(root) - 1] == back + root.pop() + root.append(node) + else: + parent_nodes = back.parent.nodes + assert parent_nodes[len(parent_nodes) - 1] == back + parent_nodes.pop() + parent_nodes.append(node) + # 升级并取代 + nodes.pop() + nodes.append(node) + elif operator == "elif": + if not isinstance(back, TemplateIfNode): + raise ParseError("Unexpected elif branch", line, row) + closed_else = TemplateIfElseNode(back.parent, back) + # 从root或者父节点中删除back + if back.parent is None: + assert root[len(root) - 1] == back + root.pop() + root.append(closed_else) + else: + parent_nodes = back.parent.nodes + assert parent_nodes[len(parent_nodes) - 1] == back + parent_nodes.pop() + parent_nodes.append(closed_else) + node = TemplateIfNode(closed_else, expression) + closed_else.nodes.append(node) + # 取代 + nodes.pop() + nodes.append(node) + elif operator == "end": + if back is None: + raise ParseError("Unexpected block end", line, row) + nodes.pop() # 完成一个节点 + else: + assert operator == "" + node = TemplateExpressionNode(back, expression) + root.append(node) if back is None else back.nodes.append(node) + if len(nodes) != 0: + raise ParseError("Unclosed block", self._consumer.get_line(), self._consumer.get_row()) + return root + + +def render_template(template, **context): + p = TemplateParser(template) + root = p.process() + output = [] + stack = [iter(root)] + while stack: + node = stack.pop() + if isinstance(node, str): + output.append(node) + elif isinstance(node, TemplateExpressionNode): + output.append(str(node.render(context))) + elif isinstance(node, TemplateNode): + stack.append(node.render(context)) + else: + new_node = next(node, None) + if new_node is not None: + stack.append(node) + stack.append(new_node) + return "".join(output) + + +# ---------------------------------------- 代码生成 ---------------------------------------- + + +def generate_code(header_template: str, source_template: str, analyzer: GrammarAnalyzer, header_filename: str): + # 对所有符号进行整理,下标即最终的符号ID + symbols = [kEofSymbol] + tmp = list(analyzer.document().terminals()) + tmp.sort(key=lambda s: s.id()) + symbols.extend(tmp) + token_cnt = len(symbols) + tmp = list(analyzer.document().non_terminals()) + tmp.sort(key=lambda s: s.id()) + symbols.extend(tmp) + + # 生成token信息 + token_info = [] + for i in range(0, token_cnt): + assert symbols[i].type() == SYMBOL_TERMINAL or symbols[i].type() == SYMBOL_EOF + token_info.append({ + "id": i, + "c_name": "_" if symbols[i] == kEofSymbol else symbols[i].id(), + "raw": symbols[i] + }) + + # 生成映射表 + symbol_mapping = {} + for i in range(0, len(symbols)): + s = symbols[i] + symbol_mapping[s] = i + + # 生成产生式信息 + production_info = [] + for i in range(0, len(analyzer.document().productions())): + p = analyzer.document().productions()[i] + assert i == p.index() + production_info.append({ + "symbol": symbol_mapping[p.left()], + "count": len(p), + "raw": p + }) + + # 生成动作表 + actions = [] + state_remap_id_to_state_id = {} + state_id_to_state_remap_id = {} + offset = 0 + state_cnt = 0 + for i in range(0, analyzer.max_state() + 1): + empty_state = True + if i in analyzer.actions()[kEofSymbol]: + empty_state = False + else: + for s in analyzer.document().symbols(): + if i in analyzer.actions()[s]: + empty_state = False + break + if empty_state: + offset += 1 + else: + assert i not in state_id_to_state_remap_id + assert (i - offset) not in state_remap_id_to_state_id + state_id_to_state_remap_id[i] = i - offset + state_remap_id_to_state_id[i - offset] = i + state_cnt += 1 + for i in range(0, state_cnt): + action = [] + for j in range(0, len(symbols)): + s = symbols[j] + one_action = [0, 0] + state = state_remap_id_to_state_id[i] + if state in analyzer.actions()[s]: + act = analyzer.actions()[s][state] + one_action[0] = act.action() + if act.action() == ACTION_GOTO: + one_action[1] = state_id_to_state_remap_id[act.arg().state()] + elif act.action() == ACTION_REDUCE: + assert analyzer.document().productions()[act.arg().index()] == act.arg() + one_action[1] = act.arg().index() + action.append(one_action) + actions.append(action) + + # 生成C++类型 + token_types = [] + need_monostate = False + for s in analyzer.document().terminals(): + if s.replace() is None: + need_monostate = True + else: + assert s.replace().strip() == s.replace() + assert s.replace() != "std::monostate" + if s.replace() not in token_types: + token_types.append(s.replace()) + token_types.sort() + if need_monostate or len(token_types) == 0: + token_types.insert(0, "std::monostate") + production_types = [] + need_monostate = False + for s in analyzer.document().non_terminals(): + if s.replace() is None: + need_monostate = True + else: + assert s.replace().strip() == s.replace() + assert s.replace() != "std::monostate" + if s.replace() not in production_types: + production_types.append(s.replace()) + production_types.sort() + if need_monostate or len(production_types) == 0: + production_types.insert(0, "std::monostate") + + # generate the context + args = analyzer.document().generator_args() or {} + context = { + "namespace": args.get("namespace", None), + "class_name": args.get("class_name", "Parser"), + "includes": args.get("includes", []), + "symbols": symbols, + "token_info": token_info, + "token_types": token_types, + "production_info": production_info, + "production_types": production_types, + "actions": actions, + "header_filename": header_filename, + } + + header_src = render_template(header_template, **context) + source_src = render_template(source_template, **context) + return header_src, source_src + +# ---------------------------------------- Main ---------------------------------------- + + +CPP_HEADER_TPL = """/** + * @file + * @date {% datetime.date.today() %} + * + * Auto generated code by 9chu/parser_gen. + */ +#pragma once +#include +#include +#include + +{% for f in includes %} +#include "{% f %}" +{% end %} + +{% if namespace is None %} +// namespace { +{% else %} +namespace {% namespace %} +{ +{% end %} + class {% class_name %} + { + public: + enum class ParseResult + { + Undecided = 0, + Accepted = 1, + Rejected = 2, + }; + + enum class TokenTypes + { + {% for t in token_info %} + {% t["c_name"] %} = {% t["id"] %}, + {% end %} + }; + + using TokenValues = std::variant< + {% for i in range(0, len(token_types)) %} + {% token_types[i] %}{% if i != len(token_types) - 1 %},{% end %} + {% end %} + >; + + using ProductionValues = std::variant< + {% for i in range(0, len(production_types)) %} + {% production_types[i] %}{% if i != len(production_types) - 1 %},{% end %} + {% end %} + >; + + using UnionValues = std::variant; + + public: + {% class_name %}(); + + public: + ParseResult operator()(TokenTypes token, const TokenValues& value); + void Reset()noexcept; + + {% if production_info[0]["raw"].left().replace() is not None %} + const {% production_info[0]["raw"].left().replace() %}& Result()const noexcept { return m_stResult; } + {% production_info[0]["raw"].left().replace() %}& Result()noexcept { return m_stResult; } + {% end %} + + private: + std::vector m_stStack; + std::vector m_stValueStack; + + {% if production_info[0]["raw"].left().replace() is not None %} + {% production_info[0]["raw"].left().replace() %} m_stResult {}; + {% end %} + }; +{% if namespace is None %} +// } +{% else %} +} +{% end %} +""" + +CPP_SOURCE_TPL = """/** + * @file + * @date {% datetime.date.today() %} + * + * Auto generated code by 9chu/parser_gen. + */ +#include "{% header_filename %}" + +#include + +{% if namespace is not None %} +using namespace {% namespace %}; +{% end %} + +#define ACTION_ERROR 0 +#define ACTION_ACCEPT 1 +#define ACTION_GOTO 2 +#define ACTION_REDUCE 3 + +namespace { + {% for idx in range(0, len(production_info)) %} + {% class_name %}::ProductionValues Reduce{% idx %}(std::vector<{% class_name %}::UnionValues>& stack_) + { + // binding values + assert(stack_.size() >= {% len(production_info[idx]["raw"]) %}); + {% for pos in production_info[idx]["raw"].binding() %} + auto {% production_info[idx]["raw"].binding()[pos] %} = + {% if production_info[idx]["raw"][pos].type() == 2 %} + std::move(std::get<{% production_info[idx]["raw"][pos].replace() %}>( + std::get<{% class_name %}::ProductionValues>( + std::move(stack_[stack_.size() - {% len(production_info[idx]["raw"]) - pos %}]) + ) + )); + {% else %} + std::move(std::get<{% production_info[idx]["raw"][pos].replace() %}>( + std::get<{% class_name %}::TokenValues>( + std::move(stack_[stack_.size() - {% len(production_info[idx]["raw"]) - pos %}]) + ) + ));{% end %} + {% end %} + + // user code + {% if production_info[idx]["raw"].left().replace() is not None %} + auto ret = [&]() { + {% production_info[idx]["raw"].replace().strip() %} + }(); + return {% class_name %}::ProductionValues { std::move(ret) }; + {% else %} + {% if production_info[idx]["raw"].replace() is not None %} + {% production_info[idx]["raw"].replace() %} + {% end %} + return {% class_name %}::ProductionValues {}; + {% end %} + } + + {% end %} +} + +using ReduceFunction = {% class_name %}::ProductionValues(*)(std::vector<{% class_name %}::UnionValues>&); + +struct ProductionInfo +{ + uint32_t NonTerminal; + uint32_t SymbolCount; + ReduceFunction Callback; +}; + +struct ActionInfo +{ + uint8_t Action; + uint32_t Arg; +}; + +static const ProductionInfo kProductions[{% len(production_info) %}] = { + {% for i in range(0, len(production_info)) %} + { {% production_info[i]["symbol"] %}, {% production_info[i]["count"] %}, ::Reduce{% i %} }, + {% end %} +}; + +static const ActionInfo kActions[{% len(actions) %}][{% len(symbols) %}] = { + {% for action in actions %} + { {% for act in action %}{ {% act[0] %}, {% act[1] %} },{% end %} }, + {% end %} +}; + +{% class_name %}::{% class_name %}() +{ + Reset(); +} + +{% class_name %}::ParseResult {% class_name %}::operator()(TokenTypes token, const TokenValues& value) +{ + while (true) + { + assert(!m_stStack.empty()); + assert(static_cast(token) < {% len(token_info) %}); + + const ActionInfo& act = kActions[m_stStack.back()][static_cast(token)]; + if (act.Action == ACTION_ACCEPT) + { + {% if production_info[0]["raw"].left().replace() is not None %} + // store the result + assert(!m_stValueStack.empty()); + m_stResult = + std::move(std::get<{% production_info[0]["raw"].left().replace() %}>( + std::get(std::move(m_stValueStack.back())) + )); + {% end %} + + Reset(); + return ParseResult::Accepted; + } + else if (act.Action == ACTION_ERROR) + { + Reset(); + return ParseResult::Rejected; + } + else if (act.Action == ACTION_GOTO) + { + m_stStack.push_back(static_cast(token)); + m_stStack.push_back(act.Arg); + assert(m_stStack.back() < {% len(actions) %}); + + m_stValueStack.push_back(value); + } + else + { + assert(act.Action == ACTION_REDUCE); + assert(act.Arg < {% len(production_info) %}); + + const ProductionInfo& info = kProductions[act.Arg]; + auto val = info.Callback(m_stValueStack); + + assert(m_stStack.size() >= info.SymbolCount * 2); + m_stStack.resize(m_stStack.size() - info.SymbolCount * 2); + + assert(m_stValueStack.size() >= info.SymbolCount); + m_stValueStack.resize(m_stValueStack.size() - info.SymbolCount); + + m_stValueStack.emplace_back(std::move(val)); + assert(!m_stStack.empty()); + + const ActionInfo& act2 = kActions[m_stStack.back()][info.NonTerminal]; + if (act2.Action == ACTION_GOTO) + { + m_stStack.push_back(info.NonTerminal); + m_stStack.push_back(act2.Arg); + } + else + { + assert(false); + Reset(); + return ParseResult::Rejected; + } + + continue; + } + break; + } + + return ParseResult::Undecided; +} + +void {% class_name %}::Reset()noexcept +{ + m_stStack.clear(); + m_stValueStack.clear(); + + // initial state + m_stStack.push_back(0); +} +""" + + +def main(): + parser = argparse.ArgumentParser(description="A LR(1)/LALR(1) parser generator for C++17.") + parser.add_argument("--header-file", type=str, help="Output header filename", default="Parser.hpp") + parser.add_argument("--source-file", type=str, help="Output source filename", default="Parser.cpp") + parser.add_argument("-o", "--output-dir", type=str, help="Output directory", default="./") + parser.add_argument("--header-template", type=str, help="User defined header template", default="") + parser.add_argument("--source-template", type=str, help="User defined source template", default="") + parser.add_argument("--lalr", action="store_true", help="Set to LALR(1) mode", default=False) + parser.add_argument("--print-actions", action="store_true", help="Print action table", default=False) + parser.add_argument("grammar", help="Grammar filename") + args = parser.parse_args() + + doc = GrammarDocument() + doc.parse(args.grammar) + + analyzer = GrammarAnalyzer(doc) + analyzer.process(GRAMMAR_MODE_LALR if args.lalr else GRAMMAR_MODE_LR1) + + if args.print_actions: + print(analyzer.printable_actions()) + + resolve_rr_cnt, resolve_sr_by_prec_cnt, resolve_sr_by_shift_cnt = analyzer.resolve_stat() + sys.stderr.write(f"Reduce/Reduce conflict resolved count: {resolve_rr_cnt}\n") + sys.stderr.write(f"Shift/Reduce conflict resolved count (by Operator Precedence): {resolve_sr_by_prec_cnt}\n") + sys.stderr.write(f"Shift/Reduce conflict resolved count (by Shift Priority): {resolve_sr_by_shift_cnt}\n") + + header_tpl_content = CPP_HEADER_TPL + source_tpl_content = CPP_SOURCE_TPL + if args.header_template != "": + with open(args.header_template, "r", encoding="utf-8") as f: + header_tpl_content = f.read() + if args.source_template != "": + with open(args.source_template, "r", encoding="utf-8") as f: + source_tpl_content = f.read() + header_output, source_output = generate_code(header_tpl_content, source_tpl_content, analyzer, args.header_file) + with open(os.path.join(args.output_dir, args.header_file), "w", encoding="utf-8") as f: + f.write(header_output) + with open(os.path.join(args.output_dir, args.source_file), "w", encoding="utf-8") as f: + f.write(source_output) + + +if __name__ == "__main__": + main() diff --git a/src/rapidcsv.h b/src/rapidcsv.h new file mode 100644 index 0000000..6a31d34 --- /dev/null +++ b/src/rapidcsv.h @@ -0,0 +1,1800 @@ +/* + * rapidcsv.h + * + * URL: https://github.com/d99kris/rapidcsv + * Version: 8.65 + * + * Copyright (C) 2017-2022 Kristofer Berggren + * All rights reserved. + * + * rapidcsv is distributed under the BSD 3-Clause license, see LICENSE for details. + * + */ + +#pragma once + +#include +#include +#include +#ifdef HAS_CODECVT +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#include +typedef SSIZE_T ssize_t; +#endif + +namespace rapidcsv +{ +#if defined(_MSC_VER) + static const bool sPlatformHasCR = true; +#else + static const bool sPlatformHasCR = false; +#endif + + /** + * @brief Datastructure holding parameters controlling how invalid numbers (including + * empty strings) should be handled. + */ + struct ConverterParams + { + /** + * @brief Constructor + * @param pHasDefaultConverter specifies if conversion of non-numerical strings shall be + * converted to a default numerical value, instead of causing + * an exception to be thrown (default). + * @param pDefaultFloat floating-point default value to represent invalid numbers. + * @param pDefaultInteger integer default value to represent invalid numbers. + * @param pNumericLocale specifies whether to honor LC_NUMERIC locale (default + * true). + */ + explicit ConverterParams(const bool pHasDefaultConverter = false, + const long double pDefaultFloat = std::numeric_limits::signaling_NaN(), + const long long pDefaultInteger = 0, + const bool pNumericLocale = true) + : mHasDefaultConverter(pHasDefaultConverter) + , mDefaultFloat(pDefaultFloat) + , mDefaultInteger(pDefaultInteger) + , mNumericLocale(pNumericLocale) + { + } + + /** + * @brief specifies if conversion of non-numerical strings shall be converted to a default + * numerical value, instead of causing an exception to be thrown (default). + */ + bool mHasDefaultConverter; + + /** + * @brief floating-point default value to represent invalid numbers. + */ + long double mDefaultFloat; + + /** + * @brief integer default value to represent invalid numbers. + */ + long long mDefaultInteger; + + /** + * @brief specifies whether to honor LC_NUMERIC locale. + */ + bool mNumericLocale; + }; + + /** + * @brief Exception thrown when attempting to access Document data in a datatype which + * is not supported by the Converter class. + */ + class no_converter : public std::exception + { + /** + * @brief Provides details about the exception + * @returns an explanatory string + */ + virtual const char* what() const throw() + { + return "unsupported conversion datatype"; + } + }; + + /** + * @brief Class providing conversion to/from numerical datatypes and strings. Only + * intended for rapidcsv internal usage, but exposed externally to allow + * specialization for custom datatype conversions. + */ + template + class Converter + { + public: + /** + * @brief Constructor + * @param pConverterParams specifies how conversion of non-numerical values to + * numerical datatype shall be handled. + */ + Converter(const ConverterParams& pConverterParams) + : mConverterParams(pConverterParams) + { + } + + /** + * @brief Converts numerical value to string representation. + * @param pVal numerical value + * @param pStr output string + */ + void ToStr(const T& pVal, std::string& pStr) const + { + if (typeid(T) == typeid(int) || + typeid(T) == typeid(long) || + typeid(T) == typeid(long long) || + typeid(T) == typeid(unsigned) || + typeid(T) == typeid(unsigned long) || + typeid(T) == typeid(unsigned long long) || + typeid(T) == typeid(float) || + typeid(T) == typeid(double) || + typeid(T) == typeid(long double) || + typeid(T) == typeid(char)) + { + std::ostringstream out; + out << pVal; + pStr = out.str(); + } + else + { + throw no_converter(); + } + } + + /** + * @brief Converts string holding a numerical value to numerical datatype representation. + * @param pVal numerical value + * @param pStr output string + */ + void ToVal(const std::string& pStr, T& pVal) const + { + try + { + if (typeid(T) == typeid(int)) + { + pVal = static_cast(std::stoi(pStr)); + return; + } + else if (typeid(T) == typeid(long)) + { + pVal = static_cast(std::stol(pStr)); + return; + } + else if (typeid(T) == typeid(long long)) + { + pVal = static_cast(std::stoll(pStr)); + return; + } + else if (typeid(T) == typeid(unsigned)) + { + pVal = static_cast(std::stoul(pStr)); + return; + } + else if (typeid(T) == typeid(unsigned long)) + { + pVal = static_cast(std::stoul(pStr)); + return; + } + else if (typeid(T) == typeid(unsigned long long)) + { + pVal = static_cast(std::stoull(pStr)); + return; + } + } + catch (...) + { + if (!mConverterParams.mHasDefaultConverter) + { + throw; + } + else + { + pVal = static_cast(mConverterParams.mDefaultInteger); + return; + } + } + + try + { + if (mConverterParams.mNumericLocale) + { + if (typeid(T) == typeid(float)) + { + pVal = static_cast(std::stof(pStr)); + return; + } + else if (typeid(T) == typeid(double)) + { + pVal = static_cast(std::stod(pStr)); + return; + } + else if (typeid(T) == typeid(long double)) + { + pVal = static_cast(std::stold(pStr)); + return; + } + } + else + { + if ((typeid(T) == typeid(float)) || + (typeid(T) == typeid(double)) || + (typeid(T) == typeid(long double))) + { + std::istringstream iss(pStr); + iss >> pVal; + if (iss.fail() || iss.bad() || !iss.eof()) + { + throw std::invalid_argument("istringstream: no conversion"); + } + return; + } + } + } + catch (...) + { + if (!mConverterParams.mHasDefaultConverter) + { + throw; + } + else + { + pVal = static_cast(mConverterParams.mDefaultFloat); + return; + } + } + + if (typeid(T) == typeid(char)) + { + pVal = static_cast(pStr[0]); + return; + } + else + { + throw no_converter(); + } + } + + private: + const ConverterParams& mConverterParams; + }; + + /** + * @brief Specialized implementation handling string to string conversion. + * @param pVal string + * @param pStr string + */ + template<> + inline void Converter::ToStr(const std::string& pVal, std::string& pStr) const + { + pStr = pVal; + } + + /** + * @brief Specialized implementation handling string to string conversion. + * @param pVal string + * @param pStr string + */ + template<> + inline void Converter::ToVal(const std::string& pStr, std::string& pVal) const + { + pVal = pStr; + } + + template + using ConvFunc = std::function; + + /** + * @brief Datastructure holding parameters controlling which row and column should be + * treated as labels. + */ + struct LabelParams + { + /** + * @brief Constructor + * @param pColumnNameIdx specifies the zero-based row index of the column labels, setting + * it to -1 prevents column lookup by label name, and gives access + * to all rows as document data. Default: 0 + * @param pRowNameIdx specifies the zero-based column index of the row labels, setting + * it to -1 prevents row lookup by label name, and gives access + * to all columns as document data. Default: -1 + */ + explicit LabelParams(const ssize_t pColumnNameIdx = 0, const ssize_t pRowNameIdx = -1) + : mColumnNameIdx(pColumnNameIdx) + , mRowNameIdx(pRowNameIdx) + { + if (mColumnNameIdx < -1) + { + const std::string errStr = "invalid column name index " + + std::to_string(mColumnNameIdx) + " < -1"; + throw std::out_of_range(errStr); + } + + if (mRowNameIdx < -1) + { + const std::string errStr = "invalid row name index " + + std::to_string(mRowNameIdx) + " < -1"; + throw std::out_of_range(errStr); + } + } + + /** + * @brief specifies the zero-based row index of the column labels. + */ + ssize_t mColumnNameIdx; + + /** + * @brief specifies the zero-based column index of the row labels. + */ + ssize_t mRowNameIdx; + }; + + /** + * @brief Datastructure holding parameters controlling how the CSV data fields are separated. + */ + struct SeparatorParams + { + /** + * @brief Constructor + * @param pSeparator specifies the column separator (default ','). + * @param pTrim specifies whether to trim leading and trailing spaces from + * cells read (default false). + * @param pHasCR specifies whether a new document (i.e. not an existing document read) + * should use CR/LF instead of only LF (default is to use standard + * behavior of underlying platforms - CR/LF for Win, and LF for others). + * @param pQuotedLinebreaks specifies whether to allow line breaks in quoted text (default false) + * @param pAutoQuote specifies whether to automatically dequote data during read, and add + * quotes during write (default true). + */ + explicit SeparatorParams(const char pSeparator = ',', const bool pTrim = false, + const bool pHasCR = sPlatformHasCR, const bool pQuotedLinebreaks = false, + const bool pAutoQuote = true) + : mSeparator(pSeparator) + , mTrim(pTrim) + , mHasCR(pHasCR) + , mQuotedLinebreaks(pQuotedLinebreaks) + , mAutoQuote(pAutoQuote) + { + } + + /** + * @brief specifies the column separator. + */ + char mSeparator; + + /** + * @brief specifies whether to trim leading and trailing spaces from cells read. + */ + bool mTrim; + + /** + * @brief specifies whether new documents should use CR/LF instead of LF. + */ + bool mHasCR; + + /** + * @brief specifies whether to allow line breaks in quoted text. + */ + bool mQuotedLinebreaks; + + /** + * @brief specifies whether to automatically dequote cell data. + */ + bool mAutoQuote; + }; + + /** + * @brief Datastructure holding parameters controlling how special line formats should be + * treated. + */ + struct LineReaderParams + { + /** + * @brief Constructor + * @param pSkipCommentLines specifies whether to skip lines prefixed with + * mCommentPrefix. Default: false + * @param pCommentPrefix specifies which prefix character to indicate a comment + * line. Default: # + * @param pSkipEmptyLines specifies whether to skip empty lines. Default: false + */ + explicit LineReaderParams(const bool pSkipCommentLines = false, + const char pCommentPrefix = '#', + const bool pSkipEmptyLines = false) + : mSkipCommentLines(pSkipCommentLines) + , mCommentPrefix(pCommentPrefix) + , mSkipEmptyLines(pSkipEmptyLines) + { + } + + /** + * @brief specifies whether to skip lines prefixed with mCommentPrefix. + */ + bool mSkipCommentLines; + + /** + * @brief specifies which prefix character to indicate a comment line. + */ + char mCommentPrefix; + + /** + * @brief specifies whether to skip empty lines. + */ + bool mSkipEmptyLines; + }; + + /** + * @brief Class representing a CSV document. + */ + class Document + { + public: + /** + * @brief Constructor + * @param pPath specifies the path of an existing CSV-file to populate the Document + * data with. + * @param pLabelParams specifies which row and column should be treated as labels. + * @param pSeparatorParams specifies which field and row separators should be used. + * @param pConverterParams specifies how invalid numbers (including empty strings) should be + * handled. + * @param pLineReaderParams specifies how special line formats should be treated. + */ + explicit Document(const std::string& pPath = std::string(), + const LabelParams& pLabelParams = LabelParams(), + const SeparatorParams& pSeparatorParams = SeparatorParams(), + const ConverterParams& pConverterParams = ConverterParams(), + const LineReaderParams& pLineReaderParams = LineReaderParams()) + : mPath(pPath) + , mLabelParams(pLabelParams) + , mSeparatorParams(pSeparatorParams) + , mConverterParams(pConverterParams) + , mLineReaderParams(pLineReaderParams) + { + if (!mPath.empty()) + { + ReadCsv(); + } + } + + /** + * @brief Constructor + * @param pStream specifies a binary input stream to read CSV data from. + * @param pLabelParams specifies which row and column should be treated as labels. + * @param pSeparatorParams specifies which field and row separators should be used. + * @param pConverterParams specifies how invalid numbers (including empty strings) should be + * handled. + * @param pLineReaderParams specifies how special line formats should be treated. + */ + explicit Document(std::istream& pStream, + const LabelParams& pLabelParams = LabelParams(), + const SeparatorParams& pSeparatorParams = SeparatorParams(), + const ConverterParams& pConverterParams = ConverterParams(), + const LineReaderParams& pLineReaderParams = LineReaderParams()) + : mPath() + , mLabelParams(pLabelParams) + , mSeparatorParams(pSeparatorParams) + , mConverterParams(pConverterParams) + , mLineReaderParams(pLineReaderParams) + { + ReadCsv(pStream); + } + + /** + * @brief Read Document data from file. + * @param pPath specifies the path of an existing CSV-file to populate the Document + * data with. + * @param pLabelParams specifies which row and column should be treated as labels. + * @param pSeparatorParams specifies which field and row separators should be used. + * @param pConverterParams specifies how invalid numbers (including empty strings) should be + * handled. + * @param pLineReaderParams specifies how special line formats should be treated. + */ + void Load(const std::string& pPath, + const LabelParams& pLabelParams = LabelParams(), + const SeparatorParams& pSeparatorParams = SeparatorParams(), + const ConverterParams& pConverterParams = ConverterParams(), + const LineReaderParams& pLineReaderParams = LineReaderParams()) + { + mPath = pPath; + mLabelParams = pLabelParams; + mSeparatorParams = pSeparatorParams; + mConverterParams = pConverterParams; + mLineReaderParams = pLineReaderParams; + ReadCsv(); + } + + /** + * @brief Read Document data from stream. + * @param pStream specifies a binary input stream to read CSV data from. + * @param pLabelParams specifies which row and column should be treated as labels. + * @param pSeparatorParams specifies which field and row separators should be used. + * @param pConverterParams specifies how invalid numbers (including empty strings) should be + * handled. + * @param pLineReaderParams specifies how special line formats should be treated. + */ + void Load(std::istream& pStream, + const LabelParams& pLabelParams = LabelParams(), + const SeparatorParams& pSeparatorParams = SeparatorParams(), + const ConverterParams& pConverterParams = ConverterParams(), + const LineReaderParams& pLineReaderParams = LineReaderParams()) + { + mPath = ""; + mLabelParams = pLabelParams; + mSeparatorParams = pSeparatorParams; + mConverterParams = pConverterParams; + mLineReaderParams = pLineReaderParams; + ReadCsv(pStream); + } + + /** + * @brief Write Document data to file. + * @param pPath optionally specifies the path where the CSV-file will be created + * (if not specified, the original path provided when creating or + * loading the Document data will be used). + */ + void Save(const std::string& pPath = std::string()) + { + if (!pPath.empty()) + { + mPath = pPath; + } + WriteCsv(); + } + + /** + * @brief Write Document data to stream. + * @param pStream specifies a binary output stream to write the data to. + */ + void Save(std::ostream& pStream) + { + WriteCsv(pStream); + } + + /** + * @brief Clears loaded Document data. + * + */ + void Clear() + { + mData.clear(); + mColumnNames.clear(); + mRowNames.clear(); +#ifdef HAS_CODECVT + mIsUtf16 = false; + mIsLE = false; +#endif + } + + /** + * @brief Get column index by name. + * @param pColumnName column label name. + * @returns zero-based column index. + */ + ssize_t GetColumnIdx(const std::string& pColumnName) const + { + if (mLabelParams.mColumnNameIdx >= 0) + { + if (mColumnNames.find(pColumnName) != mColumnNames.end()) + { + return static_cast(mColumnNames.at(pColumnName)) - (mLabelParams.mRowNameIdx + 1); + } + } + return -1; + } + + /** + * @brief Get column by index. + * @param pColumnIdx zero-based column index. + * @returns vector of column data. + */ + template + std::vector GetColumn(const size_t pColumnIdx) const + { + const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx); + std::vector column; + Converter converter(mConverterParams); + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) + { + if (std::distance(mData.begin(), itRow) > mLabelParams.mColumnNameIdx) + { + if (dataColumnIdx < itRow->size()) + { + T val; + converter.ToVal(itRow->at(dataColumnIdx), val); + column.push_back(val); + } + else + { + const std::string errStr = "requested column index " + + std::to_string(pColumnIdx) + " >= " + + std::to_string(itRow->size() - GetDataColumnIndex(0)) + + " (number of columns on row index " + + std::to_string(std::distance(mData.begin(), itRow) - + (mLabelParams.mColumnNameIdx + 1)) + ")"; + throw std::out_of_range(errStr); + } + } + } + return column; + } + + /** + * @brief Get column by index. + * @param pColumnIdx zero-based column index. + * @param pToVal conversion function. + * @returns vector of column data. + */ + template + std::vector GetColumn(const size_t pColumnIdx, ConvFunc pToVal) const + { + const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx); + std::vector column; + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) + { + if (std::distance(mData.begin(), itRow) > mLabelParams.mColumnNameIdx) + { + T val; + pToVal(itRow->at(dataColumnIdx), val); + column.push_back(val); + } + } + return column; + } + + /** + * @brief Get column by name. + * @param pColumnName column label name. + * @returns vector of column data. + */ + template + std::vector GetColumn(const std::string& pColumnName) const + { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) + { + throw std::out_of_range("column not found: " + pColumnName); + } + return GetColumn(static_cast(columnIdx)); + } + + /** + * @brief Get column by name. + * @param pColumnName column label name. + * @param pToVal conversion function. + * @returns vector of column data. + */ + template + std::vector GetColumn(const std::string& pColumnName, ConvFunc pToVal) const + { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) + { + throw std::out_of_range("column not found: " + pColumnName); + } + return GetColumn(static_cast(columnIdx), pToVal); + } + + /** + * @brief Set column by index. + * @param pColumnIdx zero-based column index. + * @param pColumn vector of column data. + */ + template + void SetColumn(const size_t pColumnIdx, const std::vector& pColumn) + { + const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx); + + while (GetDataRowIndex(pColumn.size()) > GetDataRowCount()) + { + std::vector row; + row.resize(GetDataColumnCount()); + mData.push_back(row); + } + + if ((dataColumnIdx + 1) > GetDataColumnCount()) + { + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) + { + itRow->resize(GetDataColumnIndex(dataColumnIdx + 1)); + } + } + + Converter converter(mConverterParams); + for (auto itRow = pColumn.begin(); itRow != pColumn.end(); ++itRow) + { + std::string str; + converter.ToStr(*itRow, str); + mData.at(static_cast(std::distance(pColumn.begin(), itRow) + mLabelParams.mColumnNameIdx + 1)).at(dataColumnIdx) = str; + } + } + + /** + * @brief Set column by name. + * @param pColumnName column label name. + * @param pColumn vector of column data. + */ + template + void SetColumn(const std::string& pColumnName, const std::vector& pColumn) + { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) + { + throw std::out_of_range("column not found: " + pColumnName); + } + SetColumn(static_cast(columnIdx), pColumn); + } + + /** + * @brief Remove column by index. + * @param pColumnIdx zero-based column index. + */ + void RemoveColumn(const size_t pColumnIdx) + { + const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx); + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) + { + itRow->erase(itRow->begin() + static_cast(dataColumnIdx)); + } + + UpdateColumnNames(); + } + + /** + * @brief Remove column by name. + * @param pColumnName column label name. + */ + void RemoveColumn(const std::string& pColumnName) + { + ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) + { + throw std::out_of_range("column not found: " + pColumnName); + } + + RemoveColumn(static_cast(columnIdx)); + } + + /** + * @brief Insert column at specified index. + * @param pColumnIdx zero-based column index. + * @param pColumn vector of column data (optional argument). + * @param pColumnName column label name (optional argument). + */ + template + void InsertColumn(const size_t pColumnIdx, const std::vector& pColumn = std::vector(), + const std::string& pColumnName = std::string()) + { + const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx); + + std::vector column; + if (pColumn.empty()) + { + column.resize(GetDataRowCount()); + } + else + { + column.resize(GetDataRowIndex(pColumn.size())); + Converter converter(mConverterParams); + for (auto itRow = pColumn.begin(); itRow != pColumn.end(); ++itRow) + { + std::string str; + converter.ToStr(*itRow, str); + const size_t rowIdx = static_cast(std::distance(pColumn.begin(), itRow) + (mLabelParams.mColumnNameIdx + 1)); + column.at(rowIdx) = str; + } + } + + while (column.size() > GetDataRowCount()) + { + std::vector row; + const size_t columnCount = std::max(static_cast(mLabelParams.mColumnNameIdx + 1), + GetDataColumnCount()); + row.resize(columnCount); + mData.push_back(row); + } + + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) + { + const size_t rowIdx = static_cast(std::distance(mData.begin(), itRow)); + itRow->insert(itRow->begin() + static_cast(dataColumnIdx), column.at(rowIdx)); + } + + if (!pColumnName.empty()) + { + SetColumnName(pColumnIdx, pColumnName); + } + + UpdateColumnNames(); + } + + /** + * @brief Get number of data columns (excluding label columns). + * @returns column count. + */ + size_t GetColumnCount() const + { + const ssize_t count = static_cast((mData.size() > 0) ? mData.at(0).size() : 0) - + (mLabelParams.mRowNameIdx + 1); + return (count >= 0) ? static_cast(count) : 0; + } + + /** + * @brief Get row index by name. + * @param pRowName row label name. + * @returns zero-based row index. + */ + ssize_t GetRowIdx(const std::string& pRowName) const + { + if (mLabelParams.mRowNameIdx >= 0) + { + if (mRowNames.find(pRowName) != mRowNames.end()) + { + return static_cast(mRowNames.at(pRowName)) - (mLabelParams.mColumnNameIdx + 1); + } + } + return -1; + } + + /** + * @brief Get row by index. + * @param pRowIdx zero-based row index. + * @returns vector of row data. + */ + template + std::vector GetRow(const size_t pRowIdx) const + { + const size_t dataRowIdx = GetDataRowIndex(pRowIdx); + std::vector row; + Converter converter(mConverterParams); + for (auto itCol = mData.at(dataRowIdx).begin(); itCol != mData.at(dataRowIdx).end(); ++itCol) + { + if (std::distance(mData.at(dataRowIdx).begin(), itCol) > mLabelParams.mRowNameIdx) + { + T val; + converter.ToVal(*itCol, val); + row.push_back(val); + } + } + return row; + } + + /** + * @brief Get row by index. + * @param pRowIdx zero-based row index. + * @param pToVal conversion function. + * @returns vector of row data. + */ + template + std::vector GetRow(const size_t pRowIdx, ConvFunc pToVal) const + { + const size_t dataRowIdx = GetDataRowIndex(pRowIdx); + std::vector row; + Converter converter(mConverterParams); + for (auto itCol = mData.at(dataRowIdx).begin(); itCol != mData.at(dataRowIdx).end(); ++itCol) + { + if (std::distance(mData.at(dataRowIdx).begin(), itCol) > mLabelParams.mRowNameIdx) + { + T val; + pToVal(*itCol, val); + row.push_back(val); + } + } + return row; + } + + /** + * @brief Get row by name. + * @param pRowName row label name. + * @returns vector of row data. + */ + template + std::vector GetRow(const std::string& pRowName) const + { + ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) + { + throw std::out_of_range("row not found: " + pRowName); + } + return GetRow(static_cast(rowIdx)); + } + + /** + * @brief Get row by name. + * @param pRowName row label name. + * @param pToVal conversion function. + * @returns vector of row data. + */ + template + std::vector GetRow(const std::string& pRowName, ConvFunc pToVal) const + { + ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) + { + throw std::out_of_range("row not found: " + pRowName); + } + return GetRow(static_cast(rowIdx), pToVal); + } + + /** + * @brief Set row by index. + * @param pRowIdx zero-based row index. + * @param pRow vector of row data. + */ + template + void SetRow(const size_t pRowIdx, const std::vector& pRow) + { + const size_t dataRowIdx = GetDataRowIndex(pRowIdx); + + while ((dataRowIdx + 1) > GetDataRowCount()) + { + std::vector row; + row.resize(GetDataColumnCount()); + mData.push_back(row); + } + + if (pRow.size() > GetDataColumnCount()) + { + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) + { + itRow->resize(GetDataColumnIndex(pRow.size())); + } + } + + Converter converter(mConverterParams); + for (auto itCol = pRow.begin(); itCol != pRow.end(); ++itCol) + { + std::string str; + converter.ToStr(*itCol, str); + mData.at(dataRowIdx).at(static_cast(std::distance(pRow.begin(), itCol) + mLabelParams.mRowNameIdx + 1)) = str; + } + } + + /** + * @brief Set row by name. + * @param pRowName row label name. + * @param pRow vector of row data. + */ + template + void SetRow(const std::string& pRowName, const std::vector& pRow) + { + ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) + { + throw std::out_of_range("row not found: " + pRowName); + } + return SetRow(static_cast(rowIdx), pRow); + } + + /** + * @brief Remove row by index. + * @param pRowIdx zero-based row index. + */ + void RemoveRow(const size_t pRowIdx) + { + const size_t dataRowIdx = GetDataRowIndex(pRowIdx); + mData.erase(mData.begin() + static_cast(dataRowIdx)); + UpdateRowNames(); + } + + /** + * @brief Remove row by name. + * @param pRowName row label name. + */ + void RemoveRow(const std::string& pRowName) + { + ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) + { + throw std::out_of_range("row not found: " + pRowName); + } + + RemoveRow(static_cast(rowIdx)); + } + + /** + * @brief Insert row at specified index. + * @param pRowIdx zero-based row index. + * @param pRow vector of row data (optional argument). + * @param pRowName row label name (optional argument). + */ + template + void InsertRow(const size_t pRowIdx, const std::vector& pRow = std::vector(), + const std::string& pRowName = std::string()) + { + const size_t rowIdx = GetDataRowIndex(pRowIdx); + + std::vector row; + if (pRow.empty()) + { + row.resize(GetDataColumnCount()); + } + else + { + row.resize(GetDataColumnIndex(pRow.size())); + Converter converter(mConverterParams); + for (auto itCol = pRow.begin(); itCol != pRow.end(); ++itCol) + { + std::string str; + converter.ToStr(*itCol, str); + row.at(static_cast(std::distance(pRow.begin(), itCol) + mLabelParams.mRowNameIdx + 1)) = str; + } + } + + while (rowIdx > GetDataRowCount()) + { + std::vector tempRow; + tempRow.resize(GetDataColumnCount()); + mData.push_back(tempRow); + } + + mData.insert(mData.begin() + static_cast(rowIdx), row); + + if (!pRowName.empty()) + { + SetRowName(pRowIdx, pRowName); + } + + UpdateRowNames(); + } + + /** + * @brief Get number of data rows (excluding label rows). + * @returns row count. + */ + size_t GetRowCount() const + { + const ssize_t count = static_cast(mData.size()) - (mLabelParams.mColumnNameIdx + 1); + return (count >= 0) ? static_cast(count) : 0; + } + + /** + * @brief Get cell by index. + * @param pColumnIdx zero-based column index. + * @param pRowIdx zero-based row index. + * @returns cell data. + */ + template + T GetCell(const size_t pColumnIdx, const size_t pRowIdx) const + { + const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx); + const size_t dataRowIdx = GetDataRowIndex(pRowIdx); + + T val; + Converter converter(mConverterParams); + converter.ToVal(mData.at(dataRowIdx).at(dataColumnIdx), val); + return val; + } + + /** + * @brief Get cell by index. + * @param pColumnIdx zero-based column index. + * @param pRowIdx zero-based row index. + * @param pToVal conversion function. + * @returns cell data. + */ + template + T GetCell(const size_t pColumnIdx, const size_t pRowIdx, ConvFunc pToVal) const + { + const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx); + const size_t dataRowIdx = GetDataRowIndex(pRowIdx); + + T val; + pToVal(mData.at(dataRowIdx).at(dataColumnIdx), val); + return val; + } + + /** + * @brief Get cell by name. + * @param pColumnName column label name. + * @param pRowName row label name. + * @returns cell data. + */ + template + T GetCell(const std::string& pColumnName, const std::string& pRowName) const + { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) + { + throw std::out_of_range("column not found: " + pColumnName); + } + + const ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) + { + throw std::out_of_range("row not found: " + pRowName); + } + + return GetCell(static_cast(columnIdx), static_cast(rowIdx)); + } + + /** + * @brief Get cell by name. + * @param pColumnName column label name. + * @param pRowName row label name. + * @param pToVal conversion function. + * @returns cell data. + */ + template + T GetCell(const std::string& pColumnName, const std::string& pRowName, ConvFunc pToVal) const + { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) + { + throw std::out_of_range("column not found: " + pColumnName); + } + + const ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) + { + throw std::out_of_range("row not found: " + pRowName); + } + + return GetCell(static_cast(columnIdx), static_cast(rowIdx), pToVal); + } + + /** + * @brief Get cell by column name and row index. + * @param pColumnName column label name. + * @param pRowIdx zero-based row index. + * @returns cell data. + */ + template + T GetCell(const std::string& pColumnName, const size_t pRowIdx) const + { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) + { + throw std::out_of_range("column not found: " + pColumnName); + } + + return GetCell(static_cast(columnIdx), pRowIdx); + } + + /** + * @brief Get cell by column name and row index. + * @param pColumnName column label name. + * @param pRowIdx zero-based row index. + * @param pToVal conversion function. + * @returns cell data. + */ + template + T GetCell(const std::string& pColumnName, const size_t pRowIdx, ConvFunc pToVal) const + { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) + { + throw std::out_of_range("column not found: " + pColumnName); + } + + return GetCell(static_cast(columnIdx), pRowIdx, pToVal); + } + + /** + * @brief Get cell by column index and row name. + * @param pColumnIdx zero-based column index. + * @param pRowName row label name. + * @returns cell data. + */ + template + T GetCell(const size_t pColumnIdx, const std::string& pRowName) const + { + const ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) + { + throw std::out_of_range("row not found: " + pRowName); + } + + return GetCell(pColumnIdx, static_cast(rowIdx)); + } + + /** + * @brief Get cell by column index and row name. + * @param pColumnIdx zero-based column index. + * @param pRowName row label name. + * @param pToVal conversion function. + * @returns cell data. + */ + template + T GetCell(const size_t pColumnIdx, const std::string& pRowName, ConvFunc pToVal) const + { + const ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) + { + throw std::out_of_range("row not found: " + pRowName); + } + + return GetCell(pColumnIdx, static_cast(rowIdx), pToVal); + } + + /** + * @brief Set cell by index. + * @param pRowIdx zero-based row index. + * @param pColumnIdx zero-based column index. + * @param pCell cell data. + */ + template + void SetCell(const size_t pColumnIdx, const size_t pRowIdx, const T& pCell) + { + const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx); + const size_t dataRowIdx = GetDataRowIndex(pRowIdx); + + while ((dataRowIdx + 1) > GetDataRowCount()) + { + std::vector row; + row.resize(GetDataColumnCount()); + mData.push_back(row); + } + + if ((dataColumnIdx + 1) > GetDataColumnCount()) + { + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) + { + itRow->resize(dataColumnIdx + 1); + } + } + + std::string str; + Converter converter(mConverterParams); + converter.ToStr(pCell, str); + mData.at(dataRowIdx).at(dataColumnIdx) = str; + } + + /** + * @brief Set cell by name. + * @param pColumnName column label name. + * @param pRowName row label name. + * @param pCell cell data. + */ + template + void SetCell(const std::string& pColumnName, const std::string& pRowName, const T& pCell) + { + const ssize_t columnIdx = GetColumnIdx(pColumnName); + if (columnIdx < 0) + { + throw std::out_of_range("column not found: " + pColumnName); + } + + const ssize_t rowIdx = GetRowIdx(pRowName); + if (rowIdx < 0) + { + throw std::out_of_range("row not found: " + pRowName); + } + + SetCell(static_cast(columnIdx), static_cast(rowIdx), pCell); + } + + /** + * @brief Get column name + * @param pColumnIdx zero-based column index. + * @returns column name. + */ + std::string GetColumnName(const size_t pColumnIdx) + { + const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx); + if (mLabelParams.mColumnNameIdx < 0) + { + throw std::out_of_range("column name row index < 0: " + std::to_string(mLabelParams.mColumnNameIdx)); + } + + return mData.at(static_cast(mLabelParams.mColumnNameIdx)).at(dataColumnIdx); + } + + /** + * @brief Set column name + * @param pColumnIdx zero-based column index. + * @param pColumnName column name. + */ + void SetColumnName(size_t pColumnIdx, const std::string& pColumnName) + { + if (mLabelParams.mColumnNameIdx < 0) + { + throw std::out_of_range("column name row index < 0: " + std::to_string(mLabelParams.mColumnNameIdx)); + } + + const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx); + mColumnNames[pColumnName] = dataColumnIdx; + + // increase table size if necessary: + const size_t rowIdx = static_cast(mLabelParams.mColumnNameIdx); + if (rowIdx >= mData.size()) + { + mData.resize(rowIdx + 1); + } + auto& row = mData[rowIdx]; + if (dataColumnIdx >= row.size()) + { + row.resize(dataColumnIdx + 1); + } + + mData.at(static_cast(mLabelParams.mColumnNameIdx)).at(dataColumnIdx) = pColumnName; + } + + /** + * @brief Get column names + * @returns vector of column names. + */ + std::vector GetColumnNames() + { + if (mLabelParams.mColumnNameIdx >= 0) + { + return std::vector(mData.at(static_cast(mLabelParams.mColumnNameIdx)).begin() + + (mLabelParams.mRowNameIdx + 1), + mData.at(static_cast(mLabelParams.mColumnNameIdx)).end()); + } + + return std::vector(); + } + + /** + * @brief Get row name + * @param pRowIdx zero-based column index. + * @returns row name. + */ + std::string GetRowName(const size_t pRowIdx) + { + const size_t dataRowIdx = GetDataRowIndex(pRowIdx); + if (mLabelParams.mRowNameIdx < 0) + { + throw std::out_of_range("row name column index < 0: " + std::to_string(mLabelParams.mRowNameIdx)); + } + + return mData.at(dataRowIdx).at(static_cast(mLabelParams.mRowNameIdx)); + } + + /** + * @brief Set row name + * @param pRowIdx zero-based row index. + * @param pRowName row name. + */ + void SetRowName(size_t pRowIdx, const std::string& pRowName) + { + const size_t dataRowIdx = GetDataRowIndex(pRowIdx); + mRowNames[pRowName] = dataRowIdx; + if (mLabelParams.mRowNameIdx < 0) + { + throw std::out_of_range("row name column index < 0: " + std::to_string(mLabelParams.mRowNameIdx)); + } + + // increase table size if necessary: + if (dataRowIdx >= mData.size()) + { + mData.resize(dataRowIdx + 1); + } + auto& row = mData[dataRowIdx]; + if (mLabelParams.mRowNameIdx >= static_cast(row.size())) + { + row.resize(static_cast(mLabelParams.mRowNameIdx) + 1); + } + + mData.at(dataRowIdx).at(static_cast(mLabelParams.mRowNameIdx)) = pRowName; + } + + /** + * @brief Get row names + * @returns vector of row names. + */ + std::vector GetRowNames() + { + std::vector rownames; + if (mLabelParams.mRowNameIdx >= 0) + { + for (auto itRow = mData.begin(); itRow != mData.end(); ++itRow) + { + if (std::distance(mData.begin(), itRow) > mLabelParams.mColumnNameIdx) + { + rownames.push_back(itRow->at(static_cast(mLabelParams.mRowNameIdx))); + } + } + } + return rownames; + } + + private: + void ReadCsv() + { + std::ifstream stream; + stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + stream.open(mPath, std::ios::binary); + ReadCsv(stream); + } + + void ReadCsv(std::istream& pStream) + { + Clear(); + pStream.seekg(0, std::ios::end); + std::streamsize length = pStream.tellg(); + pStream.seekg(0, std::ios::beg); + +#ifdef HAS_CODECVT + std::vector bom2b(2, '\0'); + if (length >= 2) + { + pStream.read(bom2b.data(), 2); + pStream.seekg(0, std::ios::beg); + } + + static const std::vector bomU16le = { '\xff', '\xfe' }; + static const std::vector bomU16be = { '\xfe', '\xff' }; + if ((bom2b == bomU16le) || (bom2b == bomU16be)) + { + mIsUtf16 = true; + mIsLE = (bom2b == bomU16le); + + std::wifstream wstream; + wstream.exceptions(std::wifstream::failbit | std::wifstream::badbit); + wstream.open(mPath, std::ios::binary); + if (mIsLE) + { + wstream.imbue(std::locale(wstream.getloc(), + new std::codecvt_utf16(std::consume_header | + std::little_endian)>)); + } + else + { + wstream.imbue(std::locale(wstream.getloc(), + new std::codecvt_utf16)); + } + std::wstringstream wss; + wss << wstream.rdbuf(); + std::string utf8 = ToString(wss.str()); + std::stringstream ss(utf8); + ParseCsv(ss, static_cast(utf8.size())); + } + else +#endif + { + // check for UTF-8 Byte order mark and skip it when found + if (length >= 3) + { + std::vector bom3b(3, '\0'); + pStream.read(bom3b.data(), 3); + static const std::vector bomU8 = { '\xef', '\xbb', '\xbf' }; + if (bom3b != bomU8) + { + // file does not start with a UTF-8 Byte order mark + pStream.seekg(0, std::ios::beg); + } + else + { + // file did start with a UTF-8 Byte order mark, simply skip it + length -= 3; + } + } + + ParseCsv(pStream, length); + } + } + + void ParseCsv(std::istream& pStream, std::streamsize p_FileLength) + { + const std::streamsize bufLength = 64 * 1024; + std::vector buffer(bufLength); + std::vector row; + std::string cell; + bool quoted = false; + int cr = 0; + int lf = 0; + + while (p_FileLength > 0) + { + const std::streamsize toReadLength = std::min(p_FileLength, bufLength); + pStream.read(buffer.data(), toReadLength); + + // With user-specified istream opened in non-binary mode on windows, we may have a + // data length mismatch, so ensure we don't parse outside actual data length read. + const std::streamsize readLength = pStream.gcount(); + if (readLength <= 0) + { + break; + } + + for (size_t i = 0; i < static_cast(readLength); ++i) + { + if (buffer[i] == '"') + { + if (cell.empty() || cell[0] == '"') + { + quoted = !quoted; + } + cell += buffer[i]; + } + else if (buffer[i] == mSeparatorParams.mSeparator) + { + if (!quoted) + { + row.push_back(Unquote(Trim(cell))); + cell.clear(); + } + else + { + cell += buffer[i]; + } + } + else if (buffer[i] == '\r') + { + if (mSeparatorParams.mQuotedLinebreaks && quoted) + { + cell += buffer[i]; + } + else + { + ++cr; + } + } + else if (buffer[i] == '\n') + { + if (mSeparatorParams.mQuotedLinebreaks && quoted) + { + cell += buffer[i]; + } + else + { + ++lf; + if (mLineReaderParams.mSkipEmptyLines && row.empty() && cell.empty()) + { + // skip empty line + } + else + { + row.push_back(Unquote(Trim(cell))); + + if (mLineReaderParams.mSkipCommentLines && !row.at(0).empty() && + (row.at(0)[0] == mLineReaderParams.mCommentPrefix)) + { + // skip comment line + } + else + { + mData.push_back(row); + } + + cell.clear(); + row.clear(); + quoted = false; + } + } + } + else + { + cell += buffer[i]; + } + } + p_FileLength -= readLength; + } + + // Handle last line without linebreak + if (!cell.empty() || !row.empty()) + { + row.push_back(Unquote(Trim(cell))); + cell.clear(); + mData.push_back(row); + row.clear(); + } + + // Assume CR/LF if at least half the linebreaks have CR + mSeparatorParams.mHasCR = (cr > (lf / 2)); + + // Set up column labels + UpdateColumnNames(); + + // Set up row labels + UpdateRowNames(); + } + + void WriteCsv() const + { +#ifdef HAS_CODECVT + if (mIsUtf16) + { + std::stringstream ss; + WriteCsv(ss); + std::string utf8 = ss.str(); + std::wstring wstr = ToWString(utf8); + + std::wofstream wstream; + wstream.exceptions(std::wofstream::failbit | std::wofstream::badbit); + wstream.open(mPath, std::ios::binary | std::ios::trunc); + + if (mIsLE) + { + wstream.imbue(std::locale(wstream.getloc(), + new std::codecvt_utf16(std::little_endian)>)); + } + else + { + wstream.imbue(std::locale(wstream.getloc(), + new std::codecvt_utf16)); + } + + wstream << static_cast(0xfeff); + wstream << wstr; + } + else +#endif + { + std::ofstream stream; + stream.exceptions(std::ofstream::failbit | std::ofstream::badbit); + stream.open(mPath, std::ios::binary | std::ios::trunc); + WriteCsv(stream); + } + } + + void WriteCsv(std::ostream& pStream) const + { + for (auto itr = mData.begin(); itr != mData.end(); ++itr) + { + for (auto itc = itr->begin(); itc != itr->end(); ++itc) + { + if (mSeparatorParams.mAutoQuote && + ((itc->find(mSeparatorParams.mSeparator) != std::string::npos) || + (itc->find(' ') != std::string::npos))) + { + // escape quotes in string + std::string str = *itc; + ReplaceString(str, "\"", "\"\""); + + pStream << "\"" << str << "\""; + } + else + { + pStream << *itc; + } + + if (std::distance(itc, itr->end()) > 1) + { + pStream << mSeparatorParams.mSeparator; + } + } + pStream << (mSeparatorParams.mHasCR ? "\r\n" : "\n"); + } + } + + size_t GetDataRowCount() const + { + return mData.size(); + } + + size_t GetDataColumnCount() const + { + return (mData.size() > 0) ? mData.at(0).size() : 0; + } + + inline size_t GetDataRowIndex(const size_t pRowIdx) const + { + return pRowIdx + static_cast(mLabelParams.mColumnNameIdx + 1); + } + + inline size_t GetDataColumnIndex(const size_t pColumnIdx) const + { + return pColumnIdx + static_cast(mLabelParams.mRowNameIdx + 1); + } + + std::string Trim(const std::string& pStr) + { + if (mSeparatorParams.mTrim) + { + std::string str = pStr; + + // ltrim + str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](int ch) { return !isspace(ch); })); + + // rtrim + str.erase(std::find_if(str.rbegin(), str.rend(), [](int ch) { return !isspace(ch); }).base(), str.end()); + + return str; + } + else + { + return pStr; + } + } + + std::string Unquote(const std::string& pStr) + { + if (mSeparatorParams.mAutoQuote && (pStr.size() >= 2) && (pStr.front() == '"') && (pStr.back() == '"')) + { + // remove start/end quotes + std::string str = pStr.substr(1, pStr.size() - 2); + + // unescape quotes in string + ReplaceString(str, "\"\"", "\""); + + return str; + } + else + { + return pStr; + } + } + + void UpdateColumnNames() + { + mColumnNames.clear(); + if ((mLabelParams.mColumnNameIdx >= 0) && + (static_cast(mData.size()) > mLabelParams.mColumnNameIdx)) + { + size_t i = 0; + for (auto& columnName : mData[static_cast(mLabelParams.mColumnNameIdx)]) + { + mColumnNames[columnName] = i++; + } + } + } + + void UpdateRowNames() + { + mRowNames.clear(); + if ((mLabelParams.mRowNameIdx >= 0) && + (static_cast(mData.size()) > + (mLabelParams.mColumnNameIdx + 1))) + { + size_t i = 0; + for (auto& dataRow : mData) + { + if (static_cast(dataRow.size()) > mLabelParams.mRowNameIdx) + { + mRowNames[dataRow[static_cast(mLabelParams.mRowNameIdx)]] = i++; + } + } + } + } + +#ifdef HAS_CODECVT +#if defined(_MSC_VER) +#pragma warning (push) +#pragma warning (disable: 4996) +#endif + static std::string ToString(const std::wstring& pWStr) + { + return std::wstring_convert, wchar_t>{ }.to_bytes(pWStr); + } + + static std::wstring ToWString(const std::string& pStr) + { + return std::wstring_convert, wchar_t>{ }.from_bytes(pStr); + } +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#endif + + static void ReplaceString(std::string& pStr, const std::string& pSearch, const std::string& pReplace) + { + size_t pos = 0; + + while ((pos = pStr.find(pSearch, pos)) != std::string::npos) + { + pStr.replace(pos, pSearch.size(), pReplace); + pos += pReplace.size(); + } + } + + private: + std::string mPath; + LabelParams mLabelParams; + SeparatorParams mSeparatorParams; + ConverterParams mConverterParams; + LineReaderParams mLineReaderParams; + std::vector> mData; + std::map mColumnNames; + std::map mRowNames; +#ifdef HAS_CODECVT + bool mIsUtf16 = false; + bool mIsLE = false; +#endif + }; +} \ No newline at end of file diff --git a/untitled/.DS_Store b/untitled/.DS_Store new file mode 100644 index 0000000..315e48b Binary files /dev/null and b/untitled/.DS_Store differ diff --git a/untitled/.idea/.gitignore b/untitled/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/untitled/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/untitled/.idea/compiler.xml b/untitled/.idea/compiler.xml new file mode 100644 index 0000000..d9e3477 --- /dev/null +++ b/untitled/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/untitled/.idea/encodings.xml b/untitled/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/untitled/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/untitled/.idea/jarRepositories.xml b/untitled/.idea/jarRepositories.xml new file mode 100644 index 0000000..712ab9d --- /dev/null +++ b/untitled/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/untitled/.idea/misc.xml b/untitled/.idea/misc.xml new file mode 100644 index 0000000..4258c62 --- /dev/null +++ b/untitled/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/untitled/pom.xml b/untitled/pom.xml new file mode 100644 index 0000000..495ed8a --- /dev/null +++ b/untitled/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + + org.example + untitled + 1.0-SNAPSHOT + + + + org.logicng + logicng + 2.3.2 + + + + + 18 + 18 + UTF-8 + + + \ No newline at end of file diff --git a/untitled/result.cnf b/untitled/result.cnf new file mode 100644 index 0000000..e5a3f90 --- /dev/null +++ b/untitled/result.cnf @@ -0,0 +1,2089 @@ +c ind 69 72 73 75 76 77 78 79 81 83 84 85 88 90 92 93 94 97 98 101 102 103 104 107 109 3 4 5 110 113 114 115 118 538 120 9 123 124 125 10 11 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 151 152 153 154 160 161 162 163 164 13 176 178 179 180 181 183 184 31 186 187 188 189 190 191 192 193 194 196 197 201 202 32 203 204 207 208 209 539 210 212 213 215 216 217 218 222 223 224 226 227 229 230 37 232 38 235 237 40 424 242 243 41 245 42 43 246 247 248 44 249 250 251 45 46 47 48 49 50 51 52 53 252 253 254 255 256 258 259 260 54 261 262 263 264 265 266 267 268 57 520 269 58 59 270 271 61 272 62 63 273 274 275 276 277 278 279 280 64 281 282 283 65 284 285 473 477 479 66 286 287 288 289 67 68 0 +p cnf 600 1413 +c MAP: Q0R -> 1 +-1 0 +c MAP: Q5J -> 2 +-2 0 +c MAP: G1W -> 3 +-3 0 +c MAP: G1X -> 4 +-4 0 +c MAP: G2B -> 5 +-5 0 +c MAP: D6I -> 6 +-6 0 +c MAP: K8M -> 7 +-7 0 +c MAP: K8T -> 8 +-8 0 +c MAP: B4L -> 9 +-9 0 +c MAP: M4A -> 10 +-10 0 +c MAP: M4B -> 11 +-11 0 +c MAP: D6M -> 12 +-12 0 +c MAP: B3J -> 13 +-13 0 +c MAP: F58L96 81 -> 14 +-14 0 +c MAP: F58LFA 0C -> 15 +-15 0 +c MAP: F58MEA 0C -> 16 +-16 0 +c MAP: AP-2 F58L96 81 -> 17 +-17 0 +c MAP: AP-2 F58L98 81 -> 18 +-18 0 +c MAP: AP-3 F58L96 81 -> 19 +-19 0 +c MAP: AP-3 F58L98 81 -> 20 +-20 0 +c MAP: AP-B F38MFA 0C -> 21 +-21 0 +c MAP: AP-B F58L96 81 -> 22 +-22 0 +c MAP: AP-B F58L98 81 -> 23 +-23 0 +c MAP: AP-B F58LFA 0C -> 24 +-24 0 +c MAP: AP-B F58MEA 0C -> 25 +-25 0 +c MAP: AP-B V18MFA 0C -> 26 +-26 0 +c MAP: K8K -> 27 +-27 0 +c MAP: K8L -> 28 +-28 0 +c MAP: K8N -> 29 +-29 0 +c MAP: D7A -> 30 +-30 0 +c MAP: M0E -> 31 +-31 0 +c MAP: Z4M -> 32 +-32 0 +c MAP: Z4R -> 33 +-33 0 +c MAP: J6C -> 34 +-34 0 +c MAP: S5E -> 35 +-35 0 +c MAP: D6C -> 36 +-36 0 +c MAP: E5K -> 37 +-37 0 +c MAP: F6T -> 38 +-38 0 +c MAP: G0L -> 39 +-39 0 +c MAP: A9X -> 40 +-40 0 +c MAP: Y4W -> 41 +-41 0 +c MAP: Q3V -> 42 +-42 0 +c MAP: V5N -> 43 +-43 0 +c MAP: X3E -> 44 +-44 0 +c MAP: M1U -> 45 +-45 0 +c MAP: M1V -> 46 +-46 0 +c MAP: M1W -> 47 +-47 0 +c MAP: M1X -> 48 +-48 0 +c MAP: M1Y -> 49 +-49 0 +c MAP: M3A -> 50 +-50 0 +c MAP: M3B -> 51 +-51 0 +c MAP: M3C -> 52 +-52 0 +c MAP: M3D -> 53 +-53 0 +c MAP: Z4J -> 54 +-54 0 +c MAP: E3W -> 55 +-55 0 +c MAP: S1G -> 56 +-56 0 +c MAP: M6E -> 57 +-57 0 +c MAP: I8N -> 58 +-58 0 +c MAP: I8O -> 59 +-59 0 +c MAP: F3Z -> 60 +-60 0 +c MAP: MB_2FT_A42_B64/62/4 -> 61 +-61 0 +c MAP: MB_2FT_WT_A64/62 -> 62 +-62 0 +c MAP: MB_2FT_WT_B64/62 -> 63 +-63 0 +c MAP: MB_EF_T_B -> 64 +-64 0 +c MAP: MB_EX_T_B -> 65 +-65 0 +c MAP: MB_SM_A/B -> 66 +-66 0 +c MAP: MB_WT_A_64/62 -> 67 +-67 0 +c MAP: MB_WT_B_64/62 -> 68 +-68 0 +c MAP: F2H -> 69 +69 0 +c MAP: D0S -> 70 +70 0 +c MAP: D8L -> 71 +71 0 +c MAP: M8Y -> 72 +72 0 +c MAP: X3H -> 73 +73 0 +c MAP: K0W -> 74 +74 0 +c MAP: S1L -> 75 +75 0 +c MAP: F5Y -> 76 +76 0 +c MAP: M5D -> 77 +77 0 +c MAP: Z4P -> 78 +78 0 +c MAP: I6X -> 79 +79 0 +c MAP: J5R -> 80 +80 0 +c MAP: W2U -> 81 +81 0 +c MAP: D4T -> 82 +82 0 +c MAP: A1G -> 83 +83 0 +c MAP: S8C -> 84 +84 0 +c MAP: K0T -> 85 +85 0 +c MAP: R1Q -> 86 +c MAP: R7S -> 87 +86 87 0 +-86 -87 0 +c MAP: U1S -> 88 +88 0 +c MAP: Q4K -> 89 +1 89 0 +-1 -89 0 +c MAP: D3F -> 90 +90 0 +c MAP: Q5U -> 91 +2 91 0 +-2 -91 0 +c MAP: M6M -> 92 +92 0 +c MAP: C6K -> 93 +93 0 +c MAP: Q1K -> 94 +94 0 +c MAP: E1K -> 95 +c MAP: E1L -> 96 +95 96 0 +-95 -96 0 +c MAP: S5Z -> 97 +97 0 +c MAP: S1D -> 98 +98 0 +c MAP: D4Y -> 99 +c MAP: D4Z -> 100 +-99 -100 0 +c MAP: F4Y -> 101 +101 0 +c MAP: C6C -> 102 +102 0 +c MAP: H8X -> 103 +103 0 +c MAP: Z5X -> 104 +104 0 +c MAP: D6F -> 105 +c MAP: D6G -> 106 +105 106 0 +-105 -106 0 +c MAP: J1V -> 107 +107 0 +c MAP: Y4Z -> 108 +108 0 +c MAP: F4I -> 109 +109 0 +c MAP: G2E -> 110 +3 4 5 110 0 +-3 -4 0 +-3 -5 0 +-3 -110 0 +-4 -5 0 +-4 -110 0 +-5 -110 0 +c MAP: I1W -> 111 +c MAP: I2F -> 112 +111 112 0 +-111 -112 0 +c MAP: F2A -> 113 +113 0 +c MAP: G5A -> 114 +114 0 +c MAP: K3M -> 115 +115 0 +c MAP: D1N -> 116 +c MAP: D2D -> 117 +116 117 0 +-116 -117 0 +c MAP: F2W -> 118 +118 0 +c MAP: K2R -> 119 +119 7 8 0 +-119 -7 0 +-119 -8 0 +-7 -8 0 +c MAP: B1F -> 120 +120 0 +c MAP: I1V -> 121 +c MAP: I2E -> 122 +121 122 0 +-121 -122 0 +c MAP: B4M -> 123 +9 123 0 +-9 -123 0 +c MAP: S1H -> 124 +124 0 +c MAP: C8B -> 125 +125 0 +c MAP: Z5E -> 126 +10 11 126 0 +-10 -11 0 +-10 -126 0 +-11 -126 0 +c MAP: M7I -> 127 +127 0 +c MAP: F1R -> 128 +128 0 +c MAP: IZY -> 129 +129 0 +c MAP: E0P -> 130 +130 0 +c MAP: O0A -> 131 +131 0 +c MAP: O1X -> 132 +132 0 +c MAP: C5P -> 133 +133 0 +c MAP: G5G -> 134 +134 0 +c MAP: F1I -> 135 +135 0 +c MAP: U1W -> 136 +136 0 +c MAP: F0X -> 137 +137 0 +c MAP: Q6Z -> 138 +138 0 +c MAP: F2P -> 139 +139 0 +c MAP: F7A -> 140 +140 0 +c MAP: O1Y -> 141 +141 0 +c MAP: A5D -> 142 +c MAP: A6Y -> 143 +142 143 0 +-142 -143 0 +c MAP: I4I -> 144 +144 0 +c MAP: D2Y -> 145 +145 0 +c MAP: I6N -> 146 +146 0 +c MAP: F3B -> 147 +c MAP: F3C -> 148 +147 148 0 +-147 -148 0 +c MAP: B1B -> 149 +c MAP: B1U -> 150 +149 150 0 +-149 -150 0 +c MAP: F6C -> 151 +151 0 +c MAP: C7F -> 152 +152 0 +c MAP: B2A -> 153 +153 0 +c MAP: C1N -> 154 +154 0 +c MAP: J2I -> 155 +c MAP: J2K -> 156 +155 156 0 +-155 -156 0 +c MAP: Q0W -> 157 +157 0 +c MAP: S1P -> 158 +c MAP: S1W -> 159 +158 159 0 +-158 -159 0 +c MAP: A1Z -> 160 +160 0 +c MAP: I6K -> 161 +161 0 +c MAP: J3V -> 162 +162 0 +c MAP: B5I -> 163 +163 0 +c MAP: E3L -> 164 +164 0 +c MAP: Q6D -> 165 +165 0 +c MAP: F3W -> 166 +c MAP: F3Y -> 167 +166 167 0 +-166 -167 0 +c MAP: F38MEA 0C -> 168 +c MAP: V18MEA 0C -> 169 +168 14 15 16 169 0 +-168 -14 0 +-168 -15 0 +-168 -16 0 +-168 -169 0 +-14 -15 0 +-14 -16 0 +-14 -169 0 +-15 -16 0 +-15 -169 0 +-16 -169 0 +c MAP: AP-2 F38MFA 0C -> 170 +c MAP: AP-2 V18MFA 0C -> 171 +170 17 18 171 0 +-170 -17 0 +-170 -18 0 +-170 -171 0 +-17 -18 0 +-17 -171 0 +-18 -171 0 +c MAP: AP-3 F38MFA 0C -> 172 +c MAP: AP-3 V18MFA 0C -> 173 +172 19 20 173 0 +-172 -19 0 +-172 -20 0 +-172 -173 0 +-19 -20 0 +-19 -173 0 +-20 -173 0 +c MAP: AP-B F38MEA 0C -> 174 +-174 -21 0 +-174 -22 0 +-174 -23 0 +-174 -24 0 +-174 -25 0 +c MAP: AP-B V18MEA 0C -> 175 +-174 -175 0 +-174 -26 0 +-21 -22 0 +-21 -23 0 +-21 -24 0 +-21 -25 0 +-21 -175 0 +-21 -26 0 +-22 -23 0 +-22 -24 0 +-22 -25 0 +-22 -175 0 +-22 -26 0 +-23 -24 0 +-23 -25 0 +-23 -175 0 +-23 -26 0 +-24 -25 0 +-24 -175 0 +-24 -26 0 +-25 -175 0 +-25 -26 0 +-175 -26 0 +c MAP: C6I -> 176 +176 0 +c MAP: Q4X -> 177 +177 0 +c MAP: M5C -> 178 +178 0 +c MAP: D3C -> 179 +179 0 +c MAP: C5B -> 180 +180 0 +c MAP: F7T -> 181 +181 0 +c MAP: K4X -> 182 +182 27 28 29 0 +-182 -27 0 +-182 -28 0 +-182 -29 0 +-27 -28 0 +-27 -29 0 +-28 -29 0 +c MAP: F7X -> 183 +183 0 +c MAP: K5Q -> 184 +184 0 +c MAP: J1H -> 185 +185 0 +c MAP: B1G -> 186 +186 0 +c MAP: M8B -> 187 +187 0 +c MAP: Z2H -> 188 +188 0 +c MAP: I6D -> 189 +189 0 +c MAP: E6I -> 190 +190 0 +c MAP: M7T -> 191 +191 0 +c MAP: E1N -> 192 +192 0 +c MAP: A2U -> 193 +193 0 +c MAP: F8E -> 194 +194 0 +c MAP: Y4A -> 195 +195 0 +c MAP: I5F -> 196 +196 0 +c MAP: L3A -> 197 +197 0 +c MAP: D1E -> 198 +c MAP: D1R -> 199 +c MAP: D2E -> 200 +198 199 200 0 +-198 -199 0 +-198 -200 0 +-199 -200 0 +c MAP: L1B -> 201 +201 0 +c MAP: F7C -> 202 +202 0 +c MAP: Z5I -> 203 +32 203 0 +-32 -203 0 +c MAP: K7N -> 204 +204 0 +c MAP: F5B -> 205 +205 0 +c MAP: E7F -> 206 +206 0 +c MAP: X2T -> 207 +207 0 +c MAP: IZS -> 208 +208 0 +c MAP: Z5Q -> 209 +209 0 +c MAP: C5D -> 210 +210 0 +c MAP: H1J -> 211 +211 0 +c MAP: C6Q -> 212 +212 0 +c MAP: Z5Y -> 213 +213 0 +c MAP: J6A -> 214 +214 34 0 +-214 -34 0 +c MAP: M5V -> 215 +215 0 +c MAP: D7R -> 216 +216 0 +c MAP: F6I -> 217 +217 0 +c MAP: C8I -> 218 +218 0 +c MAP: K5M -> 219 +219 0 +c MAP: S5A -> 220 +c MAP: S5M -> 221 +220 35 221 0 +-220 -35 0 +-220 -221 0 +-35 -221 0 +c MAP: C0A -> 222 +222 0 +c MAP: D2V -> 223 +223 0 +c MAP: DUP0 -> 224 +224 0 +c MAP: B5C -> 225 +225 0 +c MAP: C8Y -> 226 +226 0 +c MAP: D0L -> 227 +227 0 +c MAP: D4U -> 228 +228 0 +c MAP: D7G -> 229 +229 0 +c MAP: E3Q -> 230 +230 0 +c MAP: E5J -> 231 +231 0 +c MAP: F4Z -> 232 +232 0 +c MAP: F6Q -> 233 +c MAP: F6R -> 234 +233 234 0 +-233 -234 0 +c MAP: F8B -> 235 +235 0 +c MAP: G0T -> 236 +-39 -236 0 +c MAP: M5F -> 237 +237 0 +c MAP: Q0X -> 238 +238 0 +c MAP: Q0Y -> 239 +239 0 +c MAP: S6G -> 240 +c MAP: S6H -> 241 +-240 -241 0 +c MAP: S8E -> 242 +242 0 +c MAP: Y4J -> 243 +243 0 +c MAP: E2Y -> 244 +244 0 +c MAP: E8A -> 245 +245 0 +c MAP: S2B -> 246 +246 0 +c MAP: Z3H -> 247 +247 0 +c MAP: X3D -> 248 +248 44 0 +-248 -44 0 +c MAP: I8R -> 249 +249 0 +c MAP: IYY -> 250 +250 0 +c MAP: IZG -> 251 +251 0 +c MAP: M3E -> 252 +45 46 47 48 49 50 51 52 53 252 0 +-45 -46 0 +-45 -47 0 +-45 -48 0 +-45 -49 0 +-45 -50 0 +-45 -51 0 +-45 -52 0 +-45 -53 0 +-45 -252 0 +-46 -47 0 +-46 -48 0 +-46 -49 0 +-46 -50 0 +-46 -51 0 +-46 -52 0 +-46 -53 0 +-46 -252 0 +-47 -48 0 +-47 -49 0 +-47 -50 0 +-47 -51 0 +-47 -52 0 +-47 -53 0 +-47 -252 0 +-48 -49 0 +-48 -50 0 +-48 -51 0 +-48 -52 0 +-48 -53 0 +-48 -252 0 +-49 -50 0 +-49 -51 0 +-49 -52 0 +-49 -53 0 +-49 -252 0 +-50 -51 0 +-50 -52 0 +-50 -53 0 +-50 -252 0 +-51 -52 0 +-51 -53 0 +-51 -252 0 +-52 -53 0 +-52 -252 0 +-53 -252 0 +c MAP: V2B -> 253 +253 0 +c MAP: V1A -> 254 +254 0 +c MAP: ZZT -> 255 +255 0 +c MAP: O5Q -> 256 +256 0 +c MAP: U3W -> 257 +257 0 +c MAP: Z3J -> 258 +258 0 +c MAP: J8O -> 259 +259 0 +c MAP: J8Q -> 260 +260 0 +c MAP: G5L -> 261 +261 0 +c MAP: U2G -> 262 +262 0 +c MAP: U2S -> 263 +263 0 +c MAP: G0K -> 264 +264 0 +c MAP: U1E -> 265 +c MAP: U1F -> 266 +265 266 0 +-265 -266 0 +c MAP: U9Z -> 267 +267 0 +c MAP: Z4K -> 268 +268 0 +c MAP: I8M -> 269 +269 58 0 +-269 -58 0 +c MAP: I8P -> 270 +59 270 0 +-59 -270 0 +c MAP: M0C -> 271 +271 0 +c MAP: MB_2FT_A64/62 -> 272 +61 272 62 63 0 +-61 -272 0 +-61 -62 0 +-61 -63 0 +-272 -62 0 +-272 -63 0 +-62 -63 0 +c MAP: MB_CK_C -> 273 +273 0 +c MAP: MB_CMF_C -> 274 +c MAP: MB_CMF_T -> 275 +c MAP: MB_CMF_TP -> 276 +274 275 276 0 +-274 -275 0 +-274 -276 0 +-275 -276 0 +c MAP: MB_DO_C -> 277 +c MAP: MB_DO_T -> 278 +277 278 0 +-277 -278 0 +c MAP: MB_EF_C -> 279 +c MAP: MB_EF_T_A -> 280 +279 280 64 0 +-279 -280 0 +-279 -64 0 +-280 -64 0 +c MAP: MB_EX_C -> 281 +c MAP: MB_EX_ST_A -> 282 +-281 -282 0 +c MAP: MB_EX_T_A -> 283 +-281 -283 0 +-281 -65 0 +c MAP: MB_EX_T_B_B1 -> 284 +-281 -284 0 +-282 -283 0 +-282 -65 0 +-282 -284 0 +-283 -65 0 +-283 -284 0 +-65 -284 0 +c MAP: MB_FW_JO_6X4/6X2 -> 285 +285 0 +c MAP: MB_SW_G70 -> 286 +c MAP: MB_SW_G80 -> 287 +-286 -287 0 +c MAP: MB_TR_G70_6x4 -> 288 +c MAP: MB_TR_G80_6x4 -> 289 +288 289 0 +-288 -289 0 +-67 -68 0 +c analyze: M1W=>G1X&Z2H +c MAP: 4 & 188 -> 290 +290 -4 -188 0 +4 -290 0 +188 -290 0 +c MAP: -47 | 290 -> 291 +-291 -47 290 0 +47 291 0 +-290 291 0 +291 0 +c analyze: AP-B F58MEA 0C=>R8P +c MAP: R8P -> 292 +c MAP: -25 | 292 -> 293 +-293 -25 292 0 +25 293 0 +-292 293 0 +293 0 +c analyze: G2B=>G5G +c MAP: -5 | 134 -> 294 +-294 -5 134 0 +5 294 0 +-134 294 0 +294 0 +c analyze: M3A=>(G2B|G2E) +c MAP: -50 | 5 | 110 -> 295 +-295 -50 5 110 0 +50 295 0 +-5 295 0 +-110 295 0 +295 0 +c analyze: M1X=>(G1X&M4A) +c MAP: 4 & 10 -> 296 +296 -4 -10 0 +4 -296 0 +10 -296 0 +c MAP: -48 | 296 -> 297 +-297 -48 296 0 +48 297 0 +-296 297 0 +297 0 +c analyze: AP-B F58LFA 0C=>R8P +c MAP: -24 | 292 -> 298 +-298 -24 292 0 +24 298 0 +-292 298 0 +298 0 +c analyze: ~(M7I&(D6C)) +c MAP: -127 | -36 -> 299 +-299 -127 -36 0 +127 299 0 +36 299 0 +299 0 +c analyze: J5R=>J6A +c MAP: -80 | 214 -> 300 +-300 -80 214 0 +80 300 0 +-214 300 0 +300 0 +c analyze: E1N=>Z5E +c MAP: -192 | 126 -> 301 +-301 -192 126 0 +192 301 0 +-126 301 0 +301 0 +c analyze: S1I=>(B1B&D2E&S1W&S2M&X3D&(G1W|G1X|G5G)) +c MAP: S1I -> 302 +c MAP: S2M -> 303 +c MAP: 3 | 4 | 134 -> 304 +-304 3 4 134 0 +-3 304 0 +-4 304 0 +-134 304 0 +c MAP: 149 & 200 & 159 & 303 & 248 & 304 -> 305 +305 -149 -200 -159 -303 -248 -304 0 +149 -305 0 +200 -305 0 +159 -305 0 +303 -305 0 +248 -305 0 +304 -305 0 +c MAP: -302 | 305 -> 306 +-306 -302 305 0 +302 306 0 +-305 306 0 +306 0 +c analyze: AP-B V18MEA 0C=>R8P +c MAP: -175 | 292 -> 307 +-307 -175 292 0 +175 307 0 +-292 307 0 +307 0 +c analyze: AP-B F38MEA 0C=>R8P +c MAP: -174 | 292 -> 308 +-308 -174 292 0 +174 308 0 +-292 308 0 +308 0 +c analyze: E0D=>(E1K&(D6C|Y1X)) +c MAP: E0D -> 309 +c MAP: Y1X -> 310 +c MAP: 36 | 310 -> 311 +-311 36 310 0 +-36 311 0 +-310 311 0 +c MAP: 95 & 311 -> 312 +312 -95 -311 0 +95 -312 0 +311 -312 0 +c MAP: -309 | 312 -> 313 +-313 -309 312 0 +309 313 0 +-312 313 0 +313 0 +c analyze: Q0Y=>(Q0R|Q4K) +c MAP: -239 | 1 | 89 -> 314 +-314 -239 1 89 0 +239 314 0 +-1 314 0 +-89 314 0 +314 0 +c analyze: ~(E5J&(V5N)) +c MAP: -231 | -43 -> 315 +-315 -231 -43 0 +231 315 0 +43 315 0 +315 0 +c analyze: K7N=>(Z2H|Z5E) +c MAP: -204 | 188 | 126 -> 316 +-316 -204 188 126 0 +204 316 0 +-188 316 0 +-126 316 0 +316 0 +c analyze: Z5E=>(M3A|M3B|M3C|M3D|M3E) +c MAP: -126 | 50 | 51 | 52 | 53 | 252 -> 317 +-317 -126 50 51 52 53 252 0 +126 317 0 +-50 317 0 +-51 317 0 +-52 317 0 +-53 317 0 +-252 317 0 +317 0 +c analyze: ~(D6F&((D6C|D6I|D6M))) +c MAP: 36 | 6 | 12 -> 318 +-318 36 6 12 0 +-36 318 0 +-6 318 0 +-12 318 0 +c MAP: -105 | -318 -> 319 +-319 -105 -318 0 +105 319 0 +318 319 0 +319 0 +c analyze: M6E=>Z2H&(M5D&M7T&(M3A|M3B|M3C)) +c MAP: 50 | 51 | 52 -> 320 +-320 50 51 52 0 +-50 320 0 +-51 320 0 +-52 320 0 +c MAP: 188 & 77 & 191 & 320 -> 321 +321 -188 -77 -191 -320 0 +188 -321 0 +77 -321 0 +191 -321 0 +320 -321 0 +c MAP: -57 | 321 -> 322 +-322 -57 321 0 +57 322 0 +-321 322 0 +322 0 +c analyze: Q5U=>(H1J&Q4K&Q4X&Q6D) +c MAP: 211 & 89 & 177 & 165 -> 323 +323 -211 -89 -177 -165 0 +211 -323 0 +89 -323 0 +177 -323 0 +165 -323 0 +c MAP: -91 | 323 -> 324 +-324 -91 323 0 +91 324 0 +-323 324 0 +324 0 +c analyze: B3J=>(G1W|G1X) +c MAP: -13 | 3 | 4 -> 325 +-325 -13 3 4 0 +13 325 0 +-3 325 0 +-4 325 0 +325 0 +c analyze: J2K=>(J5R|J6C) +c MAP: -156 | 80 | 34 -> 326 +-326 -156 80 34 0 +156 326 0 +-80 326 0 +-34 326 0 +326 0 +c analyze: AP-B F38MFA 0C=>R8P +c MAP: -21 | 292 -> 327 +-327 -21 292 0 +21 327 0 +-292 327 0 +327 0 +c analyze: G5L=>G5G +c MAP: -261 | 134 -> 328 +-328 -261 134 0 +261 328 0 +-134 328 0 +328 0 +c analyze: S1P=>B1U +c MAP: -158 | 150 -> 329 +-329 -158 150 0 +158 329 0 +-150 329 0 +329 0 +c analyze: Q4X=>(Q5J|Q5U) +c MAP: -177 | 2 | 91 -> 330 +-330 -177 2 91 0 +177 330 0 +-2 330 0 +-91 330 0 +330 0 +c analyze: AP-B F58L98 81=>R8P +c MAP: -23 | 292 -> 331 +-331 -23 292 0 +23 331 0 +-292 331 0 +331 0 +c analyze: X3E=>(M4A|M4B) +c MAP: -44 | 10 | 11 -> 332 +-332 -44 10 11 0 +44 332 0 +-10 332 0 +-11 332 0 +332 0 +c analyze: U2G=>Z5E +c MAP: -262 | 126 -> 333 +-333 -262 126 0 +262 333 0 +-126 333 0 +333 0 +c analyze: I8P=>Z5E +c MAP: -270 | 126 -> 334 +-334 -270 126 0 +270 334 0 +-126 334 0 +334 0 +c analyze: D6I=>D6M +c MAP: -6 | 12 -> 335 +-335 -6 12 0 +6 335 0 +-12 335 0 +335 0 +c analyze: ~(E1L&((D6C|D6M))) +c MAP: 36 | 12 -> 336 +-336 36 12 0 +-36 336 0 +-12 336 0 +c MAP: -96 | -336 -> 337 +-337 -96 -336 0 +96 337 0 +336 337 0 +337 0 +c analyze: J2I=>(J5R|J6C) +c MAP: -155 | 80 | 34 -> 338 +-338 -155 80 34 0 +155 338 0 +-80 338 0 +-34 338 0 +338 0 +c analyze: D6C=>(D6G&E0D&E1K) +c MAP: 106 & 309 & 95 -> 339 +339 -106 -309 -95 0 +106 -339 0 +309 -339 0 +95 -339 0 +c MAP: -36 | 339 -> 340 +-340 -36 339 0 +36 340 0 +-339 340 0 +340 0 +c analyze: M3C=>G2E +c MAP: -52 | 110 -> 341 +-341 -52 110 0 +52 341 0 +-110 341 0 +341 0 +c analyze: Q0W=>(Q5J|Q5U) +c MAP: -157 | 2 | 91 -> 342 +-342 -157 2 91 0 +157 342 0 +-2 342 0 +-91 342 0 +342 0 +c analyze: M1Y=>(G1X&M4A) +c MAP: 4 & 10 -> 343 +343 -4 -10 0 +4 -343 0 +10 -343 0 +c MAP: -49 | 343 -> 344 +-344 -49 343 0 +49 344 0 +-343 344 0 +344 0 +c analyze: Y1X=>D7J +c MAP: D7J -> 345 +c MAP: -310 | 345 -> 346 +-346 -310 345 0 +310 346 0 +-345 346 0 +346 0 +c analyze: K2R=>Z4K +c MAP: -119 | 268 -> 347 +-347 -119 268 0 +119 347 0 +-268 347 0 +347 0 +c analyze: Q5J=>(H1J&Q0R&Q4X&Q6D) +c MAP: 211 & 1 & 177 & 165 -> 348 +348 -211 -1 -177 -165 0 +211 -348 0 +1 -348 0 +177 -348 0 +165 -348 0 +c MAP: -2 | 348 -> 349 +-349 -2 348 0 +2 349 0 +-348 349 0 +349 0 +c analyze: Q6D=>(Q5J|Q5U) +c MAP: -165 | 2 | 91 -> 350 +-350 -165 2 91 0 +165 350 0 +-2 350 0 +-91 350 0 +350 0 +c analyze: S1W=>B1B +c MAP: -159 | 149 -> 351 +-351 -159 149 0 +159 351 0 +-149 351 0 +351 0 +c analyze: M6M=>(M5D&Z5E) +c MAP: 77 & 126 -> 352 +352 -77 -126 0 +77 -352 0 +126 -352 0 +c MAP: -92 | 352 -> 353 +-353 -92 352 0 +92 353 0 +-352 353 0 +353 0 +c analyze: M7T=>Z5E +c MAP: -191 | 126 -> 354 +-354 -191 126 0 +191 354 0 +-126 354 0 +354 0 +c analyze: G5G=>(G2B|G2E) +c MAP: -134 | 5 | 110 -> 355 +-355 -134 5 110 0 +134 355 0 +-5 355 0 +-110 355 0 +355 0 +c analyze: Z4K=>(K2R|K4X|K8M) +c MAP: -268 | 119 | 182 | 7 -> 356 +-356 -268 119 182 7 0 +268 356 0 +-119 356 0 +-182 356 0 +-7 356 0 +356 0 +c analyze: H1J=>(Q5J|Q5U) +c MAP: -211 | 2 | 91 -> 357 +-357 -211 2 91 0 +211 357 0 +-2 357 0 +-91 357 0 +357 0 +c analyze: K8N=>(K0W&K8T&Z4R&Z5E) +c MAP: 74 & 8 & 33 & 126 -> 358 +358 -74 -8 -33 -126 0 +74 -358 0 +8 -358 0 +33 -358 0 +126 -358 0 +c MAP: -29 | 358 -> 359 +-359 -29 358 0 +29 359 0 +-358 359 0 +359 0 +c analyze: ~(G1X&(G5G)) +c MAP: -4 | -134 -> 360 +-360 -4 -134 0 +4 360 0 +134 360 0 +360 0 +c analyze: S6H=>B1B +c MAP: -241 | 149 -> 361 +-361 -241 149 0 +241 361 0 +-149 361 0 +361 0 +c analyze: L1G=>Z5E +c MAP: L1G -> 362 +c MAP: -362 | 126 -> 363 +-363 -362 126 0 +362 363 0 +-126 363 0 +363 0 +c analyze: J1H=>J6A +c MAP: -185 | 214 -> 364 +-364 -185 214 0 +185 364 0 +-214 364 0 +364 0 +c analyze: ~(G1W&(G5G)) +c MAP: -3 | -134 -> 365 +-365 -3 -134 0 +3 365 0 +134 365 0 +365 0 +c analyze: M0E=>((M3C&(B3J|G2E))|((M3A|M3B)&(B3J|G2B|G2E))) +c MAP: 13 | 110 -> 366 +-366 13 110 0 +-13 366 0 +-110 366 0 +c MAP: 50 | 51 -> 367 +-367 50 51 0 +-50 367 0 +-51 367 0 +c MAP: 13 | 5 | 110 -> 368 +-368 13 5 110 0 +-13 368 0 +-5 368 0 +-110 368 0 +c MAP: 52 & 366 -> 369 +369 -52 -366 0 +52 -369 0 +366 -369 0 +c MAP: 367 & 368 -> 370 +370 -367 -368 0 +367 -370 0 +368 -370 0 +c MAP: -31 | 369 | 370 -> 371 +-371 -31 369 370 0 +31 371 0 +-369 371 0 +-370 371 0 +371 0 +c analyze: R8P=>R8F +c MAP: R8F -> 372 +c MAP: -292 | 372 -> 373 +-373 -292 372 0 +292 373 0 +-372 373 0 +373 0 +c analyze: M3B=>(G1X|G2E) +c MAP: -51 | 4 | 110 -> 374 +-374 -51 4 110 0 +51 374 0 +-4 374 0 +-110 374 0 +374 0 +c analyze: D6M=>(D6G&D6I&D7A&E1K) +c MAP: 106 & 6 & 30 & 95 -> 375 +375 -106 -6 -30 -95 0 +106 -375 0 +6 -375 0 +30 -375 0 +95 -375 0 +c MAP: -12 | 375 -> 376 +-376 -12 375 0 +12 376 0 +-375 376 0 +376 0 +c analyze: U3W=>J6A&Z2H +c MAP: 214 & 188 -> 377 +377 -214 -188 0 +214 -377 0 +188 -377 0 +c MAP: -257 | 377 -> 378 +-378 -257 377 0 +257 378 0 +-377 378 0 +378 0 +c analyze: S2M=>(B1B&S1W) +c MAP: 149 & 159 -> 379 +379 -149 -159 0 +149 -379 0 +159 -379 0 +c MAP: -303 | 379 -> 380 +-380 -303 379 0 +303 380 0 +-379 380 0 +380 0 +c analyze: I8M=>Z5E +c MAP: -269 | 126 -> 381 +-381 -269 126 0 +269 381 0 +-126 381 0 +381 0 +c analyze: K8T=>(Z4R&((K8L&(M4A|M4B))|(K8N&Z5E))) +c MAP: 10 | 11 -> 382 +-382 10 11 0 +-10 382 0 +-11 382 0 +c MAP: 28 & 382 -> 383 +383 -28 -382 0 +28 -383 0 +382 -383 0 +c MAP: 29 & 126 -> 384 +384 -29 -126 0 +29 -384 0 +126 -384 0 +c MAP: 383 | 384 -> 385 +-385 383 384 0 +-383 385 0 +-384 385 0 +c MAP: 33 & 385 -> 386 +386 -33 -385 0 +33 -386 0 +385 -386 0 +c MAP: -8 | 386 -> 387 +-387 -8 386 0 +8 387 0 +-386 387 0 +387 0 +c analyze: Q4K=>Q5U +c MAP: -89 | 91 -> 388 +-388 -89 91 0 +89 388 0 +-91 388 0 +388 0 +c analyze: K8L=>(K0W&K8T&Z4R&(M4A|M4B)) +c MAP: 10 | 11 -> 389 +-389 10 11 0 +-10 389 0 +-11 389 0 +c MAP: 74 & 8 & 33 & 389 -> 390 +390 -74 -8 -33 -389 0 +74 -390 0 +8 -390 0 +33 -390 0 +389 -390 0 +c MAP: -28 | 390 -> 391 +-391 -28 390 0 +28 391 0 +-390 391 0 +391 0 +c analyze: R8F=>R8P +c MAP: -372 | 292 -> 392 +-392 -372 292 0 +372 392 0 +-292 392 0 +392 0 +c analyze: Z5Q=>(G2B|G2E) +c MAP: -209 | 5 | 110 -> 393 +-393 -209 5 110 0 +209 393 0 +-5 393 0 +-110 393 0 +393 0 +c analyze: K8M=>Z4K +c MAP: -7 | 268 -> 394 +-394 -7 268 0 +7 394 0 +-268 394 0 +394 0 +c analyze: S5M=>S1W +c MAP: -221 | 159 -> 395 +-395 -221 159 0 +221 395 0 +-159 395 0 +395 0 +c analyze: U2S=>U2G +c MAP: -263 | 262 -> 396 +-396 -263 262 0 +263 396 0 +-262 396 0 +396 0 +c analyze: Z5I=>Z5E +c MAP: -203 | 126 -> 397 +-397 -203 126 0 +203 397 0 +-126 397 0 +397 0 +c analyze: AP-B F58L96 81=>R8P +c MAP: -22 | 292 -> 398 +-398 -22 292 0 +22 398 0 +-292 398 0 +398 0 +c analyze: S3A=>(D0A&D2E&X3D) +c MAP: S3A -> 399 +c MAP: D0A -> 400 +c MAP: 400 & 200 & 248 -> 401 +401 -400 -200 -248 0 +400 -401 0 +200 -401 0 +248 -401 0 +c MAP: -399 | 401 -> 402 +-402 -399 401 0 +399 402 0 +-401 402 0 +402 0 +c analyze: I8N=>Z5E +c MAP: -58 | 126 -> 403 +-403 -58 126 0 +58 403 0 +-126 403 0 +403 0 +c analyze: M3E=>G2E +c MAP: -252 | 110 -> 404 +-404 -252 110 0 +252 404 0 +-110 404 0 +404 0 +c analyze: G0L=>(G1W|G1X) +c MAP: -39 | 3 | 4 -> 405 +-405 -39 3 4 0 +39 405 0 +-3 405 0 +-4 405 0 +405 0 +c analyze: S1G=>(B1B&S1W&S2M&(G1W|G1X)) +c MAP: 3 | 4 -> 406 +-406 3 4 0 +-3 406 0 +-4 406 0 +c MAP: 149 & 159 & 303 & 406 -> 407 +407 -149 -159 -303 -406 0 +149 -407 0 +159 -407 0 +303 -407 0 +406 -407 0 +c MAP: -56 | 407 -> 408 +-408 -56 407 0 +56 408 0 +-407 408 0 +408 0 +c analyze: M3D=>G2E +c MAP: -53 | 110 -> 409 +-409 -53 110 0 +53 409 0 +-110 409 0 +409 0 +c analyze: M5V=>(M5D&Z5E) +c MAP: 77 & 126 -> 410 +410 -77 -126 0 +77 -410 0 +126 -410 0 +c MAP: -215 | 410 -> 411 +-411 -215 410 0 +215 411 0 +-410 411 0 +411 0 +c analyze: M4A=>(M1W|M1X|M1Y) +c MAP: -10 | 47 | 48 | 49 -> 412 +-412 -10 47 48 49 0 +10 412 0 +-47 412 0 +-48 412 0 +-49 412 0 +412 0 +c analyze: G0K=>(Z5E&((B3J&(G1W|G1X))|(G5G&(B3J|G2B|G2E)))) +c MAP: 3 | 4 -> 413 +-413 3 4 0 +-3 413 0 +-4 413 0 +c MAP: 13 | 5 | 110 -> 414 +-414 13 5 110 0 +-13 414 0 +-5 414 0 +-110 414 0 +c MAP: 13 & 413 -> 415 +415 -13 -413 0 +13 -415 0 +413 -415 0 +c MAP: 134 & 414 -> 416 +416 -134 -414 0 +134 -416 0 +414 -416 0 +c MAP: 415 | 416 -> 417 +-417 415 416 0 +-415 417 0 +-416 417 0 +c MAP: 126 & 417 -> 418 +418 -126 -417 0 +126 -418 0 +417 -418 0 +c MAP: -264 | 418 -> 419 +-419 -264 418 0 +264 419 0 +-418 419 0 +419 0 +c analyze: M1V=>(G1W&M4B) +c MAP: 3 & 11 -> 420 +420 -3 -11 0 +3 -420 0 +11 -420 0 +c MAP: -46 | 420 -> 421 +-421 -46 420 0 +46 421 0 +-420 421 0 +421 0 +c analyze: Y4Z=>D0S +c MAP: -108 | 70 -> 422 +-422 -108 70 0 +108 422 0 +-70 422 0 +422 0 +c analyze: Q0R=>Q5J +c MAP: -1 | 2 -> 423 +-423 -1 2 0 +1 423 0 +-2 423 0 +423 0 +c analyze: S1R=>(B1B&S1W&S2M&Z5E) +c MAP: S1R -> 424 +c MAP: 149 & 159 & 303 & 126 -> 425 +425 -149 -159 -303 -126 0 +149 -425 0 +159 -425 0 +303 -425 0 +126 -425 0 +c MAP: -424 | 425 -> 426 +-426 -424 425 0 +424 426 0 +-425 426 0 +426 0 +c analyze: K4X=>(K2R&Z5E)&(K0W&Z4K) +c MAP: 119 & 126 & 74 & 268 -> 427 +427 -119 -126 -74 -268 0 +119 -427 0 +126 -427 0 +74 -427 0 +268 -427 0 +c MAP: -182 | 427 -> 428 +-428 -182 427 0 +182 428 0 +-427 428 0 +428 0 +c analyze: X3D=>Z5E +c MAP: -248 | 126 -> 429 +-429 -248 126 0 +248 429 0 +-126 429 0 +429 0 +c analyze: M1U=>(G1W&M4B) +c MAP: 3 & 11 -> 430 +430 -3 -11 0 +3 -430 0 +11 -430 0 +c MAP: -45 | 430 -> 431 +-431 -45 430 0 +45 431 0 +-430 431 0 +431 0 +c analyze: M4B=>(M1U|M1V) +c MAP: -11 | 45 | 46 -> 432 +-432 -11 45 46 0 +11 432 0 +-45 432 0 +-46 432 0 +432 0 +c analyze: M5D=>Z5E +c MAP: -77 | 126 -> 433 +-433 -77 126 0 +77 433 0 +-126 433 0 +433 0 +c analyze: K0W=>(K4X|K8K|K8L|K8N) +c MAP: -74 | 182 | 27 | 28 | 29 -> 434 +-434 -74 182 27 28 29 0 +74 434 0 +-182 434 0 +-27 434 0 +-28 434 0 +-29 434 0 +434 0 +c analyze: AP-B V18MFA 0C=>R8P +c MAP: -26 | 292 -> 435 +-435 -26 292 0 +26 435 0 +-292 435 0 +435 0 +c analyze: I8O=>Z5E +c MAP: -59 | 126 -> 436 +-436 -59 126 0 +59 436 0 +-126 436 0 +436 0 +c analyze: K8K=>(K0W&K2R&Z4R&(M4A|M4B)) +c MAP: 10 | 11 -> 437 +-437 10 11 0 +-10 437 0 +-11 437 0 +c MAP: 74 & 119 & 33 & 437 -> 438 +438 -74 -119 -33 -437 0 +74 -438 0 +119 -438 0 +33 -438 0 +437 -438 0 +c MAP: -27 | 438 -> 439 +-439 -27 438 0 +27 439 0 +-438 439 0 +439 0 +c analyze: S6G=>B1B +c MAP: -240 | 149 -> 440 +-440 -240 149 0 +240 440 0 +-149 440 0 +440 0 +c analyze: G2E=>G5G +c MAP: -110 | 134 -> 441 +-441 -110 134 0 +110 441 0 +-134 441 0 +441 0 +c analyze: MB_CMF_T=>D4T&D4U&D8L&E2Y&D0A&D4N&D5B&D5Z&D6G&D7J&F3C +c MAP: D4N -> 442 +c MAP: D5B -> 443 +c MAP: D5Z -> 444 +c MAP: 82 & 228 & 71 & 244 & 400 & 442 & 443 & 444 & 106 & 345 & 148 -> 445 +445 -82 -228 -71 -244 -400 -442 -443 -444 -106 -345 -148 0 +82 -445 0 +228 -445 0 +71 -445 0 +244 -445 0 +400 -445 0 +442 -445 0 +443 -445 0 +444 -445 0 +106 -445 0 +345 -445 0 +148 -445 0 +c MAP: -275 | 445 -> 446 +-446 -275 445 0 +275 446 0 +-445 446 0 +446 0 +c analyze: MB_CMF_TP=>D4T&D4U&D8L&E2Y&D0A&D4N&D5B&D5Z&D6G&D7J&F3C&D2D&D4Z&E0D&E1K&Y1X +c MAP: 82 & 228 & 71 & 244 & 400 & 442 & 443 & 444 & 106 & 345 & 148 & 117 & 100 & 309 & 95 & 310 -> 447 +447 -82 -228 -71 -244 -400 -442 -443 -444 -106 -345 -148 -117 -100 -309 -95 -310 0 +82 -447 0 +228 -447 0 +71 -447 0 +244 -447 0 +400 -447 0 +442 -447 0 +443 -447 0 +444 -447 0 +106 -447 0 +345 -447 0 +148 -447 0 +117 -447 0 +100 -447 0 +309 -447 0 +95 -447 0 +310 -447 0 +c MAP: -276 | 447 -> 448 +-448 -276 447 0 +276 448 0 +-447 448 0 +448 0 +c analyze: MB_DO_C=>B5C&D0S&E5J&K5M&Y4A&Y4Z&E7F +c MAP: 225 & 70 & 231 & 219 & 195 & 108 & 206 -> 449 +449 -225 -70 -231 -219 -195 -108 -206 0 +225 -449 0 +70 -449 0 +231 -449 0 +219 -449 0 +195 -449 0 +108 -449 0 +206 -449 0 +c MAP: -277 | 449 -> 450 +-450 -277 449 0 +277 450 0 +-449 450 0 +450 0 +c analyze: MB_DO_T=>B5C&D0S&E5J&K5M&Y4A&Y4Z&E7F&F3Y +c MAP: 225 & 70 & 231 & 219 & 195 & 108 & 206 & 167 -> 451 +451 -225 -70 -231 -219 -195 -108 -206 -167 0 +225 -451 0 +70 -451 0 +231 -451 0 +219 -451 0 +195 -451 0 +108 -451 0 +206 -451 0 +167 -451 0 +c MAP: -278 | 451 -> 452 +-452 -278 451 0 +278 452 0 +-451 452 0 +452 0 +c analyze: MB_EF_C=>F5B +c MAP: -279 | 205 -> 453 +-453 -279 205 0 +279 453 0 +-205 453 0 +453 0 +c analyze: MB_EF_T_A=>G0T +c MAP: -280 | 236 -> 454 +-454 -280 236 0 +280 454 0 +-236 454 0 +454 0 +c analyze: MB_EF_T_B=>G0L +c MAP: -64 | 39 -> 455 +-455 -64 39 0 +64 455 0 +-39 455 0 +455 0 +c analyze: MB_EX_C=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I +c MAP: R0Q -> 456 +c MAP: U2I -> 457 +c MAP: 149 & 456 & 159 & 303 & 240 & 221 & 457 -> 458 +458 -149 -456 -159 -303 -240 -221 -457 0 +149 -458 0 +456 -458 0 +159 -458 0 +303 -458 0 +240 -458 0 +221 -458 0 +457 -458 0 +c MAP: -281 | 458 -> 459 +-459 -281 458 0 +281 459 0 +-458 459 0 +459 0 +c analyze: MB_EX_ST_A=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I&F8V&F8W&L1H&S1I&L1G&S3A +c MAP: F8V -> 460 +c MAP: F8W -> 461 +c MAP: L1H -> 462 +c MAP: 149 & 456 & 159 & 303 & 240 & 221 & 457 & 460 & 461 & 462 & 302 & 362 & 399 -> 463 +463 -149 -456 -159 -303 -240 -221 -457 -460 -461 -462 -302 -362 -399 0 +149 -463 0 +456 -463 0 +159 -463 0 +303 -463 0 +240 -463 0 +221 -463 0 +457 -463 0 +460 -463 0 +461 -463 0 +462 -463 0 +302 -463 0 +362 -463 0 +399 -463 0 +c MAP: -282 | 463 -> 464 +-464 -282 463 0 +282 464 0 +-463 464 0 +464 0 +c analyze: MB_EX_T_A=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I&F8V&F8W&L1H&S1I +c MAP: 149 & 456 & 159 & 303 & 240 & 221 & 457 & 460 & 461 & 462 & 302 -> 465 +465 -149 -456 -159 -303 -240 -221 -457 -460 -461 -462 -302 0 +149 -465 0 +456 -465 0 +159 -465 0 +303 -465 0 +240 -465 0 +221 -465 0 +457 -465 0 +460 -465 0 +461 -465 0 +462 -465 0 +302 -465 0 +c MAP: -283 | 465 -> 466 +-466 -283 465 0 +283 466 0 +-465 466 0 +466 0 +c analyze: MB_EX_T_B=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I&F8V&F8W&L1H&S1G +c MAP: 149 & 456 & 159 & 303 & 240 & 221 & 457 & 460 & 461 & 462 & 56 -> 467 +467 -149 -456 -159 -303 -240 -221 -457 -460 -461 -462 -56 0 +149 -467 0 +456 -467 0 +159 -467 0 +303 -467 0 +240 -467 0 +221 -467 0 +457 -467 0 +460 -467 0 +461 -467 0 +462 -467 0 +56 -467 0 +c MAP: -65 | 467 -> 468 +-468 -65 467 0 +65 468 0 +-467 468 0 +468 0 +c analyze: MB_EX_T_B_B1=>B1B&R0Q&S1W&S2M&S6G&S5M&U2I&F8V&F8W&L1H +c MAP: 149 & 456 & 159 & 303 & 240 & 221 & 457 & 460 & 461 & 462 -> 469 +469 -149 -456 -159 -303 -240 -221 -457 -460 -461 -462 0 +149 -469 0 +456 -469 0 +159 -469 0 +303 -469 0 +240 -469 0 +221 -469 0 +457 -469 0 +460 -469 0 +461 -469 0 +462 -469 0 +c MAP: -284 | 469 -> 470 +-470 -284 469 0 +284 470 0 +-469 470 0 +470 0 +c analyze: MB_FW_JO_6X4/6X2=>Q5U&Q4K&Q6D&Q0W&Q0X&Q0Y&Q4X&H1J +c MAP: 91 & 89 & 165 & 157 & 238 & 239 & 177 & 211 -> 471 +471 -91 -89 -165 -157 -238 -239 -177 -211 0 +91 -471 0 +89 -471 0 +165 -471 0 +157 -471 0 +238 -471 0 +239 -471 0 +177 -471 0 +211 -471 0 +c MAP: -285 | 471 -> 472 +-472 -285 471 0 +285 472 0 +-471 472 0 +472 0 +c analyze: MB_LW_A/B_B1=>Q0A&R7S +c MAP: MB_LW_A/B_B1 -> 473 +c MAP: Q0A -> 474 +c MAP: 474 & 87 -> 475 +475 -474 -87 0 +474 -475 0 +87 -475 0 +c MAP: -473 | 475 -> 476 +-476 -473 475 0 +473 476 0 +-475 476 0 +476 0 +c analyze: MB_MT_A/B=>L1H +c MAP: MB_MT_A/B -> 477 +c MAP: -477 | 462 -> 478 +-478 -477 462 0 +477 478 0 +-462 478 0 +478 0 +c analyze: MB_RS_A/B=>F0T&F5L&F6R +c MAP: MB_RS_A/B -> 479 +c MAP: F0T -> 480 +c MAP: F5L -> 481 +c MAP: 480 & 481 & 234 -> 482 +482 -480 -481 -234 0 +480 -482 0 +481 -482 0 +234 -482 0 +c MAP: -479 | 482 -> 483 +-483 -479 482 0 +479 483 0 +-482 483 0 +483 0 +c analyze: MB_SM_A/B=>D6C&D7A&E0D&E1K&D2E&D6G +c MAP: 36 & 30 & 309 & 95 & 200 & 106 -> 484 +484 -36 -30 -309 -95 -200 -106 0 +36 -484 0 +30 -484 0 +309 -484 0 +95 -484 0 +200 -484 0 +106 -484 0 +c MAP: -66 | 484 -> 485 +-485 -66 484 0 +66 485 0 +-484 485 0 +485 0 +c analyze: MB_SW_G70=>R8F&R8P&AP-B F38MEA 0C +c MAP: 372 & 292 & 174 -> 486 +486 -372 -292 -174 0 +372 -486 0 +292 -486 0 +174 -486 0 +c MAP: -286 | 486 -> 487 +-487 -286 486 0 +286 487 0 +-486 487 0 +487 0 +c analyze: MB_SW_G80=>R8F&R8P&AP-B V18MEA 0C +c MAP: 372 & 292 & 175 -> 488 +488 -372 -292 -175 0 +372 -488 0 +292 -488 0 +175 -488 0 +c MAP: -287 | 488 -> 489 +-489 -287 488 0 +287 489 0 +-488 489 0 +489 0 +c analyze: MB_TR_G70_6x4=>I2E&I2F&F38MEA 0C&AP-2 F38MFA 0C&AP-3 F38MFA 0C +c MAP: 122 & 112 & 168 & 170 & 172 -> 490 +490 -122 -112 -168 -170 -172 0 +122 -490 0 +112 -490 0 +168 -490 0 +170 -490 0 +172 -490 0 +c MAP: -288 | 490 -> 491 +-491 -288 490 0 +288 491 0 +-490 491 0 +491 0 +c analyze: MB_TR_G80_6x4=>AP-2 V18MFA 0C&V18MEA 0C&I1V&I1W&AP-3 V18MFA 0C +c MAP: 171 & 169 & 121 & 111 & 173 -> 492 +492 -171 -169 -121 -111 -173 0 +171 -492 0 +169 -492 0 +121 -492 0 +111 -492 0 +173 -492 0 +c MAP: -289 | 492 -> 493 +-493 -289 492 0 +289 493 0 +-492 493 0 +493 0 +c analyze: MB_WT_A_64/62=>D6G&D6I&D6M&D7A&E1K&E3W&K8T&K8N&F3Z +c MAP: 106 & 6 & 12 & 30 & 95 & 55 & 8 & 29 & 60 -> 494 +494 -106 -6 -12 -30 -95 -55 -8 -29 -60 0 +106 -494 0 +6 -494 0 +12 -494 0 +30 -494 0 +95 -494 0 +55 -494 0 +8 -494 0 +29 -494 0 +60 -494 0 +c MAP: -67 | 494 -> 495 +-495 -67 494 0 +67 495 0 +-494 495 0 +495 0 +c analyze: MB_WT_B_64/62=>D6G&D6I&D6M&D7A&E1K&E3W&K8T&F3Z&K8L +c MAP: 106 & 6 & 12 & 30 & 95 & 55 & 8 & 60 & 28 -> 496 +496 -106 -6 -12 -30 -95 -55 -8 -60 -28 0 +106 -496 0 +6 -496 0 +12 -496 0 +30 -496 0 +95 -496 0 +55 -496 0 +8 -496 0 +60 -496 0 +28 -496 0 +c MAP: -68 | 496 -> 497 +-497 -68 496 0 +68 497 0 +-496 497 0 +497 0 +c analyze: MB_2FT_WT_A64/62=>K0W&K8T&K8N&Z4R +c MAP: 74 & 8 & 29 & 33 -> 498 +498 -74 -8 -29 -33 0 +74 -498 0 +8 -498 0 +29 -498 0 +33 -498 0 +c MAP: -62 | 498 -> 499 +-499 -62 498 0 +62 499 0 +-498 499 0 +499 0 +c analyze: MB_2FT_WT_B64/62=>K0W&K8T&Z4R&K8L +c MAP: 74 & 8 & 33 & 28 -> 500 +500 -74 -8 -33 -28 0 +74 -500 0 +8 -500 0 +33 -500 0 +28 -500 0 +c MAP: -63 | 500 -> 501 +-501 -63 500 0 +63 501 0 +-500 501 0 +501 0 +c analyze: MB_CK_C=>J6A&J1H&J5R&J2I&U3W +c MAP: 214 & 185 & 80 & 155 & 257 -> 502 +502 -214 -185 -80 -155 -257 0 +214 -502 0 +185 -502 0 +80 -502 0 +155 -502 0 +257 -502 0 +c MAP: -273 | 502 -> 503 +-503 -273 502 0 +273 503 0 +-502 503 0 +503 0 +c analyze: MB_2FT_A42_B64/62/4=>K0W&K8K&Z4R +c MAP: 74 & 27 & 33 -> 504 +504 -74 -27 -33 0 +74 -504 0 +27 -504 0 +33 -504 0 +c MAP: -61 | 504 -> 505 +-505 -61 504 0 +61 505 0 +-504 505 0 +505 0 +c analyze: MB_2FT_A64/62=>K0W&K4X +c MAP: 74 & 182 -> 506 +506 -74 -182 0 +74 -506 0 +182 -506 0 +c MAP: -272 | 506 -> 507 +-507 -272 506 0 +272 507 0 +-506 507 0 +507 0 +c analyze: MB_CMF_C=>D4T&D4U&D8L&E2Y +c MAP: 82 & 228 & 71 & 244 -> 508 +508 -82 -228 -71 -244 0 +82 -508 0 +228 -508 0 +71 -508 0 +244 -508 0 +c MAP: -274 | 508 -> 509 +-509 -274 508 0 +274 509 0 +-508 509 0 +509 0 +c analyze: MB_SW_G80=>MB_TR_G80_6x4 +c MAP: -287 | 289 -> 510 +-510 -287 289 0 +287 510 0 +-289 510 0 +510 0 +c analyze: MB_SW_G70=>MB_TR_G70_6x4 +c MAP: -286 | 288 -> 511 +-511 -286 288 0 +286 511 0 +-288 511 0 +511 0 +c analyze: (MB_DO_C|MB_DO_T)=>M7I +c MAP: -277 & -278 -> 512 +512 277 278 0 +-277 -512 0 +-278 -512 0 +c MAP: 512 | 127 -> 513 +-513 512 127 0 +-512 513 0 +-127 513 0 +513 0 +c analyze: M1X|M3A=>!(B3J|A5D) +c MAP: -48 & -50 -> 514 +514 48 50 0 +-48 -514 0 +-50 -514 0 +c MAP: -13 & -142 -> 515 +515 13 142 0 +-13 -515 0 +-142 -515 0 +c MAP: 514 | 515 -> 516 +-516 514 515 0 +-514 516 0 +-515 516 0 +516 0 +c analyze: U1F<=>S1W +c MAP: -266 | 159 -> 517 +-517 -266 159 0 +266 517 0 +-159 517 0 +c MAP: -159 | 266 -> 518 +-518 -159 266 0 +159 518 0 +-266 518 0 +c MAP: 517 & 518 -> 519 +519 -517 -518 0 +517 -519 0 +518 -519 0 +519 0 +c analyze: C8M&I2E&I2F=>MB_LW_A/B_B1 +c MAP: C8M -> 520 +c MAP: -520 | -122 | -112 | 473 -> 521 +-521 -520 -122 -112 473 0 +520 521 0 +122 521 0 +112 521 0 +-473 521 0 +521 0 +c analyze: MB_CMF_T|MB_CMF_TP=>D2E +c MAP: -275 & -276 -> 522 +522 275 276 0 +-275 -522 0 +-276 -522 0 +c MAP: 522 | 200 -> 523 +-523 522 200 0 +-522 523 0 +-200 523 0 +523 0 +c analyze: M7I=>!MB_SM_A/B +c MAP: -127 | -66 -> 524 +-524 -127 -66 0 +127 524 0 +66 524 0 +524 0 +c analyze: G0T=>((G2B|G2E)&G5G)|((G1W|G1X)&B3J)&Z5E +c MAP: 5 | 110 -> 525 +-525 5 110 0 +-5 525 0 +-110 525 0 +c MAP: 3 | 4 -> 526 +-526 3 4 0 +-3 526 0 +-4 526 0 +c MAP: 525 & 134 -> 527 +527 -525 -134 0 +525 -527 0 +134 -527 0 +c MAP: 526 & 13 & 126 -> 528 +528 -526 -13 -126 0 +526 -528 0 +13 -528 0 +126 -528 0 +c MAP: -236 | 527 | 528 -> 529 +-529 -236 527 528 0 +236 529 0 +-527 529 0 +-528 529 0 +529 0 +c analyze: MB_EX_ST_A=>S1R +c MAP: -282 | 424 -> 530 +-530 -282 424 0 +282 530 0 +-424 530 0 +530 0 +c analyze: MB_MT_A/B&X3E=>A5D&B3J +c MAP: 142 & 13 -> 531 +531 -142 -13 0 +142 -531 0 +13 -531 0 +c MAP: -477 | -44 | 531 -> 532 +-532 -477 -44 531 0 +477 532 0 +44 532 0 +-531 532 0 +532 0 +c analyze: MB_EX_T_A|MB_EX_ST_A|MB_EX_T_B=>MB_CMF_TP|MB_CMF_T|MB_SM_A/B +c MAP: -283 & -282 & -65 -> 533 +533 283 282 65 0 +-283 -533 0 +-282 -533 0 +-65 -533 0 +c MAP: 533 | 276 | 275 | 66 -> 534 +-534 533 276 275 66 0 +-533 534 0 +-276 534 0 +-275 534 0 +-66 534 0 +534 0 +c analyze: MB_EX_T_A|MB_EX_ST_A=>MB_CMF_TP|MB_CMF_T|MB_SM_A/B +c MAP: -283 & -282 -> 535 +535 283 282 0 +-283 -535 0 +-282 -535 0 +c MAP: 535 | 276 | 275 | 66 -> 536 +-536 535 276 275 66 0 +-535 536 0 +-276 536 0 +-275 536 0 +-66 536 0 +536 0 +c analyze: MB_MT_A/B&X3D=>A5D +c MAP: -477 | -248 | 142 -> 537 +-537 -477 -248 142 0 +477 537 0 +248 537 0 +-142 537 0 +537 0 diff --git a/untitled/src/.DS_Store b/untitled/src/.DS_Store new file mode 100644 index 0000000..799007c Binary files /dev/null and b/untitled/src/.DS_Store differ diff --git a/untitled/src/main/java/org/example/Main.java b/untitled/src/main/java/org/example/Main.java new file mode 100644 index 0000000..b91f319 --- /dev/null +++ b/untitled/src/main/java/org/example/Main.java @@ -0,0 +1,30 @@ +package org.example; + +import org.logicng.formulas.Formula; +import org.logicng.formulas.FormulaFactory; +import org.logicng.formulas.Variable; +import org.logicng.io.parsers.ParserException; +import org.logicng.io.readers.DimacsReader; +import org.logicng.modelcounting.ModelCounter; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.*; + +public class Main { + public static void main(String[] args) throws ParserException, IOException { + FormulaFactory f = new FormulaFactory(); + List formulas = DimacsReader.readCNF("result.cnf", f); + + SortedSet variables = new TreeSet<>(); + for(Formula formula : formulas) { + variables.addAll(formula.variables()); + } + + long time = System.currentTimeMillis(); + + BigInteger modelcount = ModelCounter.count(formulas, variables); + System.out.println("answer:" + modelcount); + System.out.println("time: " + (System.currentTimeMillis()-time) + " ms"); + } +} \ No newline at end of file diff --git a/untitled/target/classes/org/example/Main.class b/untitled/target/classes/org/example/Main.class new file mode 100644 index 0000000..cb92dad Binary files /dev/null and b/untitled/target/classes/org/example/Main.class differ diff --git a/甘棠约束条件编码器.pdf b/甘棠约束条件编码器.pdf new file mode 100644 index 0000000..a5c0a4e Binary files /dev/null and b/甘棠约束条件编码器.pdf differ