컴퓨터를 만듭시다. 어때요~ 참 쉽죠? (24)

나빌레라의 이미지

#24. 보더 더 인간 답게.

어셈블러와 링커가 만들어지면서 우리는 프로그래밍이라는 작업으로 컴퓨터를 동작시킬 수 있게되었다. 하지만 어셈블리어로 
프로그래밍하다 보니 이걸 좀더 쉽고 편하게 하는 방법은 없을까라는 생각이 들게 된다. 어셈블리어는 분명 기계어 자체보다는 
편하고 인간의 언어에 가까운 것이긴 하지만 사람들은 보다 더 이해하고 작성하기 쉬운 프로그래밍 언어를 원했다. 그래서 조금더 
인간의 언어에 가까운 프로그래밍 언어를 만들고 이 언어가 어셈블리어로 컴파일되고 어셈블리어는 어셈블러에 의해서 
오브젝트 파일로 컴파일되고 오브젝트 파일들은 링커에 의해 최종 기계어 바이너리가 만들어지는 일반적인 소프트웨어 개발 체계가
 성립되게 되었다.
 
고급 언어가 등장한 것이다. 하드웨어에 가까울 수록 low level, 인간에 가까울 수록 high level. 이런식으로 이름을 붙여서 
어셈블리어나 기계어는 low level language, C 언어 같은 것을 high level language라고 누군가 부르기 시작했는데, 그 용어가 그대로 
번역되어서 우리 나라에서는 저급 언어, 고급 언어라는 용어가 되었다. 나는 개인적으로 저급 언어, 고급 언어라는 용어를 좋아하지 
않는다. 저급, 고급이라는 단어에 내포되어 있는 질(quality)에 대한 느낌 때문이다. 영어에는 아마 그런 것이 없어서 로우 레벨, 
하이 레벨 이렇게 부르는 것이 더 직관적일지 모르겠지만 그것을 우리 나라에서 한자어로 번역해서 용어를 만드니 이상한 용어가 
되어 버렸다. C언어는 고급이고 어셈블리어는 저급이라는게 좀 이상하지 않은가? ‘저급’이라는 단어에서 풍기는 ‘구리고 후지다’라는 
느낌은 고급 언어, 저급 언어라는 용어에는 부합하지 않는다.  차라리 하위 단계 프로그래밍 언어, 상위 단계 프로그래밍 언어라고 
부르는 것이 더 나을것 같다는 것이 내 개인적인 생각이다. 
 
나도 컴퓨터와 프로그래밍 언어를 공부하면서 저런 전통적인 번역 용어를 사용한 책을 통해서 공부를 했고, 배울 때도 전통적인 번역 
용어를 통해서 공부한 선생님들을 통해서 배웠기 때문에 사실 고급 언어라는 말을 많이 사용한다. 그리고 이 글을 읽고 있는 
여러분들도 마찬가지일 것이다. 그래서 마음에 들지는 않지만 그냥 고급 언어라는 용어를 그냥 사용하겠다. 
 
이번 이야기에서는 지난 이야기를 통해 만들었던 어셈블리어를 사용하는 고급 언어를 만들어 보겠다. 고급 언어를 만든다는 말은 
쉽게 말해 고급 언어의 문법을 정의하고 이 문법에 맞춰 코드를 파싱하는 컴파일러를 만든 다음 그 컴파일러가 결과물로 
어셈블리어를 뽑아내도록 만들면 된다. 말은 간단하지만 사실 굉장히 복잡한 작업이다. 
 
물론 단순히 문법 검사와 파싱 뿐만 아니라, 스택의 사용 형태라든지 함수 호출에 있어서 메모리 사용을 어떻게 하는지 등에 대한 
규칙도 컴파일러를 만들때 모두 설계되어야 하는 내용이다. 또한 변수의 타입이나 연산할 때 변수의 타입 변환 같은 문제도 
모두 컴파일러 수준의 영역이다. 당연히 심볼 테이블 관련 내용도 어셈블러의 그것보다 훨씬 복잡하고 어렵다.
 
컴파일러를 만드는 방법과 이론에 대한 내용만 다루는 아주 두꺼운 책이 있을 정도다. 나는 주로 문법을 중심으로 간단한 방법과 
개념 위주의 이야기만 하겠다.
 
