definitely doesn't work yet, but i wanted to make a snapshot of my current progress
244 lines
4.2 KiB
ArmAsm
244 lines
4.2 KiB
ArmAsm
|
|
.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:
|
|
|