CS

[컴퓨터과학개론] 프로그래밍 언어

Grace 2023. 12. 4. 15:46

프로그래밍 언어의 개요

  • 사람의 의도를 컴퓨터에게 전달하여 컴퓨터에게 작업을 수행시키기 위해 만들어짐
  • 사람의 의도를 추상화하여 압축된 언어로 컴퓨터에게 전달되어야 함
  • 의미적으로 애매모호함이 없고 어떤 경우에도 동일한 의미로 해석되어야 함
  • 구문론적 측면에서 명확하게 정의되어야 하며, 의미론적 측면에서 언제나 동일하게 해석되어야 함
  • 논리적으로 설계되어 컴퓨터가 처리할 수 있는 이진코드로의 변환이 명확하고 정확하게 되어야 함

기계어

  • 0과 1의 이진수로 구성되는 언어로 컴퓨터 하드웨어를 직접적으로 제어하기 위한 전기 신호의 표현 형태로 전달될 수 있는 수준의 언어
  • 0과 1로 이루어지기 때문에 사람이 의미를 이해하기 어렵고, 프로그램 작성이 어려움
  • 하드웨어나 컴퓨터 구조에 따라 기계어의 구성과 명령어(0과 1의 나열)가 달라지기 때문에 범용성이 떨어짐

어셈블리어

  • 기계어와 0과 1로 이루어진 명령어를 사람의 언어와 유사한 알파벳 심벌 형태로 바꾼 언어
  • 기계어보다 훨씬 읽기 편하지만 프로그램의 실행 논리를 컴퓨터가 실행하는 논리 순서에 맞추어 생각해야 하기 때문에 이해하기 쉽지 않음

고급 언어

  • 연산, 수행 제어, 메모리 접근의 프로그램을 사람의 자연어에 유사한 형태로 표현
  • 1950년대 말(초기 고급 언어): FORTRAN(과학/공학 계산용 언어, 최초의 고급언어), COBOL(비즈니스용 언어) 등
  • 1960년대: Basic
  • 함수형 프로그래밍 언어
    • 기본적으로 수식(expression)의 연속으로 이루어져 있고 함수들을 사용해 수식을 변환
    • 수식은 사칙 연산 뿐만 아니라 일반적인 의미의 모든 함수를 의미하고, 함수의 결과를 다른 함수의 입력 값으로 사용함
    • LISP(1950년대 말, 심벌의 리스트가 연산의 기본 단위), Scheme, ML 등
  • 구조적 프로그래밍 언어
    • 현대의 프로그래밍 언어에서 사용하는 많은 개념들이 구조적 프로그래밍 언어에서 도입
    • Algol 60: 조건문과 반복문을 사용하여 실행 흐름을 제어, block 구조, 함수 호출 등 주요 개념 도입
    • Pascal, C Modula-2 등
  • 논리형 프로그래밍 언어
    • 형식 논리로 사실(fact)들과 규칙(rule)들로 이루어진 문제 도메인 모델을 정의함
    • 원하는 결과를 얻기 위해 문제 도메인에 대한 질으를 주어서 논리적인 추론에 기초한 결과가 나오게 하는 선언형 언어
    • Prolog
  • 객체지향 프로그래밍 언어
    • 객체(obejct) 개념 (클래스(class) 개념)을 정의하고, 객체에 대한 연산(메소드)과 성질(멤버 변수)을 정의하여 프로그램을 작성하는 언어
    • 구조적인 프로그래밍 언어와 달리 객체 중심의 사고의 틀을 제공함
    • Simula 67, C++, Smalltalk 80, Java 등
  • 스크립트 언어
    • Unix와 같은 운영체제의 관리와 자동화를 위해 만들어져 사용되기 시작한 언어
    • sh, bash, csh 등 쉘 스크립트와 awk, sed 등의 패턴 처리 스트립트 언어에서 시작됨
    • Perl, Python 등

프로그래밍 언어의 파싱 트리

  • 모든 언어는 사용될 수 있는 단어들의 집합과 단어들이 나열되어 구조에 대한 규칙(문법)이 있고(문장의 생성) 각각의 문장은 실세계와 연결되는 의미를 가짐
  • 대부분의 프로그래밍 언어는 형식 문법을 사용해서 언어의 구조를 기술함
  • 문장의 구조는 파스 트리 형태로 표현하면 이해가 빠르고 문법의 모호성을 파악하기 쉬움

형식문법의 요소

  • 단말 심벌
    • 문장을 이루는 단어들을 단말 심벌이라 함
    • 파스 트리의 단말 노드에 해당됨
  • 비단말 심벌
    • 단말 심벌이 아니면서 복합적으로 나열된 단말 심벌과 비단말 심벌의 조합으로 구성
    • 파스 트리의 내부 노드에 해당
  • 생성 규칙(production rule): 하나의 비단말 심벌이 다른 단말 심벌이나 비단말 심벌로 대체되는 규칙
  • 시작 심벌(start symbol)
    • 가장 상위 계층의 비단말 심벌
    • 파스 트리의 루트 노드에 해당

프로그래밍 언어의 분석

  • 실행 가능 코드
    • 프로그래밍 언어로 작성된 프로그램 코드는 사람이 읽고 이해하기 쉽지만, 그 자체로는 컴퓨터가 이해할 수 없으며 실행할 수가 없음
    • 사람이 작성한 프로그램을 분석하여 기계어의 이진 코드로 바꾸는 변환 과정을 거치면 컴퓨터가 이해하고 실행할 수 있는 프로그램이 됨
  • 프로그램 코드의 분석
    • 사람이 작성한 프로그램은 어휘 분석과 구문 분석을 통해 프로그램에 문제가 없음을 확인함
    • 어휘 분석과 구문 분석 과정을 통과한 후 최종적으로 코드 생성 단계에서 실제 실행 가능한 이진 기계어 코드가 생성됨
  • 어휘 분석(lexical analysis)
    • 프로그램을 구성하는 문자들의 나열로부터 단어(token)를 추출해내는 과정
    • 빈 칸을 기준으로 단어를 구분하고, 구분 안의 각 단어를 이름, 숫자, 수식 기호 등으로 분류하는 것
    • token: 어휘 분석의 결과로 나온 각각의 단어
  • 구문 분석(syntax analysis)
    • 어휘 분석의 결과로 나온 토큰들의 나열이 해당 프로그래밍 언어의 문법에 맞는지를 확인하는 가정
    • 언어문법의 적합성 확인을 위한 파스 트리 생성
  • 코드 생성: 구분 분석의 결과로 변수, 상수, 제어의 흐름 등이 결정되면 이러한 각각의 명령어를 어셈블리어로 풀어 쓰거나 직접 기계어 이진 코드 생성

프로그래밍 언어의 공통 개념

대입문(할당문)

  • 변수나 기억장치 주소에 값을 저장하는 역할
  • 명령형 언어의 가장 중요한 기능 중 하나
  • <수식1> = <수식2>
    • <수식1>은 왼쪽 값이라고 하고 값이 저잘될 위치(기억장치의 주소)
    • <수식2>는 오른쪽 값이라고 하고 <수식1>이 가리키고 있는 곳(기억장치의 주소)에 저장할 값(정수값, 실수값, 문자열 등)을 의미
    • <수식2>의 값을 <수식1>의 주소가 가리키는 기억장치의 저장 장소에 저장

변수형 검사

  • 변수형은 연산에 사용되는 constant나 variable의 종류를 지정해서 연산 수행 시에 호환성이 없는 변수형간의 연산을 막아서 연산의 결과로 얻게 되는 정보의 손실을 최소화 하기 위해 사용 → 정수를 문자열로 나누거나 복잡한 struct 타입으로 곱하는 것은 연산의 의미가 없음
  • 정수와 실수의 덧셈에서 정수형으로 연산을 수행하면 실수값의 일부분을 잃게 됨
  • 변수형이 호환되지 않는 연산을 찾아내는 것을 type checking이라고 함
  • 컴파일 과정에서 이루어지는 static type checking과 run-time 중에 이루어지는 dynamic type checking 방식이 있음
  • 프로그래밍 언어에 따라 변수형을 다루는 방법과 변수형을 제한하는 정도에도 많은 차이가 있음

블록과 변수의 유효 범위

  • 변수나 기타 식별자가 코드의 유효 범위인가를 결정하는 유효 범위 결정 문제 → 변수에 대한 기억 장소의 할당 및 유지에 대한 문제
  • 고급 언어들은 대부분 여러 개의 명령문이 모여서 하나의 명령문을 만드는 복합문 및 여러 개의 명령문이 모여 있는 블록을 프로그래밍 언어 내에서 구현 → 이를 기초로 변수의 유효 범위 결정
  • 블록들은 중첩되는 구조도 가질 수 있어서 블록 안에 다른 블록이 들어가 있을 수 있음
  • 전역 변수(global variable): 프로그램 코드의 모든 영역에서 기억 장소의 할당이 유효
  • 지역 변수(local variable)
    • 그 변수가 정의된 블록 안에서만 기억 장소의 할당이 유효
    • 특정 블록의 명령문이 실행되면, 블록에서 사용될 지역 변수에 대한 기억 장소의 할당이 이루어지고 종료되면 해당 지역 변수는 기억장소에서 삭제됨
  • 변수의 유효 범위 문제: 여러 단계로 중첩된 블록들 사이에서 특정 블록에서 정의되지 않은 변수의 접근 유효성의 결정 문제
  • 블록 사이에서의 변수의 유효 범위를 결정하는 기준이 필요함
  • 정적 유효 범위 규칙(static scope rule): 변수의 유효 범위 결정은 컴파일이 이루어지는 시기에 코드에서 가장 가까이 정의된 것으로 유효 범위 결정
  • 동적 유효 범위 규칙(dynamic scope rule): 코드의 실제 실행 환경에 따라 변수의 유효 범위 결정
  • 같은 이름의 변수가 프로그램의 여러 곳에서 정의되어 사용될 때, 어디서 정의된 어떤 변수의 값을 참조하고 접근할 것인가는 유효 범위 규칙에 따라 결정됨

함수의 기본 개념

부프로그램

반복 사용되는 코드 부분을 하나의 단위로 묶어서, 이에 대해 고유의 이름을 정의하고 그 이름을 일반 명령어처럼 사용할 수 있도록 만든 것

  • 함수: 함수의 코드 부분의 실행 결과값을 돌려줌(return)
    • 제어의 시작이 되는 제어 진입점이 한 곳으로 한정
    • 함수의 호출이 발생되면, 함수를 호출한 프로그램의 수행이 일시 중단되고 호출된 함수로 실행 제어 이전
    • 호출된 함수의 실행 중에 함수 종료 조건이 만족되면 실행 제어가 호출한 함수나 호출한 프로그램으로 돌아감
  • 프로시저: 실행 결과값을 돌려주지 않음
  • 함수와 프로시저의 구분 없이 모두 함수로 취급되기도 함

함수의 매개변수

  • 호출하는 프로그램과 호출되는 함수는 서로 주고 받을 정보가 필요
  • 호출하는 프로그램은 함수의 실행 대상이 되는 데이터를 알려줄 수 있는 방법이 있어야 함
  • 함수를 호출하는 프로그램은 호출될 함수 이름만을 지정하기도 하지만, 일반적인 경우에는 호출된 함수에 여러 가지 다른 조건이나 데이터를 전달하고, 이에 따라 호출된 함수가 다양한 기능을 수행할 수 있도록 함
  • 매개변수(parameter)
    • 호출하는 프로그램과 호출되는 함수 사이에서 주고받는 데이터
    • 호출된 함수에서 처리될 값을 전달하는 매개체 역할을 하고, 이 값들은 특정 데이터 타입을 가짐
  • 함수의 실행 결과를 돌려주는 반환값도 특정 데이터 타입을 가짐
