CCCPaste

be387eabcfb18

local Pawn = {}

-- Pawn token types
local TokenType = {
    KEYWORD = 1,
    IDENTIFIER = 2,
    NUMBER = 3,
    STRING = 4,
    OPERATOR = 5,
    PREPROCESSOR = 6,
    COMMENT = 7
}

-- Pawn keywords
local KEYWORDS = {
    "new", "enum", "public", "stock", "static", "const", "forward",
    "native", "if", "else", "for", "while", "do", "switch", "case",
    "default", "return", "break", "continue", "sizeof", "state",
    "goto", "tagof", "char", "bool", "int", "float", "void"
}

-- Preprocessor directives
local PREPROCESSOR_DIRECTIVES = {
    "#define", "#include", "#if", "#else", "#endif", "#ifdef", "#ifndef",
    "#pragma", "#error", "#warning"
}

function Pawn.tokenize(code)
    local tokens = {}
    local pos = 1
    local len = #code
    
    while pos <= len do
        local char = code:sub(pos, pos)
        
        -- Skip whitespace
        if char:match("%s") then
            pos = pos + 1
        
        -- Comments
        elseif char == "/" and code:sub(pos + 1, pos + 1) == "/" then
            local start = pos
            while pos <= len and code:sub(pos, pos) ~= "\n" do
                pos = pos + 1
            end
            table.insert(tokens, {
                type = TokenType.COMMENT,
                value = code:sub(start, pos - 1)
            })
        
        -- Multi-line comments
        elseif char == "/" and code:sub(pos + 1, pos + 1) == "*" then
            local start = pos
            pos = pos + 2
            while pos <= len and not (code:sub(pos, pos) == "*" and code:sub(pos + 1, pos + 1) == "/") do
                pos = pos + 1
            end
            pos = pos + 2
            table.insert(tokens, {
                type = TokenType.COMMENT,
                value = code:sub(start, pos - 1)
            })
        
        -- Preprocessor directives
        elseif char == "#" then
            local start = pos
            while pos <= len and not code:sub(pos, pos):match("%s") and code:sub(pos, pos) ~= "\n" do
                pos = pos + 1
            end
            local directive = code:sub(start, pos - 1)
            table.insert(tokens, {
                type = TokenType.PREPROCESSOR,
                value = directive
            })
        
        -- Strings
        elseif char == '"' then
            local start = pos
            pos = pos + 1
            while pos <= len and code:sub(pos, pos) ~= '"' do
                if code:sub(pos, pos) == "\\" then
                    pos = pos + 1 -- Skip escape sequences
                end
                pos = pos + 1
            end
            pos = pos + 1
            table.insert(tokens, {
                type = TokenType.STRING,
                value = code:sub(start, pos - 1)
            })
        
        -- Numbers
        elseif char:match("%d") or (char == "." and code:sub(pos + 1, pos + 1):match("%d")) then
            local start = pos
            while pos <= len and (code:sub(pos, pos):match("%d") or code:sub(pos, pos) == "." or code:sub(pos, pos):match("[eE]") or (code:sub(pos, pos) == "-" and code:sub(pos - 1, pos - 1):match("[eE]"))) do
                pos = pos + 1
            end
            table.insert(tokens, {
                type = TokenType.NUMBER,
                value = code:sub(start, pos - 1)
            })
        
        -- Identifiers and keywords
        elseif char:match("[%a_]") then
            local start = pos
            while pos <= len and code:sub(pos, pos):match("[%w_]") do
                pos = pos + 1
            end
            local identifier = code:sub(start, pos - 1)
            local isKeyword = false
            
            for _, kw in ipairs(KEYWORDS) do
                if kw == identifier then
                    isKeyword = true
                    break
                end
            end
            
            table.insert(tokens, {
                type = isKeyword and TokenType.KEYWORD or TokenType.IDENTIFIER,
                value = identifier
            })
        
        -- Operators
        else
            local operators = {"++", "--", "+=", "-=", "*=", "/=", "%=", "==", "!=", ">=", "<=", "&&", "||", ">>", "<<"}
            local found = false
            
            for _, op in ipairs(operators) do
                if code:sub(pos, pos + #op - 1) == op then
                    table.insert(tokens, {
                        type = TokenType.OPERATOR,
                        value = op
                    })
                    pos = pos + #op
                    found = true
                    break
                end
            end
            
            if not found then
                table.insert(tokens, {
                    type = TokenType.OPERATOR,
                    value = char
                })
                pos = pos + 1
            end
        end
    end
    
    return tokens
end

function Pawn.transpileToLua(pawnCode)
    local tokens = Pawn.tokenize(pawnCode)
    local luaCode = ""
    local i = 1
    
    while i <= #tokens do
        local token = tokens[i]
        
        if token.type == TokenType.PREPROCESSOR then
            if token.value == "#define" then
                -- Handle #define MACRO value
                local name = tokens[i + 1] and tokens[i + 1].value or ""
                local value = tokens[i + 2] and tokens[i + 2].value or ""
                
                if name:match("^[%a_][%w_]*$") then
                    luaCode = luaCode .. "local " .. name .. " = " .. value .. "\n"
                    i = i + 3
                else
                    luaCode = luaCode .. "-- " .. token.value .. "\n"
                    i = i + 1
                end
            else
                luaCode = luaCode .. "-- " .. token.value .. "\n"
                i = i + 1
            end
        
        elseif token.type == TokenType.KEYWORD and token.value == "enum" then
            -- Handle enum
            i = i + 1 -- skip enum
            local enumName = tokens[i].value
            i = i + 2 -- skip name and {
            
            local enumValues = {}
            local currentValue = 0
            
            while i <= #tokens and tokens[i].value ~= "}" do
                if tokens[i].type == TokenType.IDENTIFIER then
                    local name = tokens[i].value
                    i = i + 1
                    
                    if tokens[i] and tokens[i].value == "=" then
                        i = i + 1
                        currentValue = tonumber(tokens[i].value) or 0
                        i = i + 1
                    end
                    
                    table.insert(enumValues, {name = name, value = currentValue})
                    currentValue = currentValue + 1
                    
                    if tokens[i] and tokens[i].value == "," then
                        i = i + 1
                    end
                else
                    i = i + 1
                end
            end
            
            i = i + 1 -- skip }
            
            -- Convert enum to Lua table
            luaCode = luaCode .. "local " .. enumName .. " = {\n"
            for _, ev in ipairs(enumValues) do
                luaCode = luaCode .. "    " .. ev.name .. " = " .. ev.value .. ",\n"
            end
            luaCode = luaCode .. "}\n"
        
        elseif token.type == TokenType.KEYWORD and token.value == "new" then
            -- Handle variable declaration
            i = i + 1 -- skip new
            local varName = tokens[i].value
            i = i + 1
            
            if tokens[i] and tokens[i].value == "[" then
                -- Array declaration
                i = i + 1
                local size = tokens[i].value
                i = i + 2 -- skip size and ]
                
                luaCode = luaCode .. "local " .. varName .. " = {}\n"
                luaCode = luaCode .. "for i = 1, " .. size .. " do\n"
                luaCode = luaCode .. "    " .. varName .. "[i] = 0\n"
                luaCode = luaCode .. "end\n"
            else
                -- Single variable
                luaCode = luaCode .. "local " .. varName .. " = 0\n"
            end
        
        else
            -- Direct translation for other tokens
            luaCode = luaCode .. token.value .. " "
            i = i + 1
        end
    end
    
    return luaCode
end

-- Example usage:
local pawnCode = [[
#define MAX_PLAYERS 500

enum pInfo {
    PlayerName[25],
    Kills,
    Level,
    Points
}

new PlayerInfo[MAX_PLAYERS][pInfo];

public OnPlayerConnect(playerid)
{
    PlayerInfo[playerid][Kills] = 0;
    PlayerInfo[playerid][Level] = 1;
    return 1;
}
]]

local luaCode = Pawn.transpileToLua(pawnCode)
print("Transpiled Lua code:")
print(luaCode)