@@ -150,6 +150,57 @@ function Tokenizer:get_mnemonic()
150150 return mnemonic
151151end
152152
153+ local ArgumentTokenizer = {}
154+
155+ function ArgumentTokenizer :get_next (argument_type )
156+ local argument_regex = self .luasm .settings .syntax [argument_type ]
157+
158+ local matched = self .line :match (argument_regex , self .position )
159+
160+ if matched ~= nil then
161+ self .position = self .position + matched :len ()
162+ end
163+
164+ return matched
165+ end
166+
167+ function ArgumentTokenizer :skip_separator ()
168+ local matched = self .line :match (self .luasm .settings .separator , self .position )
169+
170+ if matched == nil then
171+ return false
172+ end
173+
174+ self .position = self .position + matched :len ()
175+
176+ return true
177+ end
178+
179+ function ArgumentTokenizer :reset ()
180+ self .position = 1
181+ end
182+
183+ function ArgumentTokenizer :eol ()
184+ return self .position > self .line :len ()
185+ end
186+
187+ --- Creates an argument tokenizer based upon the current state
188+ --- of the creating tokenizer.
189+ ---
190+ --- @return table The argument tokenizer
191+ function Tokenizer :argument_tokenizer ()
192+ local obj = {}
193+
194+ obj .line = self .line
195+ obj .luasm = self .luasm
196+ obj .position = 1
197+
198+ setmetatable (obj , ArgumentTokenizer )
199+ ArgumentTokenizer .__index = ArgumentTokenizer
200+
201+ return obj
202+ end
203+
153204--- Creates a new tokenizer without a specific implementation.
154205--- @return table A tokenizer instance (needs a concrete ` get_next_line` implementation ).
155206function Tokenizer :new (luasm )
@@ -220,37 +271,46 @@ end
220271--- `{ op = opcode, args = args, line = current line }`
221272---
222273--- If the parsing has errored out, it returns a string with the error message.
223- --- @param elements table Token list where ` elements[1]` is the mnemonic.
224- --- @param luasm table The LuASM instance (provides settings , etc. ).
274+ --- @param arguments table Token list where ` elements[1]` is the mnemonic.
275+ --- @param luasm table The LuASM instance (provides settings , etc. ).
225276--- @return table | string On success a table ` {op, args, line, run}` ; on failure a string error message.
226- function instruction :parse (elements , luasm )
277+ function instruction :parse (arguments , luasm )
227278 -- `elements[1]` is the mnemonic, the rest are raw operands
228279 local opcode = self .name
229280 local expected = self .structure -- e.g. {"imm","reg"}
230281
231- if # elements - 1 ~= # expected then
232- local err = string.format (
233- " Wrong number of operands for %s (expected %d, got %d)" ,
234- opcode , # expected , # elements - 1 )
235- return err
236- end
237282
238283 local args = {}
239- for i = 2 , # elements do
240- local pattern = luasm .settings .syntax [expected [i - 1 ]]
241- if pattern == nil then
242- error (" The pattern with the name of '" .. expected [i - 1 ] .. " ' does not exist." , 2 )
243- return " Pattern not found"
284+ for index , value in ipairs (expected ) do
285+ if index ~= 1 then
286+ if not arguments :skip_separator () then
287+ local err = string.format (
288+ " Expected separator after the argument number %d (for %s)" ,
289+ index - 1 , opcode
290+ )
291+ return err
292+ end
244293 end
245294
246- local arg = elements [i ]:match (pattern )
295+ local arg = arguments :get_next (value )
296+
247297 if arg == nil then
248298 local err = string.format (
249- " Could not match argument '%s' (expected %s)" ,
250- elements [i ], expected [i - 1 ])
299+ " Wrong number of operands for %s (expected %d but got less)" ,
300+ opcode , # expected
301+ )
251302 return err
252303 end
253- args [i - 1 ] = arg
304+
305+ args [# args + 1 ] = arg
306+ end
307+
308+ if not arguments :eol () then
309+ local err = string.format (
310+ " Wrong number of operands for %s (expected %d but got more)" ,
311+ opcode , # expected
312+ )
313+ return err
254314 end
255315
256316 return {
@@ -304,12 +364,16 @@ function LuASM:parse(tokenizer)
304364 local mnemonic = tokenizer :get_mnemonic ()
305365
306366 local errors = {}
367+ local argument_tokenizer = tokenizer :argument_tokenizer ()
368+
307369 for _ , instr in ipairs (self .instructions ) do
308370 if instr .name ~= mnemonic then
309371 goto inner
310372 end
311373
312- local result = instr :parse (tokenizer , self )
374+ local result = instr :parse (argument_tokenizer , self )
375+ argument_tokenizer :reset ()
376+
313377 if type (result ) == " table" then
314378 parse_data .instructions [# parse_data .instructions + 1 ] = result
315379 goto continue -- go to the outer `continue` label
0 commit comments