int f(int x) { // x: 형식매개변수
	return x+2;
}

int val;
int function_val;
val = 10;
function_val = f(val); // val: 실매개변수
  • 형식매개변수(formal parameter): 호출되는 함수의 정의에 사용되는 매개변수
  • 실매개변수(actual parameter): 호출하는 프로그램에서 함수를 호출하기 위해 사용된 매개변수
void swap (int x, int y) {
	int tmp;
	tmp = x;
	x = y;
	y = tmp;
}

int a = 2;
int b = 3;
swap(a, b);
  • 값 호출(call-by-value)
    • 함수 호출 후, 프로그램에서 a와 b를 출력하면 swap 함수를 실행했지만 변수 a와 변수 b의 값은 교환되지 않음
    • 함수 안에서 변수 a와 변수 b의 교환은 복사된 형식매개변수의 값들 간에 교환이 이루어졌기 때문에, 프로그램 안에서의 실매개변수 값에는 아무런 영향을 주지 않음
void swap (int* x, int* y) { // 매개변수의 포인터값(주소)를 매개변수로 전달받음
	int* tmp; // 함수 내에서만 접근 가능한 지역 포인터 변수 tmp 선언
	*tmp = *x; // 매개변수 x값을 지역변수 tmp에 저장
	*x = *y; // y값을 x에 대입
	*y = *tmp; // tmp 값을 y에 대입
}

int a = 2;
int b = 3;
swap(&a, &b);
  • 참조 호출 방식(call-by-reference)
    • 실매개변수가 형식매개변수 자리를 취해서 함수 안에서 형식매개변수에 행해진 모든 조작이 그대로 실매개변수에 반영
    • &연산자를 사용해서 a와 b의 주소를 계산한 후 그 주소값을 함수 호출에 사용

변수의 수명

  • 변수가 값을 저장하기 위해 기억 장소를 할당받고 있는 시간
  • 자동 할당
    • C언어에서 주로 사용
    • 변수의 수명은 그 변수가 포함된 블록의 범위
    • 한 변수가 선언된 블록이 시작할 때, 변수는 기억 장소를 할당받고 블록이 끝나면 변수의 기억 장소는 자동으로 회수
  • 정적 할당: 프로그램이 시작될 때, 기억 장소가 할당되며 블록이 끝나더라도 기억 장소는 그대로 유지되고 프로그램 종료 시 회수
  • 프로그래머 지정 할당: 프로그램의 실행 도중에 프로그래머가 기억 장소를 요청하여 할당 받고, 프로그래머가 직접 할당받은 기억 장소를 해제하여 운영체제에게 기억 장소를 회수시킬 때까지 기억 장소 유지

객체 지향 프로그램을 위한 추상 자료형

프로그래밍 언어에서 추상화라는 개념은 필수적인 속성만을 가지고 주어진 것을 묘사함으로써 나머지 부수적이거나 불필요한 속성들은 숨겨지거나 삭제됨

  • 프로시저의 추상화: 수행 방법을 기술하지 않고 무엇이 수행되는가를 묘사합으로써 추상화시켜 주는 실행 과정의 추상화 기법
  • 자료의 캡슐화: 프로그램 재사용을 위해 다양한 이름으로 여러 프로그래밍 언어에 구현
  • 자료의 추상화
    • 프로그래머에게 추상 자료형의 정의된 이름을 통해 객체를 호출하여 사용하도록 하는 window 제공
    • public part(visible part): 윈도우를 통해서 객체의 호출을 외부에 알려주는 부분
    • private part: 캡슐화를 통해 보호되는 구현 부분