.data flags: .dword 0 # value / default .byte 1 # type: , bool, string, int .byte 5 # flag length #.short 16 # help length .ascii "-help" #.ascii "prints help text" # last flag .dword 0 .dword 0 .bss entry_sp: .dword 0 saved_argc: .dword 0 saved_argv: .dword 0 # when a program starts, it should stash the initial value of the sp register somewhere # e.g. # # .data # entry_sp: # .dword 0 # _start: # la t0, entry_sp # sd sp, (t0) # # then at some opportune moment, it can call init_flags. # a0 should be used to pass in the initial sp value. # # la t0, entry_sp # ld a0, (t0) # call init_flags # in order to store argc and argv # a0 - initial stack pointer init_flags: la t0, saved_argc ld t1, (a0) sd t1, (t0) la t0, saved_argv add t2, a0, 8 sd t2, (t0) ret # a0 - flag definition struct parse_flags: la a1, saved_argc la a2, saved_argv ld a1, (a1) ld a2, (a2) tail parse_flags_args # a0 - flag definition struct # a1 - argc # a2 - argv parse_flags_args: # TODO: positional arguments # syntax: # -flag (only boolean flags) # -flag value (only non-boolean flags) # -flag=value # main loop # for each argument, if it starts with a '-' then see if it matches a flag mv s2, a2 .L_arg_loop: ld s1, (s2) # load string pointer beqz s1, .L_next_arg # skip null pointer # check if first char is a '-' ld t0, (s1) beqz t0, .Lno # empty string addi t0, t0, -'-' bnez t0, .Lno # not a dash # TODO: allow --flag # TODO: -- should end flag parsing mv s0, a0 .L_flag_loop: lbu t3, 8(s0) # type lbu t2, 9(s0) # flag length beqz t2, .Lunknown_flag call flagcmp # return value: # 0: no match # 1: match # 2: match w/ equal sign bnez t0, .Lfound .L_next_flag: addi s0, s0, 8 add s0, s0, t2 j .L_flag_loop .Lfound: add t0, s1, t2 # arg+len lbu t1, (t0) beqz t1, 1f # is it a \0 or an =? 0:# move s1 past the = addi t0, t0, 1 mv s1, t0 j 2f 1:# is this a boolean flag? li t0, 1 beq t0, t3, 2f # if not, set s1 to the next arg and advance s2 ld s1, 8(s2) addi s2, s2, 8 # TODO: if it's null, that's an error 2: # ok now parse the flag .Lparse_flag: lbu t3, 8(s0) # load type li t0, 1 beq t0, t3, boolflag li t0, 2 beq t0, t3, strflag li t0, 3 beq t0, t3, intflag j .Lbad_flag_def boolflag: lbu t0, 0(s1) # if arg is empty, set value to true beqz t0, 0f # check for "true" and "false" li t1, 'f' beq t0, t1, .Lboolcmpfalse li t1, 't' beq t0, t1, .Lboolcmptrue # anything else is an error j .Lboolbad .Lboolcmpfalse: lbu t0, 1(s1) beqz t0, .Lboolbad li t1, 'a' bne t1, t0, .Lboolbad lbu t0, 2(s1) beqz t0, .Lboolbad li t1, 'l' bne t1, t0, .Lboolbad lbu t0, 3(s1) beqz t0, .Lboolbad li t1, 's' bne t1, t0, .Lboolbad lbu t0, 4(s1) beqz t0, .Lboolbad li t1, 's' bne t1, t0, .Lboolbad lbu t0, 5(s1) bnez t0, .Lboolbad j 0b sd x0, 0(s0) j .L_next_arg .Lboolcmptrue: lbu t0, 1(s1) beqz t0, .Lboolbad li t1, 'r' bne t1, t0, .Lboolbad lbu t0, 2(s1) beqz t0, .Lboolbad li t1, 'u' bne t1, t0, .Lboolbad lbu t0, 3(s1) beqz t0, .Lboolbad li t1, 'e' bne t1, t0, .Lboolbad lbu t0, 4(s1) bnez t0, .Lboolbad 1:li t1, 1 sd t1, 0(s0) j .L_next_arg strflag: # easy, just store the string pointer # TODO: strlen sd s1, 0(s0) j .L_next_arg intflag: # gotta convert string to int # TODO: negative numbers # TODO: detect overflow # TODO: hex mv t0, x0 li t2, 10 lbu t1, 0(s1) beqz t1, .Lbadint 0:addi t1, t1, -0x30 # '0' bltz t1, .Lbadint bge t1, t2, .Lbadint mul t0, t0, t2 add t0, t0, t1 addi s1, s1, 1 lbu t1, 0(s1) bnez t1, 0b 1:sd t0, 0(s0) j .L_next_arg .L_next_arg: ret .Lbadint: .Lboolbad: .Lunknown_flag: li a0, -1 ret # t4 - flag # t5 - # t6 length # t0 - return flagcmp: mv t0, zero ret handle_flag: