lib/flags: progress
This commit is contained in:
parent
ba2d991765
commit
44d953a322
1
Makefile
1
Makefile
@ -15,6 +15,7 @@ all: true false cat env hexdump echo
|
|||||||
|
|
||||||
prtest: prtest.o lib/printregs.o lib/hex.o
|
prtest: prtest.o lib/printregs.o lib/hex.o
|
||||||
sorttest: lib/sort.o
|
sorttest: lib/sort.o
|
||||||
|
flagtest: lib/flags.o
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test:
|
test:
|
||||||
|
|||||||
35
flagtest.s
Normal file
35
flagtest.s
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
.global _start
|
||||||
|
.extern init_flags
|
||||||
|
.extern parse_flags
|
||||||
|
|
||||||
|
.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
|
||||||
|
|
||||||
|
.text
|
||||||
|
|
||||||
|
_start:
|
||||||
|
.option push
|
||||||
|
.option norelax
|
||||||
|
la gp, __global_pointer$
|
||||||
|
.option pop
|
||||||
|
|
||||||
|
mv a0, sp
|
||||||
|
call init_flags
|
||||||
|
la a0, flags
|
||||||
|
call parse_flags
|
||||||
|
|
||||||
|
li a7, 93 # sys_exit
|
||||||
|
li a0, 0
|
||||||
|
ecall
|
||||||
216
lib/flags.s
216
lib/flags.s
@ -1,4 +1,12 @@
|
|||||||
|
|
||||||
|
.option norelax
|
||||||
|
.global init_flags
|
||||||
|
.global parse_flags
|
||||||
|
|
||||||
|
.macro subi dst, src, imm
|
||||||
|
addi \dst, \src, -\imm
|
||||||
|
.endm
|
||||||
|
|
||||||
.data
|
.data
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
@ -19,6 +27,15 @@ entry_sp: .dword 0
|
|||||||
saved_argc: .dword 0
|
saved_argc: .dword 0
|
||||||
saved_argv: .dword 0
|
saved_argv: .dword 0
|
||||||
|
|
||||||
|
.section .rodata
|
||||||
|
|
||||||
|
flag_failure_msg: .ascii "flag parsing failed\n\0"
|
||||||
|
.equ flag_failure_msg_len, (.) - flag_failure_msg
|
||||||
|
unknown_flag_msg: .ascii "unknown flag\n\0"
|
||||||
|
.equ unknown_flag_msg_len, (.) - unknown_flag_msg
|
||||||
|
|
||||||
|
.text
|
||||||
|
|
||||||
# when a program starts, it should stash the initial value of the sp register somewhere
|
# when a program starts, it should stash the initial value of the sp register somewhere
|
||||||
# e.g.
|
# e.g.
|
||||||
#
|
#
|
||||||
@ -56,11 +73,13 @@ parse_flags:
|
|||||||
ld a2, (a2)
|
ld a2, (a2)
|
||||||
|
|
||||||
tail parse_flags_args
|
tail parse_flags_args
|
||||||
|
# n.b. tail clobbers t1
|
||||||
|
|
||||||
# a0 - flag definition struct
|
# a0 - flag definition struct
|
||||||
# a1 - argc
|
# a1 - argc
|
||||||
# a2 - argv
|
# a2 - argv
|
||||||
parse_flags_args:
|
parse_flags_args:
|
||||||
|
mv a7, ra
|
||||||
# TODO: positional arguments
|
# TODO: positional arguments
|
||||||
|
|
||||||
# syntax:
|
# syntax:
|
||||||
@ -68,27 +87,53 @@ parse_flags_args:
|
|||||||
# -flag value (only non-boolean flags)
|
# -flag value (only non-boolean flags)
|
||||||
# -flag=value
|
# -flag=value
|
||||||
|
|
||||||
# main loop
|
# if argc <= 1, return
|
||||||
|
li t0, 1
|
||||||
|
bleu a1, t0, .Ldone
|
||||||
|
|
||||||
|
# main loop:
|
||||||
# for each argument, if it starts with a '-' then see if it matches a flag
|
# for each argument, if it starts with a '-' then see if it matches a flag
|
||||||
mv s2, a2
|
|
||||||
|
# skip arg 0
|
||||||
|
addi s2, a2, 8
|
||||||
|
subi a1, a1, 1
|
||||||
.L_arg_loop:
|
.L_arg_loop:
|
||||||
ld s1, (s2) # load string pointer
|
ld s1, (s2) # load string pointer
|
||||||
beqz s1, .L_next_arg # skip null pointer
|
beqz s1, .L_next_arg # skip null pointer
|
||||||
# check if first char is a '-'
|
# check if first char is a '-'
|
||||||
ld t0, (s1)
|
lbu t0, 0(s1)
|
||||||
beqz t0, .Lno # empty string
|
li t1, '-'
|
||||||
addi t0, t0, -'-'
|
beq t0, t1, find_flag
|
||||||
bnez t0, .Lno # not a dash
|
|
||||||
|
.L_next_arg:
|
||||||
|
addi s2, s2, 8
|
||||||
|
subi a1, a1, 1
|
||||||
|
beqz a1, .Ldone
|
||||||
|
j .L_arg_loop
|
||||||
|
|
||||||
|
.Ldone:
|
||||||
|
mv ra, a7
|
||||||
|
ret
|
||||||
|
|
||||||
|
.Lunknown_flag:
|
||||||
|
mv ra, a7
|
||||||
|
li a7, 64 # sys_write
|
||||||
|
li a0, 2
|
||||||
|
la a1, unknown_flag_msg
|
||||||
|
li a2, unknown_flag_msg_len
|
||||||
|
ecall
|
||||||
|
li a0, -1
|
||||||
|
ret
|
||||||
|
|
||||||
# TODO: allow --flag
|
# TODO: allow --flag
|
||||||
# TODO: -- should end flag parsing
|
# TODO: -- should end flag parsing
|
||||||
|
|
||||||
|
find_flag:
|
||||||
mv s0, a0
|
mv s0, a0
|
||||||
.L_flag_loop:
|
.L_flag_loop:
|
||||||
|
|
||||||
lbu t3, 8(s0) # type
|
lbu t3, 8(s0) # type
|
||||||
lbu t2, 9(s0) # flag length
|
lbu s3, 9(s0) # flag length
|
||||||
beqz t2, .Lunknown_flag
|
beqz s3, .Lunknown_flag # len=0 signifies the end of the flag definitions
|
||||||
call flagcmp
|
call flagcmp
|
||||||
# return value:
|
# return value:
|
||||||
# 0: no match
|
# 0: no match
|
||||||
@ -97,42 +142,53 @@ parse_flags_args:
|
|||||||
bnez t0, .Lfound
|
bnez t0, .Lfound
|
||||||
|
|
||||||
.L_next_flag:
|
.L_next_flag:
|
||||||
addi s0, s0, 8
|
addi s0, s0, 10
|
||||||
add s0, s0, t2
|
add s0, s0, s3
|
||||||
j .L_flag_loop
|
j .L_flag_loop
|
||||||
|
|
||||||
|
|
||||||
.Lfound:
|
.Lfound:
|
||||||
add t0, s1, t2 # arg+len
|
subi t3, t3, 1
|
||||||
lbu t1, (t0)
|
add s1, s1, s3 # arg+len
|
||||||
beqz t1, 1f # is it a \0 or an =?
|
lbu t0, (s1)
|
||||||
0:# move s1 past the =
|
beqz t0, 1f # is it a \0 or an =?
|
||||||
addi t0, t0, 1
|
# =
|
||||||
mv s1, t0
|
# move s1 past the =
|
||||||
j 2f
|
addi s1, s1, 1
|
||||||
1:# is this a boolean flag?
|
j handle_flag
|
||||||
li t0, 1
|
|
||||||
beq t0, t3, 2f
|
1:# \0
|
||||||
|
# is this a boolean flag? then there's no value
|
||||||
|
beqz t3, handle_flag
|
||||||
# if not, set s1 to the next arg and advance s2
|
# if not, set s1 to the next arg and advance s2
|
||||||
ld s1, 8(s2)
|
ld s1, 8(s2)
|
||||||
addi s2, s2, 8
|
addi s2, s2, 8
|
||||||
|
subi a1, a1, 1
|
||||||
# TODO: if it's null, that's an error
|
# TODO: if it's null, that's an error
|
||||||
2:
|
# fallthrough
|
||||||
|
|
||||||
|
# s1 now points to the value of the flag
|
||||||
|
|
||||||
|
handle_flag:
|
||||||
# ok now parse the flag
|
# ok now parse the flag
|
||||||
.Lparse_flag:
|
#lbu t3, 8(s0) # load type
|
||||||
lbu t3, 8(s0) # load type
|
beqz t3, boolflag
|
||||||
li t0, 1
|
li t0, 2-1
|
||||||
beq t0, t3, boolflag
|
|
||||||
li t0, 2
|
|
||||||
beq t0, t3, strflag
|
beq t0, t3, strflag
|
||||||
li t0, 3
|
li t0, 3-1
|
||||||
beq t0, t3, intflag
|
beq t0, t3, intflag
|
||||||
j .Lbad_flag_def
|
j .Lbad_flag_def
|
||||||
|
|
||||||
|
strflag:
|
||||||
|
# easy, just store the string pointer
|
||||||
|
# TODO: strlen
|
||||||
|
sd s1, 0(s0)
|
||||||
|
j .L_next_arg
|
||||||
|
|
||||||
boolflag:
|
boolflag:
|
||||||
lbu t0, 0(s1)
|
lbu t0, 0(s1)
|
||||||
# if arg is empty, set value to true
|
# if arg is empty, set value to true
|
||||||
|
# TODO: should -bool and -bool= be treated differently?
|
||||||
beqz t0, 0f
|
beqz t0, 0f
|
||||||
# check for "true" and "false"
|
# check for "true" and "false"
|
||||||
li t1, 'f'
|
li t1, 'f'
|
||||||
@ -140,63 +196,56 @@ boolflag:
|
|||||||
li t1, 't'
|
li t1, 't'
|
||||||
beq t0, t1, .Lboolcmptrue
|
beq t0, t1, .Lboolcmptrue
|
||||||
# anything else is an error
|
# anything else is an error
|
||||||
j .Lboolbad
|
j .Lbadbool
|
||||||
|
|
||||||
.Lboolcmpfalse:
|
.Lboolcmpfalse:
|
||||||
lbu t0, 1(s1)
|
lbu t0, 1(s1)
|
||||||
beqz t0, .Lboolbad
|
beqz t0, .Lbadbool
|
||||||
li t1, 'a'
|
li t1, 'a'
|
||||||
bne t1, t0, .Lboolbad
|
bne t1, t0, .Lbadbool
|
||||||
|
|
||||||
lbu t0, 2(s1)
|
lbu t0, 2(s1)
|
||||||
beqz t0, .Lboolbad
|
beqz t0, .Lbadbool
|
||||||
li t1, 'l'
|
li t1, 'l'
|
||||||
bne t1, t0, .Lboolbad
|
bne t1, t0, .Lbadbool
|
||||||
|
|
||||||
lbu t0, 3(s1)
|
lbu t0, 3(s1)
|
||||||
beqz t0, .Lboolbad
|
beqz t0, .Lbadbool
|
||||||
li t1, 's'
|
li t1, 's'
|
||||||
bne t1, t0, .Lboolbad
|
bne t1, t0, .Lbadbool
|
||||||
|
|
||||||
lbu t0, 4(s1)
|
lbu t0, 4(s1)
|
||||||
beqz t0, .Lboolbad
|
beqz t0, .Lbadbool
|
||||||
li t1, 's'
|
li t1, 's'
|
||||||
bne t1, t0, .Lboolbad
|
bne t1, t0, .Lbadbool
|
||||||
|
|
||||||
lbu t0, 5(s1)
|
lbu t0, 5(s1)
|
||||||
bnez t0, .Lboolbad
|
bnez t0, .Lbadbool
|
||||||
j 0b
|
|
||||||
|
|
||||||
sd x0, 0(s0)
|
0:sd x0, 0(s0)
|
||||||
j .L_next_arg
|
j .L_next_arg
|
||||||
|
|
||||||
.Lboolcmptrue:
|
.Lboolcmptrue:
|
||||||
lbu t0, 1(s1)
|
lbu t0, 1(s1)
|
||||||
beqz t0, .Lboolbad
|
beqz t0, .Lbadbool
|
||||||
li t1, 'r'
|
li t1, 'r'
|
||||||
bne t1, t0, .Lboolbad
|
bne t1, t0, .Lbadbool
|
||||||
|
|
||||||
lbu t0, 2(s1)
|
lbu t0, 2(s1)
|
||||||
beqz t0, .Lboolbad
|
beqz t0, .Lbadbool
|
||||||
li t1, 'u'
|
li t1, 'u'
|
||||||
bne t1, t0, .Lboolbad
|
bne t1, t0, .Lbadbool
|
||||||
|
|
||||||
lbu t0, 3(s1)
|
lbu t0, 3(s1)
|
||||||
beqz t0, .Lboolbad
|
beqz t0, .Lbadbool
|
||||||
li t1, 'e'
|
li t1, 'e'
|
||||||
bne t1, t0, .Lboolbad
|
bne t1, t0, .Lbadbool
|
||||||
|
|
||||||
lbu t0, 4(s1)
|
lbu t0, 4(s1)
|
||||||
bnez t0, .Lboolbad
|
bnez t0, .Lbadbool
|
||||||
|
|
||||||
1:li t1, 1
|
1:li t0, 1
|
||||||
sd t1, 0(s0)
|
sd t0, 0(s0)
|
||||||
j .L_next_arg
|
|
||||||
|
|
||||||
strflag:
|
|
||||||
# easy, just store the string pointer
|
|
||||||
# TODO: strlen
|
|
||||||
sd s1, 0(s0)
|
|
||||||
j .L_next_arg
|
j .L_next_arg
|
||||||
|
|
||||||
intflag:
|
intflag:
|
||||||
@ -208,7 +257,7 @@ intflag:
|
|||||||
li t2, 10
|
li t2, 10
|
||||||
lbu t1, 0(s1)
|
lbu t1, 0(s1)
|
||||||
beqz t1, .Lbadint
|
beqz t1, .Lbadint
|
||||||
0:addi t1, t1, -0x30 # '0'
|
0:subi t1, t1, 0x30 # '0'
|
||||||
bltz t1, .Lbadint
|
bltz t1, .Lbadint
|
||||||
bge t1, t2, .Lbadint
|
bge t1, t2, .Lbadint
|
||||||
mul t0, t0, t2
|
mul t0, t0, t2
|
||||||
@ -219,25 +268,50 @@ intflag:
|
|||||||
1:sd t0, 0(s0)
|
1:sd t0, 0(s0)
|
||||||
j .L_next_arg
|
j .L_next_arg
|
||||||
|
|
||||||
|
.Lbad_flag_def:
|
||||||
.L_next_arg:
|
|
||||||
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
.Lbadint:
|
.Lbadint:
|
||||||
.Lboolbad:
|
.Lbadbool:
|
||||||
.Lunknown_flag:
|
mv ra, a7
|
||||||
|
li a7, 64
|
||||||
|
li a0, 2
|
||||||
|
la a1, flag_failure_msg
|
||||||
|
li a2, flag_failure_msg_len
|
||||||
|
ecall
|
||||||
li a0, -1
|
li a0, -1
|
||||||
ret
|
ret
|
||||||
|
|
||||||
# t4 - flag
|
# in: s1 - string to compare, length unknown (null terminated)
|
||||||
# t5 -
|
# in: s0 - flag definition
|
||||||
# t6 length
|
# in: s3 - flag length
|
||||||
# t0 - return
|
# out: t0 - match=1 no match=0
|
||||||
|
# clobbers t0, t1, t4, t5, t6, ra
|
||||||
flagcmp:
|
flagcmp:
|
||||||
mv t0, zero
|
add t1, s0, 10 # flag
|
||||||
|
add t0, t1, s3 # end of flag
|
||||||
|
mv t4, s1 # str
|
||||||
|
3:lbu t5, (t1)
|
||||||
|
lbu t6, (t4)
|
||||||
|
bne t5, t6, 0f
|
||||||
|
# we don't _need_ to specifically check if t6==\0
|
||||||
|
# since that should be caught by the comparison above
|
||||||
|
# unless the flag contains an embedded \0 (it shouldn't)
|
||||||
|
# but do the check anyway just to be extra safe
|
||||||
|
beqz t6, 0f
|
||||||
|
addi t1, t1, 1
|
||||||
|
addi t4, t4, 1
|
||||||
|
# once we reach the end of the flag, we just need to check
|
||||||
|
# that the argument string ends in the same place
|
||||||
|
bge t1, t0, .Ltail
|
||||||
|
j 3b # loop
|
||||||
|
.Ltail:
|
||||||
|
lbu t1, (t4)
|
||||||
|
li t0, '='
|
||||||
|
beq t0, t1, 2f
|
||||||
|
beqz t1, 1f
|
||||||
|
0:mv t0, zero
|
||||||
|
ret
|
||||||
|
2:li t0, 2
|
||||||
|
ret
|
||||||
|
1:li t0, 1
|
||||||
ret
|
ret
|
||||||
|
|
||||||
handle_flag:
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user