블로그 이미지
하루, 글. 그림. 영상매체. 표현을 도와주는 기기들. 도전 중. 동화다아아
    동화다아아

    카테고리

    분류 전체보기 (176)
    잡담 (1)
    IT 기기-리뷰&뉴스 (7)
    리뷰 - 도서 (1)
    리뷰 - 영상 (0)
    리뷰 - 그림/음악 (1)
    내장형 하드웨어 (163)
    Total
    Today
    Yesterday

     

    컴파일러(compiler, 순화 용어: 해석기, 번역기)는 특정 프로그래밍 언어로 쓰여 있는 문서를 다른 프로그래밍 언어로 옮기는 프로그램을 말한다. 원래의 문서를 소스 코드 혹은 원시 코드라고 부르고, 출력된 문서를 목적 코드라고 부른다. 목적 코드는 주로 다른 프로그램이나 하드웨어가 처리하기에 용이한 형태로 출력되지만 사람이 읽을 수 있는 문서 파일이나 그림 파일 등으로 옮기는 경우도 있다. 원시 코드에서 목적 코드로 옮기는 과정을 컴파일(compile, 순화 용어: 옮김, 번역, 문화어: 콤파일)이라고 한다. 컴파일러는 소스 프로그램을 읽어서 즉시 결과를 출력하는 인터프리터와는 구분된다.

    소스 코드를 컴파일하는 이유는 대부분 사람에게 이해하기 쉬운 형태의 고수준 언어로부터 실행 가능한 기계어 프로그램을 만들기 위해서이다. 좁은 의미의 컴파일러는 주로 고수준 언어로 쓰인 소스 코드를 저수준 언어(어셈블리어, 기계어 등)로 번역하는 프로그램을 가리킨다.


    처음의 소스파일은 우리가 작성하는 ".c" 파일이다. 실행 파일을 만들기 위해 먼저 해야될일은 전처리기(Preprocessor) 이다. 전처리기를 통해 ".i" 가 생성되고, 컴파일러에서 하드웨어 종속적인 어셈블리코드 ".s"를 생성하게 된다. 이후 어셈블러(Assembler)에 의하여 어셈블리어가 오브젝트 파일을 생성되고, 이 오브젝트 파일들이 링킹(Linking)과 재배치(Relocation) 과정을 거쳐 실행 파일이 생성된다. 

    전처리기: 컴파일을 시도할 경우 컴파일이 실행되기 전에 전처리기 명령부터 처리된다. 전처리기는 #로 시작되고 ; 를 붙이지 않으며 보이지 않게 소스 코드를 변경하며 컴파일에게 지시를 내릴 수 있다.


    어셈블러의 사용법

    오브젝트 파일이란: 어셈블의 결과 출력되는 기계어의 중간파일

    소스 리스팅(source listing): 소스 파일과 어셈블의 결과로 출력된 기계어를 대응시킨 리스트 파일

    크로스 레퍼런스(cross reference): 라벨이나 변수 이름이 여기서 정의되어 어디에서 참조 되고 있는가를 리스트 하는 파일.

    링크의 실행

    링커의 역할은 몇 개의 오브젝트 파일을 합쳐서 하나의 프로그램으로 한다든지, 라이브러리로부터 필요한 루틴을 꺼내어서 프로그램에 결합하는 것에 있습니다.

    오브젝트 모듈(object module) - 어셈블의 결과 출력되는 오브젝트 파일

    다른 모듈과 결합 -  + 기호를 사용

    실행파일(run file) - 링커에 의해 작성된 실행가능 파일

    리스트 파일 - 실행가능 파일 중에서 세그먼트나 프로시듀어의 번지나 길이를 나타냄

    링크의 결과 다음과 같은 메시지가 나오고 링크가 끝납니다.

    Warning: no STACK segment

    There was 1 error detected

    스택세그먼트는 설정하지 않아도 OS가 자동적으로 설정해 주는 것으로 되어있으므로 그대로 실행할 수가 있습니다.(다른 에러를 무시할 수는 없습니다.)

    COM 파일은 EXE 파일을 변환하여 만듭니다. EXE2BIN을 이용 확장자가 .BIN을 만들고, 확장자명인 BIN을 변경하면 됩니다.

    EXE와 COM 파일 중 COM 파일이 먼저 실행된다. 스택 세그먼트가 선언 되어 있는 EXE 파일은 변환할 수 없다. COM 모델과 EXE 모델과는 세그먼트의 초기 설정 등에 차이가 있다.

     

    우선 소스 코드를 (.cpp , .c)이 컴파일러에 의해서 컴파일 되면 바이너리 (기계어) 코드로 변경되어 .obj (오브젝트 코드)들로 저장이 된다.

    링커에 의해서 링크를 하게 되는데 이때 두가지 라이브러리를 사용할 수 있다. Static Library는 정적 라이브러리로써 실행 파일(.exe)에 아예 포함되어 버리는 라이브러리다.

    고로 .exe 자체가 소유하게 되므로 실행시에는 이 파일이 필요가 없다. 

    반대로 Import Library는 프로그램이 사용하는 특정 함수를 동적으로 가져다 쓰는 것으로써 실행을 위한 코드를 .exe 파일이 소요하는 것이 아니라 '어는 파일(DLL 파일들)에 네가 필요한 함수가 어떤 것이 있다'라고 알려만 준다. 


    고로 .exe 파일을 실행할 때, 만약 내가 특정 함수를 DLL에서 불러와 사용했다면 반드시 해당 DLL과 .exe 파일을 연결 시켜 주어야 한다. 그렇지 않으면 .exe 는 실행 할 수가 없다는 에러 메시지를 띄운다.


    단계

    (1). compile 컴파일은 소스(source, 원시) 프로그램을 목적(object) 프로그램 바꾸는 작업이다.

    (2). compiler 컴파일러는 고급 언어로 작성된 source program을 어셈블리 언어나 기계어 형태의 프로그램으로 변역하여 목적(object) 프로그램을 생성해 내는 프로그램이다. 즉 컴파일을 담당하는 프로그램이다. 컴파일 방식은 번역과 수행이 독립된 별도의 단계로 번역 과정이 번거롭고 시간이 걸리지만 한 번 번역한 후에는 source program을 수정하지 않는 한 다시 번역할 필요가 없고 수행 시 속도가 빠르다. (프로그래머가 직접 번역하는 것이 아니고 컴파일러가 번역한다. 프로그래머는 컴파일러만 수행하면 된다.)

    (3). 개략적인 컴파일 과정 

    - 구체적인 과정 Lexical analysis 어휘 분석은 원시 프로그램을 token으로 분류하는 것이 주된 작업이고 변수명의 첫 글자 확인 등의 에러처리도 한다. 여기서 토큰은 그 언어의 가장 기본적인 요소 하나하나로서 예약어, 연산자, 특수 기호, 변수, 상수 등이 모두 토큰이다. 그러나 공백은 토큰이 아니다. 어휘 분석기가 token을 구별하는 데는 연산자, 특수 기호, 공백 등을 이용한다. 하지만 예약어는 토큰 분류에 이용되지 않는다. Lexical analyzer 또는 scanner는 어휘 분석에 사용되는 프로그램이다.

      syntax analysis 구문 분석은 한 문장의 문법 구조(구문 구조, syntax)를 분석하며 parsing 이라고도 한다. 구문 구조(언어의 문법)는 tree를 이용해서 표현하는데 이러한 트리를 'parse tree'라 하고 이 트리를 생성하는 작업(parsing)이 곧 구문분석이다. 컴파일러는 최소한 구문 분석까지 수행한 후 에러 메시지를 출력하기 시작한다. syntax analyzer는 parser라고도 한다. * 별도 설명 interpretation 의미 해독은 한 문장에 대한 의미 검사, 즉 변수의 형(type) 검사를 한다. 또 선언되지 않고 사용된 변수를 체크하며 혼합형 연산의 타당성 여부를 검사하고 배열의 위치를 나타내는 첨자에 실수가 쓰였는지도 체크한다. 실수와 정수의 혼합 연산은 가능한데 이때는 정수를 실수의 형태로 바꾸어 준다. intermediate code generation 중간코드 생성을 하는 이유는 원시 프로그램과 목적 프로그램 사이의 중간 형태를 만들어 기계 독립적인 단계와 기계 종속적인 단계를 분리하는데 쓰인다.

      또한 중간 코드는 다음 단계인 코드 최적화 작업에 사용된다. * 별도 설명 code optimization 코드 최적화는 중간 코드를 가지고 작업하는데 생략하는 컴파일러도 있다. 최적화를 하는 이유는 생성되는 목적 프로그램이 같은 의미를 유지하면서도 좀 더 적은 공간을 차지하고 나중 수행시켰을 때 수행 시간을 절약할 수 있도록 하기 위함이다. 구체적인 최적화 방법에 다음과 같은 것이 있다.

      ① compile time compute 컴파일 시간 상수 연산은 부분 최적화 방법으로 constant folding이라고도 한다. 이는 프로그램 중에 상수 연산이 있으면 compile 도중 계산하는 방법으로 예를 들어 {A=2*276/92*B}와 같은 식을 {A=6*B}와 같은 식으로 변환하는 것이다.

      ② 중복된 load, store 명령어의 제거

      ③ useless인 코드 블록을 삭제 불필요한 코드 블록을 삭제하는 부분 최적화이다.

      ④ boolean expression의 최적화 부울 대수식의 최적화 또는 식의 대수학적 간소화라고 하며 부분 최적화 방법이다. 주로 if 명령어의 최적화를 의미한다.

      ⑤ strength reduction 좀 더 빠른 연산자로 바꾸어 준다. (연산의 속도는 덧셈이 가장 빠르다.) A=B**2 → A=B*B C=D*2 → C=D+D

      ⑥ common sub-expression 제거 공통된 부표현을 별도로 묶어 내는 것이다. a=b+c+d; e=b+c+f → t=b+c; a=t+d; e=t+f;

      ⑦ code motion 반복 범위내에서 값이 변하지 않는 식이 있을 때 반복 밖으로 꺼낸다.

      ⑧ loop fusion loop jamming이라고도 하며 여러개의 반복 명령어를 하나로 묶는다. storage allocation 기억 장소 할당은 변수, 상수, 임시 장소 등에 대한 기억장소 할당을 의미하며 static과 dynamic이 있는데 static은 컴파일 도중에 기억 장소를 확보하고 dynamic은 실행도중에 장소를 확보한다. code generation 코드 발생은 목적 프로그램을 생성하는 단계로 완전한 기계어 형태를 만들거나 어셈블리 언어 형태로 만든다. 어셈블리 언어 형태의 경우는 다시 어셈블 과정을 거쳐야한다. 가장 이상적인 목적 프로그램은 되도록 적은 기억 장소를 차지하고 실행 속도가 빠른 것이다. 참고 기계 독립적인 단계 하드웨어에 관계없이 작업할 수 있는 부분으로 어휘분석, 구문분석, 의미해독 등이다. 기계 의존적인 단계 하드웨어에 관계있는 부분으로 기억 장소 할당과 코드 발생 단계이다.


    1. 어휘(Token)

      ▶ 어휘(Token)

            프로그램을 구성하고 있는 문법적으로 의미 있는 최소 단위

            문장 “if (i<100) sum+=i;” 은 10개의 토큰으로 이루어짐 
             -> if, (, i, <, 100, ), sum, +=, i, ;

          Mobile C 언어의 토큰

     

    Posted by 동화다아아
    , |

    최근에 달린 댓글

    최근에 받은 트랙백

    글 보관함