Lua 언어 정리

Posted by : at

Category : NmapScriptingEngine


Lua 언어 정리

주석 처리

-- 연속으로 사용한 대쉬가 있는 한 줄을 주석으로 처리한다.

--[[
	--[[ 해당 문법은 개행이 되었을때 주석을 처리할 수 있다.]]--
--]]

변수 처리

  • 모든 수는 double 형으로 받는다.
  • 64bit double 형에는 총 52bit의 정수값을 저장할 수 있다.
T = 'STIRNGSTRING' -- Python과 동일하게 바꿀 수 없는 문자열이다.
t = "stringstring"

Tt = [[ 이중으로 작성한 대괄호는
				여러 줄 문자열의 시작과 끝을 나타낸다. ]]

t = nil -- t는 정의되지 않은 변수를 만들며, 가비지 컬렉션 기능이 존재한다.

코드 블록 표기법

  • 블록은 do, end로 표기된다.
while count < 50 do
	count = count + 1  -- 참고로 증감 연산자와 일반 단축 연산자 (++, +=...) 없다.
end

변수 및 흐름제어

if count > 30 then
	print('ERROR 30')
elseif n ~= 'PULL' then  -- '~=' 는 같지 않음을 나타낸다.
-- python과 같이 같음을 확인하는 연산자는 '=='이다. '=='는 문자열에도 사용 가능
io.write('NOT OVER 30\n') -- stdout 출력
else
	-- 변수들은 기본적으로 전역(Global) 변수로 생성된다.
	thisIsGlobal = 10 -- 변수 이름을 표기할 때는 CamelCase 표기법을 흔히 사용한다.
	
	-- 변수를 지역(local) 변수로 만드는 방법
	local line = io.read() -- stdin 줄을 읽는다.
	
	-- '..' 연산자를 사용하여 문자열 연결
	print("SO HAPPY," .. line)   -- SO HAPPY + 'stdin으로 입력한 문자열' 출력
end

-- 정의되지 않은 변수들은 nil을 리턴한다.
foo = UnknownVariable   -- foo에 UnknownVariable(정의되지 않은 변수)를 넣는다.
-- foo = nil

BoolValue = false

-- 불(boolean) 연산에서는 오직 nil, false만 거짓이다. 0, " 참이다.😀

if count > 30 then
	print('ERROR 30')
elseif n ~= 'PULL' then  -- '~=' 는 같지 않음을 나타낸다.
-- python과 같이 같음을 확인하는 연산자는 '=='이다. '=='는 문자열에도 사용 가능
io.write('NOT OVER 30\n') -- stdout 출력
else
	-- 변수들은 기본적으로 전역(Global) 변수로 생성된다.
	thisIsGlobal = 10 -- 변수 이름을 표기할 때는 CamelCase 표기법을 흔히 사용한다.
	
	-- 변수를 지역(local) 변수로 만드는 방법
	local line = io.read() -- stdin 줄을 읽는다.
	
	-- '..' 연산자를 사용하여 문자열 연결
	print("SO HAPPY," .. line)   -- SO HAPPY + 'stdin으로 입력한 문자열' 출력
end

-- 정의되지 않은 변수들은 nil을 리턴한다.
foo = UnknownVariable   -- foo에 UnknownVariable(정의되지 않은 변수)를 넣는다.
-- foo = nil

BoolValue = false

-- 불(boolean) 연산에서는 오직 nil, false만 거짓이다. 0, " 참이다.😀
if not BoolValue then print("twas false') end

-- 논리 연산자
ans = BoolValue and 'yes' or 'no' -->  'no' 삼항 연산자로 동작한다.

karlSum = 0
for i = 1, 100 do -- 그 범위의 양 끝을 포함한다.
	karlSum = karlSum + i
end

-- "100, 1, -1"를 쓰면 범위를 감소하도록 정할 수 있다.
fredSum = 0
for j = 100, 1 , -1 do
	fredSum = fredSum + j
end
-- 일반적으로, 범위는 시작, 끝 [, 증가 또는 감소량] 으로 표현

-- repat - until 루프 작성 법 C에서 do~While 유사
repeat
	print("NAMIN")
	num = num - 1
until num == 0

함수

-- 피보나치 수 (재귀 버전)
function fib(n)
	if n < 2 then return 1 end
	return fib(n-2)+fib(n-1)
end

-- 함수 안에 정의된 함수 (Closure)와 이름 없는 함수도 쓸 수 있다.
function adder(x) -- 리턴되는 함수는 adder가 호출될 때 생성된다. 그 후 x의 값을 기억한다.
	return function(y) return x + y end
end

a1 = adder(9)   -- adder가 처음 호출되었으므로 a1에 9가 들어간다.

print(a1(16))   -- a1에는 9가 들어 있다.
								-- 다시 a1 인스턴스 adder를 호출하였으므로, 9 + 16 = 25가 된다.
-- 리턴, 함수 호출, 할당은 모두 리스트로 동작한다. 
-- 리스트의 길이는 서로 다를 수 있다.
-- 매치되지 않는 수신자들은 nil로 취급된다.
-- 매치되지 않은 전송자들은 버려진다.

x, y, z = 1, 2, 3, 4
-- x = 1, y = 2, z = 3, 4는 버려진다.

function bar(a, b, c)
	print(a, b, c)
	return 4, 8, 5, 3, 2, 1
end

x, y = bar('NAMIN') -- "NAMIN nil nil' 형식으로 출력된다.
- x = 4, y = 8   당된다. 나머지 값은 버려진다.

-- 함수는 지역, 전역일 수 있다.
-- 다음 두 줄은 같다.
function f(x) return x * x end
f = function (x) return x * X end

-- 다음 두 줄도 같다.
local function g(x) return math.sin(x) end
local g; g = function (x) return math.sin(x) end
-- local g 선언은 g를 자기 참조 가능하게 만든다.

-- 삼각 함수는 라디안으로 동작한다.

-- 매개변수에 한 문자열만 들어갈 때는 (함수를 호출할 때) 괄호를 붙이지 않아도 된다.
print 'hello' -- 요런 형식으로

테이블

  • 테이블은 루아의 유일한 합성 자료 구조이다.
  • 테이블은 연관 배열이다.
  • php 배열, 자바스크립트 객체와 비슷하다.
  • 테이블은 리스트로도 사용될 수 있는 해시 참조 사전이다.
-- 테이블을 사전이나 맵으로 사용하기
-- 사전은 기본적으로 문자열 키(key)를 가진다.
t = {key1 = 'value1', key2 = false}

-- 문자열 키는 자바스크립트 같은 점 표기를 쓸 수 있다.
print(t.key1) -- 'value1' 출력
t.newKey = {} -- 새로운 key/value 쌍 추가
t.key2 = nil -- 테이블 t에서 key2 제거

-- 키로 (nil이 아닌) 임의의 표기를 사용할 수도 있다.
T = {['@!#'] = 'qbert', [{}] = 1325, [4.23] = 'tau'}
print(T[4.23]) -- 값 tau 출력

-- 키 매칭은 기본적으로 숫자와 문자열 값으로 수행된다.
-- 테이블은 동질성에 의해 수행된다.
a = T['@!#'] -- a = qbert
b = T[{}]    -- 1325가 들어갈 것같지만 아니다. 실제로 들어가는 값은 nil이다. b = nil
-- 이유는 검색에 실패하기 때문
-- 검색 실패 이유는 우리가 사용한 키가 원래 값을 저장할 때 사용된 것과 같은 객체가 아니기 때문
-- 그래서 더 이식성 높은 키는 문자열과 숫자열을 사용해야 한다.

-- 매개 변수가 테이블 하나인 함수 호출에서는 괄호가 필요 없다.
function h(x) print(x.key1) end
h{key1 = 'Namin!23'} -- 'Namin!23' 출력

for key, val in pairs(u) do -- 테이블 반복
	print(key, val)
end

-- _G는 모든 전역들 위한 특별한 테이블이다.
print(_G['_G'] == _G) -- 'true' 출력

-- 테이블을 리스트 또는 배열로 사용하기
-- 리스트는 암묵적으로 정수형 키를 설정한다.
v = {'vaule1', 'value2', 4.23, 'addr'}
for i = 1 #v do -- #v 는 리스트 v의 크기(size)이다.
	print(v[i]) -- 인덱스는 1 부터 시작
end
-- 리스트는 실제 타입이 아니다. v는 그저 하나의 테이블
-- 이 테이블은 연속적인 정수 키를 가지며, 리스트로 취급된다.

메타데이블과 메타메소드

  • 테이블 하나는 메타테이블 하나를 가질 수 있다.
  • 그 메타테이블은 ‘연산자 오버로딩’을 제공한다.
f1 = {a = 1, b = 2} -- 분수 a/b를 표현
f2 = {a = 2, b = 3}
-- f1 + f2 실패한다. (분수에 대한 덧셈은 루아에 정의되어 있지 않다.)

metafraction = {}
function metafraction.__add(f1, f2)
	sum = {}
	sum.b = f1.b * f2.b
	sum.a = f1.a * f2.b + f2.a * f1.b
	return sum
end

setmetatable(f1, metafraction)
setmetatable(f2, metafraction)

s = f1 + f2  -- f1의 메타테이블에 있는 __add(f1, f2)를 호출한다.

-- f1, f2는 자바스크립트의 프로토타입과 달리 메타테이블에 키가 없다.
-- 반드시 그 키들을 getmetatable(f1)과 같이 다시 받아와야 한다.
-- 메타테이블은 루아가 그것에 대해 아는 키를 가진 보통 테이블이다. __add 같다.

-- 다음 문법은 실패한다. 왜냐하면 s에는 메타테이블이 없기 때문
-- t = s + s
-- 아래 주어진 클래스 같은 패턴들이 이 문제를 해결한다.

-- 메터테이블에서 __index는 (myFavs.animal에 있는 점 처럼) 점 참조를 오버로드 한다.
defaultFavs = {animal = 'Namin', food = 'Woon'}
myFavs = {food = 'apple'}
setmetatable(myFavs, {__index = defaultFavs})
eatenBy = myFavs.animal

-- 직접적 테이블 검색이 실패하면, (검색은) 그 메타테이블의 __index 값을 사용하여 다시 시도
-- 계속해서 반복된다.

-- __index 값은 사용자가 원하는 대로 맞춰진 검색을 위한 함수(테이블, 키)일 수 있다.
-- (add같은) __index의 값들을 메타메소드라 불른다.
-- 메타 메소드의 전체 목록이다. a 는 메타메소드를 가진 한 테이블이다.

-- __add(a, b) --------------->  for a + b
-- __sub(a, b) --------------->  for a - b
-- __mul(a, b) --------------->  for a * b
-- __div(a, b) --------------->  for a / b
-- __mod(a, b) --------------->  for a % b
-- __pow(a, b) --------------->  for a ^ b
-- __unm(a)    --------------->  for -a
-- __concat(a, b) ------------>  for a .. b
-- __len(a)    --------------->  for #a
-- __eq(a, b)  --------------->  for a == b
-- __lt(a, b)  --------------->  for a < b
-- __le(a, b)  --------------->  for a <= b
-- __index(a, b) <함수 또는 테이블> --------------->  for a.b
-- __newindex(a, b, c) --------------->  for a.b = c
-- __call(a, ...) --------------->  for a(...)

클래스 와 유사한 테이블과 상속

  • 클래스는 (루아)에 내장되어 있지 않다.
  • 클래스는 테이블과 메타테이블을 사용하여 만들어진다.
Dog = {}                             -- 1                              

function Dog:new()                   -- 2      
  newObj = {sound = 'woof'}          -- 3  
  self.__index = self                -- 4  
  return setmetatable(newObj, self)  -- 5  
end

function Dog:makeSound()             -- 6  
  print('I say ' .. self.sound)      
end

mrDog = Dog:new()                    -- 7      
mrDog:makeSound()  -- 'I say woof'   -- 8  
  1. Dog는 클래스처럼 동작한다. (Dog는 테이블 형식이다.)
  2. function 테이블이름:함수(…)는 function 테이블이름.함수(self,…) 동일하다.
    • ‘:’은 단지 함수의 첫 인자에 self를 추가한다.
  3. newObj(새 객체)는 클래스 Dog의 한 인스턴스가 된다.
  4. self = 인스턴스로 될 클래스.
    • 흔히 self = Dog이다. 그러나 상속으로 그것이 바뀔 수 있다.
    • 우리가 newObj의 메타테이블과 self의 __index를 self로 설정하면, newObj는 self의 함수들을 얻는다.
  5. setmetatable은 그것의 첫 인자를 리턴한다.
  6. ‘:’는 2처럼 동작한다. 그러나 이번에는 self가 클래스가 아닌 인스턴스가 된다.
  7. Dog:new()는 Dog.new(Dog)와 같다. 그래서 new()에서 self=Dog이다.
  8. mrDog:makeSound()는 mrDog.makeSound(mrDog)와 같다. 여기서 self=mrDog이다.

모듈

임의의 모듈 module.lua

local M = {}

local function testMod()
  print('Namin')
end

function M.testM()
  print('Module')
  testMod()
end

return M

main section

-- 다른 파일도 module.lua 파일에 있는 기능을 사용할 수 있다.
local mod = require('module') -- module.lua 파일 실행

-- require는 모듈을 포함(include) 하게 하는 표준 방법
local mod = (function ()
		<module.lua 파일의 내용>
end)()
-- module.lua는 한 함수에 들어있는 내용처럼 한 지역 변수 mod에 대입된다.
-- 그래서 module.lua 안에 있는 지역 변수와 지역 함수들은 그 함수 밖에서는 보이지 않게 된다.

-- mod는 module.lua의 반환값 M과 같다. 
mod.testM() -- Module Namin 출력
-- 지역 함수인 testMod은 오직 module.lua 안에서만 존재하므로 메모리에서 사라진다.
mod.testMod() -- error

-- require의 리턴 값들은 메모리에 저장되 require가 여러 번 호출되더라도 한 파일은 한번만 실행
-- 예를 들어, module2.lua가 "print("BROKE")를 포함한다면
local a = require('module2') -- BROKE 출력
local b = require('module2') -- 출력 불가 a=b

-- dofile은 require와 비슷하지만 메모리에 저장을 하지 않는다
dofile('module2.lua) -- BROKE 출력
dofile('module2.lua) -- BROKE 출력 (다시 출력)

-- loadfile은 문자열을 위한 loadfile이다.
g = loadstring('print(0306)') -- 한 함수를 리턴한다.
g() -- 0306 출력한다. 이 함수가 호출되기 전까지는 아무것도 출력되지 않는다.

참조 사이트

Learn Lua in 15 Minutes

루아 15분 안에 배우기 (Learn Lua in 15 Minutes)


About Zer0Luck

Hi, my name is Young Woon.

Star this Project
Useful Links