Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
lfa:lab03-dfa-regexp [2020/10/22 11:26] pdmatei |
lfa:lab03-dfa-regexp [2021/10/16 18:57] (current) pdmatei |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== DFA and RegExp Exercises ====== | + | ====== 4. Regular expressions ====== |
- | **Exercise 1. ** Write a Regex for IP addresses. | + | ===== 4.1. Formation rules (concatenation, reunion, Kleene star) ===== |
- | **Exercise 2. ** Concatenation and Kleene operators applied on languages: | + | **4.1.1.** |
- | **2.1.** | + | $math[A=\{ 0^{2k} \mid k \geq 1 \}] |
- | $math[A =\{ 0^{2k} \text{ | k \geq 1} \}] | + | |
$ B = \{0, \epsilon \}$ | $ B = \{0, \epsilon \}$ | ||
Line 13: | Line 12: | ||
\\ | \\ | ||
- | **2.2.** | + | **4.1.2.** |
- | $ A = \{ 0^n 1^n \text{| n \geq 1} \} $ | + | $math[A = \{ 0^n 1^n \mid n \geq 1 \}] |
\\ | \\ | ||
- | $ B = \{ 1^n \text{ | n \geq 1} \} $ | + | $ B = \{ 1^n \mid n \geq 1 \} $ |
\\ | \\ | ||
$ AB = ? $ \\ $ BA = ? $ | $ AB = ? $ \\ $ BA = ? $ | ||
- | **2.3.** | + | **4.1.3.** |
$ A = \emptyset $ | $ A = \emptyset $ | ||
\\ | \\ | ||
- | $ B = \{ 1^n \text{ | n \geq 1} \} $ | + | $ B = \{ 1^n \mid n \geq 1 \} $ |
\\ | \\ | ||
$ AB = ? $ | $ AB = ? $ | ||
Line 32: | Line 31: | ||
\\ | \\ | ||
- | **Exercise 3.** Writing Regular Expressions | + | ===== 4.2. Writing Regular Expressions ===== |
- | \\ | + | |
- | **3.1.** Write a regular expression for the language of arithmetic expressions containing +, * and numbers. | + | **4.2.1.** Write a regular expression for the language of arithmetic expressions containing +, * and numbers. |
**Hint:** you can abbreviate $ 0 \cup 1 \cup ... \cup 9 $ by $ [0-9] $ | **Hint:** you can abbreviate $ 0 \cup 1 \cup ... \cup 9 $ by $ [0-9] $ | ||
- | **3.2.** Write a regular expression for $ L = \{ \omega \text{ in } \text{{0,1}} ^* \text{ | every sequence of consecutive zeros appears before ANY sequence of consecutive ones} \} $ | + | **4.2.2.** Write a regular expression for $ L = \{ \omega \text{ in } \text{{0,1}} ^* \text{ | EVERY sequence of two or more consecutive zeros appears before ANY sequence of two or more consecutive ones} \} $ |
- | **Exercise 4.** Write a DFA for $ L(( 10 \cup 0) ^* ( 1 \cup \epsilon )) $ | + | **4.2.3.** Write a DFA for $ L(( 10 \cup 0) ^* ( 1 \cup \epsilon )) $ |
- | **Exercise 5.** Write a regular expression which generates the accepted language of A: | + | **4.2.4.** Write a regular expression which generates the accepted language of A: |
{{:lfa:graf1.png?200|}} | {{:lfa:graf1.png?200|}} | ||
- | **Exercise 6.** Simplify the regular expression you found. | + | **4.2.5.** Simplify the regular expression you found. |
+ | |||
+ | **4.2.6.** Describe as precisely as possible the language generated by $math[(1 \cup 1(01^*0)1)^*] | ||
+ | |||
+ | |||
+ | ===== 4.3. Regex implementation (Python) ===== | ||
+ | |||
+ | ==== Inheritance and isinstance ==== | ||
+ | |||
+ | Python supports multiple class inheritance, however, in the spirit of it's dynamical typing strategy, it does not enforce method implementation. Hence - interfaces or abstract classes do not exist per se. | ||
+ | |||
+ | The following example illustrates class inheritance, as well as ''isinstance'': | ||
+ | <code python> | ||
+ | class Point2D: | ||
+ | # the class constructor. | ||
+ | def __init__(self,x,y): | ||
+ | self.x = x | ||
+ | self.y = y | ||
+ | |||
+ | def fun(self,a): | ||
+ | return a+1 | ||
+ | |||
+ | # class Point3D inherits Point2D | ||
+ | class Point3D(Point2D): | ||
+ | |||
+ | def __init__(self,x,y,z): | ||
+ | # using super, we call the parent class constructor | ||
+ | super().__init__(x,y) | ||
+ | # an alternative syntax with the same effects: | ||
+ | # super(Point3D,self).__init__(x,y) | ||
+ | self.z = z | ||
+ | |||
+ | def fun(self,a): | ||
+ | return a + 2 | ||
+ | |||
+ | |||
+ | p = Point3D(1,2,3) | ||
+ | print(p.fun(1)) | ||
+ | |||
+ | # another illustration of super - we use it to call fun from the parent class. | ||
+ | # super(X,O).f() will call function f from the __parent__ of type X, of object O. | ||
+ | print(super(Point3D,p).fun(1)) | ||
+ | |||
+ | # usage of isinstance to see if an object is an instance of a class (or it's parent) | ||
+ | if isinstance(p,Point3D): | ||
+ | print("Point3D") | ||
+ | |||
+ | if isinstance(p,Point2D): | ||
+ | print("Point2D") | ||
+ | |||
+ | </code> | ||
+ | |||
+ | **4.3.1.** Write a class hierarchy for Regular Expressions, and add the ''__str__'' function for each of them. Implement a constructor which reads a Regular Expression in **Prenex form**, from a string. The prenex form is illustrated below via examples: | ||
+ | |||
+ | <code Python> | ||
+ | # a* | ||
+ | s = "STAR a" | ||
+ | |||
+ | # ab | ||
+ | s = "CONCAT a b" | ||
+ | |||
+ | # a U b | ||
+ | s = "UNION a b" | ||
+ | |||
+ | # (a U b)*c* | ||
+ | s = "CONCAT STAR UNION a b STAR c" | ||
+ | </code> | ||
+ | |||
+ | Hints: | ||
+ | * To properly read a regular expression, you need a **state** of the parsing process, as well as information about what was parsed. What kind of data-structure is necessary for this step? This data-structure will be widely-used later, when we discuss Push-down Automata. | ||
+ | |||
+ | <hidden More hints> | ||
+ | The following table illustrates the string parsing and stack contents (ADT style) for the last example. | ||
+ | ^ String contents ^ Stack ^ | ||
+ | | ''CONCAT STAR UNION a b STAR c'' | Void | | ||
+ | | ''STAR UNION a b STAR c'' | Push(Concat(?,?),Void) | | ||
+ | | ''UNION a b STAR c'' | Push(Star(?), Push(Concat(?,?),Void)) | | ||
+ | | ''a b STAR c'' | Push(Union(?,?), Push(Star(?), Push(Concat(?,?),Void))) | | ||
+ | | ''b STAR c'' | Push(a, Push(Union(?,?), Push(Star(?), Push(Concat(?,?),Void)))) | | ||
+ | | ''b STAR c'' | Push(Union(a,?), Push(Star(?), Push(Concat(?,?),Void))) | | ||
+ | | ''STAR c'' | Push(b, Push(Union(a,?), Push(Star(?), Push(Concat(?,?),Void)))) | | ||
+ | | ''STAR c'' | Push(Union(a,b), Push(Star(?), Push(Concat(?,?),Void))) | | ||
+ | | ''STAR c'' | Push(Star(Union(a,b)), Push(Concat(?,?),Void))) | | ||
+ | | ''STAR c'' | Push(Concat(Star(Union(a,b)),?),Void))) | | ||
+ | | ''c'' | Push(Star(?),Push(Concat(Star(Union(a,b)),?),Void)))) | | ||
+ | | | Push(c, Push(Star(?),Push(Concat(Star(Union(a,b)),?),Void))))) | | ||
+ | | | Push(Star(c),Push(Concat(Star(Union(a,b)),?),Void)))) | | ||
+ | | | Push(Concat(Star(Union(a,b)),Star(c)),Void)))) | | ||
+ | |||
+ | The string has been consumed and the stack holds one expression, thus the result is: ''Concat(Star(Union(a,b)),Star(c))''. | ||
+ | |||
+ | </hidden> | ||
+ | |||
+ | ===== 4.4. Regex implementation (Haskell) ===== | ||
+ | |||
+ | **4.4.1.** Implement the ADT ''Regex''. | ||
+ | |||
+ | **4.4.2.** Enrol the type in class ''Show''. | ||
+ | **4.4.3.** Write a function which takes a string containing a regex in prenex form (see the Python exercises) and returns a ''Regex''. ***Hint:** use two mutually recursive functions and see the hints regarding the stack from the Python implementation section. | ||