고급 언어의 문법은 당연히 어셈블리어의 문법보다 복잡하다. 복잡한 문법을 좀더 효과적이고 수학적으로 표현하기 위한 방법으로 
BNF 표기법이라는 것이 있다. 어셈블리어 문법도 당연히 BNF 표기법으로 표현할 수 있다. BNF 표기법 자체도 문법 체계를 
가지고 있다. 즉 BNF 표기법은 문법을 표현하기 위한 문법 체계다.
 
BNF 표기법 자체를 설명하는 데에도 상당한 분량의 글을 써야하기에 나는 내가 이야기하는데 필요한 만큼만 BNF 표기법에 대해 
설명하겠다. 더 많은 내용을 알고 싶다면 별도의 경로를 통해서 공부하기 바란다. 광대한 네트에는 참 좋은 자료가 많다.
 
고급 언어는 종류가 많다. 많이 알고 있는 C언어 스타일의 알골 계열 언어가 있고 헤스켈, LISP, Erlang 같은 함수형 언어들도 있다. 
최종적으로 기계어가 되어서 CPU를 동작시키는 것은 모두 같으나 언어의 특징은 언어별로 모두 다르고 프로그래밍 언어의 개념이나 
관점 자체도 많이 다르다. 내가 여기서 이야기할 프로그래밍 언어는 알골 계열의 순차 동작 방식의 언어다. C나 파스칼과 비슷한 
종류의 아주 간단하고 이해하기 쉬운 고급 언어를 하나 설계해 볼 생각이다. 
 
프로그램은 기본적으로 여러개의 블럭으로 구성된다. 시작과 끝을 명확히 컴파일러에게 알려주기 위함이다. 각 블럭은 
{로 시작하고 }로 끝난다. 잘 알려진 C언어의 함수 스타일이다. 난 C언어를 좋아한다. 그리고 당연히 각 블럭은 이름이 있다. 
BNF 표기법으로는 아래처럼 표현한다.
 
<program> ::= <block-list>
		| ε 
 
<block-list> ::= <ident>(<idnet-list>) {<decl> <statement>} 
		| <block-list> <ident>(<idnet-list>) {<decl> <statement>}
 
<ident-list> ::= <ident> 
		| <ident-list>, <ident>
		| ε
 
BNF 문법에 대한 이야기는 생략하겠다. 그래서 바로 위 BNF를 해석하자면, program은 한 개의 block-list가 오거나 아무것도 없어야 
한다. 하나의 프로그램은 block-list한 개 혹은 그냥 아무것도 없는 빈 파일이어야 한다는 의미다. 그럼 block-list는 무엇인가? 우선 
 
 
<block-list> ::= <ident>(<idnet-list>) {<decl> <statement>} 
 
이 한 줄을 해석하자. <ident>는 그냥 쉽게 C언어에서 변수/함수 이름을 뜻하는 것이라 이해하고 넘어가자. 즉 영문자로 시작하고 
영문자와 숫자가 섞여 있는 문자열을 말한다. 블럭의 이름을 지정하는 것이다. 블럭의 이름이 나온 다음에는 반드시 
여는 괄호 ‘(’가 나와야 한다. 여는 괄호 다음엔 <ident-list>가 나온다. 역시 아랫줄에 <ident-list>에 대한 BNF 정의가 나와 있다. 
센스있는 분이라면 바로 보고 의미를 이해하셨으리라 믿는다. 
 
<ident-list>는 콤마(,)로 구분된 <ident>들의 연속이다. <ident>가 하나만 나올 경우엔 콤마없이 혼자 나오고, 아니면 없을 수도 있다. 
C언어에서 함수의 매개 변수와 같은 형식이다. 그래서 아래와 같은 표현이 모두 가능하다.
 
im_function(a,b,c,d,e,f,g)
im_function_two(this_is_param)
im_function_three()
 
<ident-list>를 이해했다면 당연히 <block-list>도 이해했으리라 본다. <block-list>는 구분 기호 없이 블록이 여러개 나올 수 있다는 
것을 뜻한다. 블록이 한 개짜리인 프로그램 혹은 블록이 여러 개인 프로그램, 아니면 아무것도 없는 프로그램(이건 사실 프로그램이 
아니다. 그냥 빈 파일)이 모두 가능하다.
 
즉, 내가 만들고 있는 이 고급 언어는 하나 이상의 블록이 반복되어 만들어 진다. 그럼 이제부터 블록의 내부는 어떻게 정의되는지 
보자. <block-list>의 문법을 보면 닫는 괄호 ‘)’ 다음에 중괄호로 둘러 쌓인 일련의 BNF 심볼이 보인다. <decl> <statement> 이렇게 
두 개다. 역할부터 말하자면, <decl>은 변수나 상수 등 선언을 하는 부분이고, <statement>는 실질적인 연산/제어문이 들어가는 
부분이다. 변수나 상수는 여러 줄에 여러개가 선언 될 수도 있고, 변수는 특별히 한 줄에 여러가 선언될 수도 있다. <decl>의 세부 
문법은 아래와 같다.
 
