33# vim: ts=4:sw=4:et:
44
55import sys
6- import os
76import re
87
98from io import StringIO
1211
1312import src .api .optimize
1413
15- from src .api import errmsg
1614from src .api import config
1715from src .api import debug
1816from src .api import global_ as gl
2321from src .api .config import OPTIONS
2422from src .api .utils import open_file
2523
26- from . import zxbparser
27- from . import zxblex
28- from . import args_parser
24+ from src . zxbc import zxbparser
25+ from src . zxbc import zxblex
26+ from src . zxbc . args_config import parse_options , FileType
2927
3028
3129RE_INIT = re .compile (r'^#[ \t]*init[ \t]+((?:[._a-zA-Z][._a-zA-Z0-9]*)|(?:"[._a-zA-Z][._a-zA-Z0-9]*"))[ \t]*$' ,
@@ -72,8 +70,8 @@ def output(memory, ofile=None):
7270
7371def main (args = None , emitter = None ):
7472 """ Entry point when executed from command line.
75- You can use zxbc.py as a module with import, and this
76- function won't be executed.
73+ zxbc can be used as python module. If so, bear in mind this function
74+ won't be executed unless explicitly called .
7775 """
7876 # region [Initialization]
7977 config .init ()
@@ -84,143 +82,11 @@ def main(args=None, emitter=None):
8482 asmparse .init ()
8583 # endregion
8684
87- parser = args_parser .parser ()
88- options = parser .parse_args (args = args )
89-
90- if os .path .isfile (options .config_file ):
91- if src .api .config .load_config_from_file (options .config_file , src .api .config .ConfigSections .ZXBC ):
92- src .api .errmsg .info (f"Config file { options .config_file } loaded" )
93-
94- # ------------------------------------------------------------
95- # Setting of internal parameters according to command line
96- # ------------------------------------------------------------
97- OPTIONS .debug_level = options .debug
98- OPTIONS .optimization_level = options .optimize
99- OPTIONS .output_filename = options .output_file
100- OPTIONS .stderr_filename = options .stderr
101- OPTIONS .array_base = options .array_base
102- OPTIONS .string_base = options .string_base
103- OPTIONS .sinclair = options .sinclair
104- OPTIONS .heap_size = options .heap_size
105- OPTIONS .memory_check = options .debug_memory
106- OPTIONS .strict_bool = options .strict_bool or OPTIONS .sinclair
107- OPTIONS .array_check = options .debug_array
108- OPTIONS .emit_backend = options .emit_backend
109- OPTIONS .enable_break = options .enable_break
110- OPTIONS .explicit = options .explicit
111- OPTIONS .memory_map = options .memory_map
112- OPTIONS .strict = options .strict
113- OPTIONS .headerless = options .headerless
114- OPTIONS .zxnext = options .zxnext
115- OPTIONS .expected_warnings = gl .EXPECTED_WARNINGS = options .expect_warnings
116- OPTIONS .hide_warning_codes = options .hide_warning_codes
117-
118- if options .arch not in arch .AVAILABLE_ARCHITECTURES :
119- parser .error (f"Invalid architecture '{ options .arch } '" )
120- return 2
121-
122- OPTIONS .architecture = options .arch
123- arch .set_target_arch (options .arch )
85+ options = parse_options (args )
86+ arch .set_target_arch (OPTIONS .architecture )
12487 backend = arch .target .backend
125-
126- # region [Enable/Disable Warnings]
127- enabled_warnings = set (options .enable_warning or [])
128- disabled_warnings = set (options .disable_warning or [])
129- duplicated_options = [f"W{ x } " for x in enabled_warnings .intersection (disabled_warnings )]
130-
131- if duplicated_options :
132- parser .error (f"Warning(s) { ', ' .join (duplicated_options )} cannot be enabled "
133- f"and disabled simultaneously" )
134- return 2
135-
136- for warn_code in enabled_warnings :
137- errmsg .enable_warning (warn_code )
138-
139- for warn_code in disabled_warnings :
140- errmsg .disable_warning (warn_code )
141-
142- # endregion
143-
144- OPTIONS .org = src .api .utils .parse_int (options .org )
145- if OPTIONS .org is None :
146- parser .error ("Invalid --org option '{}'" .format (options .org ))
147-
148- if options .defines :
149- for i in options .defines :
150- macro = list (i .split ('=' , 1 ))
151- name = macro [0 ]
152- val = '' .join (macro [1 :])
153- OPTIONS .__DEFINES [name ] = val
154- zxbpp .ID_TABLE .define (name , value = val , lineno = 0 )
155-
156- if OPTIONS .sinclair :
157- OPTIONS .array_base = 1
158- OPTIONS .string_base = 1
159- OPTIONS .strictBool = True
160- OPTIONS .case_insensitive = True
161-
162- if options .ignore_case :
163- OPTIONS .case_insensitive = True
164-
165- debug .ENABLED = OPTIONS .debug_level > 0
166-
167- if int (options .tzx ) + int (options .tap ) + int (options .asm ) + int (options .emit_backend ) + \
168- int (options .parse_only ) > 1 :
169- parser .error ("Options --tap, --tzx, --emit-backend, --parse-only and --asm are mutually exclusive" )
170- return 3
171-
172- if options .basic and not options .tzx and not options .tap :
173- parser .error ('Option --BASIC and --autorun requires --tzx or tap format' )
174- return 4
175-
176- if options .append_binary and not options .tzx and not options .tap :
177- parser .error ('Option --append-binary needs either --tap or --tzx' )
178- return 5
179-
180- if options .asm and options .memory_map :
181- parser .error ('Option --asm and --mmap cannot be used together' )
182- return 6
183-
184- OPTIONS .use_basic_loader = options .basic
185- OPTIONS .autorun = options .autorun
186-
187- if options .tzx :
188- OPTIONS .output_file_type = 'tzx'
189- elif options .tap :
190- OPTIONS .output_file_type = 'tap'
191- elif options .asm :
192- OPTIONS .output_file_type = 'asm'
193- elif options .emit_backend :
194- OPTIONS .output_file_type = 'ic'
195-
196- args = [options .PROGRAM ]
197- if not os .path .exists (options .PROGRAM ):
198- parser .error ("No such file or directory: '%s'" % args [0 ])
199- return 2
200-
201- if OPTIONS .memory_check :
202- OPTIONS .__DEFINES ['__MEMORY_CHECK__' ] = ''
203- zxbpp .ID_TABLE .define ('__MEMORY_CHECK__' , lineno = 0 )
204-
205- if OPTIONS .array_check :
206- OPTIONS .__DEFINES ['__CHECK_ARRAY_BOUNDARY__' ] = ''
207- zxbpp .ID_TABLE .define ('__CHECK_ARRAY_BOUNDARY__' , lineno = 0 )
208-
209- if OPTIONS .enable_break :
210- OPTIONS .__DEFINES ['__ENABLE_BREAK__' ] = ''
211- zxbpp .ID_TABLE .define ('__ENABLE_BREAK__' , lineno = 0 )
212-
213- OPTIONS .include_path = options .include_path
214- OPTIONS .input_filename = zxbparser .FILENAME = \
215- os .path .basename (args [0 ])
216-
217- if not OPTIONS .output_filename :
218- OPTIONS .output_filename = \
219- os .path .splitext (os .path .basename (OPTIONS .input_filename ))[0 ] + os .path .extsep + \
220- OPTIONS .output_file_type
221-
222- if OPTIONS .stderr_filename :
223- OPTIONS .stderr = open_file (OPTIONS .stderr_filename , 'wt' , 'utf-8' )
88+ args = [options .PROGRAM ] # Strip out other options, because they're already set in the OPTIONS container
89+ input_filename = options .PROGRAM
22490
22591 zxbpp .setMode ('basic' )
22692 zxbpp .main (args )
@@ -297,7 +163,7 @@ def main(args=None, emitter=None):
297163 # Now filter them against the preprocessor again
298164 zxbpp .setMode ('asm' )
299165 zxbpp .OUTPUT = ''
300- zxbpp .filter_ (asm_output , args [ 0 ] )
166+ zxbpp .filter_ (asm_output , filename = input_filename )
301167
302168 # Now output the result
303169 asm_output = zxbpp .OUTPUT .split ('\n ' )
@@ -318,7 +184,7 @@ def main(args=None, emitter=None):
318184 + ['%s:' % backend .DATA_END_LABEL , '%s:' % backend .MAIN_LABEL ] \
319185 + asm_output + backend .emit_end ()
320186
321- if options . asm : # Only output assembler file
187+ if OPTIONS . output_file_type == FileType . ASM : # Only output assembler file
322188 with open_file (OPTIONS .output_filename , 'wt' , 'utf-8' ) as output_file :
323189 output (asm_output , output_file )
324190 elif not options .parse_only :
0 commit comments