#include <stdio.h>

void main()
{
     char str[] = "10.3454";         //string
     float a;

     sscanf(str, "%f", &a);         // string to float

     printf("string = %s\n", str);
     printf("converting float = %f\n", a);
}


쓰이는곳... 내가 못찾아서 그런거일지도 모르지만...
sql 쿼리에서 받는 값이 모두 string이라 float 값을 받아와도 string으로 리턴들어옴..

vi(Visual) Editor


 

다운은 여기서 http://www.vim.org/download.php

vi는 유닉스에서 널리 쓰이는 표준 텍스트 편집기이다. vi는 20여년전에 개발 되었기 때문에 문서 편집 방법이 최근에 만들어진 편집기와는 많이 다르지만 익숙해지면 편리한 이터페이스와 다양한 기능으로 지금까지도 널리 사용되고 있다.

vi의 특징은 화면 편집기라는 것이데, 이는 vi가 개발되던 초기 유닉스 때의 상황에서 보면 획기적인 것이었다. 당시에 널리 사용되던 텍스트 편집기는 ed라는 행 단위 편집기인데 이는 문서의 행 하나를 보여주며 행 단위로 편집하기에는 너무나 불편한 편집기였다. 이후 vi는 발전을 거듭하여 여러 가지 변종이 나오게 되었는데 현재 리눅스에서 많이 사용하는 vi는 vim으로, Vi IMproved의 약자이다. vi에 많은 기능을 추가하고 X 윈도우용 vi 인터테이스나 문서의 종류에 따라 키워드에 색상을 부여해 주는 Systax hilighting 등의 가능으로 많은 사랑을 받고 있다.


vi의 시작

vi는 터미널용 프로그램이다. vi를 시작하려면 곤솔이나 한텀에서 vi라고 입력하거나 vi뒤에 텍스트 파일 이름을 쓰면 된다.

예)

$ vi

$ vi test.txt


vi의 세가지 편집 모드


1. 명령 모드

처음 상태에는 명령 모드로 앞으로의 편집 동작을 지정할 수 있다.

예를 들어 현재 커서 위치부터 문장을 입력하고자 한다면 i 명령을 준다. esc를 누르면 언제든지 명령 보드로 들어간다.

❶ 삽입 명령

명령어

설명

명령어

설명

a

커서 뒤에 입력

A

라인 끝에 입력

i

커서 앞에 입력

I

라인시작 부분에 입력

o

커서 있는 라인 밑에 입력

O

커서가 있는 라인 위에 입력

❷ 커서 이동

명령어

설명

명령어

설명

h

좌로 한 칸 이동

H

화면 처음으로 이동

j

하로 한 칸 이동

L

화면 끝으로 이동

k

상으로 한 칸 이동

E

커서를 공백으로 구분된 다음 단어 끈으로 이동

l

우로 한 칸 이동

B

커서를 공백으로 구분된 이전 단어로 이동

e

다음 단어의 마지막으로 이동

W

커서를 공백으로 구분된 다음 단어로 이동

b

한 단어 뒤로 이동

j

커서를 한 라인 아래로 이동

o

커서 라인의 시작으로 이동

$

커서를 라인의 끝으로 이동

w

커서를 한 단어 뒤로 이동

-

커서를 전 라인의 시작으로 이동

G

커서를 텍스트의 마지막으로 이동

숫자G

커서를 숫자 라인만큼 이동

M

커서를 화면 중간 라인으로 이동

"

커서를 전 위치로 이동

❸ 삭제 명령

명령어

설명

명령어

설명

x

  커서가 있는 문서 삭제

X

커서가 있는 문자 앞에 있는 문자 삭제

dw

  커서가 있는 단어 삭제

db

커서 앞에 있는 단어 삭제

dW

공백으로 구분된 뒷 단어 삭제

dB

공백으로 구분된 앞 단어 삭제

dd

커서가 있는 라인 삭제

D

커서가 있는 라인의 나머지 삭제

d)

문장의 나머지 삭제

d}

문단의 나머지 삭제

dG

파일의 나머지 삭제

dH

화면의 시작까지 삭제

dL

화면의 나머지 삭제

J

커서와 다음 단어의 공백을 모두 삭제

❹바꾸기 명령

명령어

설명

명령어

설명

r

커서에 있는 문자 대치

R

입력 모드로 한 문자씩 덮어씀

s

커서가 있는 무자 삭제 후 입력 모드    전환

S

커서가 있는 줄을 삭제후 입력 모드

cb

커서가 있는 앞 단어 삭제후 입력 모드

cW

공백으로 구분된 뒷 단어를 삭제 후에   입력 모드

cB

공백으로 구분된 앞 단어 삭제 후 입력    모드

cc

커서가 있는 라인을 삭제하고 입력 모드

C

커서가 있는 라인의 나머지를 삭제하고   입력모드 전환

cO

커서에서부터 라인이 시작까지 텍스트   바꾸기

c

특정 텍스트 바꾸기

c)

문장의 나머지 바꾸기

c}

문단의 나머지 바꾸기

cG

파일의 나머지 바꾸기

cm

문단의 모든 것 바꾸기

cL

화면의 나머지 바꾸기

cH

화면의 시작까지 바꾸기

 

 

❺이동

명령어

설명

명령어

설명

p

삭제나 복사된 텍스트를 커서가 있는    문자나 라인뒤에 삽입

P

삭제나 복사된 텍스트를 커서가 있는    문자나 라인 앞에 삽입

dw p

커서가 있는 단어를 삭제한 후 이름을    변경한 커서 있는 것 뒤에 삽입

dw P

커서가 잇는 단어를 삭제한 후 이를 변   경한 커서 있는 곳 앞으로 삽입

d p

지정한 다음 텍스트로 삭제한 후 커서   가 가리키는 곳으로 이동

d) P

문장의 나머지로 이동

d} P

문단의 나머지로 이동

dG P

파일의 나머지로 이동

dH P

화면 시작 부분으로 이동

dL P

화면의 나머지를 이동

❻복사

명령어

설명

명령어

설명

yw

커서가 있는 단어를 복사

yb

커서가 있는 앞 단어를 복사

yW

공백으로 구분된 뒷 단어 복사

yB

공백으로 구분된 앞 단어를 복사

y

특정한 다음 텍스트 복사

yy

커서가 있는 라인을 복사, 커서가 가리   키는 곳으로 라인 이동

y)

문자의 나머지 복사

yj

문단의 나머지 복사

yG

파일의 나머지 복사

yH

화면 시작까지 복사

yL

화면의 나머지 복사

숫자yy

n라인 만큼 복사




❼검색

명령어

설명

명령어

설명

/pattern

텍스트에서 앞으로 패턴 검색

>patter n

텍스트에서 뒤로 패턴 검색

n

앞 또는 뒤로 검색 반복

N

반대 방향으로 이전 검색 반복

/

전 검색을 앞으로 반복

?

전 검색을 뒤고 반복


2. 입력 모드

실제로 문서에 글을 써넣는 모드이다. 입력한 내용이 입력되다.


3. 최하위행 모드

문서의 저장, 종료 등의 명령이나 명령 모드보다 복잡한 명령을 주고자 할 때 사용한다. 명령 모드에서 : (콜론)키를 누르면 들어온다.


❽ 종료하기

명령어

설명

명령어

설명

:q

그대로 종료하기

:x

:wq와 동일 한 연명

:q!

변경된 내용을 저장하지 않고 종표하기

:ZZ

:wq와 동인 한 명령

:wq

병경된 내용을 저장 하고 정료하기

 

 


내가 자주 사용하는 명령어

리눅스에서 많은 명령키가 있는데, 평소 vi를 사용 하면서 전부는 다 사용하지 않고. 몇 가지만 사용을 한다.

내가 자주 사용하는 명령어들 이다.


①삽입명령

a      : 커서 뒤에 입력

i       : 커서 앞에 입력


②커서이동

ꎼ h   : 좌로

ꎿ j    : 아래로

ꎾ k   : 위로

ꎽ l    : 우로

ꍭꎂ   : 다음 화면으로 이동

ꍭꍾ   : 전 화면으로 이동


③삭제명령

x      : 커서가 있는 문자 삭제

dd     : 커서가 있는 라인 삭제

D      : 커서가 있는 라인 나머지 삭제


④바꾸기 명령


⑤이동

p      : 버퍼에 있는 내용 라인 뒤에 삽입


⑥복사

yy     : 한 라인 복사(버퍼에 저장)

nyy    : n라인만큼 복사(버퍼에 저장)


⑦검색


⑧종료

: wq   : 변경된 내용 저장 하고 종료

: q     : 그대로 종료

: q!    : 저장 안하고 강제 종료

: x ( = wq )


그 외 set 옵션과 같이 주어진 옵션을 약어를 사용해 편리하게 사용 가능하고, 이 옵션을 기록하고 초기와 시키는 명령이 .exrc가 있다.


----------------------------------------------------------------------------------------

3.16. vim 설정파일 만들기

