UID192389
帖子
精華
主題
積分26826
現金
積極性
威望
違規
熱心
推廣次數
閱讀權限30
註冊時間2009-8-29
在線時間 小時
最後登錄1970-1-1
TA的每日心情 | 怒 2017-1-18 12:17 AM |
---|
簽到天數: 512 天 連續簽到: 1 天 [LV.9]以壇為家II
|
發表於 2013-3-28 12:53:50
|
顯示全部樓層
f003002 發表於 2013-3-28 09:17 AM
加油XD
你可以PO出來啊,搞不好很多人都寫過,然後你就可以Ctrl+C+V
交~作~業~ - 2013 spring PL project (OurScheme) - Project 1
- Due : 4/02(二) midnight (23:59)
- // You are to implement something like the following
-
- // 'exp' is a pointer that points to a linked list data structure;
- // The linked list data structure results from reading in
- // the user's input.
- Print 'Welcome to OurScheme!'
- Print '\n'
- Print '> '
- repeat
-
- ReadSExp(exp);
- PrintSExp(exp); // You must "pretty print" this S-expression.
- Print '> '
-
- until (OR (user entered '(exit)')
- (END-OF-FILE encountered)
- )
- Print '\n'
- Print 'Thanks for using OurScheme!' // Doesn't matter whether there is an
- // '\n' at the end
- 2. Syntax of OurScheme
- terminal :
- LEFT-PAREN // '('
- RIGHT-PAREN // ')'
- INT // e.g., '123', '+123', '-123'
- STRING // "string's (example)." (strings do not extend across lines)
- DOT // '.'
- FLOAT // '123.567', '123.', '.567', '+123.4', '-.123'
- NIL // 'nil' or '#f', but not 'NIL' nor 'nIL'
- T // 't' or '#t', but not 'T' nor '#T'
- QUOTE // '
- SYMBOL // a consecutive sequence of printable characters that are
- // not numbers, and do not contain '(', ')', single-quote,
- // double-quote and white-spaces ;
- // Symbols are case-sensitive
- // (i.e., uppercase and lowercase are different);
- Note :
- With the exception of strings, token are separated by the following "separators" :
- (a) one or more white-spaces
- (b) '(' (note : '(' is a token by itself)
- (c) ')' (note : ')' is a token by itself)
- (d) the single-quote character (') (note : it is a token by itself)
- (e) the double-quote character (") (note : it starts a STRING)
- Examples :
- '3.25' is a FLOAT.
- '3.25a' is a SYMBOL.
- 'a.b' is a SYMBOL.
- '#f' is NIL
- '#fa' (alternatively, 'a#f') is a SYMBOL.
- Note :
- '.' can mean several things :
- it is either part of a FLOAT or part of a SYMBOL or a DOT.
-
- It means a DOT only when it "stands alone".
-
- '#' can also mean two things :
- it is either part of NIL (or T) or part of a SYMBOL.
-
- It is part of NIL (or T) only when it is '#t' or '#f' that "stand alone".
-
- <S-exp> ::= <ATOM>
- | LEFT-PAREN <S-exp> { <S-exp> } [ DOT <S-exp> ] RIGHT-PAREN
- | QUOTE <S-exp>
-
- <ATOM> ::= SYMBOL | INT | FLOAT | STRING
- | NIL | T | LEFT-PAREN RIGHT-PAREN
- Once the attempt to read in an S-expression fails, the line
- containing the error-char is ignored. Start to read in an
- S-expression from the next input line.
- Note : a quoted S-expression '... is the same as (quote ...)
- a. In C, the basic program building block is a statement.
- In OurScheme, the basic program building block is
- an S-expression (S-exp, for short).
-
- b. An S-exp is either an atom, a list, or a dotted pair.
-
- c. An atom is either an integer (e.g., 123), a float
- (e.g., 12.34 or 12. or .34), a string (e.g., "Hi, there!"),
- or a symbol (e.g., abc).
-
- d. Abc, abc, aBc, a-B!c?, !??, t, nil are examples of symbols
-
- // Blanks and line-returns ("white-space characters") are
- // considered delimiters
-
- // Upper case and lower case are different, e.g., aB, AB, Ab,
- // ab are all different symbols.
-
- // Each symbol may or may not be bound to an S-exp.
-
- // When I say that a symbol abc is bound to the S-exp
- // (abc "Hi there" (5 3)),
- // you could take what I mean to be that the "value" of abc
- // is (abc "Hi there" (5 3)).
-
- // "Binding" (rather than "value") is a better way of saying
- // what the situation really is.
-
- // t, nil are two system-defined symbols
- // (t for "true" and nil for "false")
- // They cannot be bound to any S-exp (i.e., they cannot be
- // treated like user-defined symbols and cannot have values).
-
- // t is also written as #t, meaning "true"
- // nil is also written as () or #f, meaning "false"
- // In other word,
- // these two are the same : t #t
- // these three are the same : nil #f ()
-
- // OurScheme understands both 't' and '#t', but it only prints '#t'
- // OurScheme understands all these three : 'nil', '#f', '()',
- // but it only prints 'nil'.
-
- // Side remark :
- // (True) Scheme uses #t, #f and ()
- // "Other Lisps" use t, nil and ()
-
- e. An 「S-exp sequence」 is of the form
- S1 S2 S3 ... Sn
- where each Si is an S-exp.
- // e.g., (1) 1 (1 . 1)
- // e.g., 1 2 (3 4 (5))
- // Each of the above S-exp sequence contains three S-exp
- f. A dotted pair is of the form
- (SS1 . S2)
- where S2 is an S-exp, whereas SS1 is an 「S-exp sequence」.
- // Note that there is a dot between SS1 and S2,
- // with one or more spaces in between
- // e.g., (1 . 2)
- // e.g., (1 2 3 4 . 5)
- // e.g., (1 2 3 4 . ())
- // e.g., (1 . (2 . (3 . abc)))
- // e.g., (1 2 3 . abc)
- // e.g., ((1) (2 (3)) . (abc))
- // e.g., ((1) (2 (3)) . (nil))
- // e.g., ((1) (2 (3)) . nil)
-
- g. The following notations of dotted pairs are equivalent.
-
- (S1 S2 S3 S4 . S5)
- (S1 . (S2 . (S3 . (S4 . S5))))
-
- h. Comment :
- What we refer to as a "dotted pair" is different from what
- other professionals refer to as a "dotted pair".
-
- What other professionals mean by a dotted pair is just
- (S1 . S2), where S1 and S2 are S-exp.
-
- i. A list is of the form
- (SS1)
- where SS1 is an 「S-exp sequence」.
- // Note : () is known as "the empty list"
- // For historical reasons, () is defined to be the same
- // as nil or #f, meaning "false"
-
- j. A list (S1 S2 ... Sn) is actually a short-handed
- notation for the following dotted pair
- (S1 . (S2 . (...(Sn . nil)))...)))
- In other words, a list is actually a special kind of
- dotted pair.
-
- Another way of writing the list (S1 S2 ... Sn) is
- (S1 S2 ... Sn . nil)
-
- // In other word, there are three (seven?) ways for writing
- // the same list.
- // (S1 S2 S3 S4 S5)
- // (S1 . (S2 . (S3 . (S4 . (S5 . nil)))))
- // (S1 . (S2 . (S3 . (S4 . (S5 . #f )))))
- // (S1 . (S2 . (S3 . (S4 . (S5 . () )))))
- // (S1 S2 S3 S4 S5 . nil)
- // (S1 S2 S3 S4 S5 . #f)
- // (S1 S2 S3 S4 S5 . ())
-
- k. When the system prints out a dotted pair, it
- always tries to print it in list-like format.
-
- For example, if the dotted pair is
- (1 . (2 . (3 . (4 . 5))))
- Then the system prints it as
- (1 2 3 4 . 5)
-
- But if the dotted pair is
- (1 . (2 . (3 . (4 . nil))))
- The system does not print it as
- (1 2 3 4 . nil)
- Instead, the system prints it as
- (1 2 3 4)
-
- l. Line comments
-
- A line comment begins with ';' until the end-of-line.
- This ';' must be such that either it is the very first
- character of the line or there is a separater preceding this ';'
- on this line.
-
- (Therefore, for example, 'ab;b' is a symbol,
- while 'ab ;b' is the symbol 'ab' followed by a
- line comment that starts with ';b'.)
-
- 3. Here are some examples of what your program should
- do for project 1. (The following assumes that your program
- runs interactively.)
- Welcome to OurScheme!
- > (1 . (2 . (3 . 4)))
- ( 1
- 2
- 3
- .
- 4
- )
- > (1 . (2 . (3 . nil)))
- ( 1
- 2
- 3
- )
- > (1 . (2 . (3 . ())))
- ( 1
- 2
- 3
- )
- > (1 . (2 . (3 . #f)))
- ( 1
- 2
- 3
- )
- > a
- a
- > t
- #t
- > #t
- #t
- > nil
- nil
- > ()
- nil
- > #f
- nil
- > (t () . (1 2 3))
- ( #t
- nil
- 1
- 2
- 3
- )
- > (t . nil . (1 2 3))
- ERROR (unexpected character) : line 1 column 10 character '.'
- > ((1 2 3) . (4 . (5 . nil)))
- ( ( 1
- 2
- 3
- )
- 4
- 5
- )
- > ((1 2 3) . (4 . (5 . ())))
- ( ( 1
- 2
- 3
- )
- 4
- 5
- )
- > (12.5 . (4 . 5))
- ( 12.500
- 4
- .
- 5
- )
- > (10 12.()) ; same as : ( 10 12. () )
- ( 10
- 12.000
- nil
- )
- > (10 ().125) ; same as : ( 10 () .125 )
- ( 10
- nil
- 0.125
- )
- > ( 1 2.5)
- ( 1
- 2.500
- )
- > ( 1 2.a)
- ( 1
- 2.a
- )
- > (1 2.25.5.a)
- ( 1
- 2.25.5.a
- )
- > (12 ( . 3))
- ERROR (unexpected character) : line 1 column 11 character ' '
- > "Hi"
- "Hi"
- > "(1 . 2 . 3)"
- "(1 . 2 . 3)"
- > (((1 . 2)
- . ((3 4)
- .
- (5 . 6)
- )
- )
- . (7 . 8)
- )
- ( ( ( 1
- .
- 2
- )
- ( 3
- 4
- )
- 5
- .
- 6
- )
- 7
- .
- 8
- )
- > ())
- nil
- > ERROR (unexpected character) : line 1 column 1 character ')'
- > (Hi there ! How are you ?)
- ( Hi
- there
- !
- How
- are
- you
- ?
- )
- > (Hi there! How are you?)
- ( Hi
- there!
- How
- are
- you?
- )
- > (Hi! (How about using . (Lisp (instead of . C?))))
- ( Hi!
- ( How
- about
- using
- Lisp
- ( instead
- of
- .
- C?
- )
- )
- )
- > (Hi there) (How are you)
- ( Hi
- there
- )
- > ( How
- are
- you
- )
-
- > (Hi
- .
- (there .( ; note that there may be no space between
- ; '.' and '('
- How is it going?))
- )
- ( Hi
- there
- How
- is
- it
- going?
- )
- > ; Note : We have just introduced the use of comments.
- ; ';' starts a comment until the end of line.
- ; A comment is something that ReadSExp() should skip when
- ; reading in an S-expression.
-
- (1 2 3) )
- ( 1
- 2
- 3
- )
- > ERROR (unexpected character) : line 1 column 2 character ')'
- > (1 2
- 3) (4 5
- ( 1
- 2
- 3
- )
- > 6)
- ( 4
- 5
- 6
- )
- > '(Hi
- .
- (there .( ; note that there may be no space between
- ; '.' and '('
- How is it going?))
- )
- ( quote
- ( Hi
- there
- How
- is
- it
- going?
- )
- )
- >'(1 2 3) )
- ( quote
- ( 1
- 2
- 3
- )
- )
- > ERROR (unexpected character) : line 1 column 2 character ')'
- > '(1 2 3) .25
- ( quote
- ( 1
- 2
- 3
- )
- )
- > 0.250
- > (exit ; as of now, your system only understands 'exit' ;
- ) ; and the program terminates when it sees '(exit)'
- Thanks for using OurScheme!
- // =================== Q and A No. 1 =======================
- Question : '(1 2 3)的output應該是什麼?
- Answer :
- Project 1 :
- > '(1 2 3)
- ( quote
- ( 1
- 2
- 3
- )
- )
- Project 2 :
- > '(1 2 3)
- ( 1
- 2
- 3
- )
- 解釋:
- Project 1只讀進來(建出DS)、不evaluate就直接(把DS)印出去,
- 所以得 : (quote (1 2 3))。
- Project 2是讀進來(建出DS)、evaluate(此DS)、再把evaluate的result
- (依舊是個DS)印出去,所以得 : (1 2 3)。
- (將'(quote (1 2 3))'予以evaluate所得的結果是'(1 2 3)')
- // =================== Q and A No. 2 =======================
- ※ 引述《...》之銘言:
- > 請問老大~~
- > 1.當輸入'> .'時,會是ERROR嗎???
- > 若是是ERROR.msg:會是column: 1 or 2 ???
- It is an error. (Let us suppose that it is '> .$', where '$' is
- LINE-ENTER char.)
- column : 2 '.' is the very first user input char
- on this line. (the space before it is system output)
- Why column 2 and not column 1? Please see my answer to your second
- question below. (The system detects an error when it sees the LINE-
- ENTER char.)
- > 2.在測試數據中有輸入(12.5)(12(. 3))
- > 答案是:
- > > ( 12.500
- > )
- > > ERROR (unexpected character) : line 1 column 6 character ' '
- > 但是在OurScheme中
- > > (12 ( . 3))
- > ERROR (unexpected character) : line 1 column 10 character '.'
- > 之前的input是'.'錯,現在的input則是' '錯,為什麼呢???
- In the case of (the first one) '(12(. 3))', everything is still
- OK when the system (i.e., your system) "sees" '.'. Why? Because '.'
- may be followed by a digit such as '5'. The system detects an error
- only when it sees that there is a space following '.'. Therefore, the
- "error char" (the char that caused the error) is the space and not the '.'
- In the case of (the second one) '(12 ( . 3))', the error char should
- also be the space-char following that '.' You just found an error in my
- Project 1 handout. Thank you. (And I have taken the liberty to
- correct this error in both OurSchemeProj1.txt and HowToWriteOurScheme.doc)
- > 3.請問abc"abc會印出什麼呢???
- The first token is 'abc'. The second token is a string that starts
- with : "abc
- e.g., // for project 1
- > abc"abc "
- abc
- > "abc "
- → yabuki 推:老大那abc'abc算是symbol嗎?還是會有其他結果? 03/09 22:27
- → hsia 推:the case of abc'abc similar to the above case, 03/10 08:57
- → hsia 推:because single-quote, double-quote R separators 03/10 08:58
- // =================== Q and A No. 3 =======================
- ※ 引述《...》之銘言:
- > 這問題困擾很久百思不得其解。
- >
- > 依題意應該是最後一個可以執行(或印出)的Token後將行號和欄位初始化
- > 範例如下
- > () )
- > ^這玩意兒是最後的token,所以要印出在line 1錯
- > 問題來了:
- > "最後一個字串"\n
- > \n
- > \n
- > "出錯點
- > 為什麼這裡印line 3?把最後一個字串token拿掉後應該如下
- > \n 1
- > \n 2
- > \n 3
- > "出錯點 第4行
- > ---------------
- > "最後一個字串" \n 1
- > \n 2
- > \n 3
- > "出錯點 4
- > 加了空白為什麼也是line 3?
- 這沒什麼好百思不得其解的。 這是規劃時的思緒不夠細密。
- 的確,嚴格來講、按照規定、最後一個case的error應是第四行、而非第三行。
- 當初規劃時未考慮到「在legal input之後若還有(也只有)space怎麼算下一input的行數」
- 的問題。
- 不過,你就當這case是「general規定」的exception吧,意即:
- 在legal input之後(同一行)要出現「非space非tab字元」才把這一行
- 算作是下一input的第一行。 若legal input之後(同一行)只出現
- 「space或tab字元」,那這一行就不算作是下一input的第一行。
- ※ 引述《...》之銘言:
- > 請問一下PAL的proj2數據,當指令為(exit)時,output為
- >
- > Thanks for using OurScheme!
- > 為什麼不是
- > Thanks for using OurScheme!
- > 是不是要print "\nThanks for using OurScheme!"
- > 謝謝
- 答案是:
- Project要求
- > ( ;; user input, with an ENTER at the end
- ;; user input, with an ENTER at the end
- exit ;; user input, with an ENTER at the end
- ;; user input, with an ENTER at the end
- ) ;; user input, with an ENTER at the end
- Thanks for using OurScheme!;; system output
複製代碼
MY CODE- // 小鮭魚 PL Project_01
- # include <stdio.h>
- # include <stdlib.h>
- # include <string.h>
- # define MAX_LISP_COUNT 15 // 最多可儲存幾組數據的樹 (包含ERROR樹)。
- # define STRING_LENGHT 150 // 一個 token (以字串儲存) 的最大長度。
- enum Syntax_type_1{ SYN_LEFT_PAREN = 1, SYN_RIGHT_PAREN = 2, SYN_INT = 3, SYN_FLOAT = 4, SYN_STRING = 5 } ;
- enum Syntax_type_2{ SYN_NIL = 6, SYN_T = 7, SYN_DOT = 8, SYN_QUOTE = 9, SYN_SYMBOL = 10 } ;
- static int uTestNum = 0 ;
- typedef char Str_[ STRING_LENGHT ] ; // 定義一個新指令 'Str_', 用途與 char XXX[STRING_LENGHT] 相同。
- // Data Struct : 樹中的每個節點的數據內容。
- struct LISP_DS {
- Str_ str ; // 存放 token
- int synType ; // 該token 的類型
- int dot ; // 該點是否為 dot ( 0 : 未處理, 1 : 非dot, 2 : 為 dot )
- LISP_DS * l_Ptr ; // 指向該點的左節點
- LISP_DS * r_Ptr ; // 指向該點的右節點
- } ;
- typedef LISP_DS * LISP_Ptr ; // 定義一個新指令 'LISP_Ptr', 用途與 LISP_DS * XXX 相同。
- // ::::: 建樹類函數 Building Tree of Functions :::::
- void BuildLisp( int & contiScan, LISP_Ptr & lisp, Str_ & str, char & nextChar, int countLR ) ;
- bool Tree_CreateNode( LISP_Ptr & walker ) ;
- bool Tree_EndNode( LISP_Ptr & walker ) ;
- bool Tree_SetToken( LISP_Ptr & walker, Str_ str, int syntaxType ) ;
- bool Tree_SetDot( LISP_Ptr & walker, int dotType ) ;
- // ::::: 印樹類函數 Printing Tree of Functions :::::
- void PrintLisp( LISP_Ptr walker, char from_LR, int space ) ;
- bool StopPrint( LISP_Ptr lisp ) ;
- bool IsSoloToken( LISP_Ptr lisp ) ;
- // ::::: 切字元類函數 Get Token of Functions :::::
- int GetToken( Str_ & str, char & nextChar ) ;
- bool Check_Separation( char ch, char & nextChar ) ;
- int Syntax_Number( Str_ & str, char & nextChar, char & ch, int & successGet, int & stillScan ) ;
- int Syntax_String( Str_ & str, char & nextChar, char & ch, int & successGet, int & stillScan ) ;
- int Syntax_Dot( Str_ & str, char & nextChar, char & ch, int & successGet, int & stillScan ) ;
- int Syntax_Symbol( Str_ & str, char & nextChar, char & ch, int & successGet, int & stillScan ) ;
- void TokenReset( Str_ str, int syntaxType ) ;
- // ::::: 工具類函數 Tools Function :::::
- void CleanString( Str_ & str ) ;
- void SkipLine() ;
- void PrintWhiteSpace( int space ) ;
- // main - 好戲上場 :)
- int main() {
- scanf( "%d ", &uTestNum ) ;
- printf( "Welcome to OurScheme!\n" ) ;
- // 前置宣告。
- Str_ str = "\0" ;
- char nextChar = '\0' ;
- LISP_Ptr lisp_tree[ MAX_LISP_COUNT ] ; // 建立出 MAX_LISP_COUNT 個樹空間的陣列。
- int totalBuildCount = 0 ; // 總共當前已建立的樹之數量。
-
- // 建立 tree, 同時於該 function 進行資料 scan 的動作。
- // 此處的 contiScan 變數為 scanf 時, 若 EOF 則回傳 -1。
- for ( int i = 0, contiScan = 1 ; i < MAX_LISP_COUNT && contiScan != -1 ; i ++ ) {
- lisp_tree[i] = new LISP_DS(), lisp_tree[i]->l_Ptr = lisp_tree[i]->r_Ptr = NULL ;
- BuildLisp( contiScan, lisp_tree[i], str, nextChar, 0 ) ;
- totalBuildCount ++ ;
- } // for
-
- // 印出 tree, 須注意不滿 10 組樹將會顯示 Error message, 遇到 (exit), 也會立刻終止印出。
- bool stopPrint = StopPrint( lisp_tree[0] ) ; // 先判斷第一組樹是否為 (exit)
- for ( int i = 0 ; i < totalBuildCount && ! stopPrint ; i ++ ) {
- if ( ! IsSoloToken( lisp_tree[i] ) )
- printf( "\n> " ), PrintLisp( lisp_tree[i], 'S', 0 ) ;
- else
- if ( lisp_tree[i] != NULL )
- if ( lisp_tree[i]->l_Ptr != NULL )
- printf( "\n> %s\n", lisp_tree[i]->l_Ptr->str ) ;
- stopPrint = StopPrint( lisp_tree[i+1] ) ; // 預先判斷下一組樹是否為 (exit)
- } // for
-
- if ( totalBuildCount < 10 )
- printf( "ERROR : END-OF-FILE encountered when there should be more input\n\n" ) ;
- printf( "Thanks for using OurScheme!" ) ;
-
- return 0 ;
- } // main()
- // ::::: 建樹類函數 Building Tree of Functions :::::
- // BuildLisp : 建立一個完整的樹。
- void BuildLisp( int & synType, LISP_Ptr & lisp, Str_ & str, char & nextChar, int countLR ) {
- // 每次會先取得一個 token, 若 GetToken 回傳 -1 表示取得失敗 (可能為white space字元),
- // 成功取得字元後進行建樹動作, 以下為建樹步驟 :
- // 1. 若為上括號 - 新開一組節點空間 ; countLR + 1。
- // 2. 若為下括號 - 將最先遇到可存放 token 的節點存放 nil 的 token ; countLR - 1。
- // 3. 若為'.'DOT - 表示接下來的 token 與 token 連接有 DOT。
- // 4. 若為一般 token - 將最先遇到可存放 token 的節點使之存放 (存放之前先將其呈現方式轉換, 如小數點末三位...etc)。
- // 5. 當 countLR 為 0 時, 此組數據結束, BuildLisp 亦結束, 將此完成的樹回傳給 main。
- CleanString( str ) ; // 防止 error, 率先將字串清除。
- synType = GetToken( str, nextChar ) ; // nextChar 為被打回包票的字元, 他必須自成一格。
- if ( synType == -1 ) // synType 若讀到 EOF 則回傳 -1, 則結束繼續讀入建樹動作。
- return ;
-
- if ( strcmp( str, "" ) != 0 ) { // token 不為 null 才可進行判斷。
- if ( strcmp( str, "(" ) == 0 ) { // token 為 '(' 上括號。
- countLR ++ ;
- if ( countLR > 1 ) // 這裡比較特殊, 第一次遇到的括號不需要新開節點 (交給下一次的 token 吧!)。
- Tree_CreateNode( lisp ) ;
- } // if
- else if ( strcmp( str, ")" ) == 0 ) { // token 為 ')' 下括號。
- countLR -- ;
- Tree_EndNode( lisp ) ;
- } // else if
- else if ( strcmp( str, "." ) == 0 ) { // token 為 '.' DOT。
-
- } // else if
- else { // 一般 token 放入樹中。
- // if ( synType == SYN_FLOAT ) // 浮點數呈現方式轉換。
- Tree_CreateNode( lisp ) ;
- Tree_SetToken( lisp, str, synType );
- } // else
-
- if ( countLR == 0 ) // 左右括號的平均檢測, 左括號+1, 右括號-1, 為 0則完畢該樹建立。
- return ;
- } // if
-
- BuildLisp( synType, lisp, str, nextChar, countLR ) ;
- } // BuildLisp()
- // Tree_CreateNode : 節點新建, 用於 '(' 出現 與 新 token 放入前的前置作業。
- bool Tree_CreateNode( LISP_Ptr & walker ) {
- // 使用遞迴去旅行整棵樹, 將第一次遇到的 "該節點無 token 且雙向節點皆指向 NULL" 者新開節點並結束 function。
- if ( strcmp( walker->str, "" ) == 0 && walker->l_Ptr == NULL && walker->r_Ptr == NULL ) {
- walker->l_Ptr = new LISP_DS(), walker->r_Ptr = new LISP_DS() ;
- walker->l_Ptr->l_Ptr = walker->l_Ptr->r_Ptr = NULL ;
- walker->r_Ptr->l_Ptr = walker->r_Ptr->r_Ptr = NULL ;
- return true ;
- } // if
- else {
- if ( walker->l_Ptr != NULL )
- if ( Tree_CreateNode( walker->l_Ptr ) )
- return true ;
- if ( walker->r_Ptr != NULL )
- if ( Tree_CreateNode( walker->r_Ptr ) )
- return true ;
- return false ;
- } // else
- } // Tree_CreateNode()
- // Tree_EndNode : 節點完畢, 用於 ')'出現。
- // 使用遞迴去旅行整棵樹, 將第一次遇到的 "該節點無 token 且雙向節點皆指向 NULL" 存入 "nil" token 並結束 function。
- bool Tree_EndNode( LISP_Ptr & walker ) {
- if ( strcmp( walker->str, "" ) == 0 && walker->l_Ptr == NULL && walker->r_Ptr == NULL ) {
- strcpy( walker->str, "nil" ) ;
- return true ;
- } // if
- else {
- if ( walker->l_Ptr != NULL )
- if ( Tree_EndNode( walker->l_Ptr ) )
- return true ;
- if ( walker->r_Ptr != NULL )
- if ( Tree_EndNode( walker->r_Ptr ) )
- return true ;
- return false ;
- } // else
- } // Tree_EndNode()
- // Tree_SetToken : 放置 token 於節點當中。
- // 使用遞迴去旅行整棵樹, 將第一次遇到的 "該節點無 token 且雙向節點皆指向 NULL" 存入 token 並結束 function。
- bool Tree_SetToken( LISP_Ptr & walker, Str_ str, int syntaxType ) {
- if ( strcmp( walker->str, "" ) == 0 && walker->l_Ptr == NULL && walker->r_Ptr == NULL ) {
- if ( syntaxType == SYN_INT || syntaxType == SYN_FLOAT || syntaxType == SYN_NIL || syntaxType == SYN_T )
- TokenReset( str, syntaxType ) ; // 若為特殊 token, 他必須轉換後在儲存起來。
- strcpy( walker->str, str ) ;
- walker->synType = syntaxType ;
- return true ;
- } // if
- else {
- if ( walker->l_Ptr != NULL )
- if ( Tree_SetToken( walker->l_Ptr, str, syntaxType ) )
- return true ;
- if ( walker->r_Ptr != NULL )
- if ( Tree_SetToken( walker->r_Ptr, str, syntaxType ) )
- return true ;
- return false ;
- } // else
- } // Tree_SetToken()
-
- // Tree_SetDot : 放置 dot 於節點當中 (1 : 非DOT, 2 : 為DOT)。
- bool Tree_SetDot( LISP_Ptr & walker, int dotType ) {
-
-
- } // Tree_SetDot()
- // ::::: 印樹類函數 Printing Tree of Functions :::::
- // PrintLisp : 印出該樹。
- bool gSpace_Skip = true ;
- void PrintLisp( LISP_Ptr walker, char from_LR, int space ) {
- // from_LR 的用義為, 告訴遞迴的子函數, 他是左節點還是右節點 (S-Start 首節點, L-Left 左節點, R-Right 右節點)。
- // space 的用意是, 當前行數需要印出幾組空白作縮排。
- if ( walker->l_Ptr != NULL && walker->r_Ptr != NULL ) // 如果說 該節點的左節點與右節點的 token 皆為 "nil", 就別印了。
- if ( ( strcmp( walker->l_Ptr->str, "nil" ) == 0 && strcmp( walker->r_Ptr->str, "nil" ) == 0 ) ||
- ( strcmp( walker->l_Ptr->str, "nil" ) == 0 && strcmp( walker->r_Ptr->str, "nil" ) == 0 ) )
- return ;
-
- // 以下是印上括弧。
- if ( ( from_LR == 'S' || from_LR == 'L' ) && strcmp( walker->str, "" ) == 0 ) {
- if ( ! gSpace_Skip )
- PrintWhiteSpace( space ) ;
- space ++, gSpace_Skip = true ;
- printf( "( " ) ;
- } // if
- // 以下是印一般 token。
- if ( strcmp( walker->str, "nil" ) == 0 && from_LR == 'R' ) // 右節點的 nil 統一不印出來, 他只是象徵該 dotted pair 結束。
- ;
- else if ( strcmp( walker->str, "" ) != 0 ) { // 一般 token 皆須要列印出來。
- if ( ! gSpace_Skip )
- PrintWhiteSpace( space ) ;
- gSpace_Skip = false ;
- printf( "%s\n", walker->str ) ;
- } // else if
-
- // 以下是印下括弧。
- if ( strcmp( walker->str, "nil" ) == 0 && from_LR == 'R' ) {
- space -- ;
- PrintWhiteSpace( space ) ;
- printf( ")\n" ) ;
- } // if
-
- if ( walker->l_Ptr != NULL )
- PrintLisp( walker->l_Ptr, 'L', space ) ;
- if ( walker->r_Ptr != NULL )
- PrintLisp( walker->r_Ptr, 'R', space ) ;
- } // PrintLisp()
- // StopPrint : 何時停止? 遇到 (exit) 的時候ㄛ !
- // 內部儲存空間的樹必須為以下形態 :
- // 口 | 口 單一 token 無括號, 這個是不會停止的
- // ↙ ↘ | ↙ ↘
- // exit nil 此為 (exit) | exit 口 此為 exit
- bool StopPrint( LISP_Ptr lisp ) {
- if ( lisp != NULL )
- if ( lisp->l_Ptr != NULL && lisp->r_Ptr != NULL )
- if ( strcmp( lisp->l_Ptr->str, "exit" ) == 0 && strcmp( lisp->r_Ptr->str, "nil" ) == 0 )
- return true ;
-
- return false ;
- } // StopPrint()
- // isSoloToken : 是否為單一 token, 且無括號 ?
- bool IsSoloToken( LISP_Ptr lisp ) {
- if ( lisp != NULL )
- if ( lisp->l_Ptr != NULL && lisp->r_Ptr != NULL )
- if ( strcmp( lisp->l_Ptr->str, "" ) != 0 && strcmp( lisp->r_Ptr->str, "" ) == 0 )
- if ( lisp->r_Ptr->l_Ptr == NULL && lisp->r_Ptr->r_Ptr == NULL )
- return true ;
- return false ;
- } // IsSoloToken()
- // ::::: 切字元類函數 Get Token of Functions :::::
- // GetToken : 切切切字元。
- int GetToken( Str_ & str, char & nextChar ) {
- char ch = '\0' ; // 宣告 : 讀到的字元。
- int successGet = 1 ; // 宣告 : 是否成功讀到字元, 字元讀取失敗(EOF回傳 -1)。
- int stillScan = 1 ; // 宣告 : 是否要繼續讀取自元放入 token 中? (中斷原因遇到分離字元, 回傳-1)。
- int synType = 0 ; // 宣告 : 該 token 的類型, 共 10 類, 見置頂 enum。
-
- while ( successGet != -1 && stillScan != -1 ) {
- // 若 nextChar (此變數用途為, 被打回包票須自成一格的字元) 為 null,
- // 代表上一筆是正常 token, 未跟其他 token 連結在一起.
- // 1. nextChar 為 null 時, 再讀一個字元.
- // 2. nextChar 非 null 時, 不需再讀一個字元, 用 nextChar 去再切下一個 token.
- if ( nextChar == '\0' )
- successGet = scanf( "%c", & ch ) ;
- else
- ch = nextChar, nextChar = '\0' ;
-
- // white space類 : 若讀到空格或換行, 則此 token 切割完畢。
- if ( ch == ' ' || ch == '\n' )
- stillScan = -1 ;
- // 括弧類 : (回傳1)左括號 ; (回傳2)右括號。
- else if ( ch == '(' || ch == ')' ) {
- if ( ch == '(' )
- strcpy( str, "(" ), synType = SYN_LEFT_PAREN, stillScan = -1 ;
- else if ( ch == ')' )
- strcpy( str, ")" ), synType = SYN_RIGHT_PAREN, stillScan = -1 ;
- } // else if
- // 數字類 : (回傳3)整數 +123, -321 ; (回傳4)浮點數 -1.23, 3.21 ; (回傳10)Symbol 1.e, 1.5.8。
- // ASCII碼介於 0~9 且包含 +, - 兩符號。
- else if ( ( ch >= '0' && ch <= '9' ) || ch == '+' || ch == '-' ) {
- synType = Syntax_Number( str, nextChar, ch, successGet, stillScan ) ;
- } // else if
- // 字串類 : (回傳5)由雙引號開頭, 雙引號結尾, 若該字串不成立則回傳-1。
- else if ( ch == '"' ) {
- synType = Syntax_String( str, nextChar, ch, successGet, stillScan ) ;
- } // else if
- // DOT類 : (回傳4)浮點數 .0123 ; (回傳8)純DOT . ; (回傳10)Symbol .abc。
- else if ( ch == '.' ) {
- synType = Syntax_Dot( str, nextChar, ch, successGet, stillScan ) ;
- } // else if
- // 註解類 : 直到讀進 '\n'換行 或 EOF 才回傳。
- else if ( ch == ';' ) {
- SkipLine() ;
- } // else if
- // quote類 : (回傳9)單引號。
- else if ( ch == '\'' ) {
- strcpy( str, "\'" ), synType = SYN_QUOTE, stillScan = -1 ;
- } // else if
- // Symbol類 : (回傳6)nil, #f ; (回傳7)t, #t ; (回傳10)Symbol asd15a 15a.d.1。
- else {
- synType = Syntax_Symbol( str, nextChar, ch, successGet, stillScan ) ;
- } // else
- } // while
-
- if ( successGet == -1 ) // 讀到了 EOF, 結束所有建樹動作。
- return -1 ;
-
- return synType ; // 回傳該 token 類型。
- } // GetToken()
- // Check_Separation : 再各類的細分函數中, 若讀到以下字元將強制結束並將該字元設為 nextChar。
- // 分離字元有 ' '(空白), '\n'(換行), '"'(雙引號), '''(單引號), '('(上引號), ')'(下引號), ';'(分號)。
- bool Check_Separation( char ch, char & nextChar ) {
- if ( ch == ' ' || ch == '\n' || ch == '"' || ch == '\'' || ch == '(' || ch == ')' || ch == ';' ) {
- nextChar = ch ;
- return true ; // 是分離字元的其中一員, nextChar 改變。
- } // if
-
- return false ; // 並非分離字元的其中一員。
- } // Check_Separation()
- // Syntax_Number : 數字類細分 - (回傳3)整數 +123, -321 ; (回傳4)浮點數 -1.23, +.21 ; (回傳10)Symbol 1.e, 1.5.8。
- int Syntax_Number( Str_ & str, char & nextChar, char & ch, int & successGet, int & stillScan ) {
- str[ strlen( str ) ] = ch ; // 先將該 token 第一個字元放入。
- // 以下開始將為組合 token。
- while ( successGet != -1 && stillScan != -1 ) {
- successGet = scanf( "%c", & ch ) ; // 讀進下一個字元並將他傳去檢查是否為分離字元。
- if ( Check_Separation( ch, nextChar ) ) // 若是有分離字元存在, 就取消繼續組合 token。
- stillScan = -1 ;
- else
- str[ strlen( str ) ] = ch ;
- } // while
-
- // 以下開始將為 token 分類。
- int countPoint = 0 ; // 小數點計算
- for ( int i = 0 ; i < strlen( str ) ; i ++ )
- if ( str[i] == '.' ) // 若為 '.', 小數點總數上升。
- countPoint ++ ;
- // 第壹關 : 整數判斷(第一個字元允許 +,- ; 其餘字元只允許 0~9)。
- bool isInterger = true ;
- if ( countPoint == 0 ) {
- if ( str[0] == '+' || str[0] == '-' || ( str[0] >= '0' && str[0] <= '9' ) ) {
- for ( int i = 1 ; i < strlen( str ) ; i ++ ) // 若出現的字元出現非 0~9, 就不是整數 (從index = 1 開始判斷)
- if ( ! ( str[i] >= '0' && str[i] <= '9' ) )
- isInterger = false ;
- } // if
- else
- isInterger = false ;
- if ( isInterger )
- return SYN_INT ;
- } // if
- // 第貳關 : 浮點數判斷(只可出現一次小數點 ; 第一個字元允許 +,- ; 其餘字元只允許 0~9)。
- // 請問 .135 要考慮嗎 ? 不, 這種情況被歸類再 Syntax_Dot 中作處理, 但這裡有 +.123 要留意。)。
- bool isFloat = true ;
- if ( countPoint == 1 ) {
- if ( str[0] == '+' || str[0] == '-' || ( str[0] >= '0' && str[0] <= '9' ) ) {
- for ( int i = 1 ; i < strlen( str ) ; i ++ ) // 若出現的字元出現非 0~9或 ., 就不是浮點數 (從index = 1 開始判斷)
- if ( ! ( str[i] >= '0' && str[i] <= '9' ) && str[i] != '.' )
- isFloat = false ;
- } // if
- else
- isFloat = false ;
- if ( isFloat )
- return SYN_FLOAT ;
- } // if
- // 第参關 : 講了這麼多, 你就是 Symbol 啊 !
- return SYN_SYMBOL ;
- } // Syntax_Number()
- // Syntax_String : 字串類細分 - (回傳5)由雙引號開頭, 雙引號結尾, 若該字串不成立則回傳-1。
- int Syntax_String( Str_ & str, char & nextChar, char & ch, int & successGet, int & stillScan ) {
- str[ strlen( str ) ] = ch ;
- // 以下開始將為組合 token。
- while ( successGet != -1 && stillScan != -1 ) {
- successGet = scanf( "%c", & ch ) ; // 讀進下一個字元並放入 (若是 '\n'換行 , 則 ERROR)。
- str[ strlen( str ) ] = ch ;
- if ( ch == '"' ) // 讀到雙引號結束, 此 token 完畢
- stillScan = -1 ;
- else if ( ch == '\n' ) { // 讀到換行字元, 刪除此 token, 並且回報錯誤。
- stillScan = -1, CleanString( str ) ;
- return 0 ;
- } // else if
- } // while
-
- return SYN_STRING ;
- } // Syntax_String()
- // Syntax_Dot : DOT類細分 - (回傳4)浮點數 .0123 ; (回傳8)純DOT . ; (回傳10)Symbol .abc。
- int Syntax_Dot( Str_ & str, char & nextChar, char & ch, int & successGet, int & stillScan ) {
- str[ strlen( str ) ] = ch ; // 先將該 token 第一個字元放入。
- // 以下開始將為組合 token。
- while ( successGet != -1 && stillScan != -1 ) {
- successGet = scanf( "%c", & ch ) ; // 讀進下一個字元並將他傳去檢查是否為分離字元。
- if ( Check_Separation( ch, nextChar ) ) // 若是有分離字元存在, 就取消繼續組合 token。
- stillScan = -1 ;
- else
- str[ strlen( str ) ] = ch ;
- } // while
-
- // 以下開始將為 token 分類。
- int countPoint = 0 ; // 小數點計算
- for ( int i = 0 ; i < strlen( str ) ; i ++ )
- if ( str[i] == '.' ) // 若為 '.', 小數點總數上升。
- countPoint ++ ;
- // 第壹關 : 浮點數判斷(只可出現一次小數點 ; 其餘字元只允許 0~9)。
- bool isFloat = true ;
- if ( countPoint == 1 ) {
- for ( int i = 1 ; i < strlen( str ) ; i ++ ) // 若出現的字元出現非 0~9或 ., 就不是浮點數 (從index = 0 開始判斷)
- if ( ! ( str[i] >= '0' && str[i] <= '9' ) )
- isFloat = false ;
- if ( isFloat )
- return SYN_FLOAT ;
- } // if
- // 第貳關 : DOT判斷, 就只是一個 DOT 字串。
- if ( strcmp( str, "." ) == 0 )
- return SYN_DOT ;
- // 第参關 : 講了這麼多, 你就是 Symbol 啊 !
- return SYN_SYMBOL ;
- } // Syntax_Dot()
- // Syntax_Symbol : Symbol類細分 - (回傳3)整數 +123, -321 ; (回傳4)浮點數 -1.23, 3.21 ; (回傳10)Symbol 1.e, 1.5.8。
- int Syntax_Symbol( Str_ & str, char & nextChar, char & ch, int & successGet, int & stillScan ) {
- str[ strlen( str ) ] = ch ; // 先將該 token 第一個字元放入。
- // 以下開始將為組合 token。
- while ( successGet != -1 && stillScan != -1 ) {
- successGet = scanf( "%c", & ch ) ; // 讀進下一個字元並將他傳去檢查是否為分離字元。
- if ( Check_Separation( ch, nextChar ) ) // 若是有分離字元存在, 就取消繼續組合 token。
- stillScan = -1 ;
- else
- str[ strlen( str ) ] = ch ;
- } // while
-
- // 以下開始將為 token 分類。
- int countPoint = 0 ; // 小數點計算
- for ( int i = 0 ; i < strlen( str ) ; i ++ )
- if ( str[i] == '.' ) // 若為 '.', 小數點總數上升。
- countPoint ++ ;
- // 第壹關 : 整數判斷(第一個字元允許 +,- ; 其餘字元只允許 0~9)。
- bool isInterger = true ;
- if ( countPoint == 0 ) {
- if ( str[0] == '+' || str[0] == '-' || ( str[0] >= '0' && str[0] <= '9' ) ) {
- for ( int i = 1 ; i < strlen( str ) ; i ++ ) // 若出現的字元出現非 0~9, 就不是整數 (從index = 1 開始判斷)
- if ( ! ( str[i] >= '0' && str[i] <= '9' ) )
- isInterger = false ;
- } // if
- else
- isInterger = false ;
- if ( isInterger )
- return SYN_INT ;
- } // if
- // 第貳關 : 浮點數判斷(只可出現一次小數點 ; 第一個字元允許 +,- ; 其餘字元只允許 0~9)。
- // 請問 .135 要考慮嗎 ? 不, 這種情況被歸類再 Syntax_Dot 中作處理, 但這裡有 +.123 要留意。)。
- bool isFloat = true ;
- if ( countPoint == 1 ) {
- if ( str[0] == '+' || str[0] == '-' || ( str[0] >= '0' && str[0] <= '9' ) ) {
- for ( int i = 1 ; i < strlen( str ) ; i ++ ) // 若出現的字元出現非 0~9或 ., 就不是浮點數 (從index = 1 開始判斷)
- if ( ! ( str[i] >= '0' && str[i] <= '9' ) && str[i] != '.' )
- isFloat = false ; // isFloat = false ;
- } // if
- else
- isFloat = false ;
- if ( isFloat )
- return SYN_FLOAT ;
- } // if
- // 第参關 : NIL 判斷。
- if ( strcmp( str, "nil" ) == 0 || strcmp( str, "#f" ) == 0 )
- return SYN_NIL ;
- // 第肆關 : #t 判斷。
- if ( strcmp( str, "t" ) == 0 || strcmp( str, "#t" ) == 0 )
- return SYN_T ;
- // 第伍關 : 單引號判斷。
- if ( strcmp( str, "\'" ) == 0 )
- return SYN_QUOTE ;
- // 第陸關 : 講了這麼多, 你就是 Symbol 啊 !
- return SYN_SYMBOL ;
- } // Syntax_Symbol()
- // TokenReset : 這個 token 特殊類別需額外修改 (包含 SYN_INT、SYN_FLOAT、SYN_NIL、SYN_T)。
- void TokenReset( Str_ str, int syntaxType ) {
- if ( syntaxType == SYN_INT ) {
- int tempInt = atoi( str ) ;
- sprintf( str, "%d", tempInt ) ;
- } // if
- else if ( syntaxType == SYN_FLOAT ) {
- float tempFloat = atof( str ) ;
- sprintf( str, "%.3f", tempFloat ) ;
- } // else if
- else if ( syntaxType == SYN_NIL ) {
- strcpy( str, "nil" ) ;
- } // else if
- else if ( syntaxType == SYN_T ) {
- strcpy( str, "#t" ) ;
- } // else if
- } // TokenReset()
- // ::::: 工具類函數 Tools of Functions :::::
- // CleanString : 字串內容完全清除。
- void CleanString( Str_ & str ) {
- for ( int i = 0 ; i < STRING_LENGHT ; i ++ )
- str[i] = '\0' ;
- } // CleanString()
- // SkipLine : 遇到註解時的跳行字元 (直到 '\n' or EOF 時 return)。
- void SkipLine() {
- char ch = '\0' ;
- // out 為判斷 EOF 的依據。
- for ( int out = scanf( "%c", & ch ) ; ch != '\n' && out != -1 ; out = scanf( "%c", & ch ) )
- if ( ch != '\n' ) ;
- } // SkipLine()
- // PrintWhiteSpace : 印出縮排用的空白。
- void PrintWhiteSpace( int space ) {
- for ( int i = 0 ; i < space ; i ++ )
- printf( " " ) ;
- } // PrintWhiteSpace()
複製代碼 |
|