diff --git a/19/main.s b/19/main.s new file mode 100644 index 0000000..cf63a08 --- /dev/null +++ b/19/main.s @@ -0,0 +1,407 @@ +%include "utils.s" + +global _start +[bits 32] +[section .text] + +%define FILENAME "input" +;%define FILENAME "input_test" + +_start: + +mov esi, file +load_rule: +xor ebx, ebx ; id +.get_id: +lodsb +cmp al, '{' +je .got_id +shl ebx, 8 +mov bl, al ; add new byte +jmp .get_id +.got_id: +call id_to_idx ; idx in EDX +shl edx, 4 ; *16 +lea edi, [rules+edx] ; rule ptr +.get_rules: +; --- rule format --- +; [ 16 ] +; [ 4 ][ 4 ][ 4 ][ 4 ] +; [ 2 ] [ 2 ][ 2 ] [ 2 ][ 2 ] [ 2 ][ 2 ] [ 2 ] +; [bound] [ vdr ][bound] [ vdr ][bound] [ vdr ][bound] [ vdr ] + +; var, dir, & res +; FEDCBA9876543210 +; --- var --- 76543210 +; ...............1 -> Always +; .............00. -> a (ASCII .1100...) +; .............01. -> m (ASCII .1101...) +; .............10. -> s (ASCII .1110...) +; .............11. -> x (ASCII .1111...) +; --- dir --- +; ............0... -> < (ASCII .0....0.) +; ............1... -> > (ASCII .0....1.) +; --- res --- +; 111111111111.... -> R (ASCII .10....0 bit 0 - 1 -> ..111) +; 000000000000.... -> A (ASCII .10....1 bit 0 - 1 -> ..000) +; NNNNNNNNNNNN.... -> eval + +xor ecx, ecx ; output vdr & bound +xor eax, eax ; input byte +lodsb ; lowercase alpha or RA +bt ax, 5 ; low for RA, high for alpha +jc .alpha +; immediately finish with R or A +or cx, 1 ; Always +and ax, 1 ; bit 0 of ASCII +dec ax ; R -> -1, A -> 0 +shl ax, 4 ; correct position +or cx, ax +jmp .done +.alpha: ; either [xmas][><] or a multi-char ID +mov ebx, eax ; save last input +lodsb ; next byte +bt ax, 6 ; bit 6 low for >< +jnc .is_check +; immediately finish by evaluating ID +.imm_got_id_byte: +shl ebx, 8 +mov bl, al +.imm_get_full_id: +lodsb +cmp al, ',' ; ends , or } +je .imm_got_id +cmp al, '}' +jne .imm_got_id_byte +.imm_got_id: +call id_to_idx ; idx in EDX +or cx, 1 ; out.var <- Always +shl edx, 4 ; correct position +or cx, dx ; out.res <- idx +jmp .done +.is_check: +and bx, 3<<3 +shr bx, 2 +or cx, bx ; out.var <- bits 3&4 of last +and ax, 1<<1 +shl ax, 2 +or cx, ax ; out.dir <- bit 1 of ASCII +call dec_parse +mov bx, cx +mov cx, ax +shl ecx, 16 +mov cx, bx ; out.bound <- parse_dec +; parse_dec skips the : so get the res +lodsb +bt ax, 5 +jc .chk_id +; res is R or A +and ax, 1 +dec ax +shl ax, 4 +or cx, ax ; out.res <- bit 0 of ASCII - 1 +jmp .done +.chk_id: ; res is ID +xor ebx, ebx +jmp .chk_got_id_byte +.chk_next_byte: +lodsb +cmp al, ',' ; ends , +je .chk_got_id +.chk_got_id_byte: +shl ebx, 8 +mov bl, al +jmp .chk_next_byte +.chk_got_id: +call id_to_idx ; idx in EDX +shl edx, 4 +or cx, dx ; out.res <- idx +.done: +mov eax, ecx +stosd +cmp byte [esi-1], ',' +je .get_rules +cmp byte [esi], ',' +je .next_rule +cmp byte [esi-1], '}' +je .next_line +cmp byte [esi], '}' +je .next_line +cmp byte [esi-1], 10 +je .check_rules_over +call newline +.wtf: p_string wtf +jmp .wtf +.next_rule: +inc esi +jmp .get_rules +.next_line: +lodsb +cmp al, 10 ; \n +jne .next_line +.check_rules_over: +cmp byte [esi], 10 +jne load_rule + +rules_over: +mov eax, [next_rule_idx] +dec eax +call print_dec +call newline + +; find rule 'in' +mov ebx, 'ni' +call id_to_idx +mov [in_idx], edx +mov eax, edx +call print_dec +call space +shl edx, 4 +movzx eax, word [rules+edx] +call print_dec +call space +movzx eax, word [rules+edx+2] +call print_dec +call newline + +proc_next_input: +; go through the rules +mov ebx, [in_idx] +push 1 ; x min +push 4001 ; x max (exclusive) +push 1 ; m min +push 4001 ; m max (exclusive) +push 1 ; a min +push 4001 ; a max (exclusive) +push 1 ; s min +push 4001 ; s max (exclusive) +call check_rule +jmp game_over + + +; rule idx in EBX, xmas ranges on stack (args) +; ebp+36 x min +; ebp+32 x max (exclusive) +; ebp+28 m min +; ebp+24 m max (exclusive) +; ebp+20 a min +; ebp+16 a max (exclusive) +; ebp+12 s min +; ebp+ 8 s max (exclusive) +; ebp+ 4 return loc +; ebp+ 0 ebp +; ebp- 4 rule ptr +check_rule: +push ebp +mov ebp, esp ; a proper C-like stackframe!? egads! +sub esp, 4 +.inner: +shl ebx, 4 +lea esi, [rules+ebx] ; rule ptr +mov [esp], esi +.next_rule: +mov esi, [esp] +lodsd ; rule +mov [esp], esi +bt ax, 0 ; always +jc .always +; .............00. -> a +; .............01. -> m +; .............10. -> s +; .............11. -> x +; ............0... -> < +; ............1... -> > +mov esi, eax +shr esi, 16 ; bound +mov ebx, eax +and bl, 0b1110 ; dir & var +cmp bl, 0b0110 +je .xl +cmp bl, 0b0010 +je .ml +cmp bl, 0b0000 +je .al +cmp bl, 0b0100 +je .sl +cmp bl, 0b1110 +je .xg +cmp bl, 0b1010 +je .mg +cmp bl, 0b1000 +je .ag +cmp bl, 0b1100 +je .sg +mov eax, [0] ; something is horribly wrong +.xl: ; matched x range is x min to bound, inverse is bound to x max +xchg esi, [ebp+32] ; bound -> our max, our old max -> esi +call .internal_thing +xchg esi, [ebp+32] ; restore old max +mov [ebp+36], esi ; bound -> our min +jmp .next_rule +.ml: ; matched m range is m min to bound, inverse is bound to m max +xchg esi, [ebp+24] ; bound -> our max, our old max -> esi +call .internal_thing +xchg esi, [ebp+24] ; restore old max +mov [ebp+28], esi ; bound -> our min +jmp .next_rule +.al: ; matched a range is a min to bound, inverse is bound to a max +xchg esi, [ebp+16] ; bound -> our max, our old max -> esi +call .internal_thing +xchg esi, [ebp+16] ; restore old max +mov [ebp+20], esi ; bound -> our min +jmp .next_rule +.sl: ; matched s range is s min to bound, inverse is bound to s max +xchg esi, [ebp+ 8] ; bound -> our max, our old max -> esi +call .internal_thing +xchg esi, [ebp+ 8] ; restore old max +mov [ebp+12], esi ; bound -> our min +jmp .next_rule +.xg: ; matched x range is bound+1 to x max, inverse is x min to bound+1 +inc esi +xchg esi, [ebp+36] ; bound+1 -> our min, our old min -> esi +call .internal_thing +xchg esi, [ebp+36] ; restore old min +mov [ebp+32], esi ; bound+1 -> our max +jmp .next_rule +.mg: ; matched m range is bound+1 to m max, inverse is m min to bound+1 +inc esi +xchg esi, [ebp+28] ; bound+1 -> our min, our old min -> esi +call .internal_thing +xchg esi, [ebp+28] ; restore old min +mov [ebp+24], esi ; bound+1 -> our max +jmp .next_rule +.ag: ; matched a range is bound+1 to a max, inverse is a min to bound+1 +inc esi +xchg esi, [ebp+20] ; bound+1 -> our min, our old min -> esi +call .internal_thing +xchg esi, [ebp+20] ; restore old min +mov [ebp+16], esi ; bound+1 -> our max +jmp .next_rule +.sg: ; matched a range is bound+1 to s max, inverse is s min to bound+1 +inc esi +xchg esi, [ebp+12] ; bound+1 -> our min, our old min -> esi +call .internal_thing +xchg esi, [ebp+12] ; restore old min +mov [ebp+ 8], esi ; bound+1 -> our max +jmp .next_rule +.always: +shr ax, 4 ; rule.res +test ax, ax +jz .return_res_A +cmp ax, 0x0FFF +je .return_res_R +; nested rule +movzx ebx, ax +jmp .inner +.return_res_A: +call .A +.return_res_R: +add esp, 4 ; stackframe gone :c +pop ebp +ret +.internal_thing: +mov ebx, eax +shr ax, 4 ; rule.res +test ax, ax +jz .A +cmp ax, 0x0FFF +je .R +; we need to make a recursive call, set up args +push esi +movzx ebx, ax +push dword [ebp+36] ; x min +push dword [ebp+32] ; x max +push dword [ebp+28] ; m min +push dword [ebp+24] ; m max +push dword [ebp+20] ; a min +push dword [ebp+16] ; a max +push dword [ebp+12] ; s min +push dword [ebp+ 8] ; s max +call check_rule +add esp, 4*8 +pop esi +jmp .R +.A: +pushad +sub esp, 8 ; scratch memory +; final_value += (xMax-xMin)* +; (mMax-mMin)* +; (aMax-aMin)* +; (sMax-sMin); +mov eax, [ebp+32] +sub eax, [ebp+36] +js .no_add +xor edx, edx +mov ecx, [ebp+24] +sub ecx, [ebp+28] +js .no_add +imul edx, ecx +mov [esp], edx +mul ecx +mov ecx, edx +mov edx, [esp] +add ecx, edx +mov edx, [ebp+16] +sub edx, [ebp+20] +js .no_add +imul ecx, edx +mul edx +add edx, ecx +mov ecx, [ebp+ 8] +sub ecx, [ebp+12] +js .no_add +imul edx, ecx +mov [esp+4], edx +mul ecx +mov esi, eax +mov eax, [esp+4] +add edx, eax +add [final_value], esi +adc [final_value+4], edx +.no_add: +add esp,8 +popad + +.R: ; done, return to place to inverse range +ret + + + +game_over: +mov eax, [final_value] +call print_dec +call space +mov eax, [final_value+4] +call print_dec +call newline +jmp exit + +; ID in EBX, IDX return in EDX +id_to_idx: +xor edx, edx +.test: +cmp [rule_idx_to_id+edx*4], ebx +je .found +inc edx +cmp edx, [next_rule_idx] +jb .test +; new ID +mov [rule_idx_to_id+edx*4], ebx +inc dword [next_rule_idx] +.found: +ret + +[section .data] +next_rule_idx: dd 1 +in_idx: dd 0 +final_value: dd 0, 0 +file: incbin FILENAME +.over: + +[section .bss] +rules: resd 1024*4 +rule_idx_to_id: resd 1024 + +[section .rodata] +wtf: db "WTF" +.over: