테스트 파일
아래 테스트 케이스를 일일히 입력으로 넣고 빼는 게 불편해서 테스트 케이스 파일과 스크립트를 작성했다.
https://github.com/kckc0608/Programming-Language-HW/tree/main/HW2
위 레포지토리에 테스트 케이스 파일들을 저장하였다.
A. Function
함수 정의, 함수 사용 (내장 함수 포함) 횟수 카운팅
함수가 전방 선언되고 뒤에 정의된 경우, 1번으로 센다. (아래 예제의 function 값이 5가 나옴)
int funct(int a);
void main() {
funct(1);
printf("%d", funct(2));
}
int funct(int a) {
a += sizeof(int);
a = -1;
return a+1;
}
function = 5
operator = 3
int = 1
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 1
sizeof() 는 함수가 아니다
void main() {
int a = sizeof(int);
}
function = 1
operator = 1
int = 1
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
B. Operator
이항 연산과 관련된 연산자 카운트 (단, ++ 와 -- 는 포함)
void main() {
a->b; // 1
a.b; // 2
a++; // 3
a--; // 4
(float) x; // 5
a * b; // 6
a / b; // 7
a % b; // 8
a + b; // 9
a - b; // 10
a << b; // 11
a >> b; // 12
a & b; // 13
a ^ b; // 14
a | b; // 15
a < b; // 16
a > b; // 17
a <= b; // 18
a >= b; // 19
a == b; // 20
a != b; // 21
a && b; // 22
a || b; // 23
a = b; // 24
a >>= b; // 25
a <<= b; // 26
a += b; // 27
a -= b; // 28
a *= b; // 29
a /= b; // 30
a %= b; // 31
a &= b; // 32
a ^= b; // 33
a |= b; // 34
}
function = 1
operator = 34
int = 0
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
단항 연산자, 삼항 연산자는 세지 않는다.
void main() {
int a;
a = +1;
a = -1;
a = &a;
a = 1 ? 1 : 0;
}
function = 1
operator = 4
int = 1
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
C. Int
int 로 선언된 변수의 개수 세기
void main() {
int a; // 1
int b; // 2
int c; // 3
int d, e; // 4, 5
int f = 1; // 6
int g = a; // 7
int h, i=1, j=b; // 8, 9, 10
}
function = 1
operator = 4
int = 10
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
함수 파라미터에서도 세기
int func(int a, int b) { // 1, 2
return a + b;
}
void main() {
int x=1, y=2; // 3, 4
func(x, y);
}
function = 3
operator = 3
int = 4
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 1
struct coord {
short c;
};
int f(int*, int); // 무시
int g(int a, int b); // 무시
int f(int *a, int b) { // int 2, pointer 1
return a + b;
}
int main() {
struct coord a, b;
}
int g(int a, int b) { // int 2
return a - b;
}
function = 3 // f, g, main
operator = 2 // +, -
int = 4 // f 파라미터 2개, g 파라미터 2개
char = 0
pointer = 1
array = 0
selection = 0
loop = 0
return = 2
D. Char
char로 선언된 변수의 개수 세기
void main() {
char a; // 1
char b; // 2
char c; // 3
char d, e; // 4, 5
char f = 1; // 6
char g = a; // 7
char h, i=1, j=b; // 8, 9, 10
}
function = 1
operator = 4
int = 0
char = 10
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
함수 파라미터에서도 세기
int func(char a, char b) { // 1, 2
return a + b;
}
void main() {
char x=1, y=2; // 3, 4
func(x, y);
}
function = 3
operator = 3
int = 0
char = 4
pointer = 0
array = 0
selection = 0
loop = 0
return = 1
함수 포인터
int (*p) (int);
int *p (int);
int* p, q;
int* p(int a) {
return &a;
}
function = 2
operator = 0
int = 3
char = 0
pointer = 3
array = 0
selection = 0
loop = 0
return = 1
E. Pointer
포인터로 선언된 변수의 개수를 센다.
int* a, int** a 모두 각각 포인터 변수 1개씩 (int도 1개씩 증가)
파라미터 변수도 카운트
포인터 함수도 카운트 ( int (*p)(int, int) 는 함수, 포인터 1개씩 증가, int 는 증가하지 않는다. )
void function(int* a, int** b) {
return;
}
void main() {
int* a, b, c;
int ** a;
}
전방 선언과 함수 정의 모두에 대해 세어야 하는지는 잘 모르겠으나, 매개변수는 세어야 하는 것이 맞음.
위 예제는 6개의 포인터가 있음.
function = 2
operator = 0
int = 6
char = 0
pointer = 6
array = 0
selection = 0
loop = 0
return = 1
int* function2(int, int);
void main() {
}
int* function2(int a, int b) {
return &a;
}
function = 2 // main, function2
operator = 0
int = 2 // function2 에 파라미터 2개
char = 0
pointer = 0 // 함수의 반환 타입에 있는 포인터는 변수가 아니므로 카운트 X
array = 0
selection = 0
loop = 0
return = 1
F. Array
배열로 선언된 변수의 개수를 센다.
int a[3] 은 int 개수, 배열 개수 모두 1개씩 증가
int a[3] = {0} 도 처리가 가능해야 한다.
2차원 배열의 경우에도 1만 증가한다.
파라미터로 선언된 배열도 센다.
int a[3];
void function(int e[3]) {
return;
}
void main() {
int b[3] = {0};
int c[3] = {1, 2, 3};
int d[3][3];
function(a);
}
function = 3
operator = 2
int = 5
char = 0
pointer = 0
array = 5
selection = 0
loop = 0
return = 1
a, b, c, d, e 5개 카운트
int* a[3];
void function(int* e[3]) {
return;
}
void main() {
int* b[3] = {0};
int* c[3] = {1, 2, 3};
int* d[3][3];
function(a);
}
function = 3
operator = 2
int = 5
char = 0
pointer = 5
array = 5
selection = 0
loop = 0
return = 1
포인터 배열 5개 카운트
G. Selection
선택문 개수, if / switch 만 카운트, else, else if 는 세지 않음.
void main() {
int i = 0;
if (i == 0) {
i = 1;
}
if (i == 1) {
i = 2;
} else {
i = 3;
}
if (i == 2) {
i = 3;
} else if (i == 3) {
i = 4;
} else {
i = 5;
}
switch(i) {
case 1:
i = 2;
break;
case 2:
i = 3;
break;
default:
i = 5;
break;
}
}
function = 1
operator = 14
int = 1
char = 0
pointer = 0
array = 0
selection = 4
loop = 0
return = 0
void main() {
int a = 1, b = 2;
int c = a > b ? a : b;
}
삼항 연산자는 조건문으로 보지 않는다.
function = 1
operator = 4
int = 3
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
H. 반복문
void main() {
int i = 1;
while (i) {
i += 1;
}
do {
i += 1;
} while (i > 1);
for (i = 0; i < 5; i++) {
i += 1;
}
}
function = 1
operator = 8
int = 1
char = 0
pointer = 0
array = 0
selection = 0
loop = 3
return = 0
이중 반복문도 테스트 해보았다.
void main() {
int i;
while (i) {
for (i = 0; i < 5; i++) {
i += 1;
}
i -= 1;
}
}
function = 1
operator = 5
int = 1
char = 0
pointer = 0
array = 0
selection = 0
loop = 2
return = 0
I. 리턴문
return 의 개수
문법상 return 의 역할을 하는 것만 센다.
printf("return ;"); 이런 건 세면 안된다.
void main() {
printf("return ;");
return;
return 0;
}
function = 2
operator = 0
int = 0
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 2
주석도 테스트 해보았다.
void main() {
printf("return ;");
// return;
return 0;
}
function = 2
operator = 0
int = 0
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 1
J. 변수의 선언 위치 자유
void main() {
int i = 0, j;
j = 10;
int k = 5; // k 는 전방선언 하지 않음.
}
function = 1
operator = 3
int = 3
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
void main() {
int k;
k = 10;
int y = 100;
for (i = 1; i < 100; i++) {
printf("");
}
for (int i = 0; i < 100; i++) {
printf("");
}
}
function = 3
operator = 8
int = 3
char = 0
pointer = 0
array = 0
selection = 0
loop = 2
return = 0
전방 선언을 할 필요가 없다는 말은 for문에서도 내부에 변수를 선언할 수 있다는 것과 같다.
사실 이걸 해결하다보면 전방 선언이 자연스럽게 해결된다!
K. 주의 사항
1) 문맥상 오류만 찾으면 된다.
void main() {
int a = 4; int a = 10;
}
원래는 컴파일 에러가 나는 코드지만, 메모리상 문제가 아닌 문맥상 오류만 없으면 된다.
function = 1
operator = 2
int = 2
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
따라서 에러 없이 잘 나오면 정상이다.
2) overflow, 정수형 변수에 소수 넣기는 에러로 잡지 않는다.
void main() {
int a = 98765432109876543210;
int b = 3.14;
}
function = 1
operator = 2
int = 2
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
3) #include <stdio.h> 와 같이 시작할 수 있다.
#include <stdio.h>
void main() {
int a = 98765432109876543210;
int b = 3.14;
}
function = 1
operator = 2
int = 2
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
4) #define a 5 와 같은 define 처리도 할 수 있다.
#define FIVE 5
#define INT 6
void main() {
int a = FIVE;
int b = INT;
}
function = 1
operator = 2
int = 2
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
5) auto, break, case, const, continue, default, double, enum, extern, float, goto, long, register, short, signed, sizeof, static, struct, typedef, union, unsigned, volatile 처리가 가능해야 한다.
typedef 처리
typedef int* intPointer;
intPointer x;
function = 0
operator = 0
int = 0
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
자료형 변수는 명시적으로 선언된 것만 카운트한다고 하였으므로, typedef 로 선언된 것은 세지 않아도 된다.
typedef int* intPointer;
intPointer x;
typedef struct coord {
int x, y;
} Coord;
Coord c1, c2;
function = 0
operator = 0
int = 2
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
명시적으로 선언된 int 2개만 카운트한다.
register int x; // int 1
volatile char y; // char 1
register unsigned float z;
volatile signed long w;
const static double t;
union MyUnion {
int intVal; // int 1
float floatVal;
char charVal; // char 1
};
union MyUnion u;
void main() {
A:
goto A;
}
function = 1
operator = 0
int = 2
char = 2
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
6) 변수에 값을 대입할 때, 10진수, 8진수, 16진수 모두 가능해야 한다.
#include <stdio.h>
void main() {
int a = 0x16;
int b = 099;
}
function = 1
operator = 2
int = 2
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
7. 구조체로 변수를 선언할 수 있다.
#include <stdio.h>
struct coord {
int x, y;
char w, z;
short* a;
double** b;
int c[];
char d[];
};
int main() {
struct coord my_coord = {1, 1};
}
function = 1
operator = 1
int = 3
char = 3
pointer = 2
array = 2
selection = 0
loop = 0
return = 0
8. 함수 선언은 void, int, float 과 같은 기본 자료형만 반환한다. 하지만 파라미터에는 struct가 있을 수 있다.
#include <stdio.h>
struct coord {
int x, y;
char w, z;
short* a;
double** b;
int* c; // 가변 길이 배열 대신 포인터 사용
char* d; // 가변 길이 배열 대신 포인터 사용
};
void f(struct coord x, struct coord y) {
return;
}
int main() {
struct coord x, y;
f(x, y);
}
function = 3 // 함수 정의 f, main 함수 호출 f
operator = 0
int = 3 // x, y, c
char = 3 // w, z, d
pointer = 4 // a, b, c, d
array = 0
selection = 0
loop = 0
return = 1
9. 주석문 (//, /* */) 처리가 가능해야 한다.
#include <stdio.h>
struct coord {
//int x, y;
char w, z;
short* a;
double** b;
int* c; // 가변 길이 배열 대신 포인터 사용
char* d; // 가변 길이 배열 대신 포인터 사용
};
/*void f(struct coord x, struct coord y) {
return;
}*/
int main() {
struct coord x, y;
f(x, y);
}
function = 2 // main, f호출
operator = 0
int = 1 // c
char = 3 // w, z, d
pointer = 4 // a, b, c, d
array = 0
selection = 0
loop = 0
return = 0
10. 반복문 내부의 코드는 1번만 카운트 한다.
void main() {
int k;
k = 10;
int y = 100;
for (i = 1; i < 100; i++) {
printf("");
}
for (int i = 0; i < 100; i++) {
printf("");
}
}
function = 3 // printf 함수 호출 2번, main함수 정의 한번
operator = 8
int = 3
char = 0
pointer = 0
array = 0
selection = 0
loop = 2
return = 0
11. 자료형 변수는 명시적으로 선언된 것만 카운트한다.
struct Coord {
int x; int y;
};
struct Coord c1, c2;
function = 0
operator = 0
int = 2
char = 0
pointer = 0
array = 0
selection = 0
loop = 0
return = 0
'CS > 프로그래밍언어론' 카테고리의 다른 글
[프로그래밍언어론] 9. 함수형 언어 (LISP) (0) | 2024.06.12 |
---|---|
[프로그래밍언어론] 8. Name & Binding (0) | 2024.06.12 |
[ lex / yacc ] error: 'AUTO' undeclared (first use in this function) 해결 (0) | 2024.05.03 |
[프로그래밍언어론] 7. Parsing Problem (0) | 2024.04.19 |
[프로그래밍언어론] 6. C언어의 BNF 문법과 파싱 예제 (0) | 2024.04.17 |