<decl> ::= <def-decl><var-decl> 
		| <decl><def-decl><var-decl>
		| ε 
 
<def-decl> ::= <ident>  <number> 
		| ε 
 
<var-decl> ::= <ident-list> ; 
		| <var-assignment-list>; 
		|ε 
<var-assignment-list> ::= <ident>=<number> 
		| <var-assignment-list>, <ident>=<number> 
 
<def-decl>은 어셈블리어를 이야기할 때 정의했던 DEF를 선언하는 부분이고 <var-decl>은 변수 선언 부분이다.  블럭의 시작 부분에 
블록 내부에서 사용할 변수나 상수를 먼저 선언하고 프로그램 로직이 시작된다고 생각하면 된다. 앞서 <program>에서와 마찬가지로
 <decl>의 BNF도 맨 끝에 ‘| ε ’가 있기 때문에 아무 선언 없이 바로 <statement>를 작성할 수도 있다. 
<def-decl>과 <var-decl>에도 ‘| ε ’가 있기 때문에 DEF만 선언하거나 변수만 선언하는 것도 가능하고 둘 다 선언하는 건 당연히 
가능하다. 
 
DEF 선언은 어셈블리어의 그것과 동일하다. ‘이름 공백 값’ 이 형식으로 작성하면 된다. <ident>와 <number>사이에 공백이 하나 
있는 것을 놓치면 안된다. <def-decl>은 한 줄에 하나씩만 가능하다. C언어의 #define 문법과 최대한 비슷하게 하기 위해 그렇게 
결정했다.
 
변수 선언은 ‘변수이름=초기값’의 형식이다. DEF 선언과 다른 점은 콤마로 구분하여 한 줄에 여러 변수를 선언할 수 있다는 점이다. 
역시 C언어에서의 그것과 같은 문법이다. 
 
상수, 변수 선언부는 아래와 같은 문법이 모두 가능하다.
 
this_is_def 1982
this_is_anther_def 1986
 
a=10;
b=20;
c=30, d=40, e=1050;
 
C언어와 다른 점이라면 타입 선언이 없다는 점이다. 이는 여타 스크립트 형 언어의 문법적 특징에서 따온 것이다. 약간 어려운 
용어를 사용하자면 타입은 바인딩 시점에서 동적으로 결정할 수 있기 때문에 선언 시점에서 타입을 지정하지 않아도 상관없다. 
무슨 말인지 몰라도 된다. 그냥 내가 만드는 이 프로그래밍 언어는 타입 선언이 없다고 받아들이고 넘어가자. 
 
만약 위 코드가 어셈블리어로 컴파일된다면 아래처럼 될 것이다.
 
DEF 	this_is_def		1982
DEF 	this_is_anther_def	1986
 
BYTE 	a	10
BYTE	b	20
BYTE	c	30
BYTE	d	40
 
WORD	e	1050
 
BYTE와 WORD 타입 결정은 컴파일러가 컴파일하면서 결정한 것이다. 굉장히 단순화된 선언 부분이다. simple is the best. 
단순한것이 좋은것이다. 
 
<decl> 문법 옆에 <statement>문법이 나온다. 내가 만들고 있는 언어의 실질적인 문법 내용을 담고 있는 부분이다. 
전체 문법의 2/3정도가 <statement>에서 파생된다. <statement>가 어떻게 확장되는지 보자.
 
<statement> ::= <ident> = <expression> 
		| <ident>(<ident-list>) 
 		| {<statement-list>} 
 		| if <condition> then <statement> 
 		| while <condition> do <statement> 
 		|ε
 
<statement>는 총 여섯 개의 세부 문법으로 나눠진다. 하나씩 이야기해보자. 가장 먼저 나오는 
 
<ident> = <expression> 
 
는 C언어의 배정문과 동일하다. A = B, a = 3 + 8 따위의 표현이 가능하다. 오른쪽에 나오는 계산 형식을 표현하는 문법 
이름이 <expression>이다. 
 
<expression> ::= <term> 
		| <adding-operator> <term> 
 		| <expression> <adding-operator> <term> 
<adding-operator> ::= + | - 
 
<term> ::= <factor> 
		| <term> <multiplying-operator> <factor> 
<multiplying-operator> ::= * | / 
 
<factor> ::= <ident> | <number> | ( <expression> )
 
<expression>을 표현하는 문법들이 서로 연관 관계를 맺고 있어서 모두 소개했다. 그중 독립적인 문법은 <term>이다. 
<term>은 <factor>가 하나만 나오거나 <factor>와 <term>이 * 혹은 / 연산자로 연결될 수 있다. 
<factor>는 변수명 단독, 숫자 단독 혹은 <expression>이 괄호에 둘러쌓여 나올 수 있다. <factor>에 <expression>이 또 나옴으로 
해서 반복적인 문법 형태가 가능해 진다. 
 
아닐것 같지만 위 <expression> 문법은 왠만한 수학의 기초 표현이 모두 가능하다. 가능 문법은 다음과 같다.
 
A = B;
A = B + C;
A= (B + C) + D;
A = B * (B +C) + 32 * 27;
A = 3;
A = 3 + 4 + 5 + 6;
A = 3 + 4 + (5 * B + C + 7) + 3 + D + 8 – AK / 27;
 
끝도 없이 나열 할 수 있겠지만 위 몇가지 예로도 충분히 어떤 표현이 가능한지 이해하셨으리라 믿는다.
 
다음으로 <statement>에 나오는 문법은 
 
<ident>(<ident-list>) 
 
로 C 언어에서 함수를 호출하는 문법과 완전히 동일하다. 괄호 안에 <ident-list> 문법은 위에서 설명한 것으로 변수명이 콤마로 
구분되어 연속으로 나오거나 아무것도 없는 것을 의미한다. 
 
func();
func(a,b,c,d,e);
func(a);
 
같은 표현이 가능하다. 쉽게 이해하셨으리라 생각한다.
 
다음에 나오는 <statement> 문법의 파생 문법은 <statement-list>문법이다. 눈치 빠른 분들은 눈치채셨을 것이다. <statement-list> 
문법은 <statement> 문법을 반복해서 쓸 수 있게 해주는 파생 문법이다. 단 시작과 끝에 블럭과 마찬가지로 ‘{’과 ‘}’로 범위를 표시해 
주어야 한다.
 
{<statement-list>} 
<statement-list> ::= <statement> | <statement-list> ; <statement>
 
역시 C언어의 블럭 구문 사용법과 완전히 동일하다. C 언어의 문법이 우월한 문법이라고 생각하지는 않는데, 이해하기는 참 쉬운것 
같다. 블럭으로 표시되는 <statement-list> 문법이 정의되어 있기 때문에 바로 이어서 나오는 if 문과 while문의 문법도 C 언어스럽게 
완성될 수 있다.
 
if <condition> then <statement>
while <condition> do <statement>
 
<condition> ::= not <expression> 
 		|<expression> <relation> <expression> 
<relation> ::= = | <> | < | > | <= | >=
 
if문과 while문은 C 언어와 동일하진 않다. 베이직이나 쉘 스크립트에서 구문의 형태를 좀 빌려왔다. C 언어의 if, while 문은 BNF로 
표기하려니 설명할게 너무 많아져서 간단한 형태로 변형했다. 그리고 많이 쓰는 for 문이나 switch-case 문은 정의하지 않았다. 
while과 if의 조합으로 해당 기능을 모두 표현할 수 있기 때문이다.
 
if문은 어셈블리어로 어떻게 컴파일될까? CMP 명령과 조합되어 관련 브랜치 명령을 사용하면 된다. 예를 들어 
 
if A > B then
	C = A – B;
if A <= B then
	C = B – A;
 
이런 문장이 있다면 우선 CMP 명령으로 A와 B를 비교하고, 그 결과에 따라서 BGT, BLET 명령을 사용해 경우에 따라서 점프하면 
될것이다.
 
if:
	CMP A, B
	BGT sub_a_b
	BLET sub_b_a
sub_a_b:
	SUB C, A, B
	B end_if
sub_b_a:
	SUB C, B, A
	B end_if
end_if:
	:
 
컴파일러는 이처럼 BNF 정의에 맞춰 소스 코드 문법을 파싱하면서 파싱한 소스 코드의 내용을 적절하고 최적화된 어셈블리어로 
변환한다. 이렇게 문장 하나 하나 문법 하나 하나가 어셈블리어로 번역되어 만들어진 최종 결과가 고급 언어의 결과 파일이 되는 
것이고, 이 파일을 어셈블러는 다시 오브젝트 파일로 변환하고 오브젝트 파일은 링커에 의해 결합되어 최종 기계어 바이너리 파일이 
완성되는 것이다. 물론 고급 언어 컴파일러에서 어셈블리어를 만들지 않고 독자적인 중간언어를 생성해 최적화를 수행하고 직접 
기계어를 만드는 경우도 있다. 내가 이야기한것은 일반적인 경우를 말한 것이다.
 
정말 대충 고급 언어에 대해 훑어 봤다. 하드웨어 관련 이야기는 아는게 없어서 대충 넘어갔고 소프트웨어 관련 이야기는 내가 아는 
것을 다 풀어 놓으려니 도무지 끝이 날것 같지 않아서 축약하고 축약하다보니 대충 넘어가게 되는 사태가 생겨버린것 같다. 하지만 
애초에 이 이야기의 컨셉이 가볍게 소설책 읽듯이 읽어주길 바라는 것이었기 때문에 오히려 목적에는 더 부합했으리라고 스스로 
위안 삼는다. 
 
우리가 사용하는 운영 체제나 그 위에서 돌아가는 프로그램들. 모두 결국엔 위와 같은 과정을 거쳐서 만들어진 컴파일러와 
어셈블러와 링커에 의해서 생겨났다. 그리고 그 기반에서 컴파일러, 어셈블러, 링커는 더 발전했고 발전한 개발 툴들로 
소프트웨어들은 또 발전하는 끊임없는 선순환의 고리를 이어가고 있다. 
 
아무것도 없는 빈 공간에 전선과 전구만 놓고 시작한 이야기에서 기억 장치와 cpu를 만들고, 프로그래밍 언어까지 만들어 냈다. 
우리는 프로그래밍 언어를 이용해 프로그램을 작성하고 이것을 컴파일해서 정말 복잡한 동작을 하는 소프트웨어를 만들 수 있게 
되었다. 복잡함의 궁극이라는 운영체제도 이론상으로는 충분히 만들 수 있는 토대를 마련했다. 불가능하지 않다. 하면 된다.

댓글

나빌레라의 이미지

소괄호 (< >) 를 일일이 변환하기도 귀찮고 코드마다 [ code ] 태그 넣기도 귀찮고 해서

전체를 [ code ] 태그로 처리해 버렸습니다. -_-;

바로 아래에도 같은 글이 있는데 이거는 <code> 로 묶은 것이거든요,
근데 이상하게 클릭할 때 마다 30초가 넘었다고 안나오네요.

관리자님 이 댓글을 보신 다면 아래에 24편은 삭제해 주세요..
(블로그 포스팅 화면이 나오질 않아서 제가 지우질 못하고 있어요...ㅠㅠ)

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

lacovnk의 이미지

처리 중에 무한루프가 생긴 듯합니다 -_-; 추후 조사를 위해 일단 비공개로 돌렸습니다.

jwstyle의 이미지

정말 끈기가 대단하시군요...

흥미로운 강좌 감사합니다.~

----------------------------
Let's Do It

snowall의 이미지

이제 컴파일러의 영역으로 접어들고 있군요

--------------------------
피할 수 있을때 즐겨라!
http://snowall.tistory.com

피할 수 있을때 즐겨라! http://melotopia.net/b

handrake의 이미지

24편이 두번 연속으로 있네요.

나빌레라의 이미지

위에 위에 위에 있는 제 댓글에
왜 24가 두 개인지 설명이 있습니다.

관리자님께서 아직 삭제를 안해주셨어요....ㅠㅠ

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

kimback100의 이미지

완전 생초보 소설처럼 진짜 재미있네야.. 앞으로도 좋은 강좌ㅏ 부탁드립니다.

어아 다롱디리 이어청이엉ㄹ청 어사와......

완전 생초보

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.