This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
H4X0RZ's profile picture

While/for loops for my interpreter

Started by H4X0RZ, 30 May 2013 - 10:06 AM
H4X0RZ #1
Posted 30 May 2013 - 12:06 PM
Hello all,
I've started developing my Interpreter today.
Now I need a little bit of help:
How do I detect a while/for loop?
Engineer #2
Posted 30 May 2013 - 02:49 PM
Please give us more information. But why do you need to detect it anyway? I mean really, you are not interpreting native code, at all. Otherwise, string.find("while") is a good help.
H4X0RZ #3
Posted 30 May 2013 - 05:23 PM
Please give us more information. But why do you need to detect it anyway? I mean really, you are not interpreting native code, at all. Otherwise, string.find("while") is a good help.
Ok, I understand the string.find() thing.
But how does my interpreter understands the condition for it?
And how I say the interpreter where the loop stops?

I think I will post the code in a few days in the thread of it …
Bubba #4
Posted 30 May 2013 - 06:23 PM
You'll want to use regex to do this.

For example, this would detect a basic while loop in Lua (you'll have to figure out yourself how you want to do this in whatever language you're interpreting):

local theCode = [[
--this is non relevant stuff
local x = 1
local hi = "hello"
while true do
  print("This is looping")
end

--More non relevant stuff
]]

--#Now let's perform some regex

local match = theCode:match("while.-end")
print(match)

This would get the code that is inside a simple while loop and print it out. Of course, things can get pretty complicated if you're attempting to actually interpret a language, but regex is how you would go about it.

Find out more about regex here.
Bomb Bloke #5
Posted 30 May 2013 - 07:13 PM
I would have the interpreter recognise the loop's start and mark that in a table, then place nested loops (and "if" statements and so on) inside tables WITHIN that table. I'd then carry on execution without worrying where the end point was. Whenever I did hit an "end" statement I'd simply delete the most deeply nested table.

This'd allow you to place variables local to each loop in their respective tables, allowing easy cleanup when you're done with them.

If I reached the end of the program and still had nested tables, I'd throw an error complaining that the loop relating to the final most deeply nested table had no "end" statement. If I hit "end" statements and didn't have any tables at all, I'd throw an "expected <eof>" error.
H4X0RZ #6
Posted 30 May 2013 - 08:11 PM
o_O

I don't thought that it's so complex!
Engineer #7
Posted 31 May 2013 - 02:17 AM
I would rather use plus instead of a minus:

string:gmatch('while.+end')
Since the plus is greedy, it needs the end.

Please correct me if Im wrong, Im still learning regex :P/>
GopherAtl #8
Posted 31 May 2013 - 09:51 AM
Neither of those will work in all cases; consider…


function foo()
  ...
  while true do
    ...
    if cond1 then
      break
    end
  end
end
For this while loop, the first, with -, would go to the if's end, the + would go to the function's end. You'd have to stop at the "do", and match with "end"s in another way, like what bomb bloke described.

And there hasn't yet been any mention of how to parse the conditions themselves.

Basically, yes, this gets complicated. Why you would think otherwise, I have no idea.
Symmetryc #9
Posted 31 May 2013 - 03:12 PM
You would also need to detect these:

""
''
[[]]
[=[]=]
[==[]==]
[===[]===]
(etc.)
to make sure that it is not inside a string.
Symmetryc #10
Posted 31 May 2013 - 03:17 PM
I would rather use plus instead of a minus:

string:gmatch('while.+end')
Since the plus is greedy, it needs the end.

Please correct me if Im wrong, Im still learning regex :P/>
I think it's the opposite way around (not entirely sure though),
.+
matches anything except for a string with no characters at all,
.-
matches only the smallest amount required to go on with the pattern.

Oops, I wanted to edit my above post instead of add a new one in my head, but with my hands I accidentally click the reply button :P/>.
Yevano #11
Posted 31 May 2013 - 03:30 PM
If you want to do this the most "correct" way, you might want to do some research on how grammar parsing works. Here's a good Wikipedia article that helped me understand: http://en.wikipedia...._descent_parser

If you want to do this the "easy" way, you could first make a pass over all the text, using a lookup table to run functions on certain tokens. A token would be something like WHILE, END, TXTCOLOR, SHUTDOWN, etc. On each token, check for its matching argument. If you are looking at WHILE, then you'd check if the condition is true. This poses a problem for this kind of simple text interpreter. The condition can't be an expression because you'd have to implement a parser like what is mentioned in the article. You could, alternatively, have a register-based system where you can set and get register values and use them in arguments.

The second solution is not very elegant, but it's probably closest to what you're looking for. I definitely recommend doing some research on how recursive parsers are made. It's a very interesting subject.