SCM Repository
Annotation of /sml/trunk/src/cm/parse/parse.sml
Parent Directory
|
Revision Log
Revision 297 - (view) (download)
1 : | blume | 270 | (* |
2 : | * Parser for CM description files. | ||
3 : | * | ||
4 : | * (C) 1999 Lucent Technologies, Bell Laboratories | ||
5 : | * | ||
6 : | * Author: Matthias Blume (blume@kurims.kyoto-u.ac.jp) | ||
7 : | *) | ||
8 : | blume | 268 | signature CMPARSE = sig |
9 : | blume | 286 | val parse : Primitive.configuration -> AbsPath.t -> CMSemant.group option |
10 : | blume | 268 | end |
11 : | |||
12 : | structure CMParse :> CMPARSE = struct | ||
13 : | |||
14 : | val lookAhead = 30 | ||
15 : | |||
16 : | structure S = GenericVC.Source | ||
17 : | structure EM = GenericVC.ErrorMsg | ||
18 : | structure SM = GenericVC.SourceMap | ||
19 : | structure P = GenericVC.Control.Print | ||
20 : | |||
21 : | structure CMLrVals = CMLrValsFun (structure Token = LrParser.Token) | ||
22 : | structure CMLex = CMLexFun (structure Tokens = CMLrVals.Tokens) | ||
23 : | structure CMParse = | ||
24 : | JoinWithArg (structure ParserData = CMLrVals.ParserData | ||
25 : | structure Lex = CMLex | ||
26 : | structure LrParser = LrParser) | ||
27 : | |||
28 : | blume | 286 | fun parse primconf group = let |
29 : | blume | 270 | |
30 : | blume | 286 | val groupreg = GroupReg.new () |
31 : | val fnpolicy = FilenamePolicy.default | ||
32 : | val params = { groupreg = groupreg, | ||
33 : | fnpolicy = fnpolicy, | ||
34 : | blume | 295 | primconf = primconf, |
35 : | keep_going = false } | ||
36 : | blume | 268 | |
37 : | blume | 294 | val gc = ref AbsPathMap.empty (* the "group cache" *) |
38 : | blume | 273 | |
39 : | blume | 294 | fun mparse (group, groupstack) = |
40 : | case AbsPathMap.find (!gc, group) of | ||
41 : | SOME g => g | ||
42 : | | NONE => let | ||
43 : | val g = parse' (group, groupstack) | ||
44 : | in | ||
45 : | gc := AbsPathMap.insert (!gc, group, g); | ||
46 : | g | ||
47 : | end | ||
48 : | blume | 273 | |
49 : | blume | 294 | and parse' (group, groupstack) = let |
50 : | blume | 286 | (* checking for cycles among groups and printing them nicely *) |
51 : | blume | 294 | fun findCycle ([], _) = [] |
52 : | | findCycle ((h as (g, (s, p1, p2))) :: t, cyc) = | ||
53 : | if AbsPath.compare (g, group) = EQUAL then rev (h :: cyc) | ||
54 : | else findCycle (t, h :: cyc) | ||
55 : | fun report ((g, (s, p1, p2)), hist) = let | ||
56 : | fun pphist pps = let | ||
57 : | fun loop (_, []) = () | ||
58 : | | loop (g0, (g, (s, p1, p2)) :: t) = let | ||
59 : | val s = EM.matchErrorString s (p1, p2) | ||
60 : | in | ||
61 : | PrettyPrint.add_string pps s; | ||
62 : | PrettyPrint.add_string pps ": importing "; | ||
63 : | PrettyPrint.add_string pps (AbsPath.spec g0); | ||
64 : | PrettyPrint.add_newline pps; | ||
65 : | loop (g, t) | ||
66 : | end | ||
67 : | blume | 273 | in |
68 : | blume | 294 | PrettyPrint.add_newline pps; |
69 : | loop (g, hist) | ||
70 : | blume | 273 | end |
71 : | in | ||
72 : | blume | 294 | EM.error s (p1, p2) EM.COMPLAIN |
73 : | ("group hierarchy forms a cycle with " ^ | ||
74 : | AbsPath.spec group) | ||
75 : | pphist | ||
76 : | blume | 273 | end |
77 : | |||
78 : | blume | 294 | (* normal processing -- used when there is no cycle to report *) |
79 : | fun normal_processing () = let | ||
80 : | val currentDir = AbsPath.dir group | ||
81 : | val context = AbsPath.relativeContext (AbsPath.dir group) | ||
82 : | val filename = AbsPath.name group | ||
83 : | val _ = Say.vsay (concat ["[scanning ", filename, "]\n"]) | ||
84 : | val stream = TextIO.openIn filename | ||
85 : | val errcons = { linewidth = !P.linewidth, | ||
86 : | flush = P.flush, | ||
87 : | consumer = P.say } | ||
88 : | val source = S.newSource (filename, 1, stream, false, errcons) | ||
89 : | val sourceMap = #sourceMap source | ||
90 : | val _ = GroupReg.register groupreg (group, source) | ||
91 : | |||
92 : | blume | 297 | (* We can hard-wire the source into this |
93 : | * error function because the function is only for | ||
94 : | * immediate use and doesn't get stored into persistent | ||
95 : | * data structures. *) | ||
96 : | fun error r m = | ||
97 : | EM.error source r EM.COMPLAIN m EM.nullErrorBody | ||
98 : | |||
99 : | blume | 294 | (* recParse returns a group (not an option). |
100 : | * This function is used to parse aliases and sub-groups. | ||
101 : | * Errors are propagated by explicitly setting the | ||
102 : | * "anyErrors" flag of the parent group. *) | ||
103 : | fun recParse (p1, p2) p = let | ||
104 : | val groupstack' = (group, (source, p1, p2)) :: groupstack | ||
105 : | blume | 286 | in |
106 : | blume | 294 | case mparse (p, groupstack') of |
107 : | NONE => (#anyErrors source := true; | ||
108 : | CMSemant.emptyGroup group) | ||
109 : | | SOME res => res | ||
110 : | blume | 286 | end |
111 : | blume | 294 | handle exn as IO.Io _ => |
112 : | (error (p1, p2) (General.exnMessage exn); | ||
113 : | CMSemant.emptyGroup group) | ||
114 : | |||
115 : | blume | 297 | fun doMember (p, p1, p2, c) = |
116 : | blume | 294 | CMSemant.member (params, recParse (p1, p2)) |
117 : | blume | 297 | { sourcepath = p, class = c, |
118 : | group = (group, (p1, p2)) } | ||
119 : | blume | 294 | |
120 : | val lexarg = let | ||
121 : | (* local state *) | ||
122 : | val depth = ref 0 | ||
123 : | val curstring = ref [] | ||
124 : | val startpos = ref 0 | ||
125 : | val instring = ref false | ||
126 : | (* handling comments *) | ||
127 : | fun enterC () = depth := !depth + 1 | ||
128 : | fun leaveC () = let | ||
129 : | val d = !depth - 1 | ||
130 : | in | ||
131 : | depth := d; | ||
132 : | d = 0 | ||
133 : | end | ||
134 : | (* handling strings *) | ||
135 : | fun newS pos = | ||
136 : | (instring := true; curstring := []; startpos := pos) | ||
137 : | fun addS c = curstring := c :: !curstring | ||
138 : | fun addSC (s, offs) = | ||
139 : | addS (chr (ord (String.sub (s, 2)) - offs)) | ||
140 : | fun addSN (s, pos) = let | ||
141 : | val ns = substring (s, 1, 3) | ||
142 : | val n = Int.fromString ns | ||
143 : | in | ||
144 : | addS (chr (valOf n)) | ||
145 : | handle _ => | ||
146 : | error (pos, pos + size s) | ||
147 : | ("illegal decimal char spec: " ^ ns) | ||
148 : | end | ||
149 : | fun getS (pos, tok) = | ||
150 : | (instring := false; | ||
151 : | tok (implode (rev (!curstring)), !startpos, pos)) | ||
152 : | (* handling EOF *) | ||
153 : | fun handleEof () = let | ||
154 : | val pos = SM.lastChange sourceMap | ||
155 : | in | ||
156 : | if !depth > 0 then | ||
157 : | error (pos, pos) | ||
158 : | "unexpected end of input in comment" | ||
159 : | else if !instring then | ||
160 : | error (pos, pos) | ||
161 : | "unexpected end of input in string" | ||
162 : | else (); | ||
163 : | pos | ||
164 : | end | ||
165 : | (* handling line breaks *) | ||
166 : | fun newline pos = SM.newline sourceMap pos | ||
167 : | in | ||
168 : | { enterC = enterC, | ||
169 : | leaveC = leaveC, | ||
170 : | newS = newS, | ||
171 : | addS = addS, | ||
172 : | addSC = addSC, | ||
173 : | addSN = addSN, | ||
174 : | getS = getS, | ||
175 : | handleEof = handleEof, | ||
176 : | newline = newline, | ||
177 : | error = error } | ||
178 : | end | ||
179 : | |||
180 : | fun inputc k = TextIO.input stream | ||
181 : | |||
182 : | val lexer = CMLex.makeLexer inputc lexarg | ||
183 : | val tokenStream = LrParser.Stream.streamify lexer | ||
184 : | val (parseResult, _) = | ||
185 : | CMParse.parse (lookAhead, tokenStream, | ||
186 : | fn (s,p1,p2) => error (p1, p2) s, | ||
187 : | blume | 297 | (group, context, error, recParse, |
188 : | doMember, params)) | ||
189 : | blume | 268 | in |
190 : | blume | 294 | TextIO.closeIn stream; |
191 : | if !(#anyErrors source) then NONE | ||
192 : | else SOME parseResult | ||
193 : | blume | 268 | end |
194 : | blume | 294 | handle LrParser.ParseError => NONE |
195 : | blume | 268 | in |
196 : | blume | 294 | case findCycle (groupstack, []) of |
197 : | h :: t => (report (h, t); NONE) | ||
198 : | | [] => normal_processing () | ||
199 : | blume | 268 | end |
200 : | blume | 294 | |
201 : | blume | 268 | in |
202 : | blume | 294 | mparse (group, []) |
203 : | blume | 274 | end |
204 : | blume | 268 | end |
root@smlnj-gforge.cs.uchicago.edu | ViewVC Help |
Powered by ViewVC 1.0.0 |