lib/flags: wip flag parsing
definitely doesn't work yet, but i wanted to make a snapshot of my current progress
This commit is contained in:
parent
2ecbb120e2
commit
ba2d991765
243
lib/flags.s
Normal file
243
lib/flags.s
Normal file
@ -0,0 +1,243 @@
|
||||
|
||||
.data
|
||||
|
||||
flags:
|
||||
.dword 0 # value / default
|
||||
.byte 1 # type: <end>, 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:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user