지금까지 우리는 다양한 설정을 통해서 vim 을 좀더 쉽게 사용하는 방법을 알아 보았다. 그런데, 탭사이즈를 적용하기 위해서 vim 을 실행시킬때 마다 ":set ts=4" 이런식으로 하면 작업이 매우 귀찮을것이다. 이럴때는 vim 을 위한 설정파일을 만들어서, vim 이 시작할때 설정파일을 읽어들여서 환경이 자동으로 설정되도록 하면된다.

자기의 계정(Home) 디렉토리에 보면, .vimrc 라는 파일이 존재 할것이다. (존재하지 않는다면 만들도록한다) 이것이 설정파일로 아래와 같은 방법으로 자기가 원하는 내용을 설정하면 된다.


 

 

VIM을 사용하자

윤 상배

dreamyun@yahoo.co.kr

고친 과정
고침 0.9 2004년 3월 10일 17시
vim 모드와 관련된 부가내용 추가
고침 0.8 2003년 3월 1일 23시
최초 문서작성

1. vim 이란

vim 은 유닉스 계열에서 전통적으로 널리 사용도던 vi 의 improve 즉 undo, syntax coloring, split windows 등의 기능을 포함시킨 vi 의 보강된 프로그램이다.

이 문서는 vim 의 기본적인 사용법과, 프로그래밍을 위한 여러가지 팁을 담고 있다. vim 버젼은 6.0 을 기준으로 한다. vim(vi)에 대한 자세한 사용방법은 여기에서는 제시하지 않을것이다. 가장 기본적인 사항만 언급할것이며, 자세한 사용법은 vi 사용자그룹 사이트를 참고하기 바란다.


2. VIM의 기본사용법 익히기

이번장에서는 vim의 기본적인 사용법에 대해서 알아보도록 하겠다. 위에서 언급했듯이, 이문서는 VIM의 레퍼런스 가이드는 아니다. 기본적인 사용이 가능하도록 가장 기초적인 내용들만 다룰것이다.


2.1. vim 모드

다른 에디터를 사용하던 유저가 vim을 처음 접하면서 가장 난감해 하는 부분이 vim의 상태(mode)개념이다.vim은 다른 에디터들과 달리, 실행을 시켰다고 해서 즉시 입력이 이루어지지 않는다. 많은 vim을 처음 접하는 유저는 어떻게 글을 입력할지 몰라서 vim의 사용을 접게되는 경우가 발생하는데, 여기에 그 이유가 있다. vi 는 크게 세가지 상태로 나뉘어진다. 첫번째가 명령어 모드로 키입력이 바로 실행되는 상태이며, 다음은 상태모드로 실제 문서를 편집하는 모드 마지막이 ex 상태로 ex 명령을 실행시키는 상태이다.

vi 를 처음실행시키면 입력모드가 아닌 명령모드 상태에 놓이게 된다. 이 상태에서는 문자의 입력이 이루어지지 않으며, 찾기등과 같은 간단한 문서관련 명령을 실행할 수 있다. 이 명령모드 상태에서 ":" 키를 누르면 ex 상태로 a, i, o 키 등을 누르면 입력 상태로 넘어가게 된다. 일단 입력상태로 들어가게 되면 문서 편집을 할수 있게 되는데, 이때 ESC 키를 누르면 명령모드 상태로 넘어가게 된다.

표 1. vim의 상태(mode)

명령 상태 처음 vim을 실행했을때, 입력상태/명령상태에서 ESC입력시 간단한 찾기, 커서 이동, ex 상태로 넘어가기
ex 상태 명령 상태에서 (":") 각종 치환, 저장, 파일읽기, vim설정등과 같은 대부분의 작업들
입력 상태 명령 상태에서 (a,i,o 키 입력) 내용 입력

2.2. 명령어모드의 사용

우리는 명령모드에서 여러가지 명령을 입력함으로써, 복사, 붙이기, 삭제 문서입력, 문서저장, 문서불러오기, 커서이동 등의 작업을 할수 있다. 이번 장에서는 이러한 명령모드에서 사용되는 각종 명령어에 대해서 알아보도록 하겠다.


2.2.1. 커서 이동

기본적으로 vi 는 입력모드에서 방향키를 이용해서 커서 이동을 하지 못하도록 되어있다. 비록 최근의 vim 이 입력모드에서 방향키를 이용한 커서 이동을 지원하고 있기는 하지만, 명령모드에서의 키이동이 훨씬 빠르고 편하므로, 처음에는 좀 어색하더라도 명령모드에서의 키 이동을 익히도록 하자.

표 2. 커서 이동

