Introduction
1. Imperative languages는 폰 노이만 아키텍쳐의 추상 개념임
- Memory
- Processer
2. 변수들은 속성들로 특징화 되어있음
- type을 디자인 하기 위해서 scope, lifetime, type checking, initialization, and type compatibility를 고려
Names
1. 고려사항 : 대소문자 구분, 예약어 or keywords 인지 아닌지 (예약어 ⊃ keywords)
예외)
goto(Java)
- 키워드 x
- 예약어(reserved word) o
goto(python)
- 키워드 x
- 예약어 x
2. 길이가 너무 짧으면, 함축적인 의미를 가질 수 없음
3. Special characters
- PHP : 모든 변수 이름에 $가 붙음 (ex) $abc
- Perl : 모든 변수가 변수의 타입을 명시해주는 special chracters로 시작함
ex) @abc - 배열 표시
%abc - 키와 value를 갖는 것
- Ruby : @로시작하는 변수는 instance variables이고, @@로 시작하는 변수는 class variables임
4. Case sensitivity (대소문자 구분)
- 단점 : readability가 안 좋음 (이름이 대소문자에 의해서 다름)
- C 기반 언어에서의 이름은 대소문자에 예민함, 기타 언어들은 구분하지 않음
- C++, Java, C#에서 더 심각한 이유는? 미리 정의된 이름들에 대소문자가 섞여 있음
-> ex) IndexOutOfBoundsException
5. Special words
- readability를 높이는 것이 목적
- keyword는 특정 문맥에서만 특별한 의미를 가지는 단어
ex) this, super, public같은 단어는 특정 위치에서만 의미 있음
- 예약어는 언어에서 미리 의미를 정해둔 단어로, 변수나 함수 이름으로 사용 불가
- 예약어가 너무 많으면 충돌이 자주 발생함
Variables
1. 변수는 memory cell의 추상 개념임
2. 변수는 다음과 같은 특성에 의해 특징화 되어있음
- Name
- Address (메모리 주소)
- Value (변수의 주소 or 값)
ex) x = 10 (x는 addr, 10은 value)
- Type
- Lifetime (변수의 주소가 시작~끝 까지 시간)
- Scope (변수가 유효한 공간)
Variables Attributes
1. Address - 메모리 상의 주소와 연결
- 실행 중 똑같은 변수의 주소가 계속 바뀔 수 있음
- Aliases = 두 개 이상의 변수가 같은 메모리 주소를 가리키는 것
-> 포인터(pointer)와 참조 변수(reference variable)로 만들어짐
-> 단점 : readability가 떨어짐
ex) int *p = &a; int& ref = a;
2. Value - 변수에 실제로 저장된 데이터
(1) l-value : 변수의 주소
(2) r-value : 변수의 값
3. Type - 변수의 값의 범위와 가능한 연산을 결정하는 속성
- 정밀도(precision)도 타입에 따라 다름 ex) float vs double
- Static type, Dynamic type
4. Abstract memory cell - 변수와 연결된 물리적인 메모리 셀 또는 셀들의 집합
- 실제로 값이 저장되는 공간
- 변수가 점유하고 있는 메모리 블록
Concept of Binding
1. 개체(entity)와 속성(attribute)을 연결 시키는 것
- 변수에 타입이나 값을 연결시키는 것
ex)
- 변수와 값의 바인딩 -> x = 5
- 변수와 자료형(type)의 바인딩 -> int x;
- 함수 이름과 함수 정의의 연결
2. Binding time : 바인딩이 언제 일어나는지를 의미
(1) Language Design Time (언어 설계 시점)
- 연산자 기호(+, *)와 해당 연산 의미를 연결
(2) Language implementation time (언어 구현 시점)
- 타입의 세부 속성 결정 (c언어에서 int는 16비트 or 32비트 ?)
(3) Compile time
- 변수 이름을 타입에 바인딩
(4) Load time (global/static 변수)
- 정적(static) 변수와 메모리 위치를 연결
(5) Runtime (Heap/stack 영역)
- 프로그램 실행 중
- 지역(local) 변수나 동적 변수의 메모리 할당
Static and Dynamic Binding
1. Static Binding (정적 바인딩)
- 프로그램 실행 전에(컴파일 타임에) 바인딩이 이루어지고, 실행 중에는 변하지 않는 바인딩 방식
- C, C++
2. Dynamic Binding (동적 바인딩)
- 프로그램 실행 중(runtime)에 바인딩이 이루어지며, 실행 도중 바뀔 수 있음
- Java, Python
Explicit/Implicit Declaration (타입을 (비)명시적으로 선언))
1. Explicit Declaration (명시적 선언)
- 변수의 타입을 직접 코드에 명시하는 방식
- C, C++, Java
2. Implicit Declaration (비명시적 선언)
- 선언문 없이 변수의 사용이나 기본 규칙에 의해 자동으로 타입이 정해지는 방식
- Python, 자바 스크립트
- 장점 : writability가 좋음
단점 : reliability(신뢰성) 가 안 좋음
3. Type Inference (타입 추론)
- 변수에 초기값을 기반으로 컴파일러가 타입을 추론
- 명시적 선언과 암시적 선언의 중간 성격)
Dynamic Type Binding (Python, JavaScript, PHP, and C#)
- 타입을 그때 그때마다 선언
-> 타입을 잘몬 준 경우 잡을 확률이 낮음 (타입을 바꿔버림)
장점 : Flexibility
단점 : 비용이 많이 듦(dynamic type 체크와 해석 때문에)
컴파일러에 의해 type error detection이 어려움
대부분 explicit -> static , implicit -> dynamic
예외) $abc -> implicit -> static (PHP 문법?)
Variables Attributes
1. Storage Bindings & Lifetime
- Allocation & Deallocation
- Lifetime은 heap, stack, data 중 Data가 제일 긺
- lifetime은 특정 메모리 셀에 변수가 존재하는 시간임
------------------------------------------------------------------------------------------------------------------------------
Categories of Variables by Lifetimes
1. Static
- 프로그램 실행 전에 메모리 공간이 할당되고, 실행이 끝날 때까지 계속 그 메모리를 유지하는 변수
- 항상 같은 메모리 위치를 사용
- 프로그램이 종료될 때까지 살아 있음
장점 : 효율성(메모리 주소가 고정되어 있어서 빠른 접근(direct addressing)이 가능
상태유지(함수가 이전 호출에서 어떤 값을 저장했는지 기억(history-sensitive) 가능
단점 : 유연성 부족(재귀에서 동일 변수를 공유하므로 병렬처리나 독립 실행 불가능)
여러 실행 흐름 간에 같은 상태를 공유해서 의도치 않은 결과를 초래할 수 있음
예시 언어 : C, C++, Java, Python
2. Stack-dynamic
- 변수가 선언될 때(run-time시점) 메모리에 할당되고, 해당 블록이 끝나면 자동으로 해제되는 변수
- 선언과 동시에 실행되며, 런타임 스택(stack)에 저장됨
- C에서 static이 아닌 지역 변수, Java 메서드의 지역 변수 등
장점 : 재귀(recursion) 가능 -> 호출마다 새로운 스택 프레임이 생성되기 때문
메모리 절약 -> 필요한 만큼만 생성되고 끝나면 제거됨
단점 : 할당/해제 오버헤드 -> 호출할 때마다 스택에 변수 할당 -> 성능 약간 손해
히스토리 유지 불가 -> 함수 호출 간에 이전 값을 기억할 수 없음
간접 접근 -> 스택 프레임 기반으로 접근해야 해서 static 변수보다 느릴 수 있음
예시 언어 : C, C++, Java, Python
3. Explicit heap-dynamic
- 변수의 메모리 할당과 해제를 프로그래머가 명시적으로 제어하며, 실행 중(runtime)에 효과가 발생하는 변수
- 힙(heap) 영역에서 메모리 확보
- 포인터/참조 를 통해서만 접근 가능
- 할당 : new, 해제 : delete (C++)
-> Java에서는 new만 있고, Garbage Collector가 해제 담당
장점 : 동적 저장 공간 관리 기능
-> 실행 중 필요한 만큼 메모리를 할당할 수 있어 유연성이 높음
-> 객체 수나 크기가 가변적인 상황에 매우 유리 (ex)동적 리스트, 트리 등
단점 : 비효율적 -> 힙 접근은 느리고, 메모리 파편화(fragmentation) 발생 가능
신뢰성 문제
(1) 메모리 해제 누락 -> 메모리 누수
(2) 이중 해체 -> 프로그램 충돌
예시 언어 : C, C++, Java
4. Implicit heap-dynamic
- 대입문(assignment statement)에 의해 변수의 할당과 해제가 자동으로 이루어지는 변수
- 프로그래머가 직접 타입도, 메모리도 선언하지 않음
- 힙에 메모리 자동 할당
- 모든 속성(type, size 등)이 런타임에 결정됨
장점 : 최고 수전의 유연성(flexibility) -> 타입, 크기, 구조 등 모든 것이 실행 중 결정됨
단점 : 비효율성과 오류 탐지 어려움
예시 언어 : Python
------------------------------------------------------------------------------------------------------------------------------
2. Scope (유효범위)
(1) Local variable (지역변수)
- 해당 블록이나 함수 안에 선언된 변수
- 선언된 범위 내에서만 사용 가능
(2) NonLocal variable (비지역 변수)
- 현재 함수나 블록에는 선언되어 있지 않지만, 외부에서 정의되어 접근 가능한 변수
- 보통 상위 scope에 존재
(3) Global variable (전역 변수)
- 프로그램 전체에서 접근 가능한 변수
- 사실상 nonlocal 변수의 특별한 형태
(4) Scope Rule
- 언어마다 어떤 스코프의 변수를 우선 참조하는지 규칙이 다름
- 대부분은 가까운 범위(local) 우선
-> 이를 가까운 변수로 가려진다(hidden) 라고 표현
3. Static Scope (정적 유효범위) -> 우리가 사용하는 언어의 유효 범위
- 소스 코드의 구조(문자 그대로 "프로그램 텍스트")를 기준으로 변수가 어느 스코프에 속하는지를 컴파일 시점에 결정하는 방식
- 컴파일러 또는 인터프리터는 변수를 사용한 위치에서 가장 가까운 선언을 찾음
-> 먼저 로컬(local)에서 찾고, 없으면 바깥쪽 스코프로 점점 확대
- 중첩 스코프(Nested Scope)
-> 한 스코프 안에 다른 스코프를 중첩해서 정의할 수 있음
ex) def ____
def ______
def ______
Evaluation of static scoping
=> 많은 상황에서 잘 쓰임
Problem)
- 대부분의 경우, 더 많은 접근이 가능
- 초기 구조는 파괴되고, local variables이 종종 global이 되어버림 (활용도가 낮음)
----------------------------------------------------------------------------------------------------------------------------------
Blocks
- 프로그램 유닛 내부에 static scopes를 만드는 방식
The LET Construct
let 구문 : 이름을 값에 바인딩(bind) 하고, 그 이름을 사용하여 계산을 수행하는 2단 구성의 구문
let의 구성 (두 부분)
1. 이름-값 바인딩
- 변수 이름을 값(또는 표현식)에 연결
- ex) val x = 5
2. 이 바인딩을 사용하는 본문
- 바인딩된 이름을 사용하여 새로운 계산 수행
- ex) x+1
----------------------------------------------------------------------------------------------------------------------------------
4. Global Scope -> 자바는 불가능 (public static을 사용하면 의미적으로 전역변수)
(1) C, C++, Python 공통 사항
- 프로그램은 보통 여러 함수 정의들이 나열된 구조로 구성됨
- 이들 언어에서는 변수 밖에서 변수 선언 가능 -> 전역 변수
(2) C, C++의 특성
- 선언(declaration) vs 정의(definition)
-> 선언은 변수의 존재만 알리는 것이고, 정의는 실제 메모리 공간을 할당함
(3) Python의 특징
- 전역 변수는 함수 안에서 읽기는 가능, 하지만 쓰기나 수정은 제한됨
why ? 전역 변수에 대입하면 자동으로 지역 변수가 생성되기 때문에
해결법 : global x 이런 식으로 사용하면 가능
'프로그래밍 언어(PL)' 카테고리의 다른 글
프언 ch3) 프로그래밍 언어의 구문 및 의미론 (0) | 2025.03.24 |
---|---|
프언 ch2) 프로그래밍 언어 개념 및 평가 기준 (0) | 2025.03.24 |
프언 ch1)프로그래밍 언어론 (0) | 2025.03.24 |