#!/usr/bin/awk -f BEGIN { init() } function init( i,isStructure,isUngron) { for (i = 1; i < ARGC; i++) { if ((isUngron = "-u"==ARGV[i]) || (isStructure = "-s"==ARGV[i])) { delete ARGV[i] break } } Pos=1 RS="\x01" # this allows to read whole input at once if ((getline In) < 0) die("I/O error") isUngron ? ungron() : gron(isStructure) } function gron(isStructure) { # --- parse JSON --- split("", Asm); AsmLen=0 if (!ELEMENT() || Pos <= length(In)) dieAtPos("Can't parse JSON") # dbgA("--- JSON asm:",Asm) # --- generate GRON --- split("",AlreadyTracked) split("",Stack); split("",PathStack) Depth = 0 generateGron(isStructure) } function ungron( i,instr) { split("", Asm); AsmLen=0 # Gron asm split("", JsonAsm); JsonAsmLen=0 if (!STATEMENTS() || Pos <= length(In)) dieAtPos("Can't parse GRON") # --- ungron (gron asm -> json asm) --- # dbgA("--- Gron asm:",Asm) split("", AddrType) # addr -> type split("", AddrValue) # addr -> value split("", AddrCount) # addr -> segment count split("", AddrKey) # addr -> last segment name for (i=0; i "\x1F") { Pos++ res[0] = res[0] c return 1 } return 0 } function STRING(isKey, res) { return tryParse1("\"",res) && asm(isKey ? "key" : "string") && tryParseCharacters(res) && tryParse1("\"",res) && asm(res[0]) } function WS() { return tryParse("\t\n\r ") || 1 } function WS1() { return tryParse("\t ") || 1 } function VALUE() { return OBJECT() || ARRAY() || STRING() || NUMBER() || tryParseExact("true") && asm("true") || tryParseExact("false") && asm("false") || tryParseExact("null") && asm("null") } function OBJECT() { return tryParse1("{") && asm("object") && (WS() && tryParse1("}") || MEMBERS() && tryParse1("}")) && asm("end_object") } function ARRAY() { return tryParse1("[") && asm("array") && (WS() && tryParse1("]") || ELEMENTS() && tryParse1("]")) && asm("end_array") } function MEMBERS() { return MEMBER() && (tryParse1(",") ? MEMBERS() : 1) } function ELEMENTS() { return ELEMENT() && (tryParse1(",") ? ELEMENTS() : 1) } function MEMBER() { return WS() && STRING(1) && WS() && tryParse1(":") && ELEMENT() } function ELEMENT() { return WS() && VALUE() && WS() } # --- GRON --- function STATEMENTS() { for(tryParse("\n");nextChar();tryParse("\n")) { if (!STATEMENT()) return 0 } return 1 } function STATEMENT() { return asm("record") && PATH() && WS1() && tryParse1("=") && WS1() && asm("value") && VALUE_GRON() && (tryParse1(";")||1) && asm("end") } function PATH() { return BARE_WORD() && SEGMENTS() } function BARE_WORD( word) { return tryParse1("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_", word) && (tryParse("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789", word) || 1) && asm("key") && asm("\"" word[0] "\"") } function SEGMENTS() { return SEGMENT() && SEGMENTS() || 1 } function SEGMENT() { return tryParse1(".") && BARE_WORD() || tryParse1("[") && KEY() && tryParse1("]") } function KEY( idx) { return tryParse("0123456789", idx) && asm("index") && asm(idx[0]) || STRING(1) } function VALUE_GRON() { return STRING() || NUMBER() || tryParseExact("true") && asm("true") || tryParseExact("false") && asm("false") || tryParseExact("null") && asm("null") || tryParseExact("{}") && asm("object") || tryParseExact("[]") && asm("array") } # --- ungron --- function isComplex(s) { return "object"==s || "array"==s } function isSegmentType(s) { return "key" ==s || "index" ==s } function isValueHolder(s) { return "string"==s || "number"==s } function processRecord( l, addr, type, value, i) { l = arrLen(Path) addr="" for (i=0; i0?",":"") Path[i] if (i0) { aPrev = addrs[i-1] for (j=0; j 0 && (atMost==0 || i++ < atMost) && c != "") { s = s c Pos++ } res[0] = res[0] s return s != "" } function nextChar() { return substr(In,Pos,1) } function asm(inst) { Asm[AsmLen++]=inst; return 1 } # ----- function generateGron(isStructure, i, instr) { for (i=0; i v2 ? 1 : v1 < v2 ? -1 : 0 } function _digit(c) { return c >= "0" && c <= "9" } function quicksort(data, left, right, i, last) { if (left >= right) return _swap(data, left, int((left + right) / 2)) last = left for (i = left + 1; i <= right; i++) if (natOrder(data[i], data[left],1,1) < 0) _swap(data, ++last, i) _swap(data, left, last) quicksort(data, left, last - 1) quicksort(data, last + 1, right) } function _swap(data, i, j, temp) { temp = data[i] data[i] = data[j] data[j] = temp }