k 커서를 위로 움직임
j 커서를 아래로 움직임
h 커서를 왼쪽으로 움직임
l 커서를 오른쪽으로 움직임
- 커서를 줄의 처음으로 옮김
e, E 다음단어의 끝으로, 문자단위 이동
w, W 다음단어의 처음으로, 문자단위 이동
$ 줄의 마지막으로
0 줄의 처음으로
^ 줄의 처음으로(공백이 아닌 처음시작되는 문자)
Shift+g 문서의 마지막으로 이동한다.
gg, 1g 문서의 처음으로 이동한다. 1대신 다른 숫자를 입력하면 해당 숫자의 라인으로 이동한다.
), ( 다음, 이전 문장의 처음으로
}, { 다음, 이전문단의 처음으로
]], [[ 다음, 이전 구절의 처음으로

2.2.2. 화면 스크롤

위의 커서명령 이동이 매우 편하기는 하지만, 만약 페이지가 한 2000라인 될경우, 위의 커서를 이용해서 한줄씩 이동하는데에는 너무 많은 시간이 걸릴것이다. 그래서 vi 에서는 화면 단위의 스크롤이 가능한 명령들을 제공한다. 아래의 화면 스크롤 명령어들을 익히면 빠른 위치이동을 위해 매우 유용하게 사용할수 있다. ^F 는 CTRL+F 를 의미한다.

표 3. 화면 스크롤

^F 한 화면 을 앞으로 스크롤
^B 한 화면 을 뒤로 스크롤
^D 반 화면 을 앞으로 스크롤
^U 반 화면 을 뒤로 스크롤
^E 한줄 앞으로 스크롤
^Y 한줄 뒤로 스크롤
Shift + h 화면의 맨 윗줄로
Shift + m 화면의 중간줄로
Shift + l 화면의 맨 아랫줄로

2.2.3. 마크 이동

일종의 책갈피 기능이라고 보면 된다. 자주 참조해야할 라인에 마크를 해놓고 필요할때 곧바로 마크된 영역으로 이동하기 위해서 사용한다. 마크는 mx 형식으로 사용할수 있다. x 는 (a~z)까지의 문자로 마크된 영역의 이름을 지정하기 위해서 사용한다. 마크된 영역으로 이동하기 위해서는 'x 와 `x 를 사용한다. 'x 는 마크된 라인의 가장 앞으로 이동하고, `x 는 마크된 라인의 정확한 위치로 이동한다.


2.2.4. 입력 명령

지금 vi 를 실행시켜보자. vi 는 기본적으로 명령모드로 실행되므로, 지금상태에서는 문서 작성을 할수 없을것이다. 우리는 다음과 같은 키입력을 통해서 입력모드 상태로 전환할수 있다.

표 4. 입력 명령

i 현재위치에서 삽입
I 현재줄의 처음위치에서 삽입
a 현재위치에서 한칸앞으로 이동해서 삽입
A 현재줄의 마지막위치에서 삽입
o 새로운 줄을 커서 아래에 연다
O 새로운 줄을 커서 위연다
s 현재 위치의 문자를 지우고 입력모드로 들어간다.
S 현재위치의 라인을 지우고 입력모드로 들어간다.

2.2.5. 편집명령

여기에서는 vi의 편집기능인 복사, 붙이기, 삭제에 대해서 알아 보도록 하겠다. 다른 에디터들은 보통 마우스를 이용해서 블럭을 지정해서 편집을 하는 반면, vi 는 명령어 모드에서 키보드 만을 이용해서 편집이 가능하므로, 매우 편리하고 빠르게 편집작업들이 가능하다. 또한 라인단위 블럭, 블럭단위 블럭등의 선택 모드를 지원함으로써, 문서에서 원하는 부분에 대한 작업을 좀더 쉽게 할수 있다.


2.2.5.1. 편집(none visual block 모드)

visual block 모드가 아닌 상태에서이 편집에 관한 내용이다.

표 5. 복사,삭제,붙이기

y 한줄 복사
yn 현재 라인에서부터 n라인만큼을 복사
p 복사된 내용 붙이기
dd 한줄삭제
dw 한단어 삭제
Shift+d, d$ 현재커서 위치에서 마지막까지 삭제
Shift+j 현재 행의 개행문자를 제거한다. 즉 아래라인을 현재라인에 덧붙인다.

2.2.5.2. Undo (되돌리기)

vim 은 다중의 undo 기능을 지원한다. 뒤로 되돌리고 싶다면 단지 'u'키만 입력하면 된다.


2.2.5.3. 블럭 지정

이번엔 블럭지정, 그중에서도 vim 에서 지원하는 visual 블럭 지정에 대해서 알아보겠다. vim visual 블럭 지정 기능을 사용할경우 지정범위가 반전되면서 눈에 보이기 때문에, 효과적인 블럭지정이 가능하도록 도와준다. 범위지정을 위해서 'hjkl', 'Shift+g,GG' 과 같은 이동명령 과 화면스크롤 명령을 사용해서 범위지정을 좀더 빠르게 할수 있다.

표 6. 블럭지정

v 단어단위로 블럭지정이 가능하다. 블럭범위는 이동명령인 'hjkl' 로 원하는 범위 만큼 지정할수 있다.
Shift+v 라인단위 블럭지정이다. 라인전체가 선택되며, 위아래 이동명령 'hj' 으로 범위 지정이 가능하다.
Ctrl+v 블럭단위 블럭지정이다. 4각형의 블럭지정이 가능하며 이동명령인 'hjkl' 로 원하는 범위를 지정할수 있다.
Shift+v 와 같이 블럭지정을 한후 Shift+G 를 입력하면 현재라인부터 마지막 라인까지가 블럭 지정이 될것이다.

2.2.5.4. 편집(visual block 모드)

일단 vim 의 visual 블럭 지정 기능을 이용해서 편집하기 원하는 블럭을 지정했다면, 각종 편집명령을 이용해서 복사, 붙이기, 삭제 작업이 가능하다. 블럭을 지정한 상태에서 아래의 명령을 이용해서 편집을 하면 된다. 명령어는 기본적으로 none visual block 모드의 편집 명령어과 같다.

표 7. 편집(복사, 삭제, 붙이기)

y 지정된 블럭을 복사한다.
p 복사된 블럭을 현재라인(커서) 아래에 붙인다.
d 지정된 블럭을 삭제한다.
dd 현재라인을 삭제한다.

2.3. ex 모드

2.3.1. 찾기/치환

vim 의 기능중 가장편리한 기능으리면 뭐니뭐니 해도, 정규표현식을 이용한 강력한 찾기기능과 치환기능이라고 할수 있을것이다. 물론 다른 대부분의 에디터들도 찾기기능과 치환기능을 제공하긴 하지만, vim 의 기능은 다른 에디터들에 비해서 정말로 독보적인 편리함과 강력함을 제공한다. vi 사용자가 다른 에디터로 넘어가기 힘든이유중 가장큰 이유가, 바로 "키를 이용한 방향입력" 과 "찾기 및 치환" 기능 때문이다.

사실 찾기 치환의 기능을 제대로 이해하고 사용하기 위해서는 정규표현식(regular expression) 에 대한 이해가 필요로 하는데, 이것은 다음의 사이트를 참조하기 바란다. 정규 표현식의 간략한 소개

먼저 찾기 기능에 대해서 알아보겠다. 찾기기능은 ':/패턴/' 를 이용 하면된다. 찾기 원하는 문자혹은 패턴을 입력하고 엔터키를 누르면 현재 커서위치에서 가장 가까운 곳에 위치한 문자열로 커서를 이동시킨다(문서 아래방향으로). 다음 문자열을 찾기를 원한다면 'n'키를 누르면 된다. 문서에서 가장 마지막에 이르르게 되면, 문서의 가장처음부터 다시 찾기 시작한다. 'Shift+n' 을 이력하면 반대 방향(문서의 위쪽으로)으로 찾기를 시작한다.

치환이야 말로 vim 의 꽃이라고 할수 있다. :[범위]s/[oldpattern]/[newpattern]/ 의 형식으로 사용하면 된다. 범위 지정은 visual block 을 이용할수도 있으며, 직접 범위를 입력할수도 있다. visual block 를 이용한 치환은 visual block 를 지정한다음 ':' 를 입력해서 ex 모드로 넘어가면 된다. 그리고나서 ':'<,'>s/[oldpattern]/[newpattern/' 과 같은 방법으로 치환하면 된다.

visual block 를 사용하지 않고 직접범위를 입력할수도 있다. :[시작],[마지막]s/[old]/[new]/ 식으로 범위를 지정하면 된다. 여기에는 몇가지 지정된 범위를 위한 특수 기호들이 있다. '%' 는 전체문서(처음부터 끝까지), '.' 은 현재, '$' 은 마지막 을 나타낸다. 숫자를 입력할경우 숫자는 라인을 나타낸다. 다음은 간단한 사용예이다.

# 문서 처음부터 마지막까지의 char 를 _char_ 로 치환한다. 
:%s/char/_&_/g
# 현재(커서위치)부터 마지막까지의 char 를 _char_ 로 치환한다.
:.,$s/char/_&_/g
# buf_.*[255], buf_in[255], buf_get[255] 와 같은
문자열을 hello 로 변경한다.
:1,10s/buf_.*\[255\]/hello/g
마지막에 쓰인 'g' 는 global 이다. 즉 해당 라인 전체에 걸쳐서 검색후 치환한다. 'g' 를 사용하지 않을경우 라인에서 처음에 검색된 문자만 치환하고 다음 라인으로 넘어간다.


2.3.2. 파일 저장, 열기, 종료

파일열기의 경우 vi 를 실행시킬대 명령행 옵션으로 열기가 가능하다. 또한 vi 를 이미 실행 시킨후에도 명령모드에서 명령을 입력함으로 파일을 열수 있다. 열고자 하는 파일이 이미 존재할경우에는 존재하는 파일이 열리고, 열고자 하는 파일이 존재하지 않을경우 새로운 파일이 만들어진다.

표 8. 저장,열기,종료

:e [filename] filename 으로 파일열기
:q, :q!, :wq 종료, 강제종료, 저장후 종료
:w, :w [filename] 현재파일명으로 저장, filename 로 저장
:<범위>w [filename] 지정한 범위만 다른 파일로 저장
:e [filename] filename 을 편집하기 위해서 연다
ZZ 지금파일을 저장하고 vim 을 종료한다.
:f 현재 작업중인 파일의 이름과, 라인수를 출력한다

3. 개발자를 위한 vim 사용팁

3.1. 화면 나누기

vim 은 수평나누기와 수직나누기를 제공한다. 수평나누기는 ":split [파일이름]" 수직나누기는 "vs [파일이름]" 으로 나눌수 있다. 파일이름을 지정한 경우, 새로 만들어진 창에는 파일이름 을 가지는 파일이 열리고, 파일이름을 지정하지 않을경우 똑같은 파일이 열린다. 이 기능은 현재 파일의 다른 부분을 참조하고 싶을때 유용하게 사용할수 있다(참조하는 부분으로 이동하기 위해서 왔다갔다 하지 않아도 되므로). 또한 ":10split [파일이름]", "10vs [파일이름]" 등으로 창의 크기를 조절해 줄수도 있다. 창 나누기는 2개 이상 나누기도 가능하다.

이렇게 창을 분할시켜 놓으면 쏘쓰를 참조하기도 편하고, 무엇보다 편집(삭제,복사,붙이기)가 가능하므로 훨씬더 작업을 수월하게 할수 있다.


3.1.1. 화면 이동

명령 모드에서 CTRL+ww 를 입력하면 된다. 그러면 아래창으로 이동한다. 임의로 이동하기 위해서는 Ctrl+w 를 입력한 상태에서 이동명령[hjkl]를 이용하면 원하는 방향으로 창이동이 가능하다.


3.1.2. 파일 네비게이션

vim 6.0 부터는 파일네비게이션 기능이 존재합니다. 예를들어 vi 로 파일을 열때 파일을 디렉토리로 지정하면 해당디렉토리의 내용이 네비게이션 되고, 디렉토리 이동및 파일 선택이 가능하다.

 vi ./ # 현재 디렉토리내용을 네비게이션 해준다. 


3.2. 파일 네비게이션 바 만들기

윈도우의 울트라 에디트와 같은 프로그램을 보면 왼쪽에 파일네비게이션이 있어서 원하는 파일을 바로 선택해서 편집하는 기능이 있다. vim 으로도 이러한 기능을 구현할수 있다. 이것은 vim 의 file navigation 기능과 창나누기 기능을 이용해서 구현하면 된다.

vi 가 실행되 상태에서 수직창 나누기 기능을 이용해서 ":20vs ./" 명령을 내려보자 그럼 그림과 같이 오른쪽에 파일 네비게이션 바가 생김을 알수 있다.

그림 1. 파일네비게이션을 만든 화면

사용자 삽입 이미지

이제 열기를 원하는 파일위치에 가서 shift+o 를 입력해보자, 그럼 옆의 편집창에 새로운 파일이 열리는것을 알수 잇을것이다. 여기에 더해서 편집장을 split 로 나누면, 여러개의 파일을 오가면서 편집이 가능해질 것이다.

3.3. 여러개의 파일 편집하기

위에서는 창나누기를 이용한 여러개의 파일편집에 대해서 알아봤는데, 또다른 방법이 있다. 처음에 vim 을 통하여 여러개의 파일을 open 하고 여러개의 열린 파일을 이동하면서 편집하는 방법이다. 먼저 vim을 다음과 같이 실행시킨다.

 [yundream@localhost test]# vim file1.txt file2.txt ... 
그러면 처음 화면은 file1.txt 편집화면일것이다. 2번째 파일인 file2.txt 편집화면으로 넘어가길 원한다면(앞에 있는 파일 편집)
:n 
file2.txt 에서 file1.txt 를 편집하길 원한다면(뒤에 있는 파일편집)
:e# 
split 를 이용해서 여러개의 파일을 편집할때와 마찬가지로, 각종 편집기능(복사,삭제,붙이기)이 서로 공유되므로 편하게 작업이 가능하다.


3.4. 잠시 쉘로 나가기

보통 vim상에서 쉘명령어를 실행시키기 위해서 :![명령어] 를 사용하는데, 이것 보다는 Ctrl+z 를 이용해서 쉘로 빠져나가서 작업하는게 더 편하다. sehll 이 job control 기능을 이용한것으로, 쉘에서 원하는 작업을 수행하후 fg 명령을 이용해서 다시 vi 편집 상태로 되돌아 올수 있다. vim 사용자를 보면 가끔 쉘작업을 하기 위해서 vim 을 아예 종료 시켜서 쉘로 빠져나간 다음에 작업을 하고 vim 을 다시 실행시키는 경우가 있는데, 이제는 그럴필요가 없이 좀더 편하게 작업을 할수 있을것이다.


3.5. 선택된 block 를 다른 이름으로 저장하기

split 기능을 이용해서 창을 나누고, 원하는 블럭을 선택해서 복사한다음에, 새로만든창에 가져다 붙이기를 하면 된다.

그러나 이방법은 조금 복잡한 감이 없잖아 있다. 이럴때는 블럭을 선택해서 :'<,'>w [파일명] 하면 좀더 간단하게 원하는 작업을 수행할수 있다.


3.6. 빠른 괄호 이동

C나 C++ 을 사용하다보면 제어문이나 함수에서 많은 괄호('{','(')를 만나게 된다. 이때 괄호의 제일 마지막으로 이동하고 싶을때가 있을것이다. 이럴때는 ']}' 를 사용하면 된다. '[{' 를 사용하면 괄호의 처음으로 이동한다.


3.7. 위치 마크(mark)하기

일종의 북마크기능으로 자주참조할만한 라인을 마킹해두고 필요할때 간단히 해당 마킹지역으로 이동하기 위해서 사용한다. 마킹을 위해서는 명령모드에서 m키를 눌러서 마킹모드로 들어가면 된다. 그리고 영문 [a-zA-Z]키중 아무거나 눌러주면 된다. 만약 a를 눌러주었다면, 현재라인은 a이름으로 마킹된다. 이후 작업을하다가 a마킹라인으로 가고 싶다면 'a 해주면된다. 이상태에서 원래라이으로 되돌아가고 싶다면 ''를 눌려주면 된다.

물론 다중마킹도 허용한다. 마킹할수 있는 문자는 단일영문자이다. 마킹에 사용되는 영문자는 대소문자를 구분함으로 최대마킹가능한 수는 27*2가 될것이다.


3.8. 폴더(접기) 기능이용하기

vim 6.0 에 새로이 포함된 좋은 기능으로 코드의 특정영역을 접을수 있다. 그럼으로 코드를 분석할때 쓸데 없는 부분을 감춰줘서 좀더 편하게 분석이 가능합니다. visual block 를 이용해서 원하는 영역을 선택한다음 :zf 를 이용하면 해당영역이 접힌다. :zo 를 사용하면 접힌영영을 원상태로 복구할수 있고 :zc 를 사용하면 해당영역을 다시 접을수 있다. 또한 다중 접기를 허용해서 접근구역을 다시 접을수도 있다.


3.9. 간단한 man 페이지 참조

vim 을 이용 코딩중에 함수의 프로토 타입이 생각나지 않을때 주로 man page 를 참조하게 된다. 보통은 창을 하나따로 띄워서 그곳에서 man page 를 보는데, 코딩중에 간단하게 해당 함수에 대한 man page 를 볼수 있다. man page 를 원하는 함수 위로 커서를 옮긴다음 Shift + k 를 입력하면 함수의 man page 가 뜰것이다. 'q' 를 입력해서 man page 를 종료시키면 원래의 vim 화면으로 되돌아온다.


3.10. 함수/변수명 자동완성

코딩중에 가장 범하기 쉬운 잘못중의 하나가 변수명및 함수명 오타일것이다. 또 변수명이 기억이 잘 나지 않아서 처음 선언한곳을 다시 확인하는 작업역시 코딩을 매우 번거롭게 한다. 이때 함수 자동완성 기능을 이용하면 이러한 염려들을 줄일수 있다.

int client_sockfd 라고 변수 선언을 했다고 하자. 코딩중에 client_sockfd 를 쓸일이 있다면 cli^p 를 입력해보자. 그러면 변수 이름이 자동으로 완성되는것을 볼수 있을것이다. ^p는 Ctrl+p 이다.


3.11. ctags 를 이용한 쏘쓰 분석

쏘쓰를 분석하는데 있어서 가장 중요한 것은 역시 함수를 분석해서, 함수가 어떤일을 하는지 알아내는 것이다. ctags 를 이용하면 이러한 쏘쓰 분석작업을 좀더 수월하게 할수 있다. ctags 와 관련된문서는 ctags 를 이용한 쏘쓰 분석 을 참고하기 바란다.


3.12. 자동들여쓰기

프로그래밍 할때 indent 는 쏘쓰코드를 보기좋게 만들기 위한 필수 사항이다. 보통 tab 을 주로 쓰는데,

:set ai 
명령을 이용하면 자동적으로 indent (auto indent) 를 적용시켜주므로, 좀더 코딩에만 집중할수 있도록 도와준다.
:set noai 
명령을 사용해서 auto indent 상태를 해제할수 있다.

요즘의 vim 은 기본적으로 auto indent 상태이므로, 별다른 설정없이 편하게 사용가능하다. 그러나 웹에서 가져다 붙이기를 할때 여기에 auto indent 가 적용되어서 것잡을수 없이 tab 이 들어가는 경우가 생길때도 있는데, 이럴때 set noai 를 이용해서 auto indent 를 해제하고 가져다 붙이기를 하면 된다.


3.13. 탭사이즈 조정하기

쏘쓰에서 indent 를 위해서 주로 탭을 사용하는데, 보통 이 탭 사이즈는 8로 되어 있다. 그런데 8이란 탭사이즈가 때로는 너무 커서, 쏘쓰가 화면밖으로 나가서 오히려 쏘쓰 보기를 어렵게 만들때도 있다. 이럴때 는 탭사이즈를 줄여야 하는데 다음과 같은 명령을 통해서 탭사이즈 변경이 가능하다.

:set ts=4 


3.14. 라인 넘버링

코딩하다보면 라인넘버가 있으면 할때가 있다. 그럴때는

:set nu 
하면 된다.

그림 2. 라인 넘버링

사용자 삽입 이미지

라인넘버를 없애고 싶다면,
:set nonu 
하면 된다.

3.15. 코드를 HTML로 저장하기

vim 은 또한 코드를 HTML 형태로 저장하는 기능을 가지고 있다. 이 기능을 이용하면 syntax highlight 된 상태 그대로 HTML로 변환이 가능하다. 쏘쓰코드의 예제를 만들어서 웹상에 올리고자 할때 유용하게 사용할수 있는 기능이다.

:so $VIMRUNTIME/syntax/2html.vim 


3.16. vim 설정파일 만들기

지금까지 우리는 다양한 설정을 통해서 vim 을 좀더 쉽게 사용하는 방법을 알아 보았다. 그런데, 탭사이즈를 적용하기 위해서 vim 을 실행시킬때 마다 ":set ts=4" 이런식으로 하면 작업이 매우 귀찮을것이다. 이럴때는 vim 을 위한 설정파일을 만들어서, vim 이 시작할때 설정파일을 읽어들여서 환경이 자동으로 설정되도록 하면된다.

자기의 계정(Home) 디렉토리에 보면, .vimrc 라는 파일이 존재 할것이다. (존재하지 않는다면 만들도록한다) 이것이 설정파일로 아래와 같은 방법으로 자기가 원하는 내용을 설정하면 된다.

set ts=4 set nu 


출처 : http://tong.nate.com/isuk27/36690395

'리눅스 서버에 대해서 > 리눅스 팁들' 카테고리의 다른 글

쉘 프로그래밍 강좌  (0) 2013.01.10
GNU Make 강좌  (0) 2013.01.07
이클립스에서 C++ 환경 만들기  (0) 2012.12.10
Samba Domain Setting  (0) 2010.08.29
make 강좌  (0) 2010.07.04
C언어는 날짜/시간을 구할 때 하나의 함수로만 되는 것이 아니라, 다음과 같이 약간 복잡합니다.

time() 함수로, 현재 경과된 초(sec), 즉 "유닉스 시간"을 구한 후, 그것을 localtime() 함수로 연월일 시분초로 분리하여 구조체에 저장합니다.

C에서, 오늘 시각/날짜 (현재 날짜, 시간) 출력 예제


파일명: 0.cpp
#include <stdio.h>
#include <time.h>


void main(void) {
  time_t timer;
  struct tm *t;

  timer = time(NULL); // 현재 시각을 초 단위로 얻기

  t = localtime(&timer); // 초 단위의 시간을 분리하여 구조체에 넣기


  printf("유닉스 타임 (Unix Time): %d 초\n\n", timer); // 1970년 1월 1일 0시 0분 0초부터 시작하여 현재까지의 초

  printf("현재 년: %d\n",   t->tm_year + 1900);
  printf("현재 월: %d\n",   t->tm_mon + 1);
  printf("현재 일: %d\n\n", t->tm_mday);

  printf("현재 시: %d\n",   t->tm_hour);
  printf("현재 분: %d\n",   t->tm_min);
  printf("현재 초: %d\n\n", t->tm_sec);

  printf("현재 요일: %d\n", t->tm_wday); // 일요일=0, 월요일=1, 화요일=2, 수요일=3, 목요일=4, 금요일=5, 토요일=6
  printf("올해 몇 번째 날: %d\n", t->tm_yday); // 1월 1일은 0, 1월 2일은 1
  printf("서머타임 적용 여부: %d\n", t->tm_isdst); // 0 이면 서머타임 없음

}



실행 결과 화면:
D:\Z>cl 0.cpp && 0.exe
0.cpp
유닉스 타임 (Unix Time): 1160032094 초

현재 년: 2006
현재 월: 10
현재 일: 5

현재 시: 16
현재 분: 8
현재 초: 14

현재 요일: 4
올해 몇 번째 날: 277
서머타임 적용 여부: 0
D:\Z>



time.h 에 시간 구조체가 다음과 같이 정의되어 있습니다.

struct tm {
  int tm_sec;   /* Seconds */
  int tm_min;   /* Minutes */
  int tm_hour;  /* Hour (0--23) */
  int tm_mday;  /* Day of month (1--31) */
  int tm_mon;   /* Month (0--11) */
  int tm_year;  /* Year (calendar year minus 1900) */
  int tm_wday;  /* Weekday (0--6; Sunday = 0) */
  int tm_yday;  /* Day of year (0--365) */
  int tm_isdst; /* 0 if daylight savings time is not in effect) */

};




업데이트: 비주얼C 2005 이상에 최적화: ▶▶ C언어] localtime_s 함수 사용법: 비주얼 Visual C 2005 이상에서

출처 : http://mwultong.blogspot.com/2006/10/c-current-date-time.html

'C/C++언어' 카테고리의 다른 글

이클립스로 SFTP 사용하기  (0) 2008.06.24
C에서 string 문자열을 float 로 바꾸기  (1) 2008.06.15
LEX & YACC  (0) 2008.06.07
Lex와 Yacc의 사용법 강좌  (0) 2008.06.07
고정 소수점 (C++언어 버젼)  (0) 2008.05.09

Lex and yacc은

   ·컴파일러 또는 인터프리터를 작성하기 위한 도구

   ·패턴을 찾기 위한 응용분야에서 사용하기 쉽다.

특징

    ·rapid prototyping

    ·easy modification

    ·simple maintenance

Lex 및 Yacc가 이용된 예

   ·desktop calculator bc

   ·typesetting tools eqn, pic, xfig

   ·C compilers PCC, GCC

   ·menu compiler

   ·A SQL processors

   ·the lex itself

 

 

Availability of Lex and Yacc

 

Yacc was the first of the two,developed by Stephen C.Johnson. Lex was designed to work with yacc by M.E.Lesk and E.Schmidt. Both lex and yacc have been standard UNIX utilities since Version 7, and no significant differences between Berkeley and System V versions.

 

AT&T version lex and yacc

BSD version Berkeley yacc

GNU bison

GNU flex

MS-DOS, OS/2 versions

 

1.Lex and Yacc

 

The Simplest Lex Program

 

간단한 lex입력

%%

.|\n           ECHO;

%%

UNIX의 cat과 같은 기능

lex에 의하여 생성된 프로그램

#include <stdio.h>

#include <stdlib.h>

# define U(x) x

중략

yylex(){

int nstr; extern int yyprevious;

#ifdef __cplusplus

/* to avoid CC and lint complaining yyfussy not being used ...*/

static int __lex_hack = 0;

if (__lex_hack) goto yyfussy;

#endif

while((nstr = yylook()) >= 0)

yyfussy: switch(nstr){

     case 0:

             if(yywrap()) return(0); break;

     case 1:

# line 2 "ch1-1.l"

             ECHO;

             break;

     case -1:

             break;

     default:

             (void)fprintf(yyout,"bad switch yylook %d",nstr);

   } return(0); }

/* end of yylex */

생략

 

lex specification의 구성

definition section

%%

rule section

        pattern(regular expression)     action(C source code)

%%

user subroutine section(C source code)

 

 

Lex로 단어 인식 프로그램 만들기

 

인식할 단어:

is        am        are       were

was     be         being    been

do       does      did        will

would  should  can        could

has     have     had        go

 

단어 인식기 - LEX SPEC.

%{

/*

 * this sample demonstrates (very) simple recognition:

 * a verb/not a verb.

 */

%}

%%

[\t ]+         /* ignore white space */ ;

is |

am |

are |

were |

was |

be |

being |

been |

do |

does |

did |

will |

would |

should |

can |

could |

has |

have |

had |

go             { printf("%s: is a verb\n", yytext); }

[a-zA-Z]+      { printf("%s: is not a verb\n", yytext); }

.|\n           { ECHO; /* normal default anyway */ }

%%

 

main()

{

        yylex();

}

 

 

코드생성 및 실행

% lex ch-01.l

% ls

lex.yy.c

% cc lex.yy.c -o first -ll

% ls

first  lex.yy.c

% first

did I have fun?

did: is a verb

I: is not a verb

have: is a verb

fun: is not a verb

?

^D

%

 

 

문장의 다른 단어도 인식하기 - LEX SPEC

 

%{

/*

 * We expand upon the first example by adding recognition of some other

 * parts of speech.

 */

%}

%%

[\t ]+         /* ignore white space */ ;

is |

am |

are |

were |

was |

be |

being |

been |

do |

does |

did |

will |

would |

should |

can |

could |

has |

have |

had |

go             { printf("%s: is a verb\n", yytext); }

very |

simply |

gently |

quietly |

calmly |

angrily        { printf("%s: is an adverb\n", yytext); }

to |

from |

behind |

above |

below |

between |

below          { printf("%s: is a preposition\n", yytext); }

if |

then |

and |

but |

or             { printf("%s: is a conjunction\n", yytext); }

their |

my |

your |

his |

her |

its            { printf("%s: is an adjective\n", yytext); }

I |

you |

he |

she |

we |

they           { printf("%s: in a pronoun\n", yytext); }

 

[a-zA-Z]+ {

         printf("%s:  don't recognize, might be a noun\n", yytext);

        }

.|\n           { ECHO; /* normal default anyway */ }

%%

main()

{

        yylex();

}

 

 

 

Symbol Tables

단어의 품사를 선언하고 입력되는 단어의 품사를 구분하기

definition section

%{

/*

 * Word recognizer with a symbol table.

 */

enum {

        LOOKUP = 0, /* default - looking rather than defining. */

        VERB, /* 동사 */

        ADJ,  /* 형용사 */

        ADV,  /* 부사  */

        NOUN, /* 명사 */

        PREP, /* 전치사 */

        PRON, /* 대명사 */

        CONJ  /* 접속사 */

};

int state;

int add_word(int type, char *word);

int lookup_word(char *word);

%}

 

 

rule section

%%

\n     { state = LOOKUP; }    /* end of line, return to default state */

^verb  { state = VERB; }

^adj   { state = ADJ; }

^adv   { state = ADV; }

^noun  { state = NOUN; }

^prep  { state = PREP; }

^pron  { state = PRON; }

^conj  { state = CONJ; }

[a-zA-Z]+  {

                /* a normal word, define it or look it up */

             if(state != LOOKUP) {

                /* define the current word */

                add_word(state, yytext);

             } else {

                switch(lookup_word(yytext)) {

                case VERB: printf("%s: verb\n", yytext); break;

                case ADJ: printf("%s: adjective\n", yytext); break;

                case ADV: printf("%s: adverb\n", yytext); break;

                case NOUN: printf("%s: noun\n", yytext); break;

                case PREP: printf("%s: preposition\n", yytext); break;

                case PRON: printf("%s: pronoun\n", yytext); break;

                case CONJ: printf("%s: conjunction\n", yytext); break;

                default:

                        printf("%s:  don't recognize\n", yytext);

                        break;

                }

            }

          }

.      /* ignore anything else */ ;

%%

 

 

user subroutine section

main()

{

        yylex();

}

/* define a linked list of words and types */

struct word {

        char *word_name;

        int word_type;

        struct word *next;

};

struct word *word_list; /* first element in word list */

extern void *malloc();

int

add_word(int type, char *word)

{

        struct word *wp;      

        if(lookup_word(word) != LOOKUP) {

                printf("!!! warning: word %s already defined \n", word);

                return 0;

        }

       

        /* word not there, allocate a new entry and link it on the list */

        wp = (struct word *) malloc(sizeof(struct word));

        wp->next = word_list;

        /* have to copy the word itself as well */

       

        wp->word_name = (char *) malloc(strlen(word)+1);

        strcpy(wp->word_name, word);

        wp->word_type = type;

        word_list = wp;

        return 1;      /* it worked */

}

int

lookup_word(char *word)

{

        struct word *wp = word_list;

        /* search down the list looking for the word */

        for(; wp; wp = wp->next) {

                if(strcmp(wp->word_name, word) == 0)

                        return wp->word_type;

        }

        return LOOKUP; /* not found */

}

실행 예

verb is am are were be being been do

is

is: verb

noun dog cat horse cow

verb chew eat lick

verb run stand sleep

dog run

dog: noun

run: verb

chew eat sleep cow horse

chew: verb

eat: verb

sleep: verb

cow: verb

horse: noun

verb talk

talk

talk: verb

 

 

문법(Grammars)

정해진 순서대로 토큰이 입력되는가? -- 문법 기술이 필요!

 

간단한 문장의 구성

noun verb.

noun verb noun.

 

문법을 기술하는 방식이 필요함

subject → noun | pronoun

object → noun

sentence → subject verb object

 

다양한 문장을 파싱하기 위하여는 문법을 확장하여야 함.

파서에서 어휘분석기(yylex)를 부르게하기 위하여 어휘분석기를 수정해야함.

 

 

파서(parser)와 렉서(lexer)간의 통신

파서가 상위의 루틴이되어야 함;- 파서(yyparse)는 yylex를 호출, yylex는 토큰(토큰 종류, 토큰 값)을 돌려줌. 따라서, 파서와 렉서는 같은 정의의 토큰을 가져야 함.

 

ex)우리의 품사 구분에서의 예

# define NOUN 257

# define PRONOUN 258

# define VERB 259

# define ADVERB 260

# define ADJECTIVE 261

# define PROPOSITION 263

# define CONJUCTION 263

 

yacc는 토큰정의를 위해 y.tab.h를 만듬.

 

new lexer

%{

/*

 * We now build a lexical analyzer to be used by a higher-level parser.

 */

#include "ch1-05y.h"  /* token codes from the parser */

#define LOOKUP 0 /* default - not a defined word type. */

int state;

%}

%%

\n     { state = LOOKUP; }

\.\n   {      state = LOOKUP;

                return 0; /* end of sentence */

        }

^verb  { state = VERB; }

^adj   { state = ADJECTIVE; }

^adv   { state = ADVERB; }

^noun  { state = NOUN; }

^prep  { state = PREPOSITION; }

^pron  { state = PRONOUN; }

^conj  { state = CONJUNCTION; }

[a-zA-Z]+ {

             if(state != LOOKUP) {

                add_word(state, yytext);

             } else {

                switch(lookup_word(yytext)) {

                case VERB:

                  return(VERB);

                case ADJECTIVE:

                  return(ADJECTIVE);

                case ADVERB:

                  return(ADVERB);

                case NOUN:

                  return(NOUN);

                case PREPOSITION:

                  return(PREPOSITION);

                case PRONOUN:

                  return(PRONOUN);

                case CONJUNCTION:

                  return(CONJUNCTION);

                default:

                  printf("%s:  don't recognize\n", yytext);

                  /* don't return, just ignore it */

                }

            }

          }

.      ;

%%

/* define a linked list of words and types */

struct word {

        char *word_name;

        int word_type;

        struct word *next;

};

struct word *word_list; /* first element in word list */

extern void *malloc();

int

add_word(int type, char *word)

{

        struct word *wp;      

        if(lookup_word(word) != LOOKUP) {

                printf("!!! warning: word %s already defined \n", word);

                return 0;

        }

       

        /* word not there, allocate a new entry and link it on the list */

        wp = (struct word *) malloc(sizeof(struct word));

        wp->next = word_list;

        /* have to copy the word itself as well */

       

        wp->word_name = (char *) malloc(strlen(word)+1);

        strcpy(wp->word_name, word);

        wp->word_type = type;

        word_list = wp;

        return 1;      /* it worked */

}

int

lookup_word(char *word)

{

        struct word *wp = word_list;

        /* search down the list looking for the word */

        for(; wp; wp = wp->next) {

                if(strcmp(wp->word_name, word) == 0)

                        return wp->word_type;

        }

        return LOOKUP; /* not found */

}

 

 

A Yacc Parser

다음은 yacc을 사용하는 첫 번째 예이다. lex의 입력과 유사하다.

%{

/*

 * A lexer for the basic grammar to use for recognizing english sentences.

 */

#include <stdio.h>

%}

%token NOUN PRONOUN VERB ADVERB ADJECTIVE PREPOSITION CONJUNCTION

%%

sentence: subject VERB object { printf("Sentence is valid.\n"); }

        ;

subject:       NOUN

        |      PRONOUN

        ;

object:        NOUN

        ;

%%

extern FILE *yyin;

main()

{

        while(!feof(yyin)) {

                yyparse();

        }

}

yyerror(s)

char *s;

{

    fprintf(stderr, "%s\n", s);

}

 

yacc입력의 구조

definition section

%%

rule section

%%

user subroutine section

 

The Rule Section

rule section은 실제 문법이 생성규칙(production rule)의 형식으로 기술되어야 한다. 각각의 생성규칙은 ":"를 중심으로 왼쪽에는 한 개의 이름이 오고, 오른 쪽에는 문법 심볼들의 나열과 행동코드, 그리고 세미콜론(";")으로 마감한다.

 

   rule section의 기술형식:

        이름 : 문법 심볼  { 행동(C코드) } ;

 

별도로 정하지 않으면, 첫 번째 로 기술된 규칙을 시작 규칙으로 한다.

   ex)

        statement:    NAME '=' expression

                |      expression            { printf("= %d\n", $1); }

                ;

        expression:  expression '+' expression { $$ = $1 + $3; }

                |      expression '-' expression { $$ = $1 - $3; }

                |      expression '*' expression { $$ = $1 * $3; }

                |      expression '/' expression

                                        {      if($3 == 0)

                                                        yyerror("divide by zero");

                                                else

                                                        $$ = $1 / $3;

                                        }

                |      '-' expression %prec UMINUS{ $$ = -$2; }

                |      '(' expression ')'  { $$ = $2; }

                |      NUMBER                { $$ = $1; }

                ;

 

   ex)

         sentence: subject VERB object    { printf("Sentence is valid.\n"); }

                ;

        subject:      NOUN

                |      PRONOUN

                ;

        object:               NOUN

 

 

user subroutine section

파서에 포함될 어떤 C 코드도 쓸수 있다.

   ex)

        extern FILE *yyin;

        main()

        {

                while(!feof(yyin)) {

                        yyparse();

                }

        }

        yyerror(s)

        char *s;

        {

            fprintf(stderr, "%s\n", s);

        }

 

 

좀더 복잡한 문장을 파싱하도록 yacc입력을 수정-ch1-06.y

%{

#include <stdio.h>

/* we found the following required for some yacc implementations. */

/* #define YYSTYPE int */

%}

%token NOUN PRONOUN VERB ADVERB ADJECTIVE PREPOSITION CONJUNCTION

%%

sentence: simple_sentence   { printf("Parsed a simple sentence.\n"); }

        | compound_sentence { printf("Parsed a compound sentence.\n"); }

        ;

simple_sentence: subject verb object

        |      subject verb object prep_phrase

        ;

compound_sentence: simple_sentence CONJUNCTION simple_sentence

        |      compound_sentence CONJUNCTION simple_sentence

        ;

subject:      NOUN

        |      PRONOUN

        |      ADJECTIVE subject

        ;

verb:          VERB

        |      ADVERB VERB

        |      verb VERB

        ;

       

object:               NOUN

        |      ADJECTIVE object

        ;

prep_phrase: PREPOSITION NOUN

        ;

%%

extern FILE *yyin;

main()

{

        while(!feof(yyin)) {

                yyparse();

        }

}

yyerror(s)

char *s;

{

    fprintf(stderr, "%s\n", s);

}

 

Running Lex and Yacc

% lex ch1-n.l

% yacc -d ch1-m.y

% cc -c lex.yy.c y.tab.c

% cc -o example-m.n lex.yy.o y.tab.o -ll -ly

 

 

Lex vs. Handwritten Lexers

(렉스로 스캐너를 자동생성하는 것과 직접 스캐너를 프로그램하는 것과의 비교)

 

hand coded lexical analyzer (Example 1-9. Sample C lexical analyzer)

  #include <stdio.h>

  #include <ctype.h>

  char *progname;

  #define NUMBER 400

  #define COMMENT 401

  #define TEXT 402

  #define COMMAND 403

  main(argc,argv)

  int argc;

  char *argv[];

  {

  int val;

  while(val = lexer()) printf("value is %d\n", val);

  }

 

  lexer()

  {

    int c;

    while ((c=getchar()) == ' ' || c == '\t')    ;

    if (c==EOF)

       return 0;

    if (c=='.' || isdigit(c))  {       /* number */

        while ((c=getchar()) != EOF && isdigit(c));

  if (c=='.') while ((c = gerchar()) != EOF && isdight(c));

        ungetc(c, stdin);

        return NUMBER;

    }

    if (c=='#')  {      /* comment */

       int index = 1;

       while ((c = getchar() != EOF && c != '\n');

       ungetc(c,stdin);

       return COMMENT;

    }

    if (c=='"')  {  /* literal text */

       int index = 1;

       while ((c = getchar()) != EOF &&

      c != '"' && c != '\n');

       if (c == '\n') ungetc(c, stdin);

       return TEXT;

    }

    if (isalpha(c))  {    /* check to see if it is a command */

       int index = 1;

       while((c = getchar()) != EOF && isalnum(c));

       ungetc(c, stdin);

       return COMMAND;

    }

    return c;

  }

 

Sample lex lexical analyzer

%{

  #define NUMBER   400

  #define COMMENT  401

  #define TEXT     402

  #define COMMAND  403

%}

%%

[ \t]+                   ;

[0-9]+                 |

[0-9]+\.[0-9]+         |

\.[0-9]+                 { return NUMBER;   }

#*                       { return COMMENT;   }

\"[^\"\n]*\"             { return TEXT;   }

[a-zA-Z][a-ZA-Z0-9]+     { return COMMAND;   }

\n                       { return '\n';   }

%%

#include <stdio.h>

 

main (argc, argv)

int argc;

char *argv[];

{

int val;

 

while(val = yylex()) printf("value is %d\n",val);

}

 

2. Using Lex(렉스 사용법)

 

Regular Expressions

패턴을 기술하기 위하여 패턴 연산은 메타 캐랙터(metacharacter)를 써서 표기

 

1) .   "\n"을 제외한 모든 글자를 매치시킴

 

2) *   이전의 정규식(regular expression)을 0번 이상 반복하여 매치시킴

 

3) []  character class를 표시: 기술된 글자중 하나를 매치시킴 []안에 기술된 메타캐랙터는 대부분 의미를 상실하나, "^", "-", "\"들은 특별한 의미를 가진다.

       만약 "^"(circumflex)가 첫글자로 나오면 다음의 글자들을 제외하고 매치시킴

        ex) [^\n]

            [^a-zA-Z]

 

       매치시킬 글자의 범위를 표시할 수 있다.

        ex) [0123456789]는 [0-9]로 표시할 수 있다.

 

       이스케이프 문자를 표시할 수 있다.

        ex) [ \t\n] 공백, 탭문자, 뉴라인 문자

            [\40-\176] 아스키 40인 공백부터 176인 "~"까지

 

 

4) ^   입력에서 라인의 첫 자로부터 매치시킨다.

        ex) ^#include       /* C의 전처리 명령 */

 

 

5) $   이전의 정규식을 라인의 끝에서만 매치한다.

        ex) hello$      /* 라인 끝의 hello를 매치한다 */

 

 

6) {}  이전의 정규식을 몇번 매치시킬 것인가를 표시한다.

        ex) ha{1,5}  /* ha, haa, haaa, haaaa, haaaaa를 매치시킨다 */

 

 

7) \   메타캐랙터를 이스케이프 문자로 만든다. C언어의 이스케이프 문자와 같다.

        ex) \n\t

            \*\+\$

 

 

8) +   이전의 정규식을 1번이상 반복하여 매치시킨다.

        ex) [0-9]+

 

 

9) ?   이전의 정규식을 0 또는 1번 매치시킨다.

        ex) -?[0-9]+

 

 

10) |    정규식들을 택일하여 매치시킨다. OR의 의미 이다.

        ex) - | \+

            case | CASE

 

 

11) "..." 리터럴로 표시되어 " "안의 모든 문자가 정규식으로 간주된다. 따라서 모든 메타캐랙터는 의미를 상실한다.

        ex) a"*"b      /* 토큰 a*b를 매치한다 */

 

 

12) /    이전의 정규식은 / 이후의 정규식이 매치될때만 매치된다.

        ex) hello/\n        /* 정규식 hello$와 같다 */

 

 

13) ()   괄호안의 정규식을 한 덩어리로 취급한다. 복잡한 정규식에 *, +, | 등의 연산을 하려할 때 유용하다.

        ex) (ha){1,3}  /* ha, haha, hahaha를 매치한다 */

 

 

정규식 기술의 예

[0-9]

[0-9]+

[0-9]*

-?[0-9]+

[0-9]*\.[0-9]+

([0-9]+)|([0-9]*\.[0-9]+)

-?([0-9]+)|([0-9]*\.[0-9]+)

[eE][-+}?[0-9]+

-?(([0-9]+)|([0-9]*\.[0-9]+)([eE][-+}?[0-9]+)?)

 

수치를 인식하는 렉스 스펙

%%

[\n\t ]       ;

-?(([0-9]+)|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) { printf("number\n"); }

.      ECHO;

%%

main()

{

        yylex();

}

 

라인 첫글자가 "#"이면 코멘트 시작

#.*

 

C의 스트링

\"[^"\n]*["\n]

\".*\"            /* "how" to "do"를 인식할까? */

\"[^"]*\"         /* \n이 나올 때까지 "이 나오지 않으면... */

 

 

단어세기

유닉스의 wc와 같은 기능을 가지는 단어세는 프로그램

 

definition section

%{

unsigned charCount = 0, wordCount = 0, lineCount = 0;

%}

word [^ \t\n]+

eol  \n

 

rule section

%%

{word}{ wordCount++; charCount += yyleng; }

{eol}  { charCount++; lineCount++; }

.      charCount++;

 

user subroutine section

%%

main(argc,argv)

int argc;

char **argv;

{

        if (argc > 1) {

                FILE *file;

                file = fopen(argv[1], "r");

                if (!file) {

                        fprintf(stderr,"could not open %s\n",argv[1]);

                        exit(1);

                }

                yyin = file;

        }

        yylex();

        printf("%d %d %d\n",charCount, wordCount, lineCount);

        return 0;

}

 

% ch2-02 ch2-02.l

467  72  30

 

Using Yacc

 

·         Writing a Yacc Specification

 문법 규칙 및 행동

symbol:     definition

            {action}

            ;

·         Yacc Spec의 형식

declarations

%%

grammar rules

%%

C programs

선언부 

%token         Declare the names of tokens.

%left          Definite left-associative operators.

%right         Define right-associative operators.

%nonassoc      Define operators that may not associate with themselves.

%type          Declare the type of nonterminals.

%union         Declare multiple data types for semantic values.

%start         Declare the start symbol. Default is first in rules section.

%prec          Assign precedence to a rule.

 

%{

C declarations

%}

) 정수 인식

$ cat print_int.y

%token INTEGER

%%

lines:      /* empty */

     | lines line

     { printf("= %d\n", $2);  }

     ;

line:   INTEGER   '\n'

     { $$ = $1; }

     ;

%%

#include "lex.yy.c"

$ lex print-int.l

$ yacc print-int.y

$ cc -o print-int y.tab.c -ly -ll

 

$ print-int

3

= 3

15

= 15

6

= 6

zippy

syntax error

$

A Specification for a Simple Adding Machine

%{

int sum_total = 0;

%}

%token INTEGER

%%

lines:   /* empty */

     | lines line

     ;

line:     '\n'

     |  exp '\n'

     { printf("= %d\n", sum_total); }

     ;

exp:  INTEGER            {sum_total += $1; }

    | '+' INTEGER           {sum_total += $2; }

    | '-' INTEGER           {sum_total -= $2; }

    | '=' INTEGER           {sum_total = $2; }

    | '='                   {sum_total = 0; }

    ;

%%

#include "lex.yy.c"

 

Writing the Lexical Analyzer

 

%%

[0-9]+    {

          sscanf(yytext, %d", &yylval);

          return (INTEGER);

          }

\n        return ('\n');

[-+=]     return yytext[0];

quit      return 0;

.         ;

 

 

Creating the Parser

 

$ lex addup.l

$ yacc addup.y

$ cc -o addup y.tab.c -ly -ll

 

$ addup

3

= 3

5

= 8

+4

= 12

-2

= 10

= 0

= 0

4

= 4

250

= 254

= 100

= 100

-50

= 50

quit

$

 

계산기 만들기(Building a Calculator)

 

계산기를 위한 인터프리터를 구성하여

    실질적인 계산기를 개발

 

   계산기는 인터프리터의 한 종류

     ex) 3 + 4 = 7

  

4칙 연산 기능은 필수

 

   어휘분석기(lexical analyzer): 입력 글자를 토큰 스트림으로

   ex)  36.7 + 43.2 입력

       REAL PLUS REAL 의 토큰 스트림 출력

 

   파서(parser): 적법한 수식으로 인식하기 위한 규칙을 가짐

 

      ex) rexpr REAL | rexpr '+' rexpr

 

   정의된 값을 반환

      ex) $$ = $1 + $3;

 

   expression 뒤의 new line을 인식할 규칙이 필요함

 

     ex) line '\n' | rexpr '\n'

 

 

Writing Regular Expressions for Tokens

 

   2 types of operands : integer & real number

 

   ex) valid real numbers

    3.1415926

       2.718281828

       6.02E28

 

   regular expression으로

     [0-9]+

 

([0-9]*"."[0-9]+) | ([0-9]*"."[0-9]+[eE][+-]?[0-9]+)

[0-9]*"."[0-9]+

[0-9]*"."[0-9]+[eE][+-]?[0-9]+

 

대치 스트링의 정의

형식:

name   translation

 

참조:

{name}

 

오퍼랜드 정의

integer    [0-9]+

dreal    ([0-9]*"."[0-9]+)

ereal    ([0-9]*"."[0-9]+[eE][+-]?[0-9]+)

real         {dreal} | {ereal}

n1           \n

 

 

Defining the Token Types

 

   token valueyylval을 통해 전달

   How to define different token type?

   ex) yylvaldouble

  %{

   #define YYSTYPE double

  %}

 

   ex) token value가 두가지 이상의 type가지기

   %union {

       double  real;       /*  real value  */

       int   integer;      /*  integer value  */

       }

 

   ex) yacc spec 밖에 정의

   typedef union  {

      double  real;       /*  real value  */

           int  integer;       /*  integer value  */

      }  YYSTYPE

 

   union member 알리기 :  < > 안에 표기

   ex)

   %token <real> REAL

     %token <integer> INTEGER

 

   nonterminal symboltype 알리기 : %type

   ex)

   %type <real> rexpr

   %type <integer> iexpr

 

   ex) yylvalmember 표시

    {

sscanf(yytext,"%lf", &yylval.real);

    return REAL;

      }

 

 

완성된 Lex Spec

%{

#include "y.tab.h"

%}

integer  [0-9]+

dreal    ([0-9]*"."[0-9]+)

ereal    ([0-9]*"."[0-9]+[eE][+-]?[0-9]+)

real     {dreal}|{ereal}

n1       \n

%%

[ \t]+    ;

integer  {sscanf(yytext, "%d", &yylval.integer);

            return INTEGER;

           }

real     {sscanf(yytext,"%lf", &yylval.real);

            return REAL;}

n1       {extern int lineno; lineno++;

            return '';

           }

.          {return yytext[0];}

%%

 

   header file을 생성시키기 위하여 yacc option으로 -d 사용하여야 함

 

 

Yacc Spec만들기

 

declaration section

%{

#include <stdio.h>

%}

 

%union  {

    double  real;      /* real value */

    int  integer;      /* integer value */

   }

 

%token <real> REAL

%token <integer> INTEGER

 

%type <real> rexpr

%type <integer> iexpr

 

%left '+' '-'    /* define associativity */

%left '*' '/'    /* define precedence, lowest to highest */

%left UMINUS

 

 

rule section

 

lines:  /* nothing */

| lines  line

;

line:  ‘\n’

| iexpr ‘\n’

   { printf(“%d\n”, $1);}

| rexpr ‘\n’

   { printf(“%15.8lf\n”, $1);}

| error ‘\n’

   {yyerror;}

;

iexpr: INTEGER

     | iexpr '+' iexpr

       { $$ = $1 + $3; }

     | iexpr '-' iexpr

        {$$ = $1 - $3; }

     | iexpr '*' iexpr

        {$$ = $1 * $3; }

     | iexpr '/' iexpr

       { if ($3) $$ = $1 / $3;

         else {

               fprintf(stderr,"divide by zero\n");

               yyerror;

              }

       }

     | '-' iexpr %prec UMINUS  /* tell yacc binds with      */

                                 /*  the specified precedence */

        {$$ = - $2; }

     | '(' iexpr ')'

        {$$ = $2; }

     ;

 

rexpr:  REAL

      | rexpr '+' rexpr

                 {$$ = $1 + $3; }

      | rexpr '-' rexpr

                 {$$ = $1 - $3; }

      | rexpr '*' rexpr

                 {$$ = $1 * $3; }

      | rexpr '/' rexpr

                 {if($3) $$ = $1 / $3;

                  else {

                        fprintf(stderr,"divide by zero\n");

                        yyerror;

                       }

                 }

       | '-' rexpr %prec UMINUS

                 {$$ = - $2; }

       | '(' rexpr ')'

                 {$$ = $2; }

       | iexpr '+' rexpr

                 {$$ = (double)$1 + $3; }

       | iexpr '-' rexpr

                 {$$ = (double)$1 - $3; }

       | iexpr '*' rexpr

                 {$$ = (double)$1 * $3; }

       | iexpr '/' rexpr

                 {if($3) $$ = (double)$1 / $3;

                  else {

                        fprintf(stderr,"divide by zero\n");

                        yyerror;

                       }

                 }

        | rexpr '+' iexpr

                  {$$ = $1 + (double)$3; }

        | rexpr '-' iexpr

                  {$$ = $1 - (double)$3; }

        | rexpr '*' iexpr

                  {$$ = $1 * (double)$3; }

        | rexpr '/' iexpr

                  {if($3) $$ = $1 / (double)$3;

                   else {

                         fprintf(stderr,"divide by zero\n");

                         yyerror;

                        }

                  }

         ;

code section

 

char *progname;

int lineno;

 

main(int argc, char **argv) {

   progname = argv[0];

  

   yyparse();

}

yyerror(char *s) {  /* print warning message  */

   fprintf(stderr, "%s: %s", progname, s);

   fprintf(stderr, "line %d\n", lineno);

}

 

 

Compilation

 

$ lex calc.l

$ yacc -d calc.y

$ cc -o calc y.tab.c lex.yy.c -ly -ll

 

 

Showing the Results

% calc

23 * 34   

782

14 + 5

19

12 * 23.3

   279.60000000

1 / 0

divide by zero

1

1 + 0

1

2.3 * 3.2

    7.36000000

3.14 * 45

  141.30000000

255 * 255

65025

255 * 255 + (3.2 * 4.3)

 65038.76000000

1024 * 1024

1048576

[출처] 6. LEX & YACC|작성자 에러

Lex와 Yacc의 사용법 강좌

 


작성자 : 한국정보통신대학원대학교
           
컴퓨터 및 정보시스템 그룹
           
시스템 소프트웨어 연구실 병렬화 컴파일러팀 김홍숙

작성자 Email : kimkk@icu.ac.kr

문서의 목적:
본 문서는 컴파일러 제작과정중 다른 단계의 기초가 되는 font-end인 어휘 분석기와 구문 분석기를 lex, yacc 툴을 이용하여 작성하는 방법에 대하여 설명한다. 본 문서는 문서의 목적과 작성자에 대한 정보가 포함되어 있다면, 상업적인 목적을 제외한 모든 경우에 대하여 자유로이 사용, 변경, 배포할 수 있다. 작성자는 본 문서의 내용을 있는 그대로만 제공하며, 본 강좌의 내용에 따른 발생 가능한 모든 오류에 대한 책임을 지지 않는다. 다만 내용상의 문제점이나 기술된 내용이 부적절한 경우 작성자에게 전자메일을 통하여 해당 내용을 알려주면, 최선을 다하여 빠른 시간 내에 검토 수정을 할 것이다.

문서 history : 1996.12.24  WfMC WPDL작업 메모 중 lex yacc사용법 정리
                    2000.03.13   ICU 2000년 ICE501 PL과목 강의를 위한 revision
                    2000.03.16  예제보강 및 참고 문헌, 관련 링크 추가  



-목         차 -

1. 컴파일러의 개요 및 Front-end

1.1 Font-end ( tokenizing and parsing)


2. 어휘 분석기 생성 툴 lex (lexical analyzer)

2.1 Definition Section

2.2 Rule Section

2.3 User  Subroutine Section

2.4 컴파일 과정


3. 구문 분석기 생성툴 Yacc (yet another compiler compiler)

3.1문법(Grammar)

3.2 yacc specification 파일 구성

3.3 Definition Section

3.4 Rule Section

3.5 User Subroutine Section

3.6  yacc lex간의 인터페이스


4.  Lex Yacc 컴파일 과정 정리 및 자동화

4.1 Makefile의 이용


5. 참고 문헌 및 관련 링크

[출처] Lex와 Yacc의 사용법 강좌|작성자 제이씨피

+ Recent posts