108 司法特考三等 檢察事務官電子資訊組 程式語言 考古題詳解
第 一 題25 分
若有下列的 Backus-Naur Form(BNF)語法:
(一)請畫出 的剖析樹(Parsing Tree)。(15 分)
(二)請確認是否為不明確的語法(Ambiguous Grammar)。若是不明確的語法,則請舉例說明可能的解決方式;若非不明確的語法,則請說明為何沒有問題。(10 分)
登入後即可作答並保存紀錄。
核心觀念
- 上下文無關文法(Context-Free Grammar, CFG)與 BNF 語法: BNF(Backus-Naur Form)為描述程式語言語法結構的形式化表示法。文法由四元組 組成,其中 為非終端符號(Non-terminals)、 為終端符號(Terminals)、 為產生規則(Production Rules)、 為起始符號(Start Symbol)。
- 剖析樹(Parse Tree): 以樹狀結構視覺化推導(Derivation)過程。樹根為起始符號 ,內部節點為非終端符號,葉節點由左至右串接(Yield)即為產生的終端字串(包含空字串 )。
- 不明確語法(Ambiguous Grammar)之定義: 若文法中存在至少一個字串,可找出兩棵(含)以上相異的剖析樹,或存在兩條相異的最左衍生(Leftmost Derivation)/最右衍生(Rightmost Derivation),則該語法即為不明確語法(歧義語法)。
- 消除歧義(Disambiguation)策略: 語法呈現 之雙側遞迴結構時,會因無法決定結合方向(結合律,Associativity)而產生歧義。解決方式為改寫文法,規範符號的結合方向(改為嚴格的左遞迴或右遞迴)。
解題方法
(一)畫出 的剖析樹(15 分)
本題給定文法規則:
欲產生終端字串 ,可採用最左衍生推導如下:
- (套用 )
- (最左邊之 套用 )
- (最左邊之 套用 )
- ( 套用 )
- ( 套用 )
- ( 套用 )
- (最後之 套用 )
對應之剖析樹結構如下圖所示:
S
/ | \
S b S
/ | \ / | \
S a S S a S
| | | |
ε ε ε ε
葉節點由左至右驗證: 符合題目要求。
(二)確認是否為不明確的語法與解決方式(10 分)
1. 確認結果:此語法為「不明確的語法(Ambiguous Grammar)」
證明(反例法): 只要能為同一個字串找出第二棵相異的剖析樹,即可證明該語法為不明確語法。以題目指定的字串 為例,除第(一)小題繪製的剖析樹(樹根以 展開)外,尚存在另一棵完全合法的相異剖析樹(樹根以 展開):
第 二 題25 分
請問下列 Java 程式碼:
class NumAdd { public int add(int x, int y) { return (x + y); }
public int add(int x, int y, int z) {
return (x + y + z);
}
public int add(double x, int y) {
return ((int) x + y);
}
public int add(int x, double y) {
return (x + (int) y);
}
}
public class Main { public static void main(String[] args) { NumAdd na = new NumAdd();
System.out.println(na.add(1, 2));
System.out.println(na.add(3, 4, 5));
System.out.println(na.add(6.7, 8));
System.out.println(na.add(9, 10.1));
}
public Main() {
super();
}
}
(一)其執行後的輸出為何?(7 分)
(二)請註明程式碼行號,那些程式段落使用到多載(Overloading)、覆寫(Overriding)與多型(Polymorphism)功能?(18 分)
登入後即可作答並保存紀錄。
核心觀念
本題評量物件導向程式設計(OOP)的三大基礎核心機制與 Java 型態轉換:
- 方法多載(Method Overloading):在同一個類別內,定義多個「方法名稱相同」,但「參數列(Parameter List)不同」(參數個數、參數型別或參數順序不同)的方法。編譯器在編譯時期依據呼叫端傳入的引數型別與個數決定呼叫目標,屬於編譯期多型(Compile-time / Static Polymorphism)或早期繫結(Early Binding)。
- 方法覆寫(Method Overriding):子類別重新定義父類別中已存在且具備「相同方法名稱、相同參數列與相容回傳型態」的實體方法。這是實現執行期多型(Runtime / Dynamic Polymorphism)與動態繫結(Dynamic / Late Binding)的前提。特別注意:建構子(Constructor)無法被繼承,因此建構子絕不可能被覆寫。
- 多型(Polymorphism):
- 靜態多型(Static Polymorphism):主要透過「方法多載(Overloading)」實現。
- 動態多型(Dynamic Polymorphism / Subtype Polymorphism):透過「繼承(Inheritance)或介面實作(Interface Implementation)」結合「方法覆寫(Overriding)」,使父類別型態的參照變數在執行時期指向子類別物件,並動態調用子類別覆寫後的方法。
- 型態轉換(Type Casting):浮點數型態(
double)強制轉型為整數型態(int)時,會直接無條件捨去小數部分(Truncation),而非四捨五入。
程式碼行號對照基準
為便於精確標註第(二)小題之行號,本題程式碼行號標定如下:
1: class NumAdd {
2: public int add(int x, int y) {
3: return (x + y);
4: }
5:
6: public int add(int x, int y, int z) {
7: return (x + y + z);
8: }
9:
10: public int add(double x, int y) {
11: return ((int) x + y);
12: }
13:
14: public int add(int x, double y) {
15: return (x + (int) y);
16: }
17: }
18:
19: public class Main {
20: public static void main(String[] args) {
21: NumAdd na = new NumAdd;
22:
23: System.out.println(na.add(1, 2));
24: System.out.println(na.add(3, 4, 5));
25: System.out.println(na.add(6.7, 8));
26: System.out.println(na.add(9, 10.1));
27: }
28:
29: public Main {
30: super;
31: }
32: }
解題方法
(一)執行輸出追蹤
逐行推導 main 方法中的呼叫過程:
- 第 23 行:
na.add(1, 2)
- 傳入引數為兩個整數
(int, int)。 - 匹配第 2~4 行的方法
public int add(int x, int y)。 - 計算過程:。
- 輸出:
3。
- 第 24 行:
na.add(3, 4, 5)
- 傳入引數為三個整數
(int, int, int)。 - 匹配第 6~8 行的方法
public int add(int x, int y, int z)。 - 計算過程:。
- 輸出:
12。
- 第 25 行:
na.add(6.7, 8)
- 傳入引數為浮點數與整數
(double, int)。 - 匹配第 10~12 行的方法
public int add(double x, int y)。 - 計算過程:
(int) 6.7 + 8。
第 三 題25 分
請問下列兩個 Python 程式,若分別輸入 Andy、World、Everyone 後:
程式 A:
import sys
def Calc(sInput): sOutput = "Hello, " + sInput + "!" return(sOutput)
sInput = sys.stdin.readline()
while (sInput != ""): sInput = sInput.replace("\r", "").replace("\n", "") print(Calc(sInput)) sInput = sys.stdin.readline()
程式 B:
def Calc(sInput): sOutput = "Hello, " + sInput + "!" return(sOutput)
try: while(1): print(Calc(input())) except (EOFError): pass
(一)其執行後的輸出分別為何?(10 分)
(二)若兩個程式都可以被正常執行,請說明其執行方式與優缺點?(15 分)
登入後即可作答並保存紀錄。
核心觀念
本題旨在評量考生對於 Python 標準輸入(Standard Input, stdin)的處理機制、I/O 效能差異、字串換行字元處理,以及迴圈終止機制(條件哨兵值 vs. 例外處理機制)的掌握程度:
- 輸入函式行為差異:
sys.stdin.readline屬於底層緩衝讀取,會保留行尾換行字元(\n或\r\n),讀至檔案結尾(EOF)時回傳空字串"";內建函式input則會自動去除行尾換行字元,讀至 EOF 時會拋出EOFError例外。 - 流程控制哲學:程式 A 採用傳統結構化程式設計的「哨兵值(Sentinel Value)」迴圈;程式 B 採用 Python 慣用的 EAFP(Easier to Ask for Forgiveness than Permission)風格,利用「例外處理(Exception Handling)」控制流程結束。
解題方法
(一)執行後的輸出分析
題目給定輸入依序為:Andy、World、Everyone,最後觸發 EOF(輸入結束)。
- 自訂函式
Calc(sInput)行為:
- 接收字串參數
sInput,透過字串串接回傳"Hello, " + sInput + "!"。
- 程式 A 追蹤:
- 第 1 次
sys.stdin.readline讀入"Andy\n"(或 Windows 下的"Andy\r\n"),字串長度非 0,滿足sInput != ""。 - 經
.replace("\r", "").replace("\n", "")去除換行字元後,sInput變為"Andy"。 Calc("Andy")回傳"Hello, Andy!"並由print印出。- 依序處理
"World"與"Everyone",分別印出"Hello, World!"與"Hello, Everyone!"。 - 第 4 次讀取遇到 EOF,
sys.stdin.readline回傳空字串"",條件sInput != ""不成立,跳出迴圈終止程式。
- 程式 B 追蹤:
- 第 1 次
input讀入"Andy"(自動濾除行尾換行字元),呼叫Calc("Andy")印出"Hello, Andy!"。 - 第 2 次、第 3 次依序讀入
"World"與"Everyone",分別印出"Hello, World!"與"Hello, Everyone!"。 - 第 4 次
input遇到 EOF,引發EOFError。 - 程式由
except (EOFError):捕捉例外並執行pass,正常結束程式。
(二)執行方式與優缺點評析
1. 執行方式比較
- 程式 A:
- 讀取模組:依賴
sys標準函式庫,直接調用底層檔案物件的sys.stdin.readline方法。 - 迴圈終止機制:採用「前置讀取(Priming Read)」配合
while哨兵值判斷。當回傳值為長度為 0 的空字串""時判定為 EOF 並終止迴圈。 - 格式整理:必須透過字串替換方法手動濾除 CR(
\r)與 LF(\n)。 - 程式 B:
- 讀取模組:使用 Python 內建高階函式
input,無需匯入任何模組。 - 迴圈終止機制:採用無窮迴圈
while(1),完全依賴事件導向的「例外處理(try...except)」。以EOFError作為中斷信號。 - 格式整理:
input在讀入字串時自動剝除行尾換行字元。
2. 優缺點比較
第 四 題25 分
有關預存程序(Stored Procedure),請回答下列問題:
(一)請說明其定義。(7 分)
(二)請寫出程式碼範例。(10 分)
(三)請說明其優缺點為何?(8 分)
登入後即可作答並保存紀錄。
核心觀念
本題考驗關聯式資料庫管理系統(RDBMS)中預存程序(Stored Procedure, SP)的架構定位、語法設計與實務應用評估:
- 儲存與執行架構:預存程序是預先編譯並儲存於資料庫伺服器端的 SQL 語句與程序控制敘述集合,具有伺服端執行、執行計畫快取(Execution Plan Caching)等特性。
- 與一般 SQL 查詢之差異:相較於由應用程式端發送的動態 ad-hoc SQL,預存程序支援輸入/輸出參數、流程控制結構(
IF-ELSE、迴圈、例外處理),並可封裝複雜的資料交易(Transaction)。 - 資訊安全與軟體工程權衡:參數化傳遞可有效防止資料隱碼攻擊(SQL Injection),並降低網路負載;但在多層次架構(N-Tier)中,將業務邏輯放置於資料庫端會衍生伺服器負載、版本控管不易與跨平台移植(Vendor Lock-in)困難等缺點。
解題方法
本題為標準的問答申論與實作題,作答策略如下:
- 第(一)小題(定義):從「儲存位置」、「編譯機制(Pre-compiled)」、「介面特性(參數與流程控制)」三維度進行精準定義,點出其介於單純 SQL 語句與高階程式語言模組之間的特性。
- 第(二)小題(程式碼範例):採用公職考題中最普及且符合標準的 ANSI SQL / T-SQL 語法。範例必須具備「輸入參數(Input Parameter)」、「業務邏輯或交易處理」及「呼叫執行方式(
EXEC或CALL)」,展現完整的語法結構,避免僅撰寫無參數的單一SELECT語句。 - 第(三)小題(優缺點):分別從「效能與網路」、「安全與權限」、「維護與移植性」、「伺服器硬體負載」四大構面進行對稱式條列分析,確保論點全面且具實務深度。
解題技巧
- 概念區隔防踩雷:
- 預存程序 vs. 自訂函數(UDF):UDF 必須有傳回值且不能執行影響資料庫狀態的 DDL/DML(不得有副作用);預存程序可無回傳值、可傳回多個結果集(Result Sets),且允許完整的 DML 交易。
- 預存程序 vs. 觸發程序(Trigger):Trigger 是事件驅動(隱式觸發),預存程序必須顯式呼叫(Explicit Call)。
- 範例拿滿分關鍵:程式碼必須包含
CREATE PROCEDURE、宣告參數(型別)、邏輯本體(BEGIN ... END),並補上呼叫範例(如EXEC ...),閱卷評分標準方能給予完整的 10 分。
【答案】
(一)預存程序(Stored Procedure)之定義(7 分)
預存程序(Stored Procedure)是一組預先編寫、經過編譯並儲存在關聯式資料庫管理系統(RDBMS)伺服器端的一段 SQL 語句與程序導向控制結構(如條件判斷、迴圈、例外處理)的集合。
其核心特點包含:
- 預先編譯(Pre-compiled)與最佳化:資料庫在首次編譯或建立預存程序時,即完成語法解析並產生最佳化的「執行計畫(Execution Plan)」存入快取記憶體,後續呼叫可直接重複利用,大幅節省解析時間。
- 介面化與參數支援:可定義輸入參數(
IN/ 輸入變數)與輸出參數(OUT/ 回傳值),如同一段函式或副程式,供外部應用程式或其它資料庫模組傳參呼叫。 - 封裝性:將複雜的資料庫操作(如跨資料表查詢、多步交易)封裝在伺服端單一邏輯單元內。
(二)程式碼範例(10 分)
以下以業界與國考常用的標準 T-SQL(適用於 Microsoft SQL Server / Sybase)實作一個「員工調薪處理程序」,包含輸入參數、更新操作與例外控制: