전처리기(Preprocessor)
본 장에서는 전처리기의 기본 개념과 사용법에 대해서 설명한다.
1. 개요
전처리기(Preprocessor)는 소스 프로그램을 입력으로 받아 전처리기 statement에 따라 소스 프로그램 중 일부를 변경하고 출력한다. 전처리기의 출력은 컴파일러의 입력으로 사용된다.
전처리기가 입력으로 받는 소스 프로그램은 아래와 같이 3가지 요소로 구성되어 있다.
-
Preprocessor Statement
전처리기 Statement(Preprocessor Statement)들은 퍼센트 기호(%)로 시작해야만 한다. 하지만 전처리기 프러시저에 기술된 statement들은 퍼센트기호를 붙이지 않는다. 전처리기 statement는 소스프로그램에 기술된 순서대로 실행된다.
전처리기 statement를 통해서 Input text에 아래와 같은 영향을 미칠 수 있다.
-
전처리기는 전처리기 Statement를 순서대로 실행하여 그에 따라 Input text를 변경한다.
-
전처리기 Statement를 통해서 Input text를 변경할지 여부를 결정할 수 있다.
-
다른 파일이나 라이브러리에 저장되어 있는 문자열을 전처리기 입력에 포함시킬 수 있다.
다음은 전처리기 Statement를 통해서 할 수 있는 작업에 대한 설명이다.
Statement 설명 전처리기에서 사용할 변수이름과 속성을 지정할 수 있다.
%ACTIVATE statement가 실행된 것으로 간주하여 해당 변수를 activate 상태로 취급한다. 변수를 명시적으로 선언하지 않을 경우엔 CHARACTER 속성으로 선언되고 deactivate 상태로 취급한다.
Input text의 문자열을 전처리기 변수의 값으로 변환할지 여부를 지정할 수 있다.
-
%ACTIVATE: 활성화
-
%DEACTIVATE: 비활성화
다른 파일에 저장된 문자열을 전처리기 입력에 포함시킬 수 있다.
전처리기 실행 순서를 바꿀 수 있다.
전처리기 변수의 값을 변경할 수 있다.
%PROCEDURE
전처리기 프러시저를 정의하고 사용할 수 있다.
-
-
Listing Control Statement
프로그램 출력의 레이아웃을 설정할 수 있다. OpenFrame PL/I에서는 입력으로 받기만 하고 출력에 반영하지는 않는다.
-
Input text
전처리기 입력에서 위의 Preprocessor Statement, Input text를 제외한 모든 문자열을 가리킨다. Input text는 PL/I 소스 프로그램이 될 수도 있고 다른 형태의 문자열이 될 수도 있다. PL/I 상수는 변경하지 않고 그대로 출력한다. 활성화 상태의 전처리기 변수의 이름과 매칭되는 문자열은 해당 변수의 값으로 변환된다.
전처리기 변수의 옵션으로 RESCAN 또는 NORESCAN 옵션을 지정할 수 있는데, NORESCAN 옵션이 지정되어 있는 경우에는 해당 변수의 값으로 단 한번만 변환한다. RESCAN 옵션이 지정된 경우에는 변환 이후에 해당 이름의 변수가 있는지 찾아 바꾸는 작업을 반복한다.
변수 및 데이터
전처리기 변수는 %DECLARE statement로 선언할 수 있고 FIXED와 CHARACTER 속성을 줄 수 있다. 모든 변수는 STATIC 저장 공간을 가진다.
전처리기의 데이터 타입은 아래와 같이 구분된다.
구분 | 설명 |
---|---|
FIXED |
Linux C++의 integer type에 매핑된다. |
CHARACTER |
Linux C++의 std::string type에 매핑된다. |
Numeric constant는 scale이 없는 즉, 정수형태만 허용된다. String repetition factors는 허용되지 않는다. |
참조 및 표현식
전처리기 참조(Reference)와 표현식은 표현식에 설명한 방법과 같이 evaluate된다.
그 외의 특이사항은 아래와 같다.
-
표현식의 연산자(operand)는 전처리기 변수, 프러시저 참조, 고정 소수점 상수, bit 상수, 문자열 상수, 그리고 전처리기 내장함수 참조를 포함한다.
-
전처리기 프러시저 밖에서 선언된 배열은 여러 프러시저에서 참조될 수 있어도 프러시저 밖에서는 참조될 수 없다.
-
제곱 기호(**)는 사용할 수 없다.
-
정수연산의 결과가 소수점으로 나오더라도 소수점 이하는 버린다. 예를 들어, 3/5는 0.6이식 아니라 0으로 저장된다.
-
문자열이 산술 연산에 사용될 수 있지만, 정수형의 값을 가져야만 한다.
-
null 문자열은 0으로 변환한다.
-
Fixed-point value를 문자로 바꿀 때는 항상 8길이의 문자열로 변환된다.
이름의 범위
전처리기에서 사용되는 이름의 범위는 이것이 선언된 위치에 따라 결정된다.
프러시저 안에서 선언된 이름의 범위는 해당 프러시저에 국한된다. Include된 문자열에서 선언된 이름은 해당 문자열과 이후 스캔된 모든 Input text에서 참조된다. 그 외의 모든 이름은 전처리기 입력 전체에 해당한다. 하지만, 해당 이름으로 선언된 전처리기 프러시저 안에는 참조할 수 없다.
2. Procedure
본 절에서는 전처리기 프러시저의 기본 개념과 규약에 대해서 설명한다.
다음은 전처리기 프러시저의 기본 문법이다.
전처리기 프러시저를 사용하기 위해서는 매개 변수를 전달하는 방법과 반환값을 처리하는 법을 이해해야 한다.
매개 변수는 Positional과 Keyword로 전달할 수 있다. Keyword Parameter에서는 파라미터 이름에 매칭되는 인자(argument)를 전달한다. Positional Parameter에서는 인자를 순서에 따라 파라미터와 매칭한다. 인자와 파라미터의 개수는 같지 않을 수도 있다. 파라미터의 개수보다 인자의 개수가 많으면 넘치는 부분은 무시되고, 그 반대의 경우에는 초기값으로 파라미터의 값을 세팅한다. FIXED는 0 CHARACTER는 null 값이 초기값이다.
함수 참조(Function reference)가 Input text에서 참조된다면, 그 인자는 콤마(,)나 오른쪽 괄호로 구분된다. 하지만, 따옴표(quote)나 괄호로 매칭이 된다면 delimiter로 사용되지 않는다.
예를 들어 (A(B,C),D)는 두 개의 인자로 이루어져 있다. A(B,C)와 D 인자는 파라미터에 넘기기 전에 먼저 가능한 변환을 수행한다. 하지만, 이 변환은 인자 개수에는 영향을 미치지 않는다. 즉, A(B,C)로 인해서 E, F로 변환되어 E, F, D가 된다 하더라도 인자는 E, F와 D 2개이다.
만약 참조가 Input text에 나타났고 STATEMENT 옵션이 있으면 인자들은 Positional Argument 또는 Keyword Reference 둘 다 나타날 수 있다. 참조의 마지막은 세미콜론(;)으로 구분되지만 세미콜론은 출력에 나타나지 않는다.
다음은 전처리기 프러시저 선언에 대한 예제이다.
%FIND:PROC(A,B,C) STATEMENT;
위와 같이 선언 된경우 FIND는 아래와 같이 참조될 수 있다. 다음 예제는 모두 동일한 의미이다.
FIND(X,Y,Z);
FIND B(Y) C(Z) A(X);
FIND(X) C(Z) B(Y);
FIND(,Y,Z) A(X);
함수 프러시저(Function procedure)에 의해서 반환되는 값의 속성을 지정하기 위하여 CHARACTER 또는 FIXED로 지정한다.
RETURNS 속성을 가진 전처리기 프러시저에는 적어도 하나 이상의 RETURN statement가 있어야 한다. RETURN statement는 control을 invocation 위치로 돌려주고 해당 참조에 RETURN statement에 명시한 값으로 치환한다.
전처리기 프러시저를 사용하려면 다음의 사항을 고려해야 한다.
-
전처리기 프러시저는 %PROCEDURE와 %END로 경계가 정해진다.
-
procedure가 RETURNS 속성을 갖지 않으면 RETURN statement는 반드시 가지면 안 된다. 반대로, procedure가 함수이면 RETURN statement를 적어도 하나는 포함해야한다.
-
전처리기 프러시저 안에서 전처리기 statement는 퍼센트 기호(%)로 시작하지 않는다.
-
전처리기 프러시저는 중첩될 수 없다.
-
전처리기 ENTRY 선언은 전처리기 프러시저 안에서 선언될 수 없다.
-
인자와 함께 쓰여진 전처리기 프러시저 entry name은 함수 참조(Function Reference)라고 한다. 함수 참조는 전처리기 표현식안에서 호출될 수 있다.
-
전처리기 프러시저 이름은 %DECLARE statement로 선언될 필요가 없다.
-
Entry name이 활성화 되어 있을 때, 전처리기 프러시저는 invoke되기 전에는 처리할 필요가 없다. 하지만, 해당 프러시저는 전처리기 input에 포함되어 있거나 invocation 시점에 이미 include되어 있어야만 한다.
-
전처리기 프러시저 함수는 해당 함수 참조의 위치에 반환값으로 변환한다.
3. Statements
본 절에서는 전처리기 statement의 사용법에 설명한다. 모든 statement는 label을 달 수 있다.
3.1. %ACTIVATE Statement(약어: %ACT)
%ACTIVATE statement는 변수를 활성화 상태로 만들어 Input text 변환을 할 수 있도록 한다.
해당 변수가 활성화 상태인 동안에 이후 나타나는 모든 Input text의 변수는 해당 변수의 값으로 변환된다. 이미 활성화 상태의 변수에는 아무 효과가 없다.
항목 | 설명 |
---|---|
identifier |
전처리기 변수, 프러시저, 내장함수의 이름을 지정한다. 배열 변수는 지정할 수 없다. |
RESCAN |
변환된 값이 또 다시 전처리기의 이름인 경우 해당 이름으로 변환하는 것을 반복한다. 더이상 매핑되는 이름이 없을 때 까지 반복한다. |
SCAN |
단 한번만 변환한다. |
NORESCAN |
SCAN과 동일하다. |
3.2. %assignment Statement
%assignment statement는 전처리기 표현식을 연산하고 그 결과를 전처리기 변수에 할당한다.
복합적이고 다수의 인자는 허용되지 않는다( +=, -= 혹은 a = b = c ). 인자의 target은 배열이 될 수 없다.
3.3. %DEACTIVATE Statement(약어: %DEACT)
%DEACTIVATE statement는 변수를 비활성화 상태로 만든다.
항목 | 설명 |
---|---|
identifier |
전처리기 변수, 프러시저, 내장함수의 이름을 지정한다. |
변수를 비활성화하면 더이상 Input text의 변수를 변환하지 않지만, 전처리기 변수가 가지는 값은 잃어버리지 않는다. 따라서 재활성화할 때 다시 값을 할당할 필요는 없다. 비활성화 상태의 변수를 또다시 비활성화하는 것은 아무런 효과가 없다.
3.4. %DECLARE Statement
%DECLARE statement는 전처리기 변수, 프러시저, 내장함수를 위한 실별자를 정의한다. 또한 해당 변수에 대한 스캐닝 상태를 설정할 수 있다. (약어: %DCL for DECLARE, CHAR for CHARACTER, INT for INTERNAL, EXT for EXTERNAL)
또는
항목 | 설명 |
---|---|
identifier_description |
전처리기 식별자에 대한 이름과 속성들을 지정한다. |
BUILTIN |
식별자가 같은 이름을 가진 전처리기 내장함수임을 지정한다. |
ENTRY |
식별자가 전처리기 프러시저임을 지정한다. 이 선언은 해당 엔트리 이름을 활성화한다. %PROCEDURE statement에 label된 이름으로 전처리기 프러시저 엔트리 이름을 명시적으로 선언할 수 있다. 하지만, 이렇게 선언된 이름은 비활성화 상태로 초기화된다. |
identifier_description:
dimension :
attributes :
항목 | 설명 |
---|---|
CHARACTER |
Linux C++의 std::string type에 매핑된다. |
FIXED |
Linux C++의 integer type에 매핑된다. |
SCAN |
식별자를 활성화 상태로 설정하고 단 한번 변환한다. |
RESCAN |
식별자를 활성화 상태로 설정하고 변환된 값이 또다시 전처리기의 이름인 경우 해당 이름으로 변환하는 것을 반복한다. |
NOSCAN |
식별자를 비활성화 상태로 설정한다. |
3.5. %DO Statement
%DO statement는 %END statement와 함께 전처리기 DO-group을 정의한다.
DO type 1:
DO type 2:
specification1:
DO type 3:
specification2 :
DO type 4:
%DO statement에 대한 설명은 DO statement에서 설명되어 있다.
전처리기 %DO statement가 컴파일러 DO statement와 다른 점은 아래와 같다.
-
UPTHRU와 DOWNTHRU가 %DO statement에는 없다.
-
DO type3의 specification1 specification2가 %DO statement에는 반복되지 않는다.
-
DO statement에는 없는 %DO SKIP statement가 %DO Statement에서 지원된다. %DO SKIP statement는 이와 매칭되는 %END statement까지 주석 처리한다.
전처리기 do-group은 중첩될 수 있다. 전처리기 statement, Input text, listing control statement 모두 do 안에 존재할 수 있다. |
3.6. %END Statement
%END statement는 %DO, %SELECT, %PROCEDURE statement와 매핑되어 그룹이나 procedure를 정의한다. END 뒤에 따라오는 label은 반드시 %PROCEDURE, %DO, %SELECT statement의 label이어야만 한다.
3.7. %GO TO Statement
%GO TO statement는 이 statement 이후로 실행될 statement의 label을 지정한다.
항목 | 설명 |
---|---|
label |
%GO TO statement가 명시된 전처리기 프러시저 내의 statement만 지정할 수 있다. include된 파일 내의 %GO TO statement의 label은 해당 파일 내의 statement만 지정할 수 있다. |
3.8. %IF Statement
%IF statement는 전처리기 표현식의 값에 따라서 다음에 실행할 statement를 컨트롤한다. %IF statement는 중첩될 수 있다.
항목 | 설명 |
---|---|
preprocessor_expression |
evaluate되고 나서 그 값을 true 혹은 false로 임시 설정한다. 조건 표현식(Conditional expression)이 아닌 경우에는 그 값이 0인경우 false, 0이 아닌 경우 true로 설정한다. preprocessor_expression의 값이 true이면 unit1을 false이면 unit2를 실행한다. |
preprocessor_unit |
%DECLARE, %PROCEDURE, %END, %DO를 제외하고 do, SELECT-group을 포함한 모든 전처리기 statement가 될 수 있다. |
3.9. %INCLUDE Statement
%INCLUDE statement에 지정된 외부 text를 전처리기 입력의 %INCLUDE statement의 위치에 포함시킨다. 포함된 외부 text는 Included text라고 한다.
%INCLUDE statement는 중첩될 수 있다. 즉, Included text안에 또다른 %INCLUDE statement가 존재할 수 있다. 전처리문, do-group, SELECT-group 및 procedure들은 하나의 text 안에서 정의되어야 한다. 즉, 매핑되는 %END statement는 하나의 text 안에 존재해야 한다. include되는 파일명은 8자리로 제한한다.
3.10. %INSCAN Statement
%INSCAN statement는 %INCLUDE statement와 마찬가지로 외부 text를 전처리기 입력의 %INSCAN statement의 위치에 포함시킨다. 하지만 %INSCAN statement는 %INCLUDE statement와 달리 include되는 파일의 이름을 전처리기 변수에 지정할 수 있다.
3.11. %ITERATE Statement
%ITERATE statement는 이 statement가 포함된 do-group의 %END 위치로 점프한다. 이후 현재 %DO statement의 반복이 끝나고, 필요하다면 다음 반복을 계속한다.
항목 | 설명 |
---|---|
label_constant |
do-group의 label이어야만 한다. 만약 생략되어 있다면, 가장 가까운 %END로 점프한다. |
3.12. %LEAVE Statement
%LEAVE statement는 이 statement가 포함된 do-group의 반복을 모두 종료한다. 이후 현재 do-group이 종료된 것처럼 %END 이후의 작업을 계속한다.
항목 | 설명 |
---|---|
label_constant |
do-group의 label이어야만 한다. label이 명시된 do-group까지의 반복을 모두 종료한다. 만약 생략되어 있다면, 가장 가까운 do-group까지 종료한다. |
4. 전처리기 내장함수
함수 참조(Function reference)를 통해서 전처리기 내장함수를 호출할 수 있다. 전처리기 내장함수는 프로그래머가 정의한 함수를 호출하는것과 동일하게 호출할 수 있지만, 인자의 개수가 정확하게 일치 해야만 한다.
Input text에서 내장함수를 호출하기 위해서는 내장함수 이름이 활성화 상태여야 한다. 내장함수 이름은 %DECLARE와 %ACTIVATE statement를 통해서 활성화될 수 있다. 반면에 전처리기 statement에서는 내장함수 이름은 항상 활성화 상태이다. 만약, 내장함수 이름이 사용자가 정의한 프러시저 이름이라면 해당 프러시저를 참고한다.
다음은 전처리기 내장함수에 대한 설명이다. 자세한 설명은 해당 절을 참고한다.
함수 | 설명 |
---|---|
날짜와 시간을 포함하는 18자리의 문자열을 반환한다. |
|
부동소숫점 숫자를 포함하는 5자리 문자열을 반환한다. |
|
x에서 y와 일치하는 첫 번째 위치를 FIXED 타입으로 반환한다. |
|
주어진 x 문자열의 길이를 FIXED 타입으로 반환한다. |
|
파라미터가 프러시저를 호출하는 경우 세팅되었는지 여부를 반환한다. |
|
x의 y, z로 명시된 부분 문자열을 반환한다. |
4.1. COMPILETIME
COMPILETIME은 날짜와 시간을 포함하는 18자리의 문자열을 반환한다.
-
반환값
반환값은 다음의 형식으로 반환된다.
DD.MMM.YYbHH.MM.SS
다음은 반환값의 예이다.
01.JAN.14 12.01.59
4.2. COUNTER
COUNTER는 부동소숫점 숫자를 포함하는 5자리 문자열을 반환한다.
첫 번째 호출되었을 때는 00001이며, 이후 하나씩 증가한다. COUNTER가 99999번 호출되고 나면 다음 호출에는 00000이 반환된다.
4.3. INDEX
INDEX는 x에서 y와 일치하는 첫 번째 위치를 FIXED 타입으로 반환한다. 비교를 시작할 위치도 지정할 수 있다.
-
인자
항목 설명 x
탐색할 대상 문자열이다.
CHARACTER 타입이 아니면 CHARACTER 타입으로 변환한다.
y
탐색에 쓰이는 문자열이다.
CHARACTER 타입이 아니면 CHARACTER 타입으로 변환한다.
n
탐색을 시작할 x의 위치이다.
FIXED 타입이 아니면 FIXED 타입으로 변환한다.
-
반환값
-
y가 x에 없거나 x 또는 y의 길이가 0일 때 0값이 반환된다.
-
n은 0보다 크고 x의 길이 + 1 보다 작아야 한다. n이 x의 길이 + 1과 같다면 0이 반환된다.
-
4.4. LENGTH
LENGTH는 주어진 x 문자열의 길이를 FIXED 타입으로 반환한다.
-
인자
항목 설명 x
CHARACTER 타입이 아니면 CHARACTER 타입으로 변환한다.
4.5. PARMSET
PARMSET은 파라미터가 프러시저를 호출하는 경우 세팅되었는지 여부를 0 혹은 1로 반환한다.
-
인자
항목 설명 x
반드시 전처리기 프러시저의 파라미터여야만 한다.
-
반환값
-
x가 세팅되어 있으면 1 아니면 0을 반환한다.
-
4.6. SUBSTR
SUBSTR은 x의 y, z 로 명시된 부분 문자열을 반환한다.
-
인자
항목 설명 x
부분 문자열을 추출할 문자열을 명시하는 표현식이다.
CHARACTER타입이 아니면 CHARACTER 타입으로 변환한다.
y
x의 부분 문자열을 추출하기 위한 첫 번째 위치를 명시하는 표현식이다.
FIXED 타입이 아니면 FIXED 타입으로 변환한다.
z
x의 부분 문자열의 길이를 명시하는 표현식이다.
FIXED 타입이 아니면 FIXED 타입으로 변환한다. z가 0이면 null 문자열을 반환하고, z가 생략되어 있다면, x의 y 위치부터 x의 끝까지를 반환한다.
z의 값은 음수면 안되고, y와 z는 x의 부분 문자열을 추출할 수 있는 범위 내에 있어야만 한다.
-
반환값
-
y = LENGTH(x) + 1이고 z = 0이면 null 문자열이 반환된다.
-