Click here to Skip to main content
13,763,803 members
Click here to Skip to main content
Add your own
alternative version

Tagged as


84 bookmarked
Posted 19 Jul 2011
Licenced MIT

Lua Interpreter

, 22 Sep 2012
Rate this:
Please Sign up or sign in to vote.
A Lua interpreter is implemented in C#. It allows to write Lua extensions in C# and call the extensions in Lua code.

Introduction to Lua

Although I heard of Lua several years ago, I decided to study this language recently when Lua entered the top 10 languages of the TIOBE Programming Community Index. To my surprise, Lua is almost an ideal dynamic typed functional language, because it is simple, efficient and powerful. As a learning practice, I wrote a program to draw a graph of any equation or inequation with two variables in Lua. If you are new to Lua, I strongly recommend you read the book Programming in Lua and visit

Lua is an extensible extension language. Extensible means libraries can be written in C and accessed in Lua in natural ways. Extension means it can be embedded into a host application so that users can program it. However due to the following two reasons, I want to write a library in C# and call the library in Lua:

  1. I don't like to program in C/C++
  2. None of the Lua libraries can match the functionality provided by the .NET Framework

I didn't find an existing solution so I implemented an Lua interpreter by myself. Since the interpreter is written in C#, .NET library can be called in Lua code when it is appropriately wrapped in modules.

Implementation of the Interpreter

The syntax of Lua is defined with parser expression grammar in Lua.Grammar.txt file. Then given the grammar file as input, a homemade parser generator is used to generate the parser code. If the lua code is parsed successfully, a syntax tree with Chunk as root node is returned. Then the interpreter executes the Chunk according to Lua semantics.

Most of the implementation is straightforward, a little difference with standard Lua is that strings are unicode and the library function string.format uses the same formatter syntax as in C#'s string.Format.

The project code is compiled into two files: lua.exe and wlua.exe, one is command line version and the other is winform version. Here is the result after running the test.lua file:


Windows Forms Library

As a proof of the concept, I write a module to create a UI using Windows Forms. After reading the code in WinFormLib.cs, you will understand why Lua is a miraculous language, the metatable mechanism is more powerful than firstly imagined. The module is named as "Gui", the same .NET type, method, property name can be used to manipulate controls. Here is an example program in WinFormExample.wlua:

form = Gui.Form{
    Text="Main Form", Height=200, StartPosition="CenterScreen",
    Gui.Label{ Text="Hello!", Name="lable", Width=80, Height=17, Top=9, Left=12 },
    Gui.Button{ Text="Click", Width=80, Height=23, Top=30, Left=12,
        Click=function(sender,e) Gui.ShowMessage(lable.Text,"Clicked") end },


Gui.ControlTypeName returns a lua function to create an instance of the control, the function accepts a lua table as its parameter, key value pairs in the table are used to set values to control properties, array items in the table are added as child controls or sub items of the control. One special thing is that when set the Name property, a global variable is created for the control. As you see, Lua as a data descriptive language is more compact than an equivalent XAML file.

The screen shot of this example is:


The Ledger.wlua file contains a more complete and practical example, it can add and delete entries to a ledger sheet and save to a file, the saved file can be opened later. Here is the code:

form = Gui.Form{
    Text="Ledger Sheet", Width=700, Height=500, StartPosition="CenterScreen",
    Gui.SplitContainer {
        Dock="Fill", Width=700, SplitterDistance=200,
        Gui.TreeView{ Name="treeviewCategory", Dock="Fill", HideSelection=false },
                Name="listviewEntries", Dock="Fill", View="Details", 
			GridLines=true, FullRowSelect=true,
                ContextMenuStrip=Gui.ContextMenuStrip {
                    Gui.ToolStripMenuItem { Text="Delete", 
			Click=function(sender,e) DeleteEntry() end }
            Gui.StatusStrip { Name="statusStrip", Dock="Bottom" }
        Dock="Top", Top=0, Left=0, Width=700, Height=25,
        Gui.ToolStripButton { Name="btnOpen", Text="&Open", 
				Width=88, Height=22, Image="icon\\open.png" },
        Gui.ToolStripButton { Name="btnSave", Text="&Save", 
				Width=88, Height=22, Image="icon\\save.png" },
        Gui.ToolStripButton { Name="btnAdd", Text="&Add", 
				Width=88, Height=22, Image="icon\\add.png" },

incomeNode = treeviewCategory.Nodes.Add("Income")
outgoNode = treeviewCategory.Nodes.Add("Outgo")
listviewEntries.Columns.Add(Gui.ColumnHeader{ Text="Date", Width=100 })
listviewEntries.Columns.Add(Gui.ColumnHeader{ Text="Detail", Width=260 })
listviewEntries.Columns.Add(Gui.ColumnHeader{ Text="Amount", Width=120 })

dialog = Gui.Form{
    Text="Add Entry", Width=320, Height=220, StartPosition="CenterParent", 
		FormBorderStyle="FixedDialog", ShowInTaskbar = false;
    Gui.Label{ Text="Subject:", Width=60, Height=17, Top=14, Left=12 },
    Gui.RadioButton { Name="dialog_Income", Text="Income", 
				Width=80, Height=20, Top=9, Left=80 },
    Gui.RadioButton { Name="dialog_Outgo", Text="Outgo", 
				Width=80, Height=20, Top=9, Left=160, Checked=true },
    Gui.Label{ Text="Category:", Width=60, Height=17, Top=40, Left=12 },
    Gui.ComboBox { Name="dialog_Category", Width=160, Height=20, Top=36, Left=80 },
    Gui.Label{ Text="Detail:", Width=60, Height=17, Top=68, Left=12 },
    Gui.TextBox { Name="dialog_Detail", Width=160, Height=20, Top=64, Left=80 },
    Gui.Label{ Text="Amount:", Width=60, Height=17, Top=96, Left=12 },
    Gui.TextBox { Name="dialog_Amount", Width=128, Height=20, Top=92, Left=80 },
    Gui.Label{ Text="Date:", Width=60, Height=17, Top=128, Left=12 },
    Gui.DateTimePicker { Name="dialog_Date", Width=128, 
				Height=21, Top=124, Left=80, Format="Short" },
    Gui.Button{ Text="OK", Name="dialog_btnOK", Width=80, 
				Height=23, Top=156, Left=130, DialogResult="OK" },
    Gui.Button{ Text="Cancel", Name="dialog_btnCancel", Width=80, 
				Height=23, Top=156, Left=224, DialogResult="Cancel" },

Entries = {}

btnAdd.Click = function (sender,e)
    dialog_Detail.Text = ""
    dialog_Amount.Text = ""
    if treeviewCategory.SelectedNode ~= nil and 
			treeviewCategory.SelectedNode.Tag ~= nil then
        dialog_Category.Text = treeviewCategory.SelectedNode.Text
    if dialog.ShowDialog(form) == "OK" then
        local subject = dialog_Income.Checked and "income" or "outgo"
        local category = dialog_Category.Text
        local detail = dialog_Detail.Text
        local amount = dialog_Amount.Text
        local date = dialog_Date.Value.ToShortDateString()
        local entry = {date, subject, category, detail, amount}
        table.insert(Entries, entry)
        local categoryNode = UpdateCategoryTree(entry)
        if treeviewCategory.SelectedNode == categoryNode then
            treeviewCategory.SelectedNode = categoryNode

function FindCategoryNode(entry)
    local subject = entry[2]
    local category = entry[3]
    local subjectNode = subject == "outgo" and outgoNode or incomeNode
    local subNodes = subjectNode.Nodes.Find(category, false)
    if #subNodes == 0 then
        return nil, subjectNode
        return subNodes[1], subjectNode

function UpdateCategoryTree(entry)
    local categoryNode, subjectNode = FindCategoryNode(entry)
    if categoryNode == nil then
        local category = entry[3]
        categoryNode = subjectNode.Nodes.Add(category, category)
        categoryNode.Tag = {}
    table.insert(categoryNode.Tag, entry)
    return categoryNode

treeviewCategory.AfterSelect = function (sender, e)
    local entries = treeviewCategory.SelectedNode.Tag
    if entries ~= nil then
        for _,entry in ipairs(entries) do

function AddEntryToListView(entry)
    local item = Gui.ListViewItem{ Text=entry[1] }
    item.Tag = entry

function DeleteEntry()
    local item = listviewEntries.SelectedItems[1]
    local entry = item.Tag
    if entry ~= nil then
        local categoryNode = FindCategoryNode(entry)
        table.removeitem(categoryNode.Tag, entry)
        table.removeitem(Entries, entry)

btnSave.Click = function (sender, e)
    local sfd = Gui.SaveFileDialog{ Title="Save data", Filter="data file(*.dat)|*.dat" }
    if sfd.ShowDialog() == "OK" then
        local file =, "w")
        file:write("Entries = {\r\n")
        for _,entry in ipairs(Entries) do
            file:write('{"', table.concat(entry, '", "'), '"},\r\n')

btnOpen.Click = function (sender, e)
    local ofd = Gui.OpenFileDialog{ Title="Open data file", 
			Filter="data file(*.dat)|*.dat" }
    if ofd.ShowDialog() == "OK" then
        for _,entry in ipairs(Entries) do


The Ledger Sheet form:


The Add Entry dialog:


Tips to Run Lua Code File

The first method is in Visual Studio project properties, set file name as command line parameter in Debug tab page.

In this way, the lua code can be debugged indirectly through the execution of interpreter.


The second method is in Windows file explorer, drag .lua file to lua.exe, it will start lua.exe and pass .lua file as a parameter, the same works for .wlua file and wlua.exe.


The third method is when you ship the software, compiling the interpreter will lua code file path hard coded.

Matters Need Attention

The possible usage of this project is use Lua as a data description language or a script language for a .NET application. Currently the code is just enough for a demo, many features are incomplete and untested, you may need to do it by yourself if you want to include the Lua interpreter in a large project.


  • 2011-07-19 Initial release
  • 2012-09-22 Fix bug in parse "i == -1" 
  • 2012-09-23 Fix bug in parse "t={f=function() end}


This article, along with any associated source code and files, is licensed under The MIT License


About the Author

Liu Junfeng
Architect YunCheDa Hangzhou
China China
No Biography provided

You may also be interested in...

Comments and Discussions

QuestionGraphPlot Pin
Wrangly23-Oct-13 14:26
memberWrangly23-Oct-13 14:26 
AnswerRe: GraphPlot Pin
Liu Junfeng21-Nov-13 17:32
memberLiu Junfeng21-Nov-13 17:32 
BugParsing problem Pin
DickChaney18-Feb-13 1:32
memberDickChaney18-Feb-13 1:32 
QuestionMulti-Thread Pin
Jonatask2-Feb-13 0:14
memberJonatask2-Feb-13 0:14 
QuestionGood Job! Pin
sneusse25-Jan-13 0:49
membersneusse25-Jan-13 0:49 
BugBugs with x==-y Pin
Elc So5-Oct-12 3:46
memberElc So5-Oct-12 3:46 
Questionrecursive function calls Pin
Bunny99s22-Sep-12 19:28
memberBunny99s22-Sep-12 19:28 
Questionthanks for sharing! Pin
Southmountain22-Sep-12 13:55
memberSouthmountain22-Sep-12 13:55 
GeneralMy vote of 5 Pin
Southmountain22-Sep-12 13:55
memberSouthmountain22-Sep-12 13:55 
QuestionI create a virtual gameconsole for development using your project for parsing lua, thanks! =) Pin
SebaGames11-Aug-12 13:20
memberSebaGames11-Aug-12 13:20 
QuestionException when parse this: Pin
SebaGames30-Jul-12 21:23
memberSebaGames30-Jul-12 21:23 
AnswerRe: Exception when parse this: Pin
Liu Junfeng22-Sep-12 6:35
memberLiu Junfeng22-Sep-12 6:35 
Questionanonymous function in table constructors Pin
Bunny99s29-Apr-12 4:04
memberBunny99s29-Apr-12 4:04 
AnswerRe: anonymous function in table constructors Pin
Bunny99s29-Apr-12 4:56
memberBunny99s29-Apr-12 4:56 
GeneralMy vote of 5 Pin
Bunny99s29-Apr-12 3:46
memberBunny99s29-Apr-12 3:46 
Questionbad Number format Pin
tim.struppi710-Feb-12 22:55
membertim.struppi710-Feb-12 22:55 
AnswerRe: bad Number format Pin
Liu Junfeng13-Mar-12 5:22
memberLiu Junfeng13-Mar-12 5:22 
QuestionLuaInterface project on SourceForge for .Net Pin
tystent25-Jul-11 13:44
membertystent25-Jul-11 13:44 
QuestionDebugger? Pin
FZelle20-Jul-11 4:21
memberFZelle20-Jul-11 4:21 
AnswerRe: Debugger? Pin
dave.dolan28-Jul-11 17:37
memberdave.dolan28-Jul-11 17:37 
SuggestionMy vote of 5 Pin
Roberto Collina19-Jul-11 9:29
memberRoberto Collina19-Jul-11 9:29 
GeneralRe: My vote of 5 Pin
Liu Junfeng20-Jul-11 2:48
memberLiu Junfeng20-Jul-11 2:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web05-2016 | 2.8.181113.2 | Last Updated 22 Sep 2012
Article Copyright 2011 by Liu Junfeng
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid