arithmetic.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdalign.h>
  5. #include <ctype.h>
  6. #include <sys/mman.h>
  7. #include "../vec.h"
  8. #include "../hash.h"
  9. #include "../rpn.h"
  10. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  11. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  12. #include "arithmetic.h"
  13. static size_t parse(char* input, char*** output);
  14. AssemblerInfo assemblerLookup[] = {
  15. {INST_LOAD, {0x0f, 0x10}, 2, 0, "movups"},
  16. {INST_STORE, {0x0f, 0x11}, 2, 1, "movups"},
  17. {INST_MOV, {0x0f, 0x28}, 2, 0, "movaps"},
  18. {INST_ADD, {0x0f, 0x58}, 2, 0, "addps"},
  19. {INST_MUL, {0x0f, 0x59}, 2, 0, "mulps"},
  20. {INST_SUB, {0x0f, 0x5c}, 2, 0, "subps"},
  21. {INST_DIV, {0x0f, 0x5e}, 2, 0, "divps"},
  22. };
  23. AssemblerInfo* findInstr(enum InstructionType type) {
  24. for(int i = 0; i < sizeof(assemblerLookup) / sizeof(assemblerLookup[0]); i++) {
  25. AssemblerInfo* a = &assemblerLookup[i];
  26. if(type == a->type) return a;
  27. }
  28. return NULL;
  29. }
  30. char* TokTypeNames[] = {
  31. #define X(x) [T_##x] = #x,
  32. TOKEN_TYPES
  33. #undef X
  34. };
  35. enum TokType classifyToken(char* s) {
  36. switch(*s) {
  37. case '+': return T_ADD;
  38. case '-': return T_SUB;
  39. case '*': return T_MUL;
  40. case '/': return T_DIV;
  41. case '0':
  42. case '1':
  43. case '2':
  44. case '3':
  45. case '4':
  46. case '5':
  47. case '6':
  48. case '7':
  49. case '8':
  50. case '9':
  51. case '.':
  52. return T_CONST;
  53. default: return T_VAR;
  54. }
  55. }
  56. void printNode(Node* n, int indent) {
  57. for(int i = 0; i < indent; i++) printf(" ");
  58. printf("%s (%d): ", n->text, n->resultVar);
  59. if(n->l) printf("%s", n->l->text);
  60. else printf("_");
  61. printf(" / ");
  62. if(n->r) printf("%s", n->r->text);
  63. else printf("_");
  64. printf("\n");
  65. if(n->l) printNode(n->l, indent + 2);
  66. if(n->r) printNode(n->r, indent + 2);
  67. }
  68. // W = 1 means 64 bit operand size
  69. // R is the MSB of the modr/m reg field
  70. // X is the MSB of the sib index field
  71. // B is the MSB of the modr/m r/m field, sib base field, or opcode reg field
  72. static byte encodeREX(char W, char R, char X, char B) {
  73. return 0 | (1 << 6) | (!!W << 3) | (!!R << 2) | (!!X << 1) | (!!B);
  74. }
  75. // reg usually encodes the second operand, usually the destination
  76. // mod+r/m usually encode the first operand
  77. // reg sometimes stores extra opcode information
  78. // rarely, mod+rm can store extra opcode info
  79. static byte encodeModRM(unsigned char mod, unsigned char reg, unsigned char rm) {
  80. byte out = 0;
  81. out |= mod << 6;
  82. out |= (reg & 0x7) << 3;
  83. out |= (rm & 0x7);
  84. return out;
  85. }
  86. // mod = 11, r/m = 0..8
  87. // AX, CX, DX, BX, SP, BP, SI, DI
  88. // 0 1 2 3 4 5 6 7
  89. // In 64-bit mode, the default address size is 64 and operand size is 32
  90. // legacy prefix, rex prefix, opcode, modr/m, sib, disp, imm
  91. // rex prefix comes after mandatory prefix and before escape bytes
  92. // MOVUPS 0f 10 reg = dst, r/m = src
  93. // MOVUPS 0f 11 reg = src, r/m = dst
  94. // MOVAPS 0f 28 reg = dst, r/m = src
  95. // MOVAPS 0f 29 reg = src, r/m = dst
  96. // ADDPS 0f 58 reg = dst, r/m = src
  97. // MULPS 0f 59 reg = dst, r/m = src
  98. // SUBPS 0f 5C reg = dst, r/m = src
  99. // DIVPS 0f 5E reg = dst, r/m = src
  100. // MINPS 0f 5d reg = dst, r/m = src
  101. // MAXPS 0f 5f reg = dst, r/m = src
  102. // SQRTPS 0f 51 reg = dst, r/m = src
  103. // RSQRTPS 0f 52 reg = dst, r/m = src
  104. // RCPPS 0f 53 reg = dst, r/m = src // reciprocal
  105. enum {
  106. REG,
  107. MEM,
  108. };
  109. enum {
  110. M_TEMP,
  111. M_INPUT,
  112. M_CONST,
  113. M_OUTPUT,
  114. };
  115. void assignRegisters(Node* n, RegAllocInfo* info) {
  116. if(n->l) assignRegisters(n->l, info);
  117. if(n->r) assignRegisters(n->r, info);
  118. n->resultVar = info->nextVar++;
  119. }
  120. // Argument passing:
  121. // rdi, rsi, rdx, rcx, r8, r9, ....stack
  122. /*
  123. typedef void (*arithmetic_fn)(float* in, float* out, float* constants);
  124. */
  125. void encodeInst(AsmInst* inst) {
  126. byte temp[16]; // x64 instructions cannot be longer than 15 bytes, per the ISA
  127. int len = 0;
  128. byte modrm;
  129. byte disp8;
  130. unsigned int disp32;
  131. char hasDisp8 = 0;
  132. char hasDisp32 = 0;
  133. AssemblerInfo* a = findInstr(inst->instID);
  134. // TODO: prefixes here
  135. // opcode bytes
  136. for(int i = 0; i < a->numOpcodes; i++) {
  137. temp[len++] = a->opcodes[i];
  138. }
  139. // modr/m byte
  140. if(inst->srcType == MEM) {
  141. // memory
  142. if(a->dstIsRM) {
  143. // modrm = encodeModRM(0x3, inst->srcReg, inst->dstReg);
  144. printf("\n--STORE assembly not implemented--\n\n");
  145. // BUG: probably all wrong
  146. if(inst->srcReg == M_INPUT)
  147. modrm = encodeModRM(0x2, inst->srcReg, 0x7); // [rdi]+disp32
  148. if(inst->srcReg == M_OUTPUT)
  149. modrm = encodeModRM(0x2, inst->srcReg, 0x6); // [rsi]+disp32
  150. if(inst->srcReg == M_CONST)
  151. modrm = encodeModRM(0x2, inst->srcReg, 0x2); // [rdx]+disp32
  152. if(inst->srcReg == M_TEMP)
  153. modrm = encodeModRM(0x2, inst->srcReg, 0x1); // [rcx]+disp32
  154. hasDisp32 = 1;
  155. disp32 = inst->memOffset*4;
  156. }
  157. else {
  158. if(inst->srcReg == M_INPUT)
  159. modrm = encodeModRM(0x2, inst->dstReg, 0x7); // [rdi]+disp32
  160. if(inst->srcReg == M_OUTPUT)
  161. modrm = encodeModRM(0x2, inst->dstReg, 0x6); // [rsi]+disp32
  162. if(inst->srcReg == M_CONST)
  163. modrm = encodeModRM(0x2, inst->dstReg, 0x2); // [rdx]+disp32
  164. if(inst->srcReg == M_TEMP)
  165. modrm = encodeModRM(0x2, inst->dstReg, 0x1); // [rcx]+disp32
  166. hasDisp32 = 1;
  167. disp32 = inst->memOffset*4;
  168. }
  169. }
  170. else if(inst->srcType == REG && inst->dstType == REG) {
  171. // for registers
  172. // mod = 11b, r/m = 0..7 (xmm0..xmm7)
  173. // AX, CX, DX, BX, SP, BP, SI, DI
  174. if(a->dstIsRM) {
  175. modrm = encodeModRM(0x3, inst->srcReg, inst->dstReg);
  176. }
  177. else {
  178. modrm = encodeModRM(0x3, inst->dstReg, inst->srcReg);
  179. }
  180. }
  181. temp[len++] = modrm;
  182. if(hasDisp8) temp[len++] = disp8;
  183. else if(hasDisp32) {
  184. temp[len++] = disp32 & 0xff;
  185. temp[len++] = (disp32 >> 8) & 0xff;
  186. temp[len++] = (disp32 >> 16) & 0xff;
  187. temp[len++] = (disp32 >> 24) & 0xff;
  188. }
  189. inst->machineCode = malloc(len);
  190. memcpy(inst->machineCode, temp, len);
  191. inst->mcLen = len;
  192. }
  193. void assembleCode(LinearizationInfo* info) {
  194. VEC_EACHP(&info->code, i, inst) {
  195. encodeInst(inst);
  196. }
  197. }
  198. void generateCode(LinearizationInfo* info) {
  199. #define REG 0
  200. #define MEM 1
  201. #define TEMP 0
  202. #define INPUT 1
  203. #define CONST 2
  204. #define INST(id, dtype, dreg, stype, sreg, moff) \
  205. VEC_PUSH(&info->code, ((AsmInst){ \
  206. .instID = INST_##id, \
  207. .dstType = dtype, \
  208. .srcType = stype, \
  209. .dstReg = dreg, \
  210. .srcReg = sreg, \
  211. .memOffset = moff, \
  212. }));
  213. VarDef* o, *l, *r;
  214. VEC_EACH(&info->ilist, i, tia) {
  215. switch(tia->type) {
  216. case T_CONST:
  217. // load from const mem area
  218. o = &info->vars[tia->out];
  219. INST(MOV, REG, o->regNum, MEM, M_CONST, info->constSlots[info->vars[tia->out].slot].byteOffset);
  220. break;
  221. case T_VAR:
  222. o = &info->vars[tia->out];
  223. INST(MOV, REG, o->regNum, MEM, M_INPUT, info->inputSlots[info->vars[tia->out].slot].byteOffset);
  224. break;
  225. case T_ADD:
  226. o = &info->vars[tia->out];
  227. l = &info->vars[tia->inL];
  228. r = &info->vars[tia->inR];
  229. INST(MOV, REG, o->regNum, REG, l->regNum, 0);
  230. INST(ADD, REG, o->regNum, REG, r->regNum, 0);
  231. break;
  232. case T_SUB:
  233. o = &info->vars[tia->out];
  234. l = &info->vars[tia->inL];
  235. r = &info->vars[tia->inR];
  236. INST(MOV, REG, o->regNum, REG, l->regNum, 0);
  237. INST(SUB, REG, o->regNum, REG, r->regNum, 0);
  238. break;
  239. case T_MUL:
  240. o = &info->vars[tia->out];
  241. l = &info->vars[tia->inL];
  242. r = &info->vars[tia->inR];
  243. INST(MOV, REG, o->regNum, REG, l->regNum, 0);
  244. INST(MUL, REG, o->regNum, REG, r->regNum, 0);
  245. break;
  246. case T_DIV:
  247. o = &info->vars[tia->out];
  248. l = &info->vars[tia->inL];
  249. r = &info->vars[tia->inR];
  250. INST(MOV, REG, o->regNum, REG, l->regNum, 0);
  251. INST(DIV, REG, o->regNum, REG, r->regNum, 0);
  252. break;
  253. }
  254. }
  255. }
  256. void setupSlots(LinearizationInfo* info) {
  257. info->inputSlots = calloc(1, info->inputSlotCnt * sizeof(*info->inputSlots));
  258. info->constSlots = calloc(1, info->constSlotCnt * sizeof(*info->constSlots));
  259. info->tempSlots = calloc(1, info->tempSlotCnt * sizeof(*info->tempSlots));
  260. for(int i = 1; i < info->varCnt; i++) {
  261. VarDef* v = &info->vars[i];
  262. if(v->slotType == 0) {
  263. SlotInfo* slot = &info->tempSlots[v->slot];
  264. slot->varNum = v->varNum;
  265. slot->elemSize = 4;
  266. slot->byteOffset = 4 * v->slot;
  267. }
  268. else if(v->slotType == 1) {
  269. SlotInfo* slot = &info->inputSlots[v->slot];
  270. slot->varNum = v->varNum;
  271. slot->textName = v->varTextName;
  272. slot->elemSize = 4;
  273. slot->byteOffset = 4 * v->slot;
  274. }
  275. else if(v->slotType == 2) {
  276. SlotInfo* slot = &info->constSlots[v->slot];
  277. slot->varNum = v->varNum;
  278. slot->elemSize = 4;
  279. slot->byteOffset = 4 * v->slot;
  280. }
  281. if(VEC_LEN(&info->freeRegStack) > 0) {
  282. VEC_POP(&info->freeRegStack, v->regNum);
  283. }
  284. }
  285. }
  286. void linearizeAST(Node* n, LinearizationInfo* info) {
  287. ThreeAddressInstr* tai;
  288. if(n->l) linearizeAST(n->l, info);
  289. if(n->r) linearizeAST(n->r, info);
  290. int instIndex = VEC_LEN(&info->ilist);
  291. VarDef* var = &info->vars[n->resultVar];
  292. var->varNum = n->resultVar;
  293. if(n->type == T_VAR) {
  294. var->varTextName = n->text;
  295. var->slotType = 1;
  296. var->slot = info->inputSlotCnt++;
  297. }
  298. else if(n->type == T_CONST) {
  299. var->constVal = strtof(n->text, NULL);
  300. var->slotType = 2;
  301. var->slot = info->constSlotCnt++;
  302. }
  303. else {
  304. var->slotType = 0;
  305. var->slot = info->tempSlotCnt++;
  306. }
  307. var->assignmentInst = instIndex;
  308. var->lastUsedInst = instIndex;
  309. tai = calloc(1, sizeof(*tai));
  310. tai->text = n->text;
  311. tai->type = n->type;
  312. tai->out = n->resultVar;
  313. if(n->l) {
  314. tai->inL = n->l->resultVar;
  315. info->vars[n->l->resultVar].lastUsedInst = MAX(instIndex, info->vars[n->l->resultVar].lastUsedInst);
  316. }
  317. if(n->r) {
  318. tai->inR = n->r->resultVar;
  319. info->vars[n->r->resultVar].lastUsedInst = MAX(instIndex, info->vars[n->r->resultVar].lastUsedInst);
  320. }
  321. VEC_PUSH(&info->ilist, tai);
  322. }
  323. ProgramInfo* compile(char** source, size_t slen) {
  324. sti_op_prec_rule rules[] = {
  325. {"", 0, STI_OP_ASSOC_NONE, 0},
  326. {"+", 1, STI_OP_ASSOC_LEFT, 2},
  327. {"-", 1, STI_OP_ASSOC_LEFT, 2},
  328. {"*", 2, STI_OP_ASSOC_LEFT, 2},
  329. // {"**", 3, STI_OP_ASSOC_LEFT, 2},
  330. {"/", 2, STI_OP_ASSOC_LEFT, 2},
  331. {"(", 8, STI_OP_OPEN_PAREN, 0},
  332. {")", 8, STI_OP_CLOSE_PAREN, 0},
  333. {"[", 9, STI_OP_OPEN_PAREN, 0},
  334. {"]", 9, STI_OP_CLOSE_PAREN, 0},
  335. {NULL, 0, 0, 0},
  336. };
  337. char** rpn;
  338. size_t len;
  339. infix_to_rpn(rules, source, &rpn, &len);
  340. len--;
  341. printf("\n");
  342. for(int i = 0; i < len; i++) {
  343. printf("^%d - '%s'\n", i, rpn[i]);
  344. }
  345. typedef struct Token {
  346. enum TokType type;
  347. char* text;
  348. } Token;
  349. Token* toks = calloc(1, len * sizeof(*toks));
  350. for(int i = 0; i < len; i++) {
  351. toks[i].type = classifyToken(rpn[i]);
  352. toks[i].text = rpn[i];
  353. }
  354. VEC(Node*) stack;
  355. VEC_INIT(&stack);
  356. for(int i = 0; i < len; i++) {
  357. Node* n = calloc(1, sizeof(*n));
  358. n->text = toks[i].text;
  359. n->type = toks[i].type;
  360. if(toks[i].type == T_CONST || toks[i].type == T_VAR) {
  361. VEC_PUSH(&stack, n);
  362. continue;
  363. }
  364. // operators. all are binary right now
  365. VEC_POP(&stack, n->r);
  366. VEC_POP(&stack, n->l);
  367. VEC_PUSH(&stack, n);
  368. }
  369. Node* root;
  370. VEC_POP(&stack, root);
  371. // now in AST form
  372. RegAllocInfo reginfo;
  373. reginfo.nextVar = 1;
  374. assignRegisters(root, &reginfo);
  375. printNode(root, 0);
  376. // now in SSA
  377. LinearizationInfo linfo;
  378. memset(&linfo, 0, sizeof(linfo));
  379. linfo.varCnt = reginfo.nextVar;
  380. linfo.vars = calloc(1, (linfo.varCnt+1) * sizeof(*linfo.vars));
  381. for(int i = 1; i <= 7; i++) {
  382. VEC_PUSH(&linfo.freeRegStack, i);
  383. }
  384. linearizeAST(root, &linfo);
  385. printf("\nInstructions:\n");
  386. VEC_EACH(&linfo.ilist, i, tai) {
  387. if(tai->type == T_IMMED) {
  388. printf(" %ld> %d = %s\n", i, tai->out, tai->text);
  389. }
  390. else
  391. printf(" %ld> %d = %d %s %d\n", i, tai->out, tai->inL, TokTypeNames[tai->type], tai->inR);
  392. }
  393. printf("\nVariables:\n");
  394. for(int i = 1; i < linfo.varCnt; i++) {
  395. VarDef* def = &linfo.vars[i];
  396. printf(" I%d: first: %d, last: %d, ", def->varNum, def->assignmentInst, def->lastUsedInst);
  397. if(def->slotType == 0) {
  398. printf("tempvar slot = %d\n", def->slot);
  399. }
  400. else if(def->slotType == 1) {
  401. printf("input slot = %d, name = '%s'\n", def->slot, def->varTextName);
  402. }
  403. else if(def->slotType == 2) {
  404. printf("const slot = %d, value = %f\n", def->slot, def->constVal);
  405. }
  406. }
  407. // now in SSA, Three Address Code
  408. setupSlots(&linfo);
  409. // memory layout is chosen
  410. generateCode(&linfo);
  411. printf("\nInstructions:\n");
  412. VEC_EACHP(&linfo.code, i, inst) {
  413. printf(" %ld> %s ", i, InstructionTypeNames[inst->instID]);
  414. if(inst->dstType == REG) {
  415. printf("xmm%d, ", (int)inst->dstReg);
  416. }
  417. else if(inst->dstType == MEM) {
  418. if(inst->dstReg == M_CONST)
  419. printf("[CONST+%ld]\n", inst->memOffset);
  420. else if(inst->dstReg == M_INPUT)
  421. printf("[INPUT+%ld]\n", inst->memOffset);
  422. else if(inst->dstReg == M_TEMP)
  423. printf("[TEMP+%ld]\n", inst->memOffset);
  424. }
  425. if(inst->srcType == REG) {
  426. printf("xmm%d\n", (int)inst->srcReg);
  427. }
  428. else if(inst->srcType == MEM) {
  429. if(inst->srcReg == M_CONST)
  430. printf("[CONST+%ld]\n", inst->memOffset);
  431. else if(inst->srcReg == M_INPUT)
  432. printf("[INPUT+%ld]\n", inst->memOffset);
  433. else if(inst->srcReg == M_TEMP)
  434. printf("[TEMP+%ld]\n", inst->memOffset);
  435. }
  436. }
  437. assembleCode(&linfo);
  438. // done
  439. size_t totalSize = 0;
  440. printf("\nMachine Code:\n");
  441. VEC_EACHP(&linfo.code, i, inst) {
  442. printf(" %ld> ", i);
  443. for(int j = 0; j < inst->mcLen; j++) {
  444. printf("%.2x ", inst->machineCode[j]);
  445. }
  446. totalSize += inst->mcLen;
  447. printf("\n");
  448. }
  449. totalSize++;
  450. //byte* finalCode = malloc(totalSize);
  451. ProgramInfo* pi;
  452. pi = calloc(1, sizeof(*pi));
  453. pi->mcLen = totalSize;
  454. pi->width = 4;
  455. pi->fn = mmap(NULL, totalSize, PROT_EXEC|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
  456. size_t off = 0;
  457. VEC_EACHP(&linfo.code, i, inst) {
  458. memcpy((byte*)pi->fn + off, inst->machineCode, inst->mcLen);
  459. off += inst->mcLen;
  460. }
  461. ((byte*)pi->fn)[totalSize-1] = 0xc3;
  462. printf("\nFinal Executable:\n");
  463. for(int i = 0; i < totalSize; i++) {
  464. printf("%.2x ", ((unsigned char*)pi->fn)[i]);
  465. if(7 == i % 8) printf(" ");
  466. if(15 == i % 16) printf("\n");
  467. }
  468. printf("\n");
  469. return pi;
  470. }
  471. unsigned char prog[] = {
  472. 0x8d, 0x47, 0x04, 0xc3,
  473. };
  474. typedef int (*asmfn)(int);
  475. int main(int argc, char* argv[]) {
  476. ProgramInfo* pi;
  477. char** tokens;
  478. size_t len = parse("3.14*74.2-66+82.36+a", &tokens);
  479. for(int i = 0; i < len; i++) {
  480. printf("%d - '%s'\n", i, tokens[i]);
  481. }
  482. pi = compile(tokens, len);
  483. // return 0;
  484. _Alignas(16) float in[200] = {2.0};
  485. _Alignas(16) float out[200] = {};
  486. _Alignas(16) float constants[200] = {};
  487. pi->fn(in, out, constants);
  488. // printf("b: %f\n", b);
  489. return 0;
  490. }
  491. size_t parse(char* input, char*** output) {
  492. char* s = input;
  493. size_t alloc = 32;
  494. size_t len = 0;
  495. char** out = malloc(alloc * sizeof(*out));
  496. for(; *s; ) {
  497. if(len >= alloc) {
  498. alloc *= 2;
  499. out = realloc(out, alloc * sizeof(*out));
  500. }
  501. if(isalnum(*s) || *s == '.') {
  502. char* e = s;
  503. while(*e && (isalnum(*e) || *e == '.')) e++;
  504. out[len] = strndup(s, e - s);
  505. len++;
  506. s = e;
  507. continue;
  508. }
  509. switch(*s) {
  510. case '*':
  511. case '/':
  512. case '+':
  513. case '-':
  514. case '(':
  515. case ')':
  516. case '[':
  517. case ']':
  518. case ',':
  519. out[len] = strndup(s, 1);
  520. len++;
  521. s++;
  522. break;
  523. case ' ':
  524. case '\r':
  525. case '\n':
  526. s++;
  527. continue;
  528. }
  529. }
  530. // null-terminate the list
  531. if(len >= alloc) {
  532. out = realloc(out, (alloc+1) * sizeof(*out));
  533. }
  534. out[len] = NULL;
  535. *output = out;
  536. return len;
  537. }