mirror of
https://github.com/russolsen/sallyforth
synced 2024-12-25 21:58:18 +01:00
Clean up forth eval/execute, make repl more forth driven.
This commit is contained in:
parent
62acb4ab95
commit
a956438aec
11 changed files with 214 additions and 59 deletions
|
@ -32,14 +32,14 @@ def import_native_module(forth, m, alias=None, excludes=[]):
|
||||||
val = getattr(m, name)
|
val = getattr(m, name)
|
||||||
forth.namespace.set(localname, const_f(val))
|
forth.namespace.set(localname, const_f(val))
|
||||||
|
|
||||||
def xx_w_nexttoken(f, i):
|
|
||||||
token = f.read_next_token()
|
|
||||||
f.stack.push(token)
|
|
||||||
return i+1
|
|
||||||
|
|
||||||
def w_eval(f, i):
|
def w_eval(f, i):
|
||||||
token = f.stack.pop()
|
token = f.stack.pop()
|
||||||
f.execute_token(token)
|
f.evaluate_string(token)
|
||||||
|
return i+1
|
||||||
|
|
||||||
|
def w_execute(f, i):
|
||||||
|
token = f.stack.pop()
|
||||||
|
f.execute_string(token)
|
||||||
return i+1
|
return i+1
|
||||||
|
|
||||||
def w_no_op(f, i):
|
def w_no_op(f, i):
|
||||||
|
@ -155,6 +155,20 @@ def w_call(f, i):
|
||||||
f.stack.push(result)
|
f.stack.push(result)
|
||||||
return i+1
|
return i+1
|
||||||
|
|
||||||
|
def w_kwcall(f, i):
|
||||||
|
func = f.stack.pop()
|
||||||
|
kws = f.stack.pop()
|
||||||
|
args = f.stack.pop()
|
||||||
|
print('f', f, 'args', args, 'kws', kws)
|
||||||
|
try:
|
||||||
|
result = func(*args, **kws)
|
||||||
|
except:
|
||||||
|
print(f'Error executing {func}{list(args)}{kws}')
|
||||||
|
raise
|
||||||
|
print('result', result)
|
||||||
|
f.stack.push(result)
|
||||||
|
return i+1
|
||||||
|
|
||||||
def w_nl(f, i):
|
def w_nl(f, i):
|
||||||
print()
|
print()
|
||||||
return i+1
|
return i+1
|
||||||
|
@ -165,11 +179,16 @@ def w_return(f, i):
|
||||||
def w_colon(f, i):
|
def w_colon(f, i):
|
||||||
f.compiler = Compiler()
|
f.compiler = Compiler()
|
||||||
|
|
||||||
|
def i_inline(f, i):
|
||||||
|
f.compiler.inline = True
|
||||||
|
|
||||||
def i_semi(forth, i):
|
def i_semi(forth, i):
|
||||||
forth.compiler.add_instruction(w_return)
|
forth.compiler.add_instruction(w_return)
|
||||||
name = forth.compiler.name
|
name = forth.compiler.name
|
||||||
word_f = execute_f(name, forth.compiler.instructions)
|
word_f = execute_f(name, forth.compiler.instructions)
|
||||||
forth.defword(name, word_f)
|
entry = forth.defword(name, word_f)
|
||||||
|
entry.inline = forth.compiler.inline
|
||||||
|
entry.definition = forth.compiler.instructions
|
||||||
forth.compiler = None
|
forth.compiler = None
|
||||||
return i+1
|
return i+1
|
||||||
|
|
||||||
|
@ -277,4 +296,7 @@ def w_enlist(f, i):
|
||||||
f.stack.push([x])
|
f.stack.push([x])
|
||||||
return i+1
|
return i+1
|
||||||
|
|
||||||
|
def w_raise(f, i):
|
||||||
|
ex = f.stack.pop()
|
||||||
|
raise ex
|
||||||
|
return i+1
|
||||||
|
|
|
@ -5,10 +5,14 @@ class Compiler:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.instructions = []
|
self.instructions = []
|
||||||
self.offsets = Stack()
|
self.offsets = Stack()
|
||||||
|
self.inline = False
|
||||||
|
|
||||||
def add_instruction(self, ins):
|
def add_instruction(self, ins):
|
||||||
self.instructions.append(ins)
|
self.instructions.append(ins)
|
||||||
|
|
||||||
|
def add_instructions(self, instructions):
|
||||||
|
self.instructions.extend(instructions)
|
||||||
|
|
||||||
def offset(self):
|
def offset(self):
|
||||||
return len(self.instructions)
|
return len(self.instructions)
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,9 @@
|
||||||
|
|
||||||
: prompt-and-run ( -- prog-status)
|
: prompt-and-run ( -- prog-status)
|
||||||
">> " read-line
|
">> " read-line
|
||||||
dup "x" =
|
dup "q" =
|
||||||
if
|
if
|
||||||
"Exit!" p
|
"Quit!" p
|
||||||
drop
|
drop
|
||||||
else
|
else
|
||||||
tokenize
|
tokenize
|
||||||
|
@ -47,3 +47,5 @@
|
||||||
recur
|
recur
|
||||||
then
|
then
|
||||||
;
|
;
|
||||||
|
|
||||||
|
: % "Toggle" p ;
|
||||||
|
|
|
@ -50,10 +50,10 @@ class Forth:
|
||||||
self.namespace = user_ns
|
self.namespace = user_ns
|
||||||
|
|
||||||
def defword(self, name, value):
|
def defword(self, name, value):
|
||||||
self.namespace.set(name, value)
|
return self.namespace.set(name, value)
|
||||||
|
|
||||||
def defvar(self, name, value):
|
def defvar(self, name, value):
|
||||||
self.defword(name, const_f(value))
|
return self.defword(name, const_f(value))
|
||||||
|
|
||||||
def compiling(self):
|
def compiling(self):
|
||||||
return self.compiler
|
return self.compiler
|
||||||
|
@ -61,7 +61,7 @@ class Forth:
|
||||||
def _compile_token(self, kind, token):
|
def _compile_token(self, kind, token):
|
||||||
#print(f"compile: {self.compiler.name}: {token}")
|
#print(f"compile: {self.compiler.name}: {token}")
|
||||||
if self.compiler.name == None:
|
if self.compiler.name == None:
|
||||||
print(f'Compiling {token}')
|
#print(f'Compiling {token}')
|
||||||
self.compiler.name = token
|
self.compiler.name = token
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -75,6 +75,8 @@ class Forth:
|
||||||
if entry.immediate:
|
if entry.immediate:
|
||||||
value = entry.get_ivalue()
|
value = entry.get_ivalue()
|
||||||
value(self, 0)
|
value(self, 0)
|
||||||
|
elif entry.inline:
|
||||||
|
self.compiler.add_instructions(entry.definition[slice(0,-1)])
|
||||||
else:
|
else:
|
||||||
value = entry.get_cvalue()
|
value = entry.get_cvalue()
|
||||||
self.compiler.add_instruction(value)
|
self.compiler.add_instruction(value)
|
||||||
|
@ -82,12 +84,13 @@ class Forth:
|
||||||
|
|
||||||
n = to_number(token)
|
n = to_number(token)
|
||||||
if n == None:
|
if n == None:
|
||||||
print(f'{token}? Compile of {self.compiler.name} terminated.')
|
print(f'[{token}]?? Compile of [{self.compiler.name}] terminated.')
|
||||||
self.compiler = None
|
self.compiler = None
|
||||||
else:
|
else:
|
||||||
self.compiler.add_instruction(const_f(n))
|
self.compiler.add_instruction(const_f(n))
|
||||||
|
|
||||||
def _eval_token(self, kind, token):
|
def _eval_token(self, kind, token):
|
||||||
|
#print(f'eval token {token} kind {kind}')
|
||||||
if kind in ['dqstring', 'sqstring']:
|
if kind in ['dqstring', 'sqstring']:
|
||||||
self.stack.push(token)
|
self.stack.push(token)
|
||||||
return
|
return
|
||||||
|
@ -153,7 +156,7 @@ class Forth:
|
||||||
for a in rargs:
|
for a in rargs:
|
||||||
# print("pushing", a);
|
# print("pushing", a);
|
||||||
self.stack.push(a)
|
self.stack.push(a)
|
||||||
print(f'Before eval stack is {str(self.stack)}')
|
#print(f'Before eval stack is {str(self.stack)}')
|
||||||
return self.evaluate_string(s)
|
return self.evaluate_string(s)
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,7 +171,7 @@ class Forth:
|
||||||
for part in parts[1::]:
|
for part in parts[1::]:
|
||||||
result.append(['sqstring', part])
|
result.append(['sqstring', part])
|
||||||
result.append(['word', '.>'])
|
result.append(['word', '.>'])
|
||||||
print(result)
|
#print(result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def set_ns(self, ns_name):
|
def set_ns(self, ns_name):
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
class Entry:
|
class Entry:
|
||||||
def __init__(self, name, value, immediate):
|
def __init__(self, name, value, immed):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.value = value
|
self.value = value
|
||||||
self.immediate = immediate
|
self.immediate = immed
|
||||||
|
self.inline = False
|
||||||
|
self.definition = None
|
||||||
|
|
||||||
def get_ivalue(self):
|
def get_ivalue(self):
|
||||||
return self.value
|
return self.value
|
||||||
|
@ -11,7 +13,10 @@ class Entry:
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f'Entry {self.name} {self.immediate}'
|
result = f'Entry {self.name} {self.immediate} {self.inline}\n'
|
||||||
|
for x in self.definition:
|
||||||
|
result += f'{x}\n'
|
||||||
|
return result
|
||||||
|
|
||||||
class Namespace:
|
class Namespace:
|
||||||
def __init__(self, name, initial_contents={}, refers=[]):
|
def __init__(self, name, initial_contents={}, refers=[]):
|
||||||
|
@ -51,6 +56,7 @@ class Namespace:
|
||||||
entry.cvalue = cvalue
|
entry.cvalue = cvalue
|
||||||
entry.immediate = immediate
|
entry.immediate = immediate
|
||||||
self.contents[name] = entry
|
self.contents[name] = entry
|
||||||
|
return entry
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self.contents.keys()
|
return self.contents.keys()
|
||||||
|
|
|
@ -44,16 +44,21 @@ def setup_forth():
|
||||||
|
|
||||||
def repl(f):
|
def repl(f):
|
||||||
while True:
|
while True:
|
||||||
prompt = f.evaluate_string('*prompt*')
|
|
||||||
try:
|
try:
|
||||||
line = input(prompt)
|
prompt = f.evaluate_string('*prompt*')
|
||||||
except EOFError:
|
try:
|
||||||
return
|
line = input(prompt)
|
||||||
try:
|
line += "\n"
|
||||||
f.execute_string(line)
|
except EOFError:
|
||||||
except:
|
return
|
||||||
traceback.print_exc()
|
try:
|
||||||
|
f.stack.push(line)
|
||||||
|
f.execute_string("*execute-command*")
|
||||||
|
#f.execute_string(line)
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
f = setup_forth()
|
f = setup_forth()
|
||||||
|
|
|
@ -23,6 +23,9 @@ class Stack:
|
||||||
for i in range(0, self.top+1):
|
for i in range(0, self.top+1):
|
||||||
yield self.stack[i]
|
yield self.stack[i]
|
||||||
|
|
||||||
|
def depth(self):
|
||||||
|
return self.top + 1
|
||||||
|
|
||||||
def empty(self):
|
def empty(self):
|
||||||
return self.top == -1
|
return self.top == -1
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,10 @@ def w_dot(f, i):
|
||||||
print(a, end='')
|
print(a, end='')
|
||||||
return i+1
|
return i+1
|
||||||
|
|
||||||
|
def w_stackdepth(f, i):
|
||||||
|
d = f.stack.depth()
|
||||||
|
f.stack.push(d)
|
||||||
|
|
||||||
def w_splat(f, i):
|
def w_splat(f, i):
|
||||||
l = f.stack.pop()
|
l = f.stack.pop()
|
||||||
l.reverse()
|
l.reverse()
|
||||||
|
@ -29,12 +33,6 @@ def w_dup(f, i):
|
||||||
return i+1
|
return i+1
|
||||||
|
|
||||||
def w_tmb(f, i): # A noop
|
def w_tmb(f, i): # A noop
|
||||||
# t = f.stack.pop()
|
|
||||||
# m = f.stack.pop()
|
|
||||||
# b = f.stack.pop()
|
|
||||||
# f.stack.push(b)
|
|
||||||
# f.stack.push(m)
|
|
||||||
# f.stack.push(t)
|
|
||||||
return i+1
|
return i+1
|
||||||
|
|
||||||
def w_tbm(f, i):
|
def w_tbm(f, i):
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
"io" require
|
"io" require
|
||||||
"time" require
|
"time" require
|
||||||
|
|
||||||
|
'builtins import
|
||||||
|
|
||||||
\ Basic aliases
|
\ Basic aliases
|
||||||
|
|
||||||
'None 'nil alias
|
'None 'nil alias
|
||||||
|
@ -36,13 +38,14 @@
|
||||||
'current_ns '*ns* alias
|
'current_ns '*ns* alias
|
||||||
|
|
||||||
: *prompt* "Sally> " ;
|
: *prompt* "Sally> " ;
|
||||||
|
: *execute-command* stack execute ;
|
||||||
|
|
||||||
\ Make a list.
|
\ Make a list.
|
||||||
'list-marker unique def
|
'list-marker unique def
|
||||||
: [ list-marker ;
|
: [ list-marker inline ;
|
||||||
: ] list-marker [list] ;
|
: ] list-marker [list] inline ;
|
||||||
|
|
||||||
: [] ( -- <empty list>) [ ] ;
|
: [] ( -- <empty list>) [ ] inline ;
|
||||||
|
|
||||||
|
|
||||||
\ Look up attributes on a value.
|
\ Look up attributes on a value.
|
||||||
|
@ -51,16 +54,16 @@
|
||||||
: $? swap ;
|
: $? swap ;
|
||||||
|
|
||||||
\ Call native functions with various # arguments.
|
\ Call native functions with various # arguments.
|
||||||
: !!0 [] swap !! ;
|
: !!0 [] swap !! inline ;
|
||||||
: !!1 swap 1 ->list swap !! ;
|
: !!1 swap 1 ->list swap !! inline ;
|
||||||
: !!2 swap 2 ->list swap !! ;
|
: !!2 swap 2 ->list swap !! inline ;
|
||||||
|
|
||||||
\ Make a map.
|
\ Make a map.
|
||||||
'map-marker unique def
|
'map-marker unique def
|
||||||
: { map-marker ;
|
: { map-marker inline ;
|
||||||
: } map-marker [list] list->map ;
|
: } map-marker [list] list->map inline ;
|
||||||
|
|
||||||
: {} ( -- <empty map>) { } ;
|
: {} ( -- <empty map>) { } inline ;
|
||||||
|
|
||||||
|
|
||||||
\ Make a set.
|
\ Make a set.
|
||||||
|
@ -71,16 +74,21 @@
|
||||||
set-marker [list] \ Turn elements into list
|
set-marker [list] \ Turn elements into list
|
||||||
set-marker swap set-marker [list] \ Nest list in argument list
|
set-marker swap set-marker [list] \ Nest list in argument list
|
||||||
builtins.set !! \ Call set with 1 argument
|
builtins.set !! \ Call set with 1 argument
|
||||||
|
inline
|
||||||
;
|
;
|
||||||
|
|
||||||
: {{}} ( -- <empty set>) {{ }} ;
|
: {{}} ( -- <empty set>) {{ }} inline ;
|
||||||
|
|
||||||
: [: [ ;
|
: [: [ inline ;
|
||||||
: :] ] ->arglist ;
|
: :] ] ->arglist inline ;
|
||||||
|
|
||||||
|
|
||||||
|
: str builtins.str !!1 ;
|
||||||
|
|
||||||
: type builtins.type !!1 ;
|
: type builtins.type !!1 ;
|
||||||
|
|
||||||
|
: type? (x class -- bool) swap type = ;
|
||||||
|
|
||||||
: ctime time.ctime !!0 ;
|
: ctime time.ctime !!0 ;
|
||||||
|
|
||||||
: sleep time.sleep !!1 drop ;
|
: sleep time.sleep !!1 drop ;
|
||||||
|
@ -89,22 +97,22 @@
|
||||||
|
|
||||||
: hello "Hello" . nl ;
|
: hello "Hello" . nl ;
|
||||||
|
|
||||||
: >0 0 > ;
|
: >0 0 > inline ;
|
||||||
: =0 0 = ;
|
: =0 0 = inline ;
|
||||||
: <1 1 < ;
|
: <1 1 < inline ;
|
||||||
: <0 0 < ;
|
: <0 0 < inline ;
|
||||||
: >1 1 > ;
|
: >1 1 > inline ;
|
||||||
: <1 1 < ;
|
: <1 1 < inline ;
|
||||||
|
|
||||||
: p . nl ;
|
: p . nl ;
|
||||||
: top dup p ;
|
: top dup p ;
|
||||||
|
|
||||||
: -- -1 + ;
|
: -- -1 + inline ;
|
||||||
: ++ 1 + ;
|
: ++ 1 + inline ;
|
||||||
: *2 2 * ;
|
: *2 2 * inline ;
|
||||||
: pos? 0 > ;
|
: pos? 0 > inline ;
|
||||||
: neg? 0 < ;
|
: neg? 0 < inline ;
|
||||||
: zero? 0 = ;
|
: zero? 0 = inline ;
|
||||||
|
|
||||||
: exists? os.path.exists !!1 ;
|
: exists? os.path.exists !!1 ;
|
||||||
|
|
||||||
|
@ -123,7 +131,16 @@
|
||||||
: .!!2 (obj a1 a2 method-name -- result ) swap 2 ->list swap .!! ;
|
: .!!2 (obj a1 a2 method-name -- result ) swap 2 ->list swap .!! ;
|
||||||
: .!!3 (obj a1 a2 a3 method-name -- result ) swap 3 ->list swap .!! ;
|
: .!!3 (obj a1 a2 a3 method-name -- result ) swap 3 ->list swap .!! ;
|
||||||
|
|
||||||
\ todo : tokenize #forth.tokenizer.tokenize !!1 ;
|
: assert ( bool msg -- )
|
||||||
|
swap
|
||||||
|
if
|
||||||
|
"OK " . p
|
||||||
|
else
|
||||||
|
#builtins.AssertionError !!1
|
||||||
|
raise
|
||||||
|
then
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
"string.sf" source
|
"string.sf" source
|
||||||
"list.sf" source
|
"list.sf" source
|
||||||
|
|
93
sallyforth/test.sf
Normal file
93
sallyforth/test.sf
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
|
||||||
|
\ Test stack and arithmetic.
|
||||||
|
|
||||||
|
reset stackdepth 0 = "Stack starts empty." assert
|
||||||
|
reset 111 stackdepth 1 = "One item on stack" assert
|
||||||
|
reset 111 222 333 stackdepth 3 = "Three items on stack" assert
|
||||||
|
|
||||||
|
reset 1 2 3 reset stackdepth 0 = "Reset empties the stack." assert
|
||||||
|
|
||||||
|
10 10 = "Stack and equality." assert
|
||||||
|
1 2 < "1 less than 2." assert
|
||||||
|
2 1 > "2 bigger than 1." assert
|
||||||
|
99 99 = "99 is equal to itself." assert
|
||||||
|
|
||||||
|
1 1 + 2 = "1 + 1 = 2" assert
|
||||||
|
10 99 + 109 = "10 + 99 = 109" assert
|
||||||
|
10 1 - 9 = "10 - 1 = 9" assert
|
||||||
|
2 3 * 6 = "2*3 = 6" assert
|
||||||
|
100 5 / 20 = "100 divided by 5 is 20." assert
|
||||||
|
|
||||||
|
1 >0 "One is > 0." assert
|
||||||
|
0 =0 "Zero is equal to itself." assert
|
||||||
|
1 =0 not "One is not =0." assert
|
||||||
|
|
||||||
|
1 pos? "One is positive." assert
|
||||||
|
-1 pos? not "One is not positive." assert
|
||||||
|
|
||||||
|
1 ++ 2 = "1++ is two." assert
|
||||||
|
0 -- -1 = "0-- is -1." assert
|
||||||
|
|
||||||
|
\ Booleans
|
||||||
|
|
||||||
|
true "True is true." assert
|
||||||
|
true not false = "Not true is false" assert
|
||||||
|
false not "Not false is true." assert
|
||||||
|
|
||||||
|
true true or "T or T is T." assert
|
||||||
|
true false or "T or F is T." assert
|
||||||
|
false true or "F or T is T." assert
|
||||||
|
false false or not "F or F is F." assert
|
||||||
|
|
||||||
|
true true and "T and T is T." assert
|
||||||
|
true false and not "T and F is F." assert
|
||||||
|
false true and not "F and T is F." assert
|
||||||
|
false false and not "F and F is F." assert
|
||||||
|
|
||||||
|
\ Secondary words
|
||||||
|
|
||||||
|
: push8 8 ; push8 8 = "A word can push a number." assert
|
||||||
|
|
||||||
|
: push8-again push8 ;
|
||||||
|
push8-again 8 = "A word can call another word." assert
|
||||||
|
|
||||||
|
: push64 push8 push8 * ;
|
||||||
|
push64 64 = "A word can use primitive and sec words." assert
|
||||||
|
|
||||||
|
\ Logic
|
||||||
|
|
||||||
|
: 1-if-true if 1 then ;
|
||||||
|
|
||||||
|
reset true 1-if-true 1 = "True part of if fires." assert
|
||||||
|
reset false 1-if-true stackdepth 0 = "if does not fire on false." assert
|
||||||
|
|
||||||
|
: 1-or-2 if 1 else 2 then ;
|
||||||
|
|
||||||
|
reset true 1-or-2 1 = "True part of ifelse fires." assert
|
||||||
|
reset false 1-or-2 2 = "False part of ifelse fires." assert
|
||||||
|
|
||||||
|
\ built in functions
|
||||||
|
|
||||||
|
123 str "123" = "Str turns numbers into strings." assert
|
||||||
|
"abcd" len 4 = "Len gets length of strings." assert
|
||||||
|
|
||||||
|
\ Name lookup and calls
|
||||||
|
|
||||||
|
"12" <. builtins 'len .> !!1 2 = "Can use bracket dot notation." assert
|
||||||
|
"12" #builtins.len !!1 2 = "Can use sharp lookup notation." assert
|
||||||
|
|
||||||
|
\ Lists
|
||||||
|
|
||||||
|
0 ->list len 0 = "->list with a lenght of 0 gives you empty list." assert
|
||||||
|
44 1 ->list len 1 = "->list with a lenght of 1 gives you 1 list." assert
|
||||||
|
5 7 2 ->list len 2 = "->list with a lenght of 2 gives you 2 list." assert
|
||||||
|
|
||||||
|
[ ] 0 ->list = "Brackets are the same as ->list." assert
|
||||||
|
[ 88 ] 88 1 ->list = "Brackets are the same as ->list." assert
|
||||||
|
[ 88 99 ] 99 88 2 ->list = "Brackets are the same as ->list." assert
|
||||||
|
|
||||||
|
[ "hello" ] first "hello" = "First works" assert
|
||||||
|
|
||||||
|
[ ] empty? "Empty? knows an empty list." assert
|
||||||
|
[ 1 ] empty? not "Empty? knows a non-empty list." assert
|
||||||
|
[ 1 2 ] empty? not "Empty? knows a non-empty list." assert
|
|
@ -36,6 +36,8 @@ class TokenStream:
|
||||||
return ['eof', '']
|
return ['eof', '']
|
||||||
elif state == 'start' and ch == '\\':
|
elif state == 'start' and ch == '\\':
|
||||||
state = 'lcomment'
|
state = 'lcomment'
|
||||||
|
elif state == 'start' and ch == '%':
|
||||||
|
return ['word', ch]
|
||||||
elif state == 'lcomment' and ch == '\n':
|
elif state == 'lcomment' and ch == '\n':
|
||||||
state = 'start'
|
state = 'start'
|
||||||
elif state == 'start' and ch == '(':
|
elif state == 'start' and ch == '(':
|
||||||
|
|
Loading…
Reference